ESP8266 Arduino开发之路(5)— 使用PWM实现LED呼吸灯
一、前言
ESP8266的PWM(Pulse Width Modulation)由FRC1在软件上实现,可实现同频率、不同占空比的最多8路的PWM波形输出。需要注意如下:
PWM驱动接口不能跟硬件定时器接口函数同时使用,因为二者共用同一个硬件定时器;
PWM驱动使用NMI中断,为最高优先级中断,可以保证PWM输出波形的准确度;
不能将自动睡眠模式设置为Light Sleep,Light Sleep模式下停用CPU不能响应NMI中断;
PWM周期需要设置在1000us(1kHz)~10000(100Hz)。
二、PWM输出
我们可以将如下所示NodeMCU的全部10个IO口设置为PWM输出,
但是因为GPIO1和GPIO3作为调试串口的TX和RX,一般不做使用,所以NodeMCU一般可支持同时输出8路PWM输出。编写程序如下所示:
void setup() {
analogWrite(5, 15); // D1
analogWrite(4, 31); // D2
analogWrite(0, 63); // D3
analogWrite(2, 127); // D4
analogWrite(14, 191); // D5
analogWrite(12, 15); // D6
analogWrite(13, 31); // D7
analogWrite(15, 63); // D8
analogWrite(3, 127); // RX
analogWrite(1, 191); // TX
}
void loop() {
delay(300);
}
使用示波器抓取波形可以看到,当前输出我PWM波形周期为1ms(频率1kHz),如下为GPIO0的输出波形,可以看到占空比为25%,因为analogWrite()
函数第二个参数为0~255
,当填入63时即为25%。
三、修改PWM精度
在上面我们知道analogWrite()
函数的第二个参数为0~255
,这就决定了PWM波形的精度,当我们把这个范围扩大后,就可以提高PWM的精度,我们可以通过analogWriteRange()
函数来修改,如下所示,将其修改为1023,
void setup() {
analogWriteRange(1023);
analogWrite(2, 255); // D4 LED
}
void loop() {
delay(300);
}
从示波器获取的波形如下所示,可见,其精度提高到了0~1023
,
通过查看源文件core_esp8266_wiring_pwm.cpp
,可以知道最大范围可设置到65535,
但是这个可能存在一个bug,即当范围设置为65535时,analogWrite()
函数填入大于53804
的数不能实现想要得到的波形。另外当范围超过53687
时无法实现100%占空比,所以建议最大范围为53687。
四、修改PWM频率
使用analogWriteFreq()
函数可以修改PWM的频率,通过查看源文件core_esp8266_wiring_pwm.cpp
,可以知道其频率范围为100Hz~1kHz
,
但实际上,我们可以将其范围设置为10hz~90kHz
,编写程序如下所示
void setup() {
analogWriteFreq(90000);
analogWriteRange(65535);
analogWrite(2, 32863); // D4 LED
}
void loop() {
delay(300);
}
抓取的示波器波形如下所示
五、LED呼吸灯
编写如下程序,实现LED呼吸灯:
/*
ESP8266 使用PWM实现LED呼吸灯
*/
void setup() {
analogWriteFreq(1000); // 频率设置为1kHz,即周期为1ms
analogWriteRange(1000); // 范围设置为1000,即占空比步长为1us
analogWrite(2, 750); // GPIO2 - D4 - LED
}
void loop() {
uint8_t dir = 0;
uint32_t pwmval = 750;
while(1)
{
if(dir) pwmval++; // dir==1 pwmval递增
else pwmval--; // dir==0 pwmval递减
if( pwmval <= 500 ) dir=1; // pwmval降低至500后,方向为递增
if( pwmval == 1000) dir=0; // pwmval递增到1000后,方向改为递减
analogWrite(2, pwmval); // 修改占空比
if( pwmval==1000 ) delay(300); // 在LED熄灭时等待300ms
delay(3);
}
}
然后可得到呼吸灯的效果为
六、附录
上一篇:ESP8266 Arduino开发之路(4)— 通过HTTP进行网络通信
下一篇:ESP8266 Arduino开发之路(6)— 使用Ticker库的软件定时器