一、PWM接口函数的解析
函数1:pwm_init()
初始化PWM,包括GPIO 选择,周期和占空比。目前仅支持调用一次
void pwm_init(
uint32 period,
uint8 *duty,
uint32 pwm_channel_num,
uint32 (*pin_info_list)[3]
)
参数 | 解释 |
---|---|
period | 周期,单位是us,计算:1KHZ–1s变化1000次,1s/1000 = 1ms = 1000us |
duty | 这是一个指针变量,数组存放PWM的占空比,初始化几个PWM通道,数组就多大 |
pwm_channel_num | 初始化的PWM的通道数目 |
pin_info_list | 一个n*3的数组指针,数组里面存放了GPIO的寄存器值,PIN脚的IO复用值,GPIO的序列号 |
看一下pin_info_list
数组,例如需要初始化一个PWM通道,是映射在GPIO5
uint32 io_info[1][3] ={PERIPHS_IO_MUX_GPIO5_U,FUNC_GPIO5,5};
PERIPHS_IO_MUX_GPIO5_U
:是GPIO5
的寄存器地址
可以在Eclipse
中Ctrl
点击跳转查看,很显然0x40
是PIN5
的偏移地址
然后对PERIPHS_IO_MUX
点击跳转
是IO
外设复用基地址,地址有了,接着就是复用功能的选择
FUNC_GPIO5
:是复用功能的选择
同样的在Eclipse
里面对FUNC_GPIO5
点击跳转
FUNC_GPIO5
是0
,也就是代表着第一个功能,也可以查看一下GPIO12
的
FUNC_GPIO12
是3
,也就是代表着第4
个功能,按照这样的规则,需要复用其他的功能是同样的选择
GPIO5
的序列号是GPIO_ID_PIN(5)
,也就是5
然后调用pwm_init(1000, duty, 1, io_info);
1KHz
周期,初始化占空比的数组duty
,1通道PWM
,和GPIO
复用
上述是对一个PWM通道的初始化,如果是需要初始化两个通道,假设是GPIO5
和GPIO12
那么
uint32 duty[2] = {0};
uint32 io_info[2][3] ={
{PERIPHS_IO_MUX_GPIO5_U,FUNC_GPIO5,5},
{PERIPHS_IO_MUX_MTDI_U,FUNC_GPIO12,12}
};
pwm_init(1000, duty, 2, io_info);
函数2:pwm_start()
PWM开始函数,每次对PWM更新(周期、占空比)后都需要调用,初始化之后也是同样的
函数3:pwm_set_duty()
占空比设置函数:duty的值是随PWM周期变化的,SDK手册上说占空比的计算是duty = period*1000/45
1KHz
的周期是1000us
,按照计算的公式结果是1000*1000/45 = 22222
函数4:pwm_set_period()
周期的计算T = 1/f
,单位是us
函数5:pwm_get_duty()
获取占空比值
函数6:pwm_get_period()
获取PWM的周期值
函数7:get_pwm_version()
获取PWM的版本
二、PWM呼吸灯
在PWM
初始化的时候已经将PWM
所用的IO
口初始化了所以不需要另外去初始化IO
口
硬件定时器和PWM
是冲突的
所以使用软件定时器,ms
级别的软件定时器最小都是5ms
,但是我这里使用的是us
级别的延时
us
级别的定时器需要宏定义一个USE_US_TIMER
,并且在user_main()
,的开头调用system_timer_reinit()
函数
USE_US_TIMER
宏定义需要在osapi.h
的导入之前,否则是会报错没有定义的
这里是空宏都可以
可以看到这里使用的是#ifdef
,而不是#if
user_main()
代码:
void ICACHE_FLASH_ATTR user_main()
{
system_timer_reinit();
/*软件定时器*/
os_timer_disarm(&ledtimer); // 关闭定时器
os_timer_setfn(&ledtimer, (os_timer_func_t *)Pwm_Led, (void*)0); // 设置定时器的回调函数
os_timer_arm_us(&ledtimer, 1000, 1); // 打开定时器,1ms,重复
/*PWM初始化*/
pwm_init(1000, duty, 1, io_info);
pwm_start();
}
Pwm_Led
代码
/*
* @name: Pwm_Led[PwmLED]
*/
void Pwm_Led(void)
{
if (down_flag == 0)
led_value += 22;
if (down_flag)
led_value -= 22;
pwm_set_duty(led_value, 0);
pwm_start();
if (led_value >= 22220)
down_flag = 1;
if (led_value == 0)
down_flag = 0;
}
为什么是定时1ms
,结合起两部分代码来看,首先呼吸灯的话我控制的大概就是10ms
增加1%
的占空比,0~22222
的范围值,1%
的占空比是222
,我这里一次加22
,一次1ms
,也就是10ms
加220
这样子