You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Arduino框架下PlatformIO环境ESP32无法单独设置各PWM通道频率

问题原因排查

核心根源

  • ESP32的LEDC PWM外设采用定时器+通道的分离架构:定时器负责生成统一的频率和分辨率基准,多个通道可挂载到同一个定时器下,所有挂载同一定时器的通道强制共享相同的频率和分辨率,无法单独修改。
  • Arduino ESP32核心的ledcSetup()默认按通道号自动分配定时器,你使用的0~3号通道正好被分配到2个定时器上:通道0、1共享第一个定时器,通道2、3共享第二个定时器。因此修改通道0的频率时,同定时器的通道1(对应GPIO25)频率同步改变;修改通道3的频率时,同定时器的通道2(对应GPIO26)频率同步改变,和你测量到的现象完全吻合。

修复方案

你只需要手动为4个PWM通道分配4个独立的定时器即可实现完全独立的频率控制,ESP32最多支持8个LEDC定时器,完全满足需求。

代码修改参考

// 新增定义:为每个PWM通道分配独立的定时器编号(0~7都可以用,只要不重复)
const uint8_t DC_IO_TIMER_TABLE[DC_IO_PORTS_QUANTITY] = {0, 1, 2, 3};

// 初始化函数修改为手动绑定定时器(以ESP32 Arduino核心2.0+版本为例)
void DC_IO_Init(uint8_t resolution, uint16_t freq)
{
    uint16_t half_duty_cycle;
    old_res = resolution;

    uint16_t bit_val = 1;
    full_duty_cycle = 1;
    for(uint8_t k=1;k<resolution;k++)
    {
        bit_val *= 2;
        full_duty_cycle += bit_val;
    }
    half_duty_cycle = full_duty_cycle / 2;

    for(uint8_t i=0; i<DC_IO_PORTS_QUANTITY; i++)
    {
        old_duty_cycle[i] = half_duty_cycle;
        // 传入第四个参数手动指定定时器编号,关闭自动分配
        ledcSetup(DC_IO_NUM_TABLE[i], freq, old_res, DC_IO_TIMER_TABLE[i]);
        ledcAttachPin(DC_IO_PIN_TABLE[i], DC_IO_NUM_TABLE[i]);
        ledcWrite(DC_IO_NUM_TABLE[i], old_duty_cycle[i]);
    }
    vTaskDelay(10);
}

// 频率设置函数可优化冗余逻辑,初始化绑定引脚后无需重复调用attach
void Set_DC_IO_Freq(DC_IO_NUM dc_iox, uint16_t freq)
{
    ledcSetup(dc_iox, freq, old_res);
    ledcWrite(dc_iox, old_duty_cycle[dc_iox]);
    vTaskDelay(10);
}

旧版本核心兼容方案

如果你使用的ESP32 Arduino版本没有带定时器参数的ledcSetup重载,可以直接调用官方原生的ledc_timer_config和ledc_channel_config接口,手动配置定时器参数并绑定到对应通道即可。

内容的提问来源于stack exchange,提问作者strange_bakery

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.26 09:36:04