MG90S简介
- 舵机:
是一种角度伺服电机,一般是由齿轮组、电位器、舵机控制电路、直流电机构成。由发送控制信号来控制输出轴的位置。 - 数字舵机与模拟舵机的区别:
MG90S是一款常用的数字舵机,还有一款常用的模拟电机是MG90。
①数字舵机只需发送1次PWM信号就能转动到某个角度。
模拟舵机是需要多次发送PWM信号才能够保持在规定的位置上。
②模拟舵机存在“无反应区”,对于细微的动作,反应非常迟钝,或者没有动作。
数字舵机的“无反应区”更小,反应速度更快,加速和减速时也更快、更柔和。
(原因是数字舵机的控制电路比模拟舵机的多了微处理器和晶振) - 使用参数:
舵机控制一般需要20ms左右的时基脉冲,高电平部分一般为0.5ms-2.5ms范围内的角度控制脉冲部分。总间隔为2ms。(此数据是0-180°的舵机)
0.5ms | 0° |
---|
1ms | 45° |
1.5ms | 90° |
2ms | 135 ° |
2.5ms | 180° |
需求分析
- 需求:
舵机通过PWM波型来控制,我们想要的是给舵机一个角度,让它自己转换成占空比。 - 实现:
如下图所示:脉冲周期是20ms,高电平部分是2.5ms,表示180°。
上文已提到(0°到180°)对应着(0.5ms-2.5ms)。
假设角度为A,则A角度所占时间的比例为:(A/180)×(2.5-0.5),再加上0°初始时间,A角度所占的时间为0.5+(A/180) ×(2.5-0.5)。时间基数是20ms,那么占空比为[0.5+(A/180) ×(2.5-0.5)]/20。
上面计算的占空比,乘以20ms内总的定时器的计数次数,得到捕获比较寄存器(TIM_Pulse)的脉冲值,也就是A角度所占的定时器计数次数:[0.5+(A/180) ×(2.5-0.5)]/20×10000。10000是本设计设定的计数器的计数次数(详情见下文)。 - 分频系数和计数器设置:
此设计使用的是72M的单片机,分频系数设为(144-1),72000000Hz/144=500000Hz,频率为500K,周期为1/500000=2us。计数次数为(10000-1),也就是10000次,2us×10000=20ms。也就是定时器的周期是20ms。 - 误差计算:
当然定时器周期20ms,还有很多种设法。设计时,计数周期应该尽可能的大,这样计错一次数对舵机角度的影响越小(注意计数周期最大存在上限)。
0-180°是0.5-2.5ms,量程是2ms,1度约为11.11us。计数器计数一次是2us, 2/11.11约为0.18度。也就是说计数器计数一次,约为0.18°。如果计数器计错一次,误差0.18°。所以本设计的误差0.18°,这对于一般的设计来说完全足够。

代码实现
#include "SG90.h"
void TIM1_PWM_Init(u16 arr,u16 psc)
{
GPIO_InitTypeDef GPIO_InitStructure;
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_OCInitTypeDef TIM_OCInitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA , ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
TIM_DeInit(TIM1);
TIM_TimeBaseStructure.TIM_Period = arr;
TIM_TimeBaseStructure.TIM_Prescaler =psc;
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure);
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2;
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low;
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStructure.TIM_Pulse = 750;
TIM_OC2Init(TIM1, &TIM_OCInitStructure);
TIM_Cmd(TIM1, ENABLE);
TIM_CtrlPWMOutputs(TIM1,ENABLE);
TIM_OC2PreloadConfig(TIM1,ENABLE);
TIM_ARRPreloadConfig(TIM1, ENABLE);
}
void SERVO_Angle_Control(uint8_t Angle)
{
uint16_t temp=0;
temp = Angle*50/9 + 250;
TIM_SetCompare2(TIM1, temp);
}
#include "stm32f10x.h"
#include "SG90.h"
#include "Delay.h"
uint8_t Anglecount=0;
int main(void)
{
TIM1_PWM_Init(10000-1,144-1);
SERVO_Angle_Control(0);
while(1)
{
int i=0;
SERVO_Angle_Control(0);
delay_ms(1000);
for(i=0;i<90;i++)
{
SERVO_Angle_Control(i);
}
SERVO_Angle_Control(90);
delay_ms(1000);
}
}