ESP8266_07----------------PWM呼吸灯

先看下的效果:

呼吸灯

1.硬件电路:

---------------------------LED的阴极与我们的GPIO4相连。----------------------------

2.PWM介绍:

PWM

英文名为
Pulse Width Modulation
,是脉冲宽度调制的缩写,通过对一系列脉冲的宽度    进行调制,来等效地获得所需要的波形(含形状和幅值)。我们通过连续改变占空比就可以控制LED灯的亮度,从而实现呼吸灯的效果。
占空比:是指在一个脉冲循环内,通电时间相对于总时间所占的比例(也就是说高电平时间占的      比例)。

使用时的注意事项:

1.PWM
输出和硬件定时器不能够同时使用,因为他们使用的是同一个硬件。
2.
使用
PWM
输出的时候不支持进入
Deep Sleep
自动睡眠模式。
3.PWM
使用
NMI
中断,最多可以扩展
8

PWM
输出,但是
8

PWM
的周期相同,占空比可       以不同。
4.PWM
的分辨率可最高达到
45ns
,能够稳定输出的
PWM
波信号周期为1000us-10000us,对应     频率为
1kHz-100Hz

3.用到的函数:

PWM 的所有接口文件在“pwm.h”内声明

1.pwm_param结构体:

struct pwm_param {
    uint32 period;//周期
    uint32 freq;  //频率
    uint32  duty[PWM_CHANNEL_NUM_MAX];  //PWM_CHANNEL<=8 //八个通道的各自占空比
};
2..初始化
PWM
配置,设置
PWM
输出的
GPIO
、周期、占空比:
在使用pwm_init()函数之前,要配置好pwm_param结构体,它指明了我们PWM波形的周期和    占空比,而pwm_init()函数的最后一个参数:uint32 (*pin_info_list)[3])指明了我们的PWM各个通道用哪个GPIO端口。
void pwm_init(uint32 period,uint8 *duty,uint32 pwm_channel_num,uint32 (*pin_info_list)[3])
//uint32 period:PWM 周期,单位 us;
//uint8 *duty:各路 PWM 占空比;
//uint32 pwm_channel_num:PWM 输出通道数目;
//uint32 (*pin_info_list)[3]):PWM 各个通道的 GPIO 硬件参数。本参数为一个
//N*3 的数组指针,也就是一个二维数组,每一个通道有三个参数,对应存放在数
//组中,分别是 GPIO 的寄存器、对应的 PIN 脚的 IO 复用功能、GPIO 对应的序号。
//注意:此函数只允许调用一次。

例:

//PWM输出通道配置
uint32_t PWM_GPIO[1][3]={PERIPHS_IO_MUX_GPIO4_U,FUNC_GPIO4,GPIO_ID_PIN(4)};
//PWM结构体:参数:周期,频率,8路的占空比(存在数组内)
struct pwm_param PWM_Param_Struct={1000,1000,{0}};
//PWM初始化:参数:周期,占空比,通道个数,PWM通道GPIO配置
pwm_init(PWM_Param_Struct.period,PWM_Param_Struct.duty,1,PWM_GPIO);
3..PWM
开始输出:
void pwm_start(void)
//注意:每一次更改了 PWM 的设置的时候都需要调用此函数,因为此函数内部进行了相应的计算。
4.设置
PWM
某一个通道的占空比:

void pwm_set_duty(uint32 duty,uint8 channel)
//设置 PWM 某个通道信号的占空⽐。设置各路 PWM 信号⾼电平所占的时间,duty 的范围随
//PWM 周期改变,最⼤值为:Period * 1000 /45。例如,1KHz PWM,duty 范围是:0 ~ 22222
//注意:设置完成后,需要调⽤ pwm_start ⽣效

 例:在频率=1KHz、通道=0情况下,我们可以计算duty范围: 0 ~ 1000*1000/45(0~22222)

       要产生占空比为50%的PWM波形:duty = 22222/2=11111。

      ( 注意:修改占空比之后需要调用 void pwm_start(void)才有效。)

void pwm_set_duty(11111,0);//配置通道0的占空比为50%
 5. 
