基于STM32F4的舵机控制

舵机的控制一般需要一个20ms左右的时基脉冲,该脉冲的高电平部分一般为0.5ms-2.5ms范围内的角度控制脉冲部分,总间隔为2ms。以180度角度伺服为例,那么对应的控制关系是这样的: 0.5ms--------------0度; 1.0ms------------45度; 1.5ms------------90度; 2.0ms-----------135度;

2.5ms-----------180度;

对于stm32来说,我们可以使用定时器PWM输出来控制舵机。

下面给出封装的舵机控制程序:

第一步:初始化定时器

void initServoPWM(TIM_TypeDef* TIMx,uint32_t RCC_APB1Periph_TIMx) { TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; //开启TIMx时钟 RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIMx, ENABLE); //配置TIMx TIM_DeInit(TIMx); TIM_TimeBaseStructure.TIM_Period = 2000;//20ms 50频率 TIM_TimeBaseStructure.TIM_Prescaler =819;//定时器分频系数,定时器时钟为82MHz,分频后得0.01MHz,即10kHz,0.1ms定时器加1 TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; TIM_TimeBaseStructure.TIM_RepetitionCounter = 0; TIM_TimeBaseInit(TIMx, &TIM_TimeBaseStructure); }

第二步:初始化PWM输出通道

void initServoChannel(GPIO_TypeDef* GPIOx,uint32_t RCC_AHB1Periph_GPIOx,u16 GPIO_Pin_x,uint16_t GPIO_PinSourcex,uint8_t GPIO_AF_TIMx,TIM_TypeDef* TIMx,u8 ch,u16 servoInitAngle) { servo_angle=servoInitAngle; RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOx, ENABLE); //配置复用功能,AGPIO1复用位TIMx GPIO_PinAFConfig(GPIOx,GPIO_PinSourcex,GPIO_AF_TIMx); //配置PWM输出管脚 初始化 GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.GPIO_Pin = GPIO_Pin_x; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;//设置为复用模式 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz; GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;//复用推挽输出 GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;//上拉 GPIO_Init(GPIOx, &GPIO_InitStructure); //PWM模式设置 与通道设置TIMx_CHx,每个定时器只有一个频率,每个通道可以设置不同的占空比 TIM_OCInitTypeDef TIM_OCInitStructure; TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;//模式PWM1,无论定时器是向上计数还是向下计数,计数值>有效值时为有效电平。PWM2模式相反 TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;//输出比较使能 TIM_OCInitStructure.TIM_Pulse = servoInitAngle*200/180+50;//设置比较值,写CCRx,当计数器到达100时,电平发送跳变,即设置CCRx的值 TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;//设输出极性为高,即有效值为高电平,当计数器<200时,PWM为高电平 switch(ch)//选择pwm通道 { case 1: TIM_OC1Init(TIMx, &TIM_OCInitStructure);//通道2初始化 TIM_OC1PreloadConfig(TIMx, TIM_OCPreload_Enable);//使能输出比较预装载 break; case 2: TIM_OC2Init(TIMx, &TIM_OCInitStructure);//通道初始化 TIM_OC2PreloadConfig(TIMx, TIM_OCPreload_Enable);//使能输出比较预装载 break; case 3: TIM_OC3Init(TIMx, &TIM_OCInitStructure);//通道初始化 TIM_OC3PreloadConfig(TIMx, TIM_OCPreload_Enable);//使能输出比较预装载 break; case 4: TIM_OC4Init(TIMx, &TIM_OCInitStructure);//通道初始化 TIM_OC4PreloadConfig(TIMx, TIM_OCPreload_Enable);//使能输出比较预装载 break; } TIM_ARRPreloadConfig(TIMx, ENABLE);//使能自动重装载寄存器允许位 //开启TIMx TIM_Cmd(TIMx, ENABLE); }

第三步:通道改变占空比控制舵机转动的角度:

void setServoAngle(int angle,TIM_TypeDef* TIMx,u8 ch) { if(angle>180) angle=180; else if(angle<0) angle=0; servo_temp=angle*200/180+50;//计算占空比 switch(ch)//选择pwm通道 { case 1: TIM_SetCompare1(TIMx,servo_temp); break; case 2: TIM_SetCompare2(TIMx,servo_temp); break; case 3: TIM_SetCompare3(TIMx,servo_temp); break; case 4: TIM_SetCompare4(TIMx,servo_temp); break; } //计算延迟时间 servo_temp=servo_angle-angle; if(servo_temp<0) servo_temp=-servo_temp; servo_temp=servo_temp*3+10; USART_SendNumber(USART1,angle); delay_ms(servo_temp); servo_angle=angle; }

经验分享 程序员 微信小程序 职场和发展