概述
LED控制器(LEDC)主要用于控制LED的亮度,当然它也可以用于生成其他目的的PWM信号。它具有16个通道,可以生成独立的波形,这些波形可以用于驱动RGB LED器件。
LEDC的一半通道在高速模式下运行。此模式在硬件中实现,并提供PWM占空比的自动且无干扰的更改。通道的另一半在低速模式下运行,更改的时刻取决于应用软件。每组通道也可以使用不同的时钟源,但是LEDC驱动程序尚不支持此功能。
并且PWM控制器可以自动逐渐增加或减少占空比,使得允许衰减不会受到任何处理器干扰。
简单而言,这一功能就是PWM波的产生、控制器。
架构
LED_PWM 内部有 8 个高速通道以及 8 个低速通道。高速通道有 4个高速时钟模块,可以从中任选一个 h_timerx。低速通道有 4 个低速时钟模块,可以从中任选一个 l_timerx。
高速定时器的时钟源采用了 REF_TICK 或 APB_CLK,低速定时器采用了 REF_TICK 或 SLOW_CLOCK。
流程框图分析
这是其中某个高速通道的框图,表示一个 PWM 通道和它选取的分频器;在该情况下,一个高速通道配有一个高速分频器。在前面的定时器学习中已经讲过有关分频器的相关参数与用法了,这里不再赘述。
也就是该框图的左侧为定时器,通过分频器(Divder)与计数器(Counter)的设置,计数器中的数值不断的累计,达到最大值后重置,继续重新累加。而这个不断重复累加的计数器的值,就是PWM波产生的关键。
产生PWM波
上图中,左侧我们知道是定时器,右侧则是PWM产生通道,有两个比较器,即high_level_comparator 以及 low_level_comparator。
high_level_comparator的比较值是 hpoint,当计数器的值达到 hpoint 时,输出信号翻转为高电平。
low_level_comparator 的比较值是 lpoint,当计数器的值等于 lpoint 时,输出信号翻转为低电平。
所以 hpoint 与 lpoint 共同决定了PWM波的占空比,我们可以通过控制这两个数值的差,控制LEDC的亮度。
Arduino层编程
好了,前面不管你理没理解和编程基本没有几毛钱关系,不影响~
只要有以下的大致参数设置思路即可:
- 开启定时器,设置定时器的分频系数(这里也不用你算,直接填频率)和计数器值位数(这里理解为精度)。
- 将PWM通道绑定到具体的一个引脚上。
- 设置占空比
且在输出过程中也可以随时改变占空比、频率等系数。
初始化( ledcSetup)
// channel(通道):0-15 freq (频率) resolution_bits(计数器精度): 1-20
double ledcSetup(uint8_t channel, double freq, uint8_t resolution_bits);
绑定引脚(ledcAttachPin)
void ledcAttachPin(uint8_t pin, uint8_t channel); // 绑定引脚
void ledcDetachPin(uint8_t pin); // 解绑引脚
设置占空比(ledcWrite)
resolution_bits的输入为X,duty的值是:小于2x-1
且值越大,占空比越小。占空比:(2x-1-duty)/2x-1
void ledcWrite(uint8_t channel, uint32_t duty);
改频率
程序中可以修改频率
double ledcWriteTone(uint8_t channel, double freq);
这里是预制的音乐频率,可以直接修改,驱动扬声器
double ledcWriteNote(uint8_t channel, note_t note, uint8_t octave);
参数读取
读取当前设置的duty值与频率
uint32_t ledcRead(uint8_t channel);
double ledcReadFreq(uint8_t channel);
例子(LED小灯)
#include <Arduino.h>
// 使用0号通道
#define LEDC_CHANNEL_0 0
// 定时器精度为15位
#define LEDC_TIMER_13_BIT 15
// 频率
#define LEDC_BASE_FREQ 5000
// 输出引脚
#define LED_PIN 18
int brightness = 0; // LED亮度
int fadeAmount = 5; // 衰减值
// 将值映射到0-255之间,注意32766是2^15-1
void ledcAnalogWrite(uint8_t channel, uint32_t value, uint32_t valueMax = 255) {
// calculate duty, 8191 from 2 ^ 13 - 1
uint32_t duty = (32766/ valueMax) * min(value, valueMax);
// 设置占空比
ledcWrite(channel, duty);
}
void setup() {
// Setup timer and attach timer to a led pin
ledcSetup(LEDC_CHANNEL_0, LEDC_BASE_FREQ, LEDC_TIMER_13_BIT);
ledcAttachPin(LED_PIN, LEDC_CHANNEL_0);
}
void loop() {
ledcAnalogWrite(LEDC_CHANNEL_0, brightness);
brightness = brightness + fadeAmount;
if (brightness <= 0 || brightness >= 255) {
fadeAmount = -fadeAmount;
}
delay(30);
}