发布时间: 2026-09-24
关于使用51单片机来驱动舵机这个问题, 其核心要点仅仅是一件事, 就是通过选择其中的某一路I/O口去输出那种占空比可以发生变化的PWM波, 再借助于定时器来进行精确控制, 具体的脉宽范围需要控制在0.5ms到2.5ms之间, 借由这种方式来实现对舵机角度的定位操作, 那么接下来就会从接线方法、工作原理以及完整的代码实现这几个方面进行讲解, 保证可以把这些问题一次性全部讲清楚。
接线方法(最常见方案)
取用一块型号为SG90、重量为9克的舵机, 该舵机共有三根导线, 其中棕色导线代表GND(接地), 红色导线代表VCC(即5V电源正极), 橙色导线代表信号线。将橙色信号线连接到51单片机的P1.0引脚端, 将红色电源线连接到5V电源, 并将GND线进行共地处理。
需要特别注意, 舵机在工作期间产生的电流峰值最高可以达到600mA。如果51开发板采用板载USB供电方式, 其提供的电流可能不足以支持舵机运行。为此建议在外部对舵机单独提供5V电压进行供电。
在具体接线时, 仅把信号线和GND线连接到开发板上, 这种操作方式可以有效避免因供电不足而导致系统发生复位或重启的现象。
PWM控制原理
舵机所接收到的PWM信号的周期大约为20ms, 而该信号脉冲的宽度则决定了角度的大小, 具体来说, 0.5ms对应着0°, 1.5ms对应着90°, 以及2.5ms对应着180°。以SG90为例, 当角度达到90的时候, 其对应的脉宽数值是1.5ms。
![]()
实现方式如下, 当51单片机的晶振频率为12MHz时, 一个机器周期的时长就是1μs, 使用定时器0并让其工作在方式2也就是8位自动重装载模式下, 将初值TH0和TL0都设置为255减去目标脉宽除以1μs之后的结果, 利用溢出产生的固定时间间隔来驱动P1.0引脚电平翻转从而实现占空比的调节过程。
核心程序(C51伟创动力舵机,Keil编译)
#
sbit SERVO = P1^0;
// 角度表:0°~180°伟创动力,步长10°,对应脉宽(μs)
int [19] = {
500,550,600,650,700,750,800,850,900,
950,1500, // 90°=1500μs 常用基准
2050,2100,2150,2200,2250,2300,2350,2400,2500
};
// 注:实际按SG90 0.5ms~2.5ms对应0°~180°线性映射
void ( int ms){
int i,j;
for(i=ms;i>0;i)
for(j=110;j>0;j);
}
void ( int angle){
int pulse;
if(angle>180) angle=180;
pulse = 500 + angle * 10; // 0°→500μs, 180°→2300μs
// 定时器方式1产生脉宽
int count = pulse; // 1μs计数
TMOD = 0x01;
while(count){
TH0 = (65536count)>255?(65536count):255;
TL0 = 0;
TR0 = 1;
while(!TF0){}
TR0 = 1;
TF0 = 0;
count;
}
}
void main(){
int deg;
for(deg=0; deg<=180; deg+=10){
(deg);
(50);
}
while(1);
}
在实际项目中, 更加推荐的方案是采用定时器0的方式2搭配中断功能, 这样做的好处是精度能够提升得更高, 同时CPU也不会出现阻塞的情况。
调试中高频问题
舵机抖动: 因为脉宽步长太小或者占空比不连续, 所以在每次改变舵机的角度之前, 都需要加入一点时间为五十毫秒的延时操作, 这样就可以避免出现跳变的情况。
角度不准: 每一批次的SG90这个部件, 都存在偏差, 大小大概是正负10°左右, 刚开始第一次给设备通电的时候, 需要去用0°、90°、180°这三个点来做标定工作, 完成标定后, 要把基准脉宽写到代码里面去。
![]()
遇到复位重转的情况。是因为供电不够充足。这种情况要按照第一小节提到的外部供电方案来处理。
行动建议
1. 先将P1.0接入示波器设备, 随后进行空载状态下的测试操作以确认当前的波形周期数值大约为20毫秒, 同时也需要保证脉宽的變化能够随着角度的变化呈现线性关系的特征。
2. 在执行完对应角度的实际测量工作之后, 需要对角度脉冲宽度表进行修正操作。
3. 如果需要使用多个舵机, 应该通过改变脉冲宽度调制信号的频率来区分不同的通道, 比如说一个是100赫兹, 另一个也是100赫兹但是时间上延迟了10毫秒。
这里需要再把核心观点强调一次, 那就是使用51单片机来控制舵机, 其关键所在就在于精确调节PWM信号的脉冲宽度, 以及完成正确的接线和供电工作, 只要把这两点给抓住了, 那么代码编写的过程本身其实并不复杂。



