这一节主要就是一个内容:PWM的用法。
先看手册上对PWM功能的介绍(以下内容转自乐鑫手册):
ESP8266系统的PWM( Pulse Width Modulation)由FRC1在软件上实现,可实现同频
率、不同占空比的多路PWM,可用来控制彩灯、蜂鸣器和电机等设备。
说明:FRC1是一个23bts的硬件定时器。
PWM的特性如下所示。
使用NM( Non Maskable Interrupt)中断,更加精确。
可扩展最多8路PVM信号
>14bit分辨率,最小分辨率45ns。
无需配置寄存器,调用函数接口即可完成配置。
注意:PWM驱动接口不能跟硬件定时器(hw_timer)接口函数同时使用,因为二者共用一个硬件定时器。
参数说明
最小分辨率:45ns(近似对应于硬件 PWM 的输入时钟频率为22.72 MHZ ) :>14 bit PWM @1 KHZ
PWM 周期:1000 us (1 KHz )~10000 us (100 Hz)
先说频率范围,100HZ~1KHZ,这个频率实在是有些低。不过据说有些人能用到二三十K,不知道真的假的。由于本人比较懒,没有测,所以上面的说法仅供参考。
然后是用法,依然使用万能的三色LED做演示,做一个呼吸灯。
最终实现的效果,上电后,三个LED依次从暗到亮,熄灭,下一个~~~
另外,官方的SDK里面,提供了一个IoT_Demo的例程,里面有用PWM实现呼吸灯的代码。所以这里参考例程,进行一定的修改。
使用之前包含下面的头文件,同时把user_light.c文件拷到user目录下:
#include "user_light.h"
#include "pwm.h"
先说PWM的用法,很简单,只有三步。但因为我用了user_light.c里面的结构体,所以多加一步,先定义一个结构体。
1、定义一个结构体,存放PWM相关参数。
struct light_saved_param light_param;
结构体类型定义如下:
struct light_saved_param {
uint32 pwm_period;
uint32 pwm_duty[PWM_CHANNEL];
};
PWM_CHANNEL是一个宏定义,定义PWM通道个数,这里是3.结构体里面可以设置PWM的周期,以及每个通道的占空比。
2、定义一个二维数组
uint32 io_info[][3] = { {PWM_0_OUT_IO_MUX,PWM_0_OUT_IO_FUNC,PWM_0_OUT_IO_NUM},
{PWM_1_OUT_IO_MUX,PWM_1_OUT_IO_FUNC,PWM_1_OUT_IO_NUM},
{PWM_2_OUT_IO_MUX,PWM_2_OUT_IO_FUNC,PWM_2_OUT_IO_NUM},
};
这一步的意义在于,你要让哪几个IO输出PWM。数组的格式要记住,但凡用到PWM,都要以这样的格式进行定义。举例来说,第一行:
PWM_0_OUT_IO_MUX,PWM_0_OUT_IO_FUNC,PWM_0_OUT_IO_NUM
分别是:管脚名、管脚功能、管脚编号。直接看肯定看不懂,因为都是宏定义,如下:
#define PWM_0_OUT_IO_MUX PERIPHS_IO_MUX_MTDI_U
#define PWM_0_OUT_IO_NUM 12
#define PWM_0_OUT_IO_FUNC FUNC_GPIO12
有人会觉得烦,说你搞这么多宏定义累不累?
但其实不是我搞的,IoT_Demo的例程里已经写好了,直接用就可以。而且,这个格式相对比较规范,所以还是建议使用。
3、PWM初始化
pwm_init(light_param.pwm_period, light_param.pwm_duty ,PWM_CHANNEL,io_info);
共有四个参数:
第一个参数:PWM的周期,这里写的是1000,单位是us。所有通道的周期都是一样的。
第二个参数:PWM的占空比,上面周期是1000,那占空比的最大值是多少?
如果答1000,那你就太年轻了!它这里有个计算公式,也需要记住(别记了,还是查手册吧)
duty = period*1000/45
period是1000,带入计算的到22222.所以占空比的取值范围是0~22222.
第三个参数:通道个数,也就是说,你要输出几路PWM?
第四个参数:PWM各个通道的GPIO的硬件参数,也就是前面定义的那个数组。
4、启动PWM
pwm_start();
看函数名就能看懂了,不解释。
注意事项:手册里对该函数的描述是参数更新,所以但凡涉及到更新的(周期、占空比),改完之后,一定要调用一下这个函数。
经过前面四步,PWM就开始输出了。但是,咱们要做的是呼吸灯,呼吸灯是要定时修改PWM的占空比的,怎么改?再来一次pwm_init?
NO!
pwm_init只能初始化的时候调用一次,严禁多次调用。修改占空比使用下面的函数:
pwm_set_duty(duty, channel);
函数名如此简单,我已经懒得解释了。第一个参数略过,直接看第二个,channel,要写多少?
首先,这里定义了三个通道,定义的时候在数组里按照从0开始的规则,对三个通道自动进行了编号,分别是:0,1,2.
所以,你想改哪个通道,写入哪个编号即可。
注:参考手册2c-esp8266_non_os_sdk_api_reference_cn的157页,和esp8266-technical_reference_cn的100页。
保存、清理、编译、下载一条龙,然后重新上电,你会发现呼吸灯开始变化。
到此,PWM的用法说完了。
完整工程源码,请关注公众号:单片机爱好者,回复关键字:ESP8266,即可获取。