设置
PWM
的周期:
void pwm_set_period(uint32 period)
//uint32 period:PWM 输出的周期,单位 us。稳定的 PWM 输出周期范围1000us-10000us;
//注意:修改周期之后需要调用 void pwm_start(void)才有效。
6.获取某路
PWM
通道的
duty
(也就是或者
PWM
输出通道的占空比,但是实际的占空比需要经过计算获得)
uint8 pwm_get_duty(uint8 channel)
//uint8 channel:需要查询的 PWM 输出通道号,通道号从 0 开始;
//注意:调用此 API 获取到的是 PWM 波对应通道的 duty 值,实际的占空比
//大小需要经过计算,实际占空比= (duty*45)/ (period*1000)。
7.获取
PWM
的周期:

uint32 pwm_get_period(void)
//返回值:PWM 周期,单位 us。
8.查询
PWM
的版本信息:

uint32 pwm_get_period(void)
//返回值:PWM 版本信息

4.程序的编写:

因为我们需要用到定时器不断改变占空比,所以直接复制软件定时器的工程,然后新建pwm_driver.cpwm_driver.h文件,然后将他们分别添加到app/driverapp/include/driver下,刷新工程。

1.pwm_driver.h:

#ifndef __PWM_DRIVER_H
#define __PWM_DRIVER_H

#include "ets_sys.h"
#include "osapi.h"   //系统函数
#include "user_interface.h"
#include "pwm.h"

extern struct pwm_param PWM_Structure;

#endif

2.pwm_driver.c:

#include "./driver/pwm_driver.h"

//PWM结构体
struct pwm_param PWM_Structure={1000,1000,{0}};//周期,频率,占空比

//PWM输出通道配置
uint32_t PWM_GPIO[1][3]={PERIPHS_IO_MUX_GPIO4_U,FUNC_GPIO4,GPIO_ID_PIN(4)};

//PWM初始化
void ICACHE_FLASH_ATTR PWM_Init(void)
{
	pwm_init(PWM_Structure.period,PWM_Structure.duty,1,PWM_GPIO);//pwm初始化

}

3.os_timer.h:

#ifndef __OS_TIMER_H
#define __OS_TIMER_H

#include "ets_sys.h"
#include "osapi.h"   //系统函数
#include "user_interface.h"
#include "pwm.h"

void OS_Timer_1_Cb(void);//定时器回调函数
void OS_Timer_Init(uint32_t ms,bool repeat_flag);//定时器初始化函数

#endif /* OS_TIMER_H */

4.os_timer.c:

#include "./driver/os_timer.h"
#include "./driver/pwm_driver.h"

os_timer_t os_timer_1;//定义软件定时器结构体变量

//软件定时器回调函数
void OS_Timer_1_Cb(void)
{
	static uint8_t direction=0;
	int span = 300;//每次的增量或减量

	if(direction==0 && PWM_Structure.duty[0]<=22222)//占空比增大
	   {
		    PWM_Structure.duty[0]+=span;
	    }
	if(direction==1 && PWM_Structure.duty[0]>=0)//占空比减小
		{
			PWM_Structure.duty[0]-=span;
		}
	if(PWM_Structure.duty[0]>22222)//改变方向
	    {
		  direction=1;
	    }
	if(PWM_Structure.duty[0]<=span)//改变方向
		{
		  direction=0;
		}
	pwm_set_duty(PWM_Structure.duty[0],0);//设置占空比
	pwm_start();
}

//软件定时器配置初始化
void OS_Timer_Init(uint32_t ms,bool repeat_flag)
{
	os_timer_disarm(&os_timer_1);//关闭软件定时器
	os_timer_setfn(&os_timer_1,(os_timer_func_t*)OS_Timer_1_Cb,NULL);//注册软件定时器回调函数
	os_timer_arm(&os_timer_1,ms,repeat_flag);//打开软件定时器,设置定时周期,设置是否自动重装
}

5.user_main.c:

#include "ets_sys.h"
#include "user_config.h"//用户配置
#include "eagle_soc.h"//GPIO函数,宏定义
#include "c_types.h" //变量类型
#include "osapi.h"   //系统函数
#include "user_interface.h"
#include "pwm.h"

