ESP32 S3中Servo.write与analogWrite组合引发PWM频率异常问题
问题分析与解决方案
问题根源
这是ESP32Servo库与Arduino核心analogWrite的PWM通道/定时器资源冲突导致的:
- ESP32的PWM功能依赖有限的定时器和通道,ESP32Servo库默认会自动为每个
attach()的舵机分配未被占用的PWM通道,并配置为舵机所需的50Hz。 - Arduino环境下的
analogWrite函数在ESP32平台上默认使用100Hz的PWM频率(符合你的直流电机需求),但它会直接修改对应通道的定时器配置——当attach3个舵机时,第三个舵机被分配的通道恰好和analogWrite使用的通道重叠,因此被强制改成100Hz。 - 当attach4个舵机时,ESP32Servo会占用更多通道,
analogWrite只能选择未被舵机占用的通道,因此不会覆盖舵机的配置。
解决方法
方法1:手动指定舵机的PWM通道(推荐)
在attach()时手动指定舵机使用的PWM通道,避开analogWrite可能使用的通道。ESP32共有16个PWM通道(0-15),可以给舵机分配独立的通道,彻底避免冲突:
#include <Arduino.h> #include <ESP32Servo.h> const int servo1Pin = 45; const int servo2Pin = 48; const int servo3Pin = 2; const int servo4Pin = 36; const int enable1Pin = 9; const int enable2Pin = 10; Servo servo1; Servo servo2; Servo servo3; Servo servo4; void setup() { Serial.begin(115200); // 手动指定舵机使用的PWM通道(0、1、2),参数依次为引脚、最小脉宽、最大脉宽、通道号 servo1.attach(servo1Pin, 544, 2400, 0); servo2.attach(servo2Pin, 544, 2400, 1); servo3.attach(servo3Pin, 544, 2400, 2); // 不再需要虚拟舵机 } void loop(){ analogWrite(enable1Pin, abs(90)); analogWrite(enable2Pin, abs(90)); servo1.write(90); servo2.write(90); servo3.write(90); }
方法2:使用ESP32原生PWM API控制直流电机
放弃Arduino的analogWrite,改用ESP-IDF原生PWM配置函数,手动指定直流电机的PWM参数,彻底隔离舵机和电机的PWM资源:
#include <Arduino.h> #include <ESP32Servo.h> #include <driver/ledc.h> const int servo1Pin = 45; const int servo2Pin = 48; const int servo3Pin = 2; const int enable1Pin = 9; const int enable2Pin = 10; // 为直流电机分配独立的PWM通道 #define MOTOR_CH1 10 #define MOTOR_CH2 11 Servo servo1; Servo servo2; Servo servo3; void setup() { Serial.begin(115200); // 初始化舵机 servo1.attach(servo1Pin); servo2.attach(servo2Pin); servo3.attach(servo3Pin); // 配置直流电机PWM:100Hz频率,10位分辨率(占空比范围0-1023) ledcSetup(MOTOR_CH1, 100, 10); ledcSetup(MOTOR_CH2, 100, 10); // 将电机引脚绑定到对应通道 ledcAttachPin(enable1Pin, MOTOR_CH1); ledcAttachPin(enable2Pin, MOTOR_CH2); } void loop(){ // 将原analogWrite的0-255范围转换为10位分辨率的0-1023 ledcWrite(MOTOR_CH1, map(abs(90), 0, 255, 0, 1023)); ledcWrite(MOTOR_CH2, map(abs(90), 0, 255, 0, 1023)); servo1.write(90); servo2.write(90); servo3.write(90); }
方法3:保留虚拟舵机(临时方案)
如果不想修改太多代码,可以继续保留servo4.attach()的操作,让ESP32Servo占用额外通道,避免analogWrite覆盖第三个舵机的配置,但这只是绕过问题,并非根本解决方法。
内容的提问来源于stack exchange,提问作者yhq80
相关产品推荐
相关产品推荐

