玩过四足机器人、机械臂、人形机器人的朋友,几乎都会遇到同一个问题:舵机一多,Arduino 引脚就不够用了。Arduino UNO 总共才 14 个数字 IO,算上模拟口也就 20 个,扣掉 I2C、串口、几个高优先级中断脚,真正能留给舵机的没几个。就算引脚够了,自带 Servo 库是靠定时器中断打 PWM 的,多几个舵机一起跑,定时器冲突、抖动、甚至连 millis() 都不准的情况我踩过不止一次。
PCA9685 这块小板子就是专门解决这个问题的。它用 I2C 接口跟主控通信,只占 SDA 和 SCL 两个引脚,板子上自带 PWM 控制器,能独立输出 16 路 12 位 PWM,舵机该怎么抖它自己算,Arduino 只需要发个指令就行,完全不占 CPU。还能级联,最多挂 62 块板、控制 992 路舵机——当然正常人不会用到这个数,但做个六足(18 路舵机)加个机械臂(4-5 路),两块板绰绰有余。

市面上卖的 PCA9685 模块基本都是抄 Adafruit 方案,十几块钱一片,便宜量足。这篇我就照着 Adafruit 的官方教程,把接线、供电、库安装、校准、多路控制、级联这几步讲透,踩过的坑也一并写出来。
认识一下这块板
PCA9685 芯片本身是 NXP 的 16 通道 12 位 PWM 控制器,I2C 接口,默认地址 0x40。模块板把芯片、16 组 3Pin 舵机排针、电源端子、I2C 引出排针都做齐了,到手就能用。几个关键引脚先认清楚:
VCC:芯片逻辑供电,3.3V-5V 都行,接到 Arduino 的 5V 或 3.3V,这只是给芯片本身用的,不是舵机电源。V+:舵机电源输入,从蓝色端子或者每组排针旁的 V+ 针脚进去,5-6V 是舵机常用电压,最高别超 12V,而且 VCC 和 V+ 千万别接反,接反基本烧芯片。GND:逻辑地和舵机电源地,必须跟 Arduino 共地。SCL/SDA:I2C 时钟和数据线,接 Arduino 的对应引脚。OE:输出使能脚,拉低启用、拉高禁用,默认已经通过电阻拉低了,一般不用接,想做紧急停转的时候可以用。
板子上还有一组地址跳线 A0-A5,靠焊锡短路来改 I2C 地址,后面级联的时候会用到。板上 220 欧串联电阻已经焊好,信号电平和 VCC 一致,直连 5V Arduino 或 3.3V 树莓派都没问题。
接线:4 根线搞定,电源别省
接线其实非常简单,关键就两件事:逻辑线别接错、舵机电源别拿 Arduino 5V 凑。
经典 UNO 接线:VCC 接 5V,GND 接 GND,A4 接 SDA,A5 接 SCL。UNO R3 以后板子侧面有专门的 SDA/SCL 排针,直接接那两个更省事。Mega 2560 是 20=SDA、21=SCL;Leonardo 也是侧边专用排针。现在新板子基本都有标出来的 SDA/SCL,照着插就行。