/******************************************************************************
 * FunctionName : user_rf_cal_sector_set
 * Description  : SDK just reversed 4 sectors, used for rf init data and paramters.
 *                We add this function to force users to set rf cal sector, since
 *                we don't know which sector is free in user's application.
 *                sector map for last several sectors : ABCCC
 *                A : rf cal
 *                B : rf init data
 *                C : sdk parameters
 * Parameters   : none
 * Returns      : rf cal sector
*******************************************************************************/
uint32 ICACHE_FLASH_ATTR
user_rf_cal_sector_set(void)
{
    enum flash_size_map size_map = system_get_flash_size_map();
    uint32 rf_cal_sec = 0;

    switch (size_map) {
        case FLASH_SIZE_4M_MAP_256_256:
            rf_cal_sec = 128 - 5;
            break;

        case FLASH_SIZE_8M_MAP_512_512:
            rf_cal_sec = 256 - 5;
            break;

        case FLASH_SIZE_16M_MAP_512_512:
            rf_cal_sec = 512 - 5;
            break;
        case FLASH_SIZE_16M_MAP_1024_1024:
            rf_cal_sec = 512 - 5;
            break;

        case FLASH_SIZE_32M_MAP_512_512:
            rf_cal_sec = 1024 - 5;
            break;
        case FLASH_SIZE_32M_MAP_1024_1024:
            rf_cal_sec = 1024 - 5;
            break;

        case FLASH_SIZE_64M_MAP_1024_1024:
            rf_cal_sec = 2048 - 5;
            break;
        case FLASH_SIZE_128M_MAP_1024_1024:
            rf_cal_sec = 4096 - 5;
            break;
        default:
            rf_cal_sec = 0;
            break;
    }

    return rf_cal_sec;
}

void ICACHE_FLASH_ATTR
user_rf_pre_init(void)
{
}

//毫秒延时函数
void ICACHE_FLASH_ATTR
delay_ms(u32 ms)
{
	for(;ms>0;ms--){
		os_delay_us(1000);//1ms
	}
}
/******************************************************************************
 * FunctionName : user_init
 * Description  : entry of user application, init user function here
 * Parameters   : none
 * Returns      : none
*******************************************************************************/
void ICACHE_FLASH_ATTR
user_init(void)
{
  os_printf("\r\nESP8266PWM呼吸灯实验\r\n");//波特率=74880
  PWM_Init();//PWM初始化
  OS_Timer_Init(10,1);//10ms改变一次占空比,重装载
}

版权声明:本文为CSDN博主「流年_cth」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_46364710/article/details/122597435

先看下的效果:

呼吸灯

1.硬件电路:

---------------------------LED的阴极与我们的GPIO4相连。----------------------------

2.PWM介绍:

PWM

英文名为
Pulse Width Modulation
,是脉冲宽度调制的缩写,通过对一系列脉冲的宽度    进行调制,来等效地获得所需要的波形(含形状和幅值)。我们通过连续改变占空比就可以控制LED灯的亮度,从而实现呼吸灯的效果。
占空比:是指在一个脉冲循环内,通电时间相对于总时间所占的比例(也就是说高电平时间占的      比例)。

使用时的注意事项:

1.PWM
输出和硬件定时器不能够同时使用,因为他们使用的是同一个硬件。
2.
使用
PWM
输出的时候不支持进入
Deep Sleep
自动睡眠模式。
3.PWM
使用
NMI
中断,最多可以扩展
8

PWM
输出,但是
8

PWM
的周期相同,占空比可       以不同。
4.PWM
的分辨率可最高达到
45ns
,能够稳定输出的
PWM
波信号周期为1000us-10000us,对应     频率为
1kHz-100Hz

3.用到的函数:

PWM 的所有接口文件在“pwm.h”内声明

1.pwm_param结构体:

struct pwm_param {
    uint32 period;//周期
    uint32 freq;  //频率
    uint32  duty[PWM_CHANNEL_NUM_MAX];  //PWM_CHANNEL<=8 //八个通道的各自占空比
};
2..初始化
PWM
配置,设置
PWM
输出的
GPIO
、周期、占空比:
在使用pwm_init()函数之前,要配置好pwm_param结构体,它指明了我们PWM波形的周期和    占空比,而pwm_init()函数的最后一个参数:uint32 (*pin_info_list)[3])指明了我们的PWM各个通道用哪个GPIO端口。
void pwm_init(uint32 period,uint8 *duty,uint32 pwm_channel_num,uint32 (*pin_info_list)[3])
//uint32 period:PWM 周期,单位 us;
//uint8 *duty:各路 PWM 占空比;
//uint32 pwm_channel_num:PWM 输出通道数目;
//uint32 (*pin_info_list)[3]):PWM 各个通道的 GPIO 硬件参数。本参数为一个
//N*3 的数组指针,也就是一个二维数组,每一个通道有三个参数,对应存放在数
//组中,分别是 GPIO 的寄存器、对应的 PIN 脚的 IO 复用功能、GPIO 对应的序号。
//注意:此函数只允许调用一次。

