先看下的效果:
呼吸灯
1.硬件电路:
---------------------------LED的阴极与我们的GPIO4相连。----------------------------
2.PWM介绍:
:
英文名为
Pulse Width Modulation
,是脉冲宽度调制的缩写,通过对一系列脉冲的宽度 进行调制,来等效地获得所需要的波形(含形状和幅值)。我们通过连续改变占空比就可以控制LED灯的亮度,从而实现呼吸灯的效果。
使用时的注意事项:
输出和硬件定时器不能够同时使用,因为他们使用的是同一个硬件。
使用
PWM
输出的时候不支持进入
Deep Sleep
自动睡眠模式。
使用
NMI
中断,最多可以扩展
8
路
PWM
输出,但是
8
路
PWM
的周期相同,占空比可 以不同。
的分辨率可最高达到
45ns
,能够稳定输出的
PWM
波信号周期为1000us-10000us,对应 频率为
1kHz-100Hz
。
3.用到的函数:
1.pwm_param结构体:
struct pwm_param {
uint32 period;//周期
uint32 freq; //频率
uint32 duty[PWM_CHANNEL_NUM_MAX]; //PWM_CHANNEL<=8 //八个通道的各自占空比
};
PWM
配置,设置
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);
开始输出:
void pwm_start(void)
//注意:每一次更改了 PWM 的设置的时候都需要调用此函数,因为此函数内部进行了相应的计算。
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%
设置
PWM
的周期:
void pwm_set_period(uint32 period)
//uint32 period:PWM 输出的周期,单位 us。稳定的 PWM 输出周期范围1000us-10000us;
//注意:修改周期之后需要调用 void pwm_start(void)才有效。
PWM
通道的
duty
(也就是或者
PWM
输出通道的占空比,但是实际的占空比需要经过计算获得)
uint8 pwm_get_duty(uint8 channel)
//uint8 channel:需要查询的 PWM 输出通道号,通道号从 0 开始;
//注意:调用此 API 获取到的是 PWM 波对应通道的 duty 值,实际的占空比
//大小需要经过计算,实际占空比= (duty*45)/ (period*1000)。
PWM
的周期:
uint32 pwm_get_period(void)
//返回值:PWM 周期,单位 us。
PWM
的版本信息:
uint32 pwm_get_period(void)
//返回值:PWM 版本信息
4.程序的编写:
因为我们需要用到定时器不断改变占空比,所以直接复制软件定时器的工程,然后新建pwm_driver.c和pwm_driver.h文件,然后将他们分别添加到app/driver和app/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介绍:
:
英文名为
Pulse Width Modulation
,是脉冲宽度调制的缩写,通过对一系列脉冲的宽度 进行调制,来等效地获得所需要的波形(含形状和幅值)。我们通过连续改变占空比就可以控制LED灯的亮度,从而实现呼吸灯的效果。
使用时的注意事项:
输出和硬件定时器不能够同时使用,因为他们使用的是同一个硬件。
使用
PWM
输出的时候不支持进入
Deep Sleep
自动睡眠模式。
使用
NMI
中断,最多可以扩展
8
路
PWM
输出,但是
8
路
PWM
的周期相同,占空比可 以不同。
的分辨率可最高达到
45ns
,能够稳定输出的
PWM
波信号周期为1000us-10000us,对应 频率为
1kHz-100Hz
。
3.用到的函数:
1.pwm_param结构体:
struct pwm_param {
uint32 period;//周期
uint32 freq; //频率
uint32 duty[PWM_CHANNEL_NUM_MAX]; //PWM_CHANNEL<=8 //八个通道的各自占空比
};
PWM
配置,设置
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);
开始输出:
void pwm_start(void)
//注意:每一次更改了 PWM 的设置的时候都需要调用此函数,因为此函数内部进行了相应的计算。
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%
设置
PWM
的周期:
void pwm_set_period(uint32 period)
//uint32 period:PWM 输出的周期,单位 us。稳定的 PWM 输出周期范围1000us-10000us;
//注意:修改周期之后需要调用 void pwm_start(void)才有效。
PWM
通道的
duty
(也就是或者
PWM
输出通道的占空比,但是实际的占空比需要经过计算获得)
uint8 pwm_get_duty(uint8 channel)
//uint8 channel:需要查询的 PWM 输出通道号,通道号从 0 开始;
//注意:调用此 API 获取到的是 PWM 波对应通道的 duty 值,实际的占空比
//大小需要经过计算,实际占空比= (duty*45)/ (period*1000)。
PWM
的周期:
uint32 pwm_get_period(void)
//返回值:PWM 周期,单位 us。
PWM
的版本信息:
uint32 pwm_get_period(void)
//返回值:PWM 版本信息
4.程序的编写:
因为我们需要用到定时器不断改变占空比,所以直接复制软件定时器的工程,然后新建pwm_driver.c和pwm_driver.h文件,然后将他们分别添加到app/driver和app/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
暂无评论