舵机电源这边我要多说几句。9g 小舵机空载大概 100mA 以内,但一动起来、特别是顶住了或者几个舵机同时动,瞬时电流轻松上 1A。拿 Arduino 板上的 5V 引脚供舵机,电噪声和掉电能让 Arduino 随机重启甚至烧掉板上的 5V 稳压——这个坑我第一次玩 6 足的时候就踩过,舵机一摆头 UNO 就复位,查了半天才发现是电源问题。
舵机供电推荐三种方案:5V 2A 开关电源(小机器人够用)、5V 10A 开关电源(多舵机/大力矩舵机推荐)、4 节 AA 电池盒(碱性 6V、镍氢 4.8V)或者航模 2S 锂电(7.4V,舵机一般能扛但要查手册)。用蓝色端子接 V+ 和 GND 最稳,端子是反接保护的,反了插不进去。电源到板子的走线尽量粗、尽量短,舵机多的话在板子预留的电容位置焊个电解电容,经验值是舵机数×100μF 起步,5 个舵机就上 470μF 以上,能明显缓解舵机启动瞬间的电压跌落。
舵机插排针的时候注意线序:棕色/黑色是 GND 对下面一排,红色是 V+ 对中间,橙色/黄色是信号对最上面一排。不同品牌舵机线序可能不一样,插之前看一眼舵机手册。
装库:Arduino IDE 一键搞定
Adafruit 有官方库,装起来很方便。打开 Arduino IDE,菜单选「项目」→「加载库」→「管理库…」(新版本叫「库管理器」),搜索框里输入「Adafruit PWM」,找到 Adafruit PWM Servo Driver Library,点安装就行。这个库会自动把依赖的 Adafruit_BusIO 也带上。
装完以后在「文件」→「示例」里找到 Adafruit_PWMServoDriver,里面有个 servo 示例,这就是官方的舵机测试程序。我把核心代码贴一下,后面会逐段解释怎么改:
#include "Wire.h"
#include "Adafruit_PWMServoDriver.h"
Adafruit_PWMServoDriver pwm = Adafruit_PWMServoDriver();
#define SERVOMIN 150
#define SERVOMAX 600
#define USMIN 600
#define USMAX 2400
#define SERVO_FREQ 50
uint8_t servonum = 0;
void setup() {
Serial.begin(9600);
Serial.println("8 channel Servo test!");
pwm.begin();
pwm.setOscillatorFrequency(27000000);
pwm.setPWMFreq(SERVO_FREQ);
delay(10);
}
void setServoPulse(uint8_t n, double pulse) {
double pulselength;
pulselength = 1000000;
pulselength /= SERVO_FREQ;
pulselength /= 4096;
pulse *= 1000000;
pulse /= pulselength;
pwm.setPWM(n, 0, pulse);
}
void loop() {
Serial.println(servonum);
for (uint16_t pulselen = SERVOMIN; pulselen < SERVOMAX; pulselen++) {
pwm.setPWM(servonum, 0, pulselen);
}
delay(500);
for (uint16_t pulselen = SERVOMAX; pulselen > SERVOMIN; pulselen--) {
pwm.setPWM(servonum, 0, pulselen);
}
delay(500);
for (uint16_t microsec = USMIN; microsec < USMAX; microsec++) {
pwm.writeMicroseconds(servonum, microsec);
}
delay(500);
for (uint16_t microsec = USMAX; microsec > USMIN; microsec--) {
pwm.writeMicroseconds(servonum, microsec);
}
delay(500);
servonum++;
if (servonum > 7) servonum = 0;
}注意这里 #include 和 #include 我按发布规范改成了双引号形式,编译完全没问题,尖括号和双引号在 Arduino IDE 里都能识别。
代码解读:怎么让舵机转到想要的角度
先看几个宏定义。SERVOMIN=150、SERVOMAX=600,这两个是 PWM「tick」值,PCA9685 是 12 位分辨率,tick 范围 0-4095,对应一个 PWM 周期内高电平持续的 tick 数。50Hz 下一个周期 20ms,一个 tick 大概 4.88μs。150 对应约 732μs,600 对应约 2930μs。一般模拟舵机的控制脉宽是 500-2500μs 对应 0-180 度,但不同品牌、甚至同品牌不同批次的舵机这个范围会有差异,SERVOMIN/SERVOMAX 就是给你校准用的。USMIN=600、USMAX=2400 是给 writeMicroseconds() 用的微秒数,也是要校准的。
pwm.begin() 初始化 I2C,pwm.setPWMFreq(50) 把 PWM 频率设为 50Hz——这是模拟舵机的标准频率,别乱改。pwm.setOscillatorFrequency(27000000) 是校准芯片内部 25MHz 晶振的,PCA9685 内置振荡器实际频率在 23-27MHz 之间都算正常,示例给的 27MHz 是 Adafruit 板子的经验值,如果你有示波器可以抓一下 PWM 脚精确校准,没有就先用 27000000,一般够用。
setServoPulse() 是个辅助函数,把秒数转成 tick 数直接调 pwm.setPWM()。实际用得更多的是 pwm.setPWM(channel, on, off)——三个参数分别是通道号(0-15)、高电平起始 tick、高电平结束 tick。要让舵机转到某个角度,最常用的写法是 on=0、off=对应脉宽的 tick 数,就像示例里那样。如果想让通道全输出高电平(当 GPIO 用),就 setPWM(pin, 4096, 0);全关就 setPWM(pin, 0, 4096),注意这里不是 4095,是 4096,写 4095 LED 可能关不彻底。
角度转脉宽用 Arduino 自带的 map() 就行,假设已经把 SERVOMIN 校准到 0 度、SERVOMAX 校准到 180 度:
int pulselen = map(degrees, 0, 180, SERVOMIN, SERVOMAX);
pwm.setPWM(channel, 0, pulselen);writeMicroseconds() 是库封装的一层,直接给微秒数就行,写法更直观,比如 pwm.writeMicroseconds(0, 1500) 把 0 号舵机打到中位。底层做的事跟 setPWM 是一样的,只是省得自己算 tick。
校准:舵机不抖、不打齿的关键
这步千万别跳。新舵机买来,直接用默认的 SERVOMIN/SERVOMAX 就让它扫 0-180 度,运气好没事,运气差舵机走到物理极限还在使劲,齿轮咔咔响两下就扫齿了,十几块的小舵机换了不心疼,数字舵机大力矩的一百多一个,打齿了肉疼。
校准的方法很笨但有效:先把一个舵机插到 0 号口,上传扫摆示例。打开串口监视器看它从 SERVOMIN 往 SERVOMAX 走的时候,如果往 0 度方向走到底还在嗡嗡使劲转,说明 SERVOMIN 设太小了,往上调,比如从 150 改到 170、180,直到舵机刚到 0 度位置就停、不哼不抖。反过来 SERVOMAX 如果让舵机在 180 度位置顶住了就往下调。两侧都调到"能走到极限、但不顶死"就对了。USMIN/USMAX 也用同样方法校准,600/2400 是起始值,按你手里的舵机微调。
不同通道的舵机如果是同一型号,同一组 SERVOMIN/SERVOMAX 基本通用;混了不同牌子舵机的话最好各通道单独记录参数。我自己玩的时候是把每个舵机的校准值写在舵机线上贴个小标签,省得换一次工程就重新校准。
多舵机与级联
单块板 16 路舵机,用法就是 setPWM/writeMicroseconds 换通道号。loop 里从 0 循环到 15 可以做所有通道依次扫摆测试,很方便排查接线。
需要超过 16 路就要级联了。级联的硬件很简单:第一块板的 SDA/SCL 接到下一块板的 SDA/SCL(I2C 总线并联),VCC/GND 也并过去,V+ 舵机电源如果要大电流建议每块板单独从电源端子拉一组粗线,别串着供。关键是每块板必须有不同的 I2C 地址——靠右上角 A0-A5 六个地址跳线,焊锡短路一个代表二进制地址加 1,默认地址是 0x40,短路 A0 就是 0x41,短路 A1 就是 0x42,A0+A1 是 0x43,以此类推,最多能到 0x7F,62 块板(因为 0x70 是全呼地址要避开)。
代码里就要为每块板声明一个对象:
Adafruit_PWMServoDriver pwm1 = Adafruit_PWMServoDriver(0x40);
Adafruit_PWMServoDriver pwm2 = Adafruit_PWMServoDriver(0x41);
void setup() {
Serial.begin(9600);
pwm1.begin();
pwm1.setPWMFreq(50);
pwm2.begin();
pwm2.setPWMFreq(50);
}注意每块板都要 begin() 和 setPWMFreq(),漏了一个那块板就不工作。PWM 频率是每块板独立设的,但同一时刻同一块板上所有通道共享一个频率——也就是说你不能让一块板一半通道 50Hz 驱动舵机、另一半 1kHz 驱动 LED,要混用就分两块板。
几个容易踩的坑
说几个我实际用下来反复遇到的问题。第一,共地。Arduino、舵机电源、PCA9685 三者必须共地,少一根地线舵机就会乱抖或者根本不动,这是新手最常犯的错。第二,舵机电源别接 VCC。VCC 是给芯片的,最大电流很小,舵机电流从 VCC 走会把板上走线烧断。第三,OE 脚悬空没事但要注意上电瞬间。刚上电 PCA9685 输出是不确定的,有些舵机会瞬间抽一下,要做"上电不抽搐"可以在 setup 里先 delay 几十毫秒再 setPWMFreq,或者把 OE 接到 Arduino 一个数字脚,初始化完再拉低。第四,I2C 上拉。PCA9685 板上有 10K 上拉到 VCC,多块板级联时上拉电阻并联会变小,总线上挂 5 块以上就可能因为上拉太强导致信号边沿变形,建议多板级联时只留一块板的上拉、其他板拆掉上拉电阻。第五,控制多舵机不要在 loop 里 delay() 等太长,否则舵机响应会卡,多舵机并发动作要用 millis() 做非阻塞时序,这个是 Arduino 多任务的常规操作,跟 PCA9685 无关但是实战中必用。
到这里接线、校准、基础代码、级联就全通了。PCA9685 是做小机器人、机械臂、多舵机项目绕不开的一块板,十几块钱一片把引脚和定时器问题一次解决,性价比极高。下篇我打算接一块板到 ESP32 上跑 ROS2 节点,做六足舵机控制的实战,有兴趣的话到时候再聊。











校准那段写得很实在,很多教程直接跳过校准,买回来舵机咔咔打齿才知道这步多重要
舵机电源别从Arduino取这条真的是踩过的坑,我第一次做六足就是这么把UNO烧了的
级联最多62块992路真的夸张,正常人2块就顶天了哈哈哈
刚好在攒机械臂,舵机引脚不够用正愁呢,这板子看起来是标准答案了