例:

//PWM输出通道配置
uint32_t PWM_GPIO[1][3]={PERIPHS_IO_MUX_GPIO4_U,FUNC_GPIO4,GPIO_ID_PIN(4)};
//PWM结构体:参数:周期,频率,8路的占空比(存在数组内)
struct pwm_param PWM_Param_Struct={1000,1000,{0}};
//PWM初始化:参数:周期,占空比,通道个数,PWM通道GPIO配置
pwm_init(PWM_Param_Struct.period,PWM_Param_Struct.duty,1,PWM_GPIO);
3..PWM
开始输出:
void pwm_start(void)
//注意:每一次更改了 PWM 的设置的时候都需要调用此函数,因为此函数内部进行了相应的计算。
4.设置
PWM
某一个通道的占空比:

void pwm_set_duty(uint32 duty,uint8 channel)
//设置 PWM 某个通道信号的占空⽐。设置各路 PWM 信号⾼电平所占的时间,duty 的范围随
//PWM 周期改变,最⼤值为:Period * 1000 /45。例如,1KHz PWM,duty 范围是:0 ~ 22222
//注意:设置完成后,需要调⽤ pwm_start ⽣效

 例:在频率=1KHz、通道=0情况下,我们可以计算duty范围: 0 ~ 1000*1000/45(0~22222)

       要产生占空比为50%的PWM波形:duty = 22222/2=11111。

      ( 注意:修改占空比之后需要调用 void pwm_start(void)才有效。)

void pwm_set_duty(11111,0);//配置通道0的占空比为50%
 5. 
设置
PWM
的周期:
void pwm_set_period(uint32 period)
//uint32 period:PWM 输出的周期,单位 us。稳定的 PWM 输出周期范围1000us-10000us;
//注意:修改周期之后需要调用 void pwm_start(void)才有效。
6.获取某路
PWM
通道的
duty
(也就是或者
PWM
输出通道的占空比,但是实际的占空比需要经过计算获得)
uint8 pwm_get_duty(uint8 channel)
//uint8 channel:需要查询的 PWM 输出通道号,通道号从 0 开始;
//注意:调用此 API 获取到的是 PWM 波对应通道的 duty 值,实际的占空比
//大小需要经过计算,实际占空比= (duty*45)/ (period*1000)。
7.获取
PWM
的周期:

uint32 pwm_get_period(void)
//返回值:PWM 周期,单位 us。
8.查询
PWM
的版本信息:

uint32 pwm_get_period(void)
//返回值:PWM 版本信息

4.程序的编写:

因为我们需要用到定时器不断改变占空比,所以直接复制软件定时器的工程,然后新建pwm_driver.cpwm_driver.h文件,然后将他们分别添加到app/driverapp/include/driver下,刷新工程。

1.pwm_driver.h:

#ifndef __PWM_DRIVER_H
#define __PWM_DRIVER_H

#include "ets_sys.h"
#include "osapi.h"   //系统函数
#include "user_interface.h"
#include "pwm.h"

extern struct pwm_param PWM_Structure;

#endif

2.pwm_driver.c:

#include "./driver/pwm_driver.h"

//PWM结构体
struct pwm_param PWM_Structure={1000,1000,{0}};//周期,频率,占空比

//PWM输出通道配置
uint32_t PWM_GPIO[1][3]={PERIPHS_IO_MUX_GPIO4_U,FUNC_GPIO4,GPIO_ID_PIN(4)};

//PWM初始化
void ICACHE_FLASH_ATTR PWM_Init(void)
{
	pwm_init(PWM_Structure.period,PWM_Structure.duty,1,PWM_GPIO);//pwm初始化

}

3.os_timer.h:

#ifndef __OS_TIMER_H
#define __OS_TIMER_H

#include "ets_sys.h"
#include "osapi.h"   //系统函数
#include "user_interface.h"
#include "pwm.h"

void OS_Timer_1_Cb(void);//定时器回调函数
void OS_Timer_Init(uint32_t ms,bool repeat_flag);//定时器初始化函数

#endif /* OS_TIMER_H */

