1.接线
SG90带有一个3P的接头 根据颜色分为
黄线(信号线)红线(电源线)棕色 (地线)
舵机的工作电压在4.8V-6V,接在STM32系统板上驱动不了,所以需要接电源模块单独的5V供电,我使用的是如图所示的电源模块 注: 如果STM32系统板供电和舵机供电不为同一模块,则需要共地,否则控制不成功!!!
2.舵机的控制
舵机的控制需要一个20ms左右的时基脉冲,该脉冲的高电平部分0.5ms到2.5ms控制舵机转动角度0°-180°呈线性变化。
控制原理:舵机内部有一个基准电路,产生周期20ms,宽度1.5ms的基准信号,通过比较器,将外加信号与基准信号相比较,判断出方向和大小,从而产生电机的转动信号。
知道原理之后,让我们来编写驱动代码,首先需要一个总周期为20ms的时基脉冲,这里采用TIM3CH2(定时器3通道2)对应的GPIOB5作为输出控制信号
首先是PWM的基础配置
void TIM3_PWM_Init(u16 arr,u16 psc)//GPIOB5
{
GPIO_InitTypeDef GPIO_InitStruct;
TIM_TimeBaseInitTypeDef TIM_TimeBaseStruct;
TIM_OCInitTypeDef TIM_OCInitStruct;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB|RCC_APB2Periph_AFIO,ENABLE);//RCC配置GPIO,复用时钟 ->APB2
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);//TIM3->APB1
//GPIO初始化
GPIO_InitStruct.GPIO_Pin=GPIO_Pin_5;//GPIOB5
GPIO_InitStruct.GPIO_Mode=GPIO_Mode_AF_PP;//复用推挽输出
GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOB,&GPIO_InitStruct);
GPIO_PinRemapConfig(GPIO_PartialRemap_TIM3,ENABLE);//设置部分重映射
//初始化TIM3
TIM_TimeBaseStruct.TIM_Period=arr;//定时器周期
TIM_TimeBaseStruct.TIM_Prescaler=psc;//预分频系数定时器周期
TIM_TimeBaseStruct.TIM_CounterMode=TIM_CounterMode_Up;//向上计数
TIM_TimeBaseStruct.TIM_ClockDivision=TIM_CKD_DIV1;
TIM_TimeBaseInit(TIM3,&TIM_TimeBaseStruct);
//设置比较通道CH2
/*
PWM模式2- 在向上计数时,一旦TIMx_CNT 有效电平;在向下计数时,一旦TIMx_CNT>TIMx_CCR1时通道1为有效电平,否则为无效电平。 PWM模式1- 在向上计数时,一旦TIMx_CNT 无效电平;在向下计数时,一旦TIMx_CNT>TIMx_CCR1时通道1为无效电平,否则为有效电平。 */ //PWM1极性高 向上记数 CNT小于CCR为高电平 TIM_OCInitStruct.TIM_OCMode=TIM_OCMode_PWM1; //PWM输出模式选择 TIM_OCInitStruct.TIM_Pulse=0; //通道比较值设定,可以自己设定 TIM_OCInitStruct.TIM_OCPolarity=TIM_OCPolarity_High; //极性选择 (有效电平为高/低) TIM_OCInitStruct.TIM_OutputState=TIM_OutputState_Enable;//输出状态使能 TIM_OC2Init(TIM3,&TIM_OCInitStruct); //通道CH2 GPIOB5 //使能预装载寄存器 TIM_OC2PreloadConfig(TIM3, TIM_OCPreload_Enable); //通道CH2 GPIOB5 //定时器使能 TIM_Cmd(TIM3,ENABLE); } 然后根据需要的周期设置总记数值以及分频系数 void Sg90_Init(void){ //舵机控制总周期要求为20ms //通过改变脉宽0.5ms-2.5ms代表0-180° TIM3_PWM_Init(2000-1,720-1); //2000*720/72M = 20000us = 20ms } 然后通过改变比较值来改变舵机转动的角度 void SetAngle(int angle){ //angle 范围为0-180 if(angle >= 0 || angle <= 180){ //总记数值为2000 比较值50-250代表0°-180° TIM_SetCompare2(TIM3,50+(200*angle/180));//修改定时器3通道2的比较值 } } 附带一个测试函数 void Sg90_Test(void){//运行一次角度+10° 大于180°时重新从0开始 static int n = 0; n += 10; SetAngle(n%180); } main.c sys.h为官方库函数文件 #include "sys.h" #include "delay.h" #include "led.h" #include "sg90.h" int main() { delay_init(); LedInit(); Sg90_Init(); while(1) { delay_ms(500); LED1 = ~LED1; Sg90_Test(); } } 这里使用了板载的LED灯,监测运行是否正常。 sg90.c #include "sg90.h" /********* SG90控制 GPIOB5 *********/ void Sg90_Init(void){ //舵机控制总周期要求为20ms //通过改变脉宽0.5ms-2.5ms代表0-180° TIM3_PWM_Init(1999,719); //2000*720/72M = 20000us = 20ms } void TIM3_PWM_Init(u16 arr,u16 psc)//GPIOB5 { GPIO_InitTypeDef GPIO_InitStruct; TIM_TimeBaseInitTypeDef TIM_TimeBaseStruct; TIM_OCInitTypeDef TIM_OCInitStruct; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB|RCC_APB2Periph_AFIO,ENABLE);//RCC配置GPIO,复用时钟 ->APB2 RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);//TIM3->APB1 //GPIO初始化 GPIO_InitStruct.GPIO_Pin=GPIO_Pin_5;//GPIOB5 GPIO_InitStruct.GPIO_Mode=GPIO_Mode_AF_PP;//复用推挽输出 GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz; GPIO_Init(GPIOB,&GPIO_InitStruct); GPIO_PinRemapConfig(GPIO_PartialRemap_TIM3,ENABLE);//设置部分重映射 //初始化TIM3 TIM_TimeBaseStruct.TIM_Period=arr;//定时器周期 TIM_TimeBaseStruct.TIM_Prescaler=psc;//预分频系数定时器周期 TIM_TimeBaseStruct.TIM_CounterMode=TIM_CounterMode_Up;//向上计数 TIM_TimeBaseStruct.TIM_ClockDivision=TIM_CKD_DIV1; TIM_TimeBaseInit(TIM3,&TIM_TimeBaseStruct); //设置比较通道CH2 /* PWM模式2- 在向上计数时,一旦TIMx_CNT 有效电平;在向下计数时,一旦TIMx_CNT>TIMx_CCR1时通道1为有效电平,否则为无效电平。 PWM模式1- 在向上计数时,一旦TIMx_CNT 无效电平;在向下计数时,一旦TIMx_CNT>TIMx_CCR1时通道1为无效电平,否则为有效电平。 */ //PWM1极性高 向上记数 CNT小于CCR为高电平 TIM_OCInitStruct.TIM_OCMode=TIM_OCMode_PWM1; //PWM输出模式选择 TIM_OCInitStruct.TIM_Pulse=0; //通道比较值设定,可以自己设定 TIM_OCInitStruct.TIM_OCPolarity=TIM_OCPolarity_High; //极性选择 (有效电平为高/低) TIM_OCInitStruct.TIM_OutputState=TIM_OutputState_Enable;//输出状态使能 TIM_OC2Init(TIM3,&TIM_OCInitStruct); //通道CH2 GPIOB5 //使能预装载寄存器 TIM_OC2PreloadConfig(TIM3, TIM_OCPreload_Enable); //通道CH2 GPIOB5 //定时器使能 TIM_Cmd(TIM3,ENABLE); } void SetAngle(int angle){ //angle 范围为0-180 if(angle >= 0 || angle <= 180){ //总记数值为2000 比较值50-250代表0°-180° TIM_SetCompare2(TIM3,50+(200*angle/180));//修改定时器3通道2的比较值 } } void Sg90_Test(void){//运行一次角度+10° 大于180°时重新从0开始 static int n = 0; n += 10; SetAngle(n%180); } sg90.h #ifndef __SG90_H_ #define __SG90_H_ #include "sys.h" void Sg90_Init(void); void SetAngle(int angle); void Sg90_Test(void); void TIM3_PWM_Init(u16 arr,u16 psc); #endif //__SG90_H_ led.c #include "led.h" void LedInit(void) { //库函数版本 GPIO_InitTypeDef GPIO_InitStructor; //开启硬件时钟 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC,ENABLE); //配置IO 推挽输出,输出速度 GPIO_InitStructor.GPIO_Pin=GPIO_Pin_13; GPIO_InitStructor.GPIO_Mode=GPIO_Mode_Out_PP; GPIO_InitStructor.GPIO_Speed=GPIO_Speed_50MHz; GPIO_Init(GPIOC,&GPIO_InitStructor); } led.h #ifndef __LED_H_ #define __LED_H_ #include "sys.h" #define LED1 PCout(13) void LedInit(void); #endif //__LED_H_ 附带项目总体文件 点击下载项目文件 链接:https://pan.baidu.com/s/1SlVU4H5foOcHIOLDQ_t5NQ?pwd=6666 提取码:6666 参考阅读
发表评论