发布时间: 2026-09-23
这本文主要是说给那些正在搞51系列单片机的人看的, 这些人, 是要去驱动像SG90还有MG90S这种很常见的舵机, 当然, 也包括那些在学习嵌入式系统的朋友们, 所以本文提供的路径是实操性的, 这个实操路径是从定时器怎么配置开始说起, 一直到拿出完整的用语言写的代码为止, 那么核心之处就在于要解决一个特定的问题, 具体来讲, 这个问题就是用51单片机的定时器来产生那些符合舵机协议的PWM波形, 通过这种方式, 最终就能实现对角度的非常精确的控制。
舵机控制协议基础
舵机所使用的通用控制信号, 具体表现为一种频率为50Hz的PWM波, 其信号周期固定等于20ms。该信号中高电平的脉宽范围设定在0.5ms到2.5ms之间, 这个范围对应于舵机从0度位置转变到180度位置的运动过程。
它们之间的换算关系是确定的, 即当脉宽为0.5ms时舵机处于0度状态, 当脉宽变为1.5ms时舵机处于90度状态, 而当脉宽达到2.5ms时舵机则处于180度状态。如果系统以1微秒作为最小的计时单位来进行计算, 那么这些脉宽数值就依次对应为从500至2500的计数值区间。
51单片机定时器配置要点
以像这样常见的51系列芯片作为例子, 一般来说, 大家通常选用定时器0或者是定时器1来产生PWM信号, 关键的部分参数如下所述:
晶振的频率是12MHz, 这是最常见的配置。
定时器模式指的是模式1, 该模式是一个16位的定时器。
![]()
中断的时间间隔设定为每一毫秒触发一次事件, 在二十毫秒的整个时间段内总共产生二十次中断。
进行初值计算的操作是将65536减去1000, 得到的结果是64536, 这个结果也可以表示为十六进制的数字, 该数值是在1毫秒的定时初值设定情况下得出的。
完整C代码(Keil C51)
#
sbit SERVO = P1^0;
char = 0;
int = 1500; // 默认90°伟创动力,单位μs
void () {
TMOD |= 0x01;
TH0 = 0xFC;
TL0 = 0x18;
ET0 = 1;
EA = 1;
TR0 = 1;
}
void () 1 {
TH0 = 0xFC;
TL0 = 0x18;
++;
if ( >= 20000)
= 0;
if ( < )
SERVO = 1;
else
SERVO = 0;
}
void (float angle) {
= ( int)(500 + angle * 20.0);
}
void main() {
();
(90.0);
while(1) {
(0);
// 延时或等待
(180);
// 延时或等待
}
}
常见案例与疑难
在实际进行调试的时候, 常常会遇到以下三个问题。
1. 舵机出现持续抖动的现象: 这通常是定时初值计算出错, 从而导致周期偏离了标准的20毫秒。当使用12MHz晶振时, 1毫秒的定时初值设置为;若是采用11.晶振, 那就需要按照公式T=(65536−初值)×1.085μs重新进行换算和处理。
2. 角度精度不足: 占空比分辨率偏低。把判断粒度从ms级降低到μs级, 比如以1μs为步长, 这样可以让角度分辨率从6°增加到大约0.09°, 这是为了能够解决角度精度不够的问题, 同时还需要提高判断的精细程度, 从而使得角度的测量更加准确。
![]()
3. 多路舵机扩展: 因为51系列资源的限制情况, 当需要控制两路以上的时候, 建议改用带有CCP硬件PWM功能的增强型芯片, 或者直接借助于外部扩展芯片, 从而避免出现纯软件中断抢占时间的现象。
行动建议
1. 使用示波器去测量那个SERVO引脚, 这个操作是为了确认周期是20ms的, 然后还要确认脉宽是和设定的角度一一对应的。
2. 我们将把变量 从500逐步增加到2500, 并且每一步都会进行具体的测试。在这时候, 我们主要观察的方向是舵机的转动状况, 看看它的运行流程是否能实现完全平滑的效果, 以及内部是否出现了任何可能导致停止或停滞的卡顿现象。
3. 针对各个不同型号的舵机来说, 需要将原本存在于公式里面的那个系数20.0, 换成通过实际测试并且经过标定以后获得的那个数值。
4. 在机械装置这一侧, 额外安装上限位信号或者用来检测堵转情况的模块, 通过这种方式, 能够有效防止因为出现过冲现象而导致机器内部的齿轮遭受损坏。
等你彻底掌握了上面提到的定时配置逻辑, 同时又把基本的代码框架都弄清楚了之后, 51单片机驱动单路舵机这个动作就能始终保持稳定运作。
接着你要想再多扩展几路控制信号, 或者还得引入由ADC提供的闭环位置反馈环节时伟创动力舵机,整个过程中那些核心的PWM基本原理其实并不会发生改变, 你只需要对中断的分发策略做一些调整, 再去改动一下脉宽的核算计算方式就可以了。