4.os_timer.c:

#include "./driver/os_timer.h"
#include "./driver/pwm_driver.h"

os_timer_t os_timer_1;//定义软件定时器结构体变量

//软件定时器回调函数
void OS_Timer_1_Cb(void)
{
	static uint8_t direction=0;
	int span = 300;//每次的增量或减量

	if(direction==0 && PWM_Structure.duty[0]<=22222)//占空比增大
	   {
		    PWM_Structure.duty[0]+=span;
	    }
	if(direction==1 && PWM_Structure.duty[0]>=0)//占空比减小
		{
			PWM_Structure.duty[0]-=span;
		}
	if(PWM_Structure.duty[0]>22222)//改变方向
	    {
		  direction=1;
	    }
	if(PWM_Structure.duty[0]<=span)//改变方向
		{
		  direction=0;
		}
	pwm_set_duty(PWM_Structure.duty[0],0);//设置占空比
	pwm_start();
}

//软件定时器配置初始化
void OS_Timer_Init(uint32_t ms,bool repeat_flag)
{
	os_timer_disarm(&os_timer_1);//关闭软件定时器
	os_timer_setfn(&os_timer_1,(os_timer_func_t*)OS_Timer_1_Cb,NULL);//注册软件定时器回调函数
	os_timer_arm(&os_timer_1,ms,repeat_flag);//打开软件定时器,设置定时周期,设置是否自动重装
}

5.user_main.c:

#include "ets_sys.h"
#include "user_config.h"//用户配置
#include "eagle_soc.h"//GPIO函数,宏定义
#include "c_types.h" //变量类型
#include "osapi.h"   //系统函数
#include "user_interface.h"
#include "pwm.h"

/******************************************************************************
 * FunctionName : user_rf_cal_sector_set
 * Description  : SDK just reversed 4 sectors, used for rf init data and paramters.
 *                We add this function to force users to set rf cal sector, since
 *                we don't know which sector is free in user's application.
 *                sector map for last several sectors : ABCCC
 *                A : rf cal
 *                B : rf init data
 *                C : sdk parameters
 * Parameters   : none
 * Returns      : rf cal sector
*******************************************************************************/
uint32 ICACHE_FLASH_ATTR
user_rf_cal_sector_set(void)
{
    enum flash_size_map size_map = system_get_flash_size_map();
    uint32 rf_cal_sec = 0;

    switch (size_map) {
        case FLASH_SIZE_4M_MAP_256_256:
            rf_cal_sec = 128 - 5;
            break;

        case FLASH_SIZE_8M_MAP_512_512:
            rf_cal_sec = 256 - 5;
            break;

        case FLASH_SIZE_16M_MAP_512_512:
            rf_cal_sec = 512 - 5;
            break;
        case FLASH_SIZE_16M_MAP_1024_1024:
            rf_cal_sec = 512 - 5;
            break;

        case FLASH_SIZE_32M_MAP_512_512:
            rf_cal_sec = 1024 - 5;
            break;
        case FLASH_SIZE_32M_MAP_1024_1024:
            rf_cal_sec = 1024 - 5;
            break;

        case FLASH_SIZE_64M_MAP_1024_1024:
            rf_cal_sec = 2048 - 5;
            break;
        case FLASH_SIZE_128M_MAP_1024_1024:
            rf_cal_sec = 4096 - 5;
            break;
        default:
            rf_cal_sec = 0;
            break;
    }

    return rf_cal_sec;
}

void ICACHE_FLASH_ATTR
user_rf_pre_init(void)
{
}

//毫秒延时函数
void ICACHE_FLASH_ATTR
delay_ms(u32 ms)
{
	for(;ms>0;ms--){
		os_delay_us(1000);//1ms
	}
}
/******************************************************************************
 * FunctionName : user_init
 * Description  : entry of user application, init user function here
 * Parameters   : none
 * Returns      : none
*******************************************************************************/
void ICACHE_FLASH_ATTR
user_init(void)
{
  os_printf("\r\nESP8266PWM呼吸灯实验\r\n");//波特率=74880
  PWM_Init();//PWM初始化
  OS_Timer_Init(10,1);//10ms改变一次占空比,重装载
}

版权声明:本文为CSDN博主「流年_cth」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_46364710/article/details/122597435

生成海报
点赞 0

流年_cth

我还没有学会写个人说明!

暂无评论

相关推荐