Page 1 of 1

[分享] 如何解决 LEDC 初始化通道时 GPIO 会输出短暂低电平的问题

Posted: Sat Apr 27, 2019 5:59 am
by ESP_houwenxiang
ESP32 上 LEDC 主要用于 LED 灯的调光电路. LED 控制电路的驱动电平有两种, 高电平驱动或者低电平驱动. 通过控制输出 PWM 的占空比, 可达到调光的目的. 今天分享的是如何解决低电平驱动的 LED 控制电路中, 由于初始化 LEDC 导致灯闪烁的问题. 灯闪烁的原因是初始化 LEDC 瞬间, 通道会出现 54us 的低电平.

首先看 LEDC 硬件的组成:

1. LEDC Timer: 对 LEDC 时钟计数, 计数的范围是 0 ~ (2^n -1) (其中 n 通过 duty_resolution 寄存器来进行配置). 这也是 LEDC 输出信号的周期.

2. LEDC Channel: 将通道的 duty 值与 timer 中的计数值进行比较, 然后根据比较结果输出 PWM 信号.

在初始化 LEDC 时, 对 LEDC Timer 和 LEDC Channel 均需要进行配置. 但需要注意的是 LEDC Channel 配置, 需要等待 LEDC Timer 计数值溢出之后才会生效. 正常的初始化流程是先初始化 LEDC Timer, 接着初始化 LEDC Channel. e.g.:

Code: Select all

    ledc_timer_config_t ledc_timer = {
        .duty_resolution = LEDC_TIMER_13_BIT,
        .freq_hz = 5000,
        .speed_mode = LEDC_HIGH_SPEED_MODE,
        .timer_num = LEDC_TIMER_0,
    };
    ledc_channel_config_t ledc_channel = {
        .channel    = LEDC_HS_CH0_CHANNEL,
        .duty       = 0x1 << (LEDC_TIMER_13_BIT),
        .gpio_num   = GPIO_NUM_18,
        .speed_mode = LEDC_HIGH_SPEED_MODE,
        .hpoint     = 0,
        .timer_sel  = LEDC_TIMER_0,
    };
    ledc_timer_config(&ledc_timer);
    ledc_channel_config(&ledc_channel);
在低电平驱动的 LEDC 控制电路中, 需要初始化 LEDC 的整个过程 LEDC 的输出信号一直是高电平. 但是实际上初始化时, 即使 LEDC Channel 的输出占空比是 100%, LEDC 仍会输出 54us 的低脉冲, 如下图:
LEDC1.png
LEDC1.png (6.51 KiB) Viewed 3531 times
上面提到过, LEDC Chennel 的配置需要等到 LEDC Timer 计数值溢出之后才会更新. 在配置完 LEDC Chennel 的时候, LEDC Timer 计数值并未溢出, 这个时候 LEDC 输出的将是 IDLE 电平(默认是 0), 等到 LEDC Timer 计数值溢出后, 再根据 LEDC Channel 的配置来输出电平.

解决方案是将 LEDC IDLE 电平配置成高电平.

Code: Select all

    ledc_timer_config_t ledc_timer = {
        .duty_resolution = LEDC_TIMER_13_BIT,
        .freq_hz = 5000,
        .speed_mode = LEDC_HIGH_SPEED_MODE,
        .timer_num = LEDC_TIMER_0,
    };
    ledc_channel_config_t ledc_channel = {
        .channel    = LEDC_HS_CH0_CHANNEL,
        .duty       = 0x1 << (LEDC_TIMER_13_BIT),
        .gpio_num   = GPIO_NUM_18,
        .speed_mode = LEDC_HIGH_SPEED_MODE,
        .hpoint     = 0,
        .timer_sel  = LEDC_TIMER_0,
    };
    ledc_timer_config(&ledc_timer);
    ledc_stop(LEDC_HS_MODE, LEDC_HS_CH0_CHANNEL, 1); //主要的作用是将 IDLE 电平配置成高电平.
    ledc_channel_config(&ledc_channel);
    ledc_update_duty(LEDC_HS_MODE, LEDC_HS_CH0_CHANNEL);
此时输出波形是:
LEDC2.png
LEDC2.png (3.92 KiB) Viewed 3531 times
这时候 LEDC 初始化时不会再出现低脉冲了.