Arduino 入门学习笔记(十):LED_PWM实验
开发板:正点原子ESP32S3
例程源码在文章顶部可免费下载
1. LED PWM 控制器介绍
1.1 PWM 介绍
PWM(Pulse Width Modulation),简称脉宽调制,是一种将模拟信号变为脉冲信号的技术。PWM 可以控制 LED 亮度、直流电机的转速等。
PWM 的主要参数如下:
- PWM 频率。 PWM 频率是 PWM 信号在 1s 内从高电平到低电平再回到高电平的次数,也就是说 1s 内有多少个 PWM 周期,单位为 Hz。
- PWM 周期。 PWM 周期是 PWM 频率的倒数,即 T=1/f, T 是 PWM 周期, f 是 PWM 频率。如果 PWM 频率为 50Hz,也就是说 PWM 周期为 20ms,即 1s 由 50 个 PWM 周期。
- PWM 占空比。 PWM 占空比是指在一个 PWM 周期内,高电平的时间与整个周期时间的比例,取值范围为 0%~100%。 PWM 占空比如下图所示:
PWM 周期是一个 PWM 信号的时间:脉宽时间是指高电平时间;脉宽时间占 PWM 周期的比例就是占空比。例如,如果 PWM 周期是 10ms,而脉宽时间为 8ms,那么 PWM 占空比就是8/10=80%,此时的 PWM 信号就是占空比为 80%的 PWM 信号。 PWM 名为脉冲宽度调制,顾名思义,就是通过调节 PWM 占空比来调节 PWM 脉宽时间。
在使用 PWM 控制 LED 时,亮 1s 后灭 1s,往复循环,就可以看到 LED 在闪烁。如果把这个周期缩小到 200ms,亮 100ms 后灭 100ms,往复循环,就可以看到 LED 灯在高频闪烁。继续把这个周期持续缩小,总有一个临界值使人眼分辨不出 LED 在闪烁,此时 LED 的亮度处于灭与亮之间亮度的中间值,达到了 1/2 亮度。 PWM 占空比和亮度的关系如下图所示:
1.2 LED_PWM 控制器介绍
ESP32-S3 的 LED PWM 控制器,简写为 LEDC,用于生成控制 LED 的脉冲宽度调制信号。
LED PWM 控制器具有八个独立的 PWM 生成器(即八个通道)。每个 PWM 生成器会从四个通用定时器中选择一个,以该定时器的计数值作为基准生成 PWM 信号。 LED PWM 定时器如下图所示:
为了实现 PWM 输出,先需要设置指定通道的 PWM 参数:频率、分辨率、占空比,然后将该通道映射到指定引脚,该引脚输出对应通道的 PWM 信号,通道和引脚的关系所下图所示。
1.3 LED_PWM 函数介绍
本小节介绍到的函数可在以下文件中找到:
C:\Users\ 用户名 \AppData\Local\Arduino15\staging\packages\esp32-3.2.0\cores\esp32\esp32-hal-ledc.c
接下来,我们介绍一下本章节所用到的 LED PWM 相关函数。
第一个函数: ledcSetup 函数,该函数功能是指定 LEDC 通道的 PWM 信号频率和占空比分辨率。
double ledcSetup(uint8_t chan, double freq, uint8_t bit_num);
参数 chan 为 LEDC 通道号,取值为 0~7,共 8 个通道;
参数 freq 为待设置的 PWM 脉宽信号的频率;
参数 bit_num 为计数位数, 即 PWM 信号占空比的分辨率;
返回值: 通道 PWM 信号的频率。
第二个函数: ledcAttachPin 函数,该函数功能是将指定的 LEDC 通道绑定到指定 GPIO 引脚上,即由该引脚输出 LEDC 的 PWM 信号。
void ledcAttachPin(uint8_t pin, uint8_t chan);
参数 pin 为数字引脚编号;
参数 chan 为 LEDC 通道号,取值为 0~7,共 8 个通道;
无返回值。
第三个函数: ledcWrite 函数,该函数功能是设置指定通道输出的占空比数值。
void ledcWrite(uint8_t chan, uint32_t duty);
参数 chan 为 LEDC 通道号,取值为 0~7,共 8 个通道;
参数 duty 为待设置的 PWM 占空比数值。该数值的范围由通道初始化设置函数 ledcSetup()中的计数位数决定。例如,计数位数为 8,那么占空比设置值的范围就为 0~255。要输出占空比
50%的 PWM 信号,该参数应设置为 128。
无返回值。
2. 硬件设计
2.1 例程功能
实现 LED0 由暗变亮,再从亮变暗,依次循环。
2.2 硬件资源
1) LED PWM:LED-IO1
2.3 原理图
本章实验使用的 LED PWM 为 ESP32-S3 的片上资源,因此并没有相应的连接原理图。
3. 软件设计
3.1 程序流程图
下面看看本实验的程序流程图
3.2 程序解析
pwm 驱动代码
这里我们只讲解核心代码,详细的源码请大家参考光盘本实验对应源码。 PWM 驱动源码包括两个文件: pwm.cpp 和 pwm.h。
下面我们先解析 pwm.h 的程序。 对 LED PWM 做了相关定义。
ESP32新版本ledc库进行了修改,如果使用新版本,代码也需要进行相应修改
#define LED_PWM_PIN 1 /* PWM 信号输出的引脚 */
#define LED_PWM_CHANNEL 0 /* LED PWM 通道号 */
我们选择使用 LED PWM 的通道 0,将该通道映射到 IO1,最终 IO1 引脚会输出通道 0 的PWM 信号。
下面我们再解析 pwm.cpp 的程序,这里有两个函数 led_pwm_init 和 pwm_set_duty,其定义如下:
/**
* @brief LED PWM 初始化函数
* @param frequency: PWM 输出频率,单位 HZ
* @param resolution: PWM 占空比的分辨率 1-16,比如设置 8,分辨率范围 0~255
* @retval 无
*/
void led_pwm_init(uint16_t frequency, uint8_t resolution)
{
ledcSetup(LED_PWM_CHANNEL, frequency, resolution);
/* PWM 初始化,引脚和通道由 pwm.h 的 LED_PWM_PIN 和 LED_PWM_CHANNEL 宏修改 */
ledcAttachPin(LED_PWM_PIN, LED_PWM_CHANNEL);
/* 绑定 PWM 通道到 LED_PWM_PIN 上 */
/* 新版本使用以下初始化代码 v3.2.0*/
//ledcAttachChannel(LED_PWM_PIN, frequency, resolution,LED_PWM_CHANNEL);
}
/**
* @brief PWM 占空比设置
* @param duty: PWM 占空比
* @retval 无
*/
void pwm_set_duty(uint16_t duty)
{
ledcWrite(LED_PWM_CHANNEL, duty);
/* 改变 PWM 的占空比,通道由 pwm.h 的 LED_PWM_CHANNEL 宏修改 */
/* 新版本使用以下代码 v3.2.0*/
//ledcWriteChannel(LED_PWM_CHANNEL, duty);
}
led_pwm_init 函数是初始化 PWM 输出功能, 首先调用 ledcSetup 函数设置 LEDC 通道参数: PWM 通道、 PWM 频率和占空比的分辨率。然后调用 ledcAttachPin 函数绑定 PWM 通道到IO1 引脚。
pwm_set_duty 函数就是调用 ledcWrite 函数去完成 PWM 占空比的修改。
07_led_pwm.ino 代码
在 07_led_pwm.ino 里面编写如下代码:
#include "pwm.h"
uint16_t g_ledpwmval = 0; /* 占空比值 */
uint8_t g_dir = 1; /* 变化方向(1 增大 0 减小) */
/**
* @brief 当程序开始执行时,将调用 setup()函数,通常用来初始化变量、函数等
* @param 无
* @retval 无
*/
void setup()
{
led_pwm_init(1000, 10);/* LED PWM 初始化,PWM 输出频率为 1000HZ,占空比分辨率为 10 */
}
/**
* @brief 循环函数,通常放程序的主体或者需要不断刷新的语句
* @param 无
* @retval 无
*/
void loop()
{
if (g_dir)
{
g_ledpwmval += 5;
}
else
{
g_ledpwmval -= 5;
}
if (g_ledpwmval > 1005)
{
g_dir = 0;
}
if (g_ledpwmval < 5)
{
g_dir = 1;
}
pwm_set_duty(g_ledpwmval);
delay(10);
}
在 setup 函数中,调用 led_pwm_init 函数完成 PWM 输出的初始化。
在 loop 函数中, 通过简单的逻辑判断,让 g_ledpwmval 变量可从小变大,又从大变小,最终通过 pwm_set_duty 函数传递 g_ledpwmval 参数去修改占空比,达到修改 LED 亮度效果。为了让效果更为明显,添加了延时 10ms 操作。
4. 下载验证
下载代码完成后, ESP32-S3开发板上LED灯的亮度会以一个平稳的速度从最暗变到最亮,然后再从最亮变到最暗,实现呼吸灯的效果。