定时器舵机转动角度

1.什么是舵机

下图所示,最便宜的舵机sg90,常用三根或者四根接线,黄色为PWM信号控制
用处:垃圾桶项目开盖用、智能小车的全比例转向、摄像头云台、机械臂等
常见的有0-90°、0-180°、0-360°

黄色线接受PWM信号,红色及灰色分别接VCC和GND。

2.如何控制舵机?

上述说到黄色线接受PWM信号,通过向黄色线“灌入”PWM信号控制舵机转动。

2.1 PWM信号介绍

PWM,英文名Pulse Width Modulation,是脉冲宽度调制缩写,它是通过对一系列脉冲的宽度进
行调制,等效出所需要的波形(包含形状以及幅值),对模拟信号电平进行数字编码,也就是说
过调节占空比的变化来调节信号、能量等的变化
占空比就是指在一个周期内,信号处于高电平的
时间占据整个信号周期的百分比,例如方波的占空比就是50%,如下图所示。

2.2 如何输出PWM信号

2.2.1 硬件级PWM

通过查阅芯片手册,IO会标注这个输入输出口是否为PWM口,如下图的增强c51

<think>我们正在讨论使用定时器实现PWM控制舵机转动角度的方法。根据引用资料,舵机控制需要50Hz的PWM信号(周期20ms),其中高电平脉冲宽度在0.5ms到2.5ms之间对应舵机角度0°到180°。 步骤: 1. 配置定时器:设置定时器时钟和预分频,使得定时器计数周期为20ms(50Hz)。 2. 设置占空比:根据所需角度,计算对应的高电平时间(脉宽),然后转换为定时器的比较值(CCR)。 3. 在中断服务程序(或使用PWM输出模式)中更新比较值,以改变脉宽。 具体步骤: 一、定时器配置(以STM32为例) 假设系统时钟为72MHz,定时器预分频系数设置为7200-1,则定时器时钟频率为: 72MHz / 7200 = 10kHz(即计数周期为0.1ms) 自动重装载值(ARR)设置为200-1,则定时器周期为: 200 * 0.1ms = 20ms(满足50Hz要求) 二、角度转换 脉宽范围:0.5ms ~ 2.5ms 对应0°~180°。 定时器计数值与时间的关系:每0.1ms计数1次,所以: 0.5ms 对应计数值 = 5 2.5ms 对应计数值 = 25 因此,角度θ(0°~180°)对应的计数值(即比较寄存器CCR的值)为: $$ CCR = 5 + \frac{(25-5) \times \theta}{180} = 5 + \frac{20 \times \theta}{180} = 5 + \frac{\theta}{9} $$ 例如: 0° -> CCR=5 90° -> CCR=5+10=15 180° -> CCR=25 三、代码实现(参考引用[4]) 初始化定时器PWM模式(或使用定时器中断模拟)后,在主循环中设置角度即可。 示例代码(STM32标准库): ```c #include "stm32f10x.h" void PWM_Init(uint16_t arr, uint16_t psc) { // 初始化定时器和PWM输出(具体寄存器配置略) // 配置ARR和PSC } // 设置舵机角度 void SetAngle(uint8_t angle) { // 将角度转换为CCR值 uint16_t ccr = 5 + (angle / 9.0); // 注意:浮点运算,实际应用中可优化为整数运算 // 设置比较寄存器(假设使用TIM3通道2) TIM_SetCompare2(TIM3, ccr); } int main() { // 初始化PWM:ARR=199, PSC=7199(即7200-1) PWM_Init(199, 7199); while(1) { for(uint8_t angle = 0; angle <= 180; angle += 90) { SetAngle(angle); Delay_ms(1000); // 延时1秒 } } } ``` 四、注意事项 1. 浮点运算:在嵌入式系统中,浮点运算可能消耗较多资源,可以优化为整数运算。例如: ccr = 5 + (angle * 20) / 180; // 但这样会损失精度 更精确的做法是使用整数运算并四舍五入: ccr = 5 + (angle * 20 + 90) / 180; // 先乘以20,加90(即180/2)再除以180,实现四舍五入 2. 舵机响应时间:改变角度后,舵机需要一定时间转动,因此设置延时(如Delay_ms(500))让舵机到位。 3. 多路舵机控制:可以使用同一个定时器的多个通道(硬件PWM)或多个定时器。若使用软件模拟,则需在定时器中断中管理多个GPIO的状态。 五、软件模拟PWM(当硬件PWM不够时) 使用一个定时器中断(例如1ms中断),在中断服务函数中维护多个舵机控制线的状态(高电平开始时间和低电平持续时间)。 但注意:50Hz的PWM要求20ms周期,所以需要维护一个计数器,计数到20(即20ms)复位,然后在每个舵机需要翻转的时刻设置GPIO。 示例(伪代码): ```c // 假设控制4个舵机 uint8_t servo_count = 0; // 20ms周期计数器 uint8_t servo_pin[4] = {PIN0, PIN1, PIN2, PIN3}; uint8_t servo_high_start[4] = {0, 0, 0, 0}; // 每个舵机高电平开始的计数点 uint8_t servo_high_end[4] = {5, 5, 5, 5}; // 每个舵机高电平结束的计数点(初始0°) void Timer_IRQHandler() { servo_count++; if(servo_count >= 20) servo_count = 0; for(int i=0; i<4; i++) { if(servo_count == servo_high_start[i]) { // 设置对应引脚高电平 GPIO_Set(servo_pin[i]); } else if(servo_count == servo_high_end[i]) { // 设置对应引脚低电平 GPIO_Reset(servo_pin[i]); } } } // 设置舵机角度 void SetServoAngle(uint8_t id, uint8_t angle) { // 计算高电平时间(0.5~2.5ms)对应计数器值:假设每1ms计数1次,则高电平时间占0.5~2.5个计数点(但精度不够) // 为了提高精度,可将定时器中断设置为0.1ms一次,则20ms需要200个计数点,高电平占5~25个计数点 uint8_t high_time = 5 + angle / 9; // 0.1ms为单位,计算高电平持续时间的计数点数 servo_high_start[id] = 0; // 每个周期开始就置高电平(也可以固定起点) servo_high_end[id] = high_time; // 高电平结束点 } ``` 注意:软件模拟PWM会占用CPU资源,且精度不如硬件PWM,但可以控制多个舵机。 总结: 使用定时器实现PWM控制舵机的关键在于: - 配置定时器周期为20ms(50Hz) - 根据角度计算高电平时间(0.5ms~2.5ms),并转换为定时器的比较值(CCR) - 使用硬件PWM(定时器自带)或软件模拟(定时器中断)输出PWM信号 §§相关问题§§ 1. 如何优化舵机角度控制中的浮点运算? 2. 怎样用同一个定时器控制多路舵机? 3. 舵机控制信号产生抖动的原因是什么?如何消除? 4. 如何用STM32的定时器输出多路PWM信号? </think>### 使用定时器实现PWM控制舵机角度的方法 以下是基于STM32的定时器实现PWM精确控制舵机角度的完整方案(其他单片机原理类似): --- #### 1. **核心原理** 舵机控制需要满足两个关键参数: - **频率固定**:50Hz(周期 $T = 20ms$) - **脉宽可调**:高电平时间 $t$ 与角度 $\theta$ 的线性关系: $$ t = 0.5ms + \frac{\theta}{180^\circ} \times 2ms \quad (0^\circ \leq \theta \leq 180^\circ) $$ 对应关系: | 高电平时间 | 角度 | |------------|------| | 0.5ms | 0° | | 1.5ms | 90° | | 2.5ms | 180° | --- #### 2. **定时器配置步骤** 以STM32为例(系统时钟72MHz): ##### (1) 计算定时器参数 - **目标周期**:20ms(50Hz) - **预分频设置**: 若预分频值 $PSC = 7200 - 1$,则定时器时钟频率: $$ f_{tim} = \frac{72\text{MHz}}{7200} = 10\text{kHz} \quad (计数周期=0.1ms) $$ - **自动重载值**: $$ ARR = \frac{20ms}{0.1ms} - 1 = 200 - 1 $$ ##### (2) 角度转换公式 角度 $\theta$ 对应比较寄存器值 $CCR$: $$ CCR = \frac{t}{0.1ms} = 5 + \frac{\theta}{9} \quad \text{(浮点运算)} $$ 整数优化版(避免浮点): $$ CCR = 5 + \frac{\theta \times 20}{180} = 5 + \frac{\theta}{9} \quad \text{(四舍五入)} $$ --- #### 3. **代码实现** ##### (1) 初始化定时器(标准库示例) ```c void PWM_Init(uint16_t arr, uint16_t psc) { // 1. 开启时钟 RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); // 2. 配置时基单元 TIM_TimeBaseInitTypeDef TIM_TimeBaseStruct; TIM_TimeBaseStruct.TIM_Period = arr; // ARR值 TIM_TimeBaseStruct.TIM_Prescaler = psc; // PSC值 TIM_TimeBaseStruct.TIM_CounterMode = TIM_CounterMode_Up; TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStruct); // 3. 配置PWM模式 TIM_OCInitTypeDef TIM_OCStruct; TIM_OCStruct.TIM_OCMode = TIM_OCMode_PWM1; TIM_OCStruct.TIM_OutputState = TIM_OutputState_Enable; TIM_OCStruct.TIM_Pulse = 0; // 初始CCR值 TIM_OC2Init(TIM3, &TIM_OCStruct); // 使用通道2 // 4. 启动定时器 TIM_Cmd(TIM3, ENABLE); TIM_OC2PreloadConfig(TIM3, TIM_OCPreload_Enable); } ``` ##### (2) 角度控制函数 ```c // 设置角度(0~180) void SetAngle(uint8_t angle) { // 计算CCR值(浮点版) float ccr_f = 5.0 + angle / 9.0; // 整数优化版(四舍五入) uint16_t ccr = 5 + (angle * 20 + 90) / 180; TIM_SetCompare2(TIM3, ccr); // 更新比较寄存器 } ``` ##### (3) 主函数应用 ```c int main() { PWM_Init(199, 7199); // ARR=199, PSC=7199 → 20ms周期 while(1) { SetAngle(0); // 0° Delay_ms(1000); SetAngle(90); // 90° Delay_ms(1000); SetAngle(180); // 180° Delay_ms(1000); } } ``` --- #### 4. **关键注意事项** 1. **角度分辨率**: 每1°角度对应脉宽变化 $\Delta t = \frac{2ms}{180} \approx 11\mu s$,定时器精度需 $\leq 11\mu s$[^2] 2. **多路舵机控制**: - **硬件PWM**:同一定时器的不同通道(如TIM3-CH1/CH2/CH3/CH4) - **软件模拟**:定时器中断中管理多个GPIO(需高精度中断) 3. **防抖动措施**: - 电源端并联 $100\mu F$ 电解电容 + $0.1\mu F$ 陶瓷电容 - 信号线串联 $100-220\Omega$ 电阻 - 避免频繁角度切换(间隔 $\geq 200ms$) --- #### 5. **常见问题解决** | 问题现象 | 可能原因 | 解决方案 | |---------------|--------------------------|--------------------------| | 舵机抖动 | 电源不稳/PWM精度不足 | 增强电源滤波/提高定时器精度 | | 角度不准确 | 脉宽计算错误 | 校准 $0.5ms$ 和 $2.5ms$ 基准点 | | 响应延迟 | CPU负载过高 | 使用DMA更新CCR寄存器 |
评论 2
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值