STM32之使用PWM控制多路舵机

前言

    最近在玩一个6自由度的机械臂,我手上这台机械臂的核心控制器件就是那六个能够180度旋转的舵机了。想想之前在学校还没有系统性的把舵机给玩明白,所以就索性拿手上的STM32来自己写驱动代码,将6个舵机给驱动起来。

舵机控制原理

    舵机的控制原理还是比较简单的,而且控制的角度和精度能够比较好的按照开发者的意愿来进行,因此经常被应用与一些控制类器械中,如机械手、云台、2自由度摄像头等产品中。

    舵机的外接线一般分为3根线,电源线、地线和信号线,而控制舵机转动,就是通过信号线给舵机发送一系列的周期信号(一般的舵机的能接收的信号周期为20ms),然后通过控制周期信号的高电平的持续时间来达到控制舵机转动的目的。我手上的舵机就是根据高电平持续时间(0.5ms~2.5ms)来实现0~180的转动的。下面附上一张舵机周期信号控制和转动角度的图片说明。

    当然了,周期信号的产生可以使用很多方式,但是使用PWM来控制高电平的占空比不失为一种最好的应用方式。在STM32中,STM32的定时器也都提供有PWM的功能。下面就说明一下STM32输出PWM的具体实现方式。

使用STM32控制单个舵机

    在STM32中控制舵机,实际上就是开发STM32上的PWM功能,这部分功能需要配置STM32的定时器和GPIO复用共功能,然后就是通过修改定时器计数器的比较寄存器的数值来达到控制PWM的高电平占空比的目的。

    这里以STM32F767为例,说明一下具体的实现。

   下面使用到了STM32F7中的定时器3作为主定时器,使用通道4来产生PWM。需要注意的定时器3的通道4是通过GPIOB1接口输出的,因此还需要将GPIOB1配置为复用输出功能。PWM的输出比较极性设置为高。

TIM_HandleTypeDef TIM3_Handler;
TIM_OC_InitTypeDef TIM3_CH4Handler;
//arr 为自动重装值
//psc 为时钟预分频数
void TIM3_PWM_Init(u16 arr,u16 psc)
{ 
    TIM3_Handler.Instance=TIM3;    
    TIM3_Handler.Init.Prescaler=psc;      
    TIM3_Handler.Init.CounterMode=TIM_COUNTERMODE_UP;
    TIM3_Handler.Init.Period=arr;         
    TIM3_Handler.Init.ClockDivision=TIM_CLOCKDIVISION_DIV1;
    HAL_TIM_PWM_Init(&TIM3_Handler);      
    
    TIM3_CH4Handler.OCMode=TIM_OCMODE_PWM1; 
    TIM3_CH4Handler.Pulse=arr/2; 
    TIM3_CH4Handler.OCPolarity=TIM_OCPOLARITY_HIGH; //设置输出比较极性
    HAL_TIM_PWM_ConfigChannel(&TIM3_Handler,&TIM3_CH4Handler,TIM_CHANNEL_4);
	
    HAL_TIM_PWM_Start(&TIM3_Handler,TIM_CHANNEL_4);
}
//htim 为定时器句柄

void HAL_TIM_PWM_MspInit(TIM_HandleTypeDef *htim)
{
    GPIO_InitTypeDef GPIO_Initure;
 __HAL_RCC_TIM3_CLK_ENABLE();  
    __HAL_RCC_GPIOB_CLK_ENABLE();   
 
    GPIO_Initure.Pin=GPIO_PIN_1;
    GPIO_Initure.Mode=GPIO_MODE_AF_PP;  
    GPIO_Initure.Pull=GPIO_PULLUP;        
    GPIO_Initure.Speed=GPIO_SPEED_HIGH;     
 GPIO_Initure.Alternate= GPIO_AF2_TIM3;
    HAL_GPIO_Init(GPIOB,&GPIO_Initure);
}
//设置定时器的比较寄存器的值
void TIM_SetTIM3Compare4(u32 compare)
{
	TIM3->CCR4=compare; 
}
 
 
 
 

    以上的配置代码完成之后,就可以在主函数里面进行调用,并且使用PWM功能了。

//配置定时器3的自动重装值和时钟预分频数,定时器3使用的时钟为108MHz,这里进行108分频,定时器的预分频设置为1MHz
//自动重装值设置为20000,既该定时器每计数20000次触发一次中断,预分频为1MHz,则周期为20ms
TIM3_PWM_Init(20000-1,108-1)

    定时器初始化配置完之后,在主循环之前要对舵机进行一次复位操作,从上面的图中可以看出,在高电平持续时间为1.5ms的情况下,舵机能够回中,因此需要调用以下函数,设置定时器的初始比较寄存器的值为1500,即可以使得定时器复位回中。

TIM_SetTIM3Compare4(1500);

    需要说明一下,在修改定时器的比较寄存器的值的过程中,要有一些短暂的延时,以保证舵机将动作执行完成。

使用STM32控制多路舵机

    单个舵机控制能够完成之后,就可以尝试使用STM32的定时器控制多路舵机了。STM32的定时器中通用定时器能够产生多达4路PWM输出,高级定时器TIM1和TIM8还能够产生多达7路定时器。因此,我们完全可以使用STM32的一个定时器外设控制多路舵机,通过修改不同通道的比较寄存器的值,来达到控制舵机运动的目的。

    下面就以STM32F7控制4路舵机为例,贴出来定时器配置相关代码。

TIM_HandleTypeDef TIM3_Handler;         //定时器句柄 
TIM_OC_InitTypeDef TIM3_CH1Handler;     //定时器3通道1句柄
TIM_OC_InitTypeDef TIM3_CH2Handler;     //定时器3通道2句柄

TIM_OC_InitTypeDef TIM3_CH3Handler;     //定时器3通道3句柄
TIM_OC_InitTypeDef TIM3_CH4Handler;     //定时器3通道4句柄

//arr:自动重装值
//psc:时钟预分频数
void TIM3_PWM_Init(u16 arr,u16 psc)
{ 
    TIM3_Handler.Instance=TIM3;            //定时器3
    TIM3_Handler.Init.Prescaler=psc;       //定时器分频
	TIM3_Handler.Init.CounterMode=TIM_COUNTERMODE_UP;//向上计数模式
    TIM3_Handler.Init.Period=arr;          //自动重装载值
    TIM3_Handler.Init.ClockDivision=TIM_CLOCKDIVISION_DIV1;
    HAL_TIM_PWM_Init(&TIM3_Handler);       //初始化PWM
    
	
	TIM3_CH1Handler.OCMode=TIM_OCMODE_PWM1; 
	TIM3_CH1Handler.Pulse=arr/2;
	TIM3_CH1Handler.OCPolarity=TIM_OCPOLARITY_HIGH;
	HAL_TIM_PWM_ConfigChannel(&TIM3_Handler,&TIM3_CH1Handler,TIM_CHANNEL_1);//配置TIM3通道1
	HAL_TIM_PWM_Start(&TIM3_Handler,TIM_CHANNEL_1);//开启PWM通道1
	
	TIM3_CH2Handler.OCMode=TIM_OCMODE_PWM1; 
	TIM3_CH2Handler.Pulse=arr/2;
	TIM3_CH2Handler.OCPolarity=TIM_OCPOLARITY_HIGH;
	HAL_TIM_PWM_ConfigChannel(&TIM3_Handler,&TIM3_CH2Handler,TIM_CHANNEL_2);//配置TIM3通道2
	HAL_TIM_PWM_Start(&TIM3_Handler,TIM_CHANNEL_2);//开启PWM通道2
	
	
	TIM3_CH3Handler.OCMode=TIM_OCMODE_PWM1; //模式选择PWM1
	TIM3_CH3Handler.Pulse=arr/2;
	TIM3_CH3Handler.OCPolarity=TIM_OCPOLARITY_HIGH; 
	HAL_TIM_PWM_ConfigChannel(&TIM3_Handler,&TIM3_CH3Handler,TIM_CHANNEL_3);//配置TIM3通道3
	HAL_TIM_PWM_Start(&TIM3_Handler,TIM_CHANNEL_3);//开启PWM通道3

    TIM3_CH4Handler.OCMode=TIM_OCMODE_PWM1; //模式选择PWM1
    TIM3_CH4Handler.Pulse=arr/2;            //设置比较值,此值用来确定占空比,
                                            //默认比较值为自动重装载值的一半,即占空比为50%
    TIM3_CH4Handler.OCPolarity=TIM_OCPOLARITY_HIGH; 
    HAL_TIM_PWM_ConfigChannel(&TIM3_Handler,&TIM3_CH4Handler,TIM_CHANNEL_4);//配置TIM3通道4
    HAL_TIM_PWM_Start(&TIM3_Handler,TIM_CHANNEL_4);//开启PWM通道4
}
//此函数会被HAL_TIM_PWM_Init()调用 //htim:定时器句柄 void HAL_TIM_PWM_MspInit(TIM_HandleTypeDef *htim) {     GPIO_InitTypeDef GPIO_Initure;  __HAL_RCC_TIM3_CLK_ENABLE();   //使能定时器3     __HAL_RCC_GPIOB_CLK_ENABLE();   //开启GPIOB时钟  __HAL_RCC_GPIOA_CLK_ENABLE();   //开启GPIOA时钟         GPIO_Initure.Pin=GPIO_PIN_6|GPIO_PIN_7; //PA6 PA7     GPIO_Initure.Mode=GPIO_MODE_AF_PP;   //复用推完输出     GPIO_Initure.Pull=GPIO_PULLUP;          //上拉     GPIO_Initure.Speed=GPIO_SPEED_HIGH;     //高速  GPIO_Initure.Alternate=GPIO_AF2_TIM3; //PB1复用为TIM3_CH4    HAL_GPIO_Init(GPIOA,&GPIO_Initure);       GPIO_Initure.Pin=GPIO_PIN_1;            //PB1     GPIO_Initure.Mode=GPIO_MODE_AF_PP;   //复用推完输出     GPIO_Initure.Pull=GPIO_PULLUP;          //上拉     GPIO_Initure.Speed=GPIO_SPEED_HIGH;     //高速  GPIO_Initure.Alternate=GPIO_AF2_TIM3; //PB1复用为TIM3_CH4    HAL_GPIO_Init(GPIOB,&GPIO_Initure);       GPIO_Initure.Pin=GPIO_PIN_0 ;           //PB0     GPIO_Initure.Mode=GPIO_MODE_AF_PP;   //复用推完输出     GPIO_Initure.Pull=GPIO_PULLUP;          //上拉     GPIO_Initure.Speed=GPIO_SPEED_HIGH;     //高速  GPIO_Initure.Alternate=GPIO_AF2_TIM3; //PB1复用为TIM3_CH3         HAL_GPIO_Init(GPIOB,&GPIO_Initure); }
//设置TIM3通道1的占空比 //compare:比较值 void TIM_SetTIM3Compare1(u32 compare) {  TIM3->CCR1=compare; }
//设置TIM3通道2的占空比 //compare:比较值 void TIM_SetTIM3Compare2(u32 compare) {  TIM3->CCR2=compare; }
//设置TIM通道4的占空比 //compare:比较值 void TIM_SetTIM3Compare4(u32 compare) {  TIM3->CCR4=compare; }
//设置TIM通道3的占空比 //compare:比较值 void TIM_SetTIM3Compare3(u32 compare) {  TIM3->CCR3=compare; }

总结

    善于利用STM32单片机的外设资源,能够让开发效率大大提高。

   后续就是要对这些函数进行封装,用来作为舵机控制的统一接口,直接传递舵机控制的角度,来达到控制舵机的目的。






猜你喜欢

转载自blog.csdn.net/weixin_37127273/article/details/80492288