STM32 F767 控制舵机
前两天用阿波罗f7的开发板做了一下舵机控制,写个笔记做个记录以便以后复习,有错误的地方希望大家批评指正。
1. 舵机介绍
2. PWM信号产生原理
3. STM32 F7 PWM产生
4.代码
1.舵机介绍
舵机=小型直流电机+变速齿轮组+可调电位器+控制电路板
一般买舵机有三根线分别是 正极(红色线)接5v电压源 负极(棕色线)接GND 信号线(黄色/橙色)接io口 。
舵机接收的是PWM信号,当信号进入内部电路产生一个偏置电压,触发电机通过减速齿轮带动电位器移动,使电压差为零时,电机停转,从而达到伺服的效果。简单来说就是给舵机一个特定的PWM信号,舵机就可以旋转到指定的位置。
下图舵机内部构成:
舵机旋转角度与脉冲控制关系
舵机的控制一般需要一个20ms的时基脉冲,该脉冲的高电平部分一般为0.5ms~2.5ms范围内的角度控制脉冲部分。以180度角度舵机为例,那么对应的控制关系是这样的:
0.5ms--------------0度; 1.0ms------------45度;
1.5ms------------90度; 2.0ms-----------135度;
2.5ms-----------180度;
如下图所示:
2.pwm信号产生原理
脉冲宽度调制(PWM),是英文“Pulse Width Modulation”的缩写,简称脉宽调制,就是可以产生一个由TIMx_ARR寄存器确定频率,由TIMx_CCRx寄存器确定占空比的信号。它是利用微处理器的数字输出来对模拟电路进行控制的一种非常有效的技术。
在PWM输出模式下,除了CNT(计数器当前值)、ARR(自动重装载值)之外,还多了一个值CCRx(捕获/比较寄存器值)。
通用定时器可以利用GPIO引脚进行脉冲输出,在配置为比较输出,PWM输出功能时,捕获/比较寄存器TIMx_CCR,被用作比较功能简称比较寄存器。
过程:若配置脉冲计数器TIMx_CNT为向上计数,而重载寄存器TIMx_ARR被配置为N,即TIMx_CNT的当前计数值X在TIMx_CLK时钟源的驱动下不断累加,当TIMx_CNT的数值X大于N时,会重置TIMx_CNT数值为0重新计数。
而在TIMx_CNT技术的同时,TIMx_CNT的计数值X会与比较寄存器TIMx_CCR预先存储了的数值A进行比较。当脉冲计数器TIMx_CNT的值小于比较寄存器TIMx_CCR的值A时,输出高电平,相反则输出低电平。
如此循环,得到的脉冲周期就是重载寄存器TIMx_ARR存储的数值(N+1)乘以脉冲触发的时间周期,其脉冲宽度则为比较寄存器TIMx_CCR的值A乘以触发脉冲的周期,即输出pwm的占空比为A/(N+1),因为计数器时从0开始计时所以要加一。
下图为pwm产生原理图
3. STM32 F7 PWM产生
执行PWM操作之前,在软件中完成以下工作:
1、设置提供调制方波的片上定时器/计数器的周期
2、 在PWM控制寄存器中设置接通时间
3、设置PWM输出的方向,这个输出是一个通用I/O管脚
4、启动定时器
5、使能PWM控制器
在STM32中控制舵机,需要配置STM32的定时器和GPIO复用功能,然后就是通过修改定时器计数器的比较寄存器的数值来达到控制PWM的高电平占空比的目的。
我用了STM32F767中的TIM3作为主定时器,使用通道4来产生PWM。需要注意的定时器3的通道4是通过GPIOPB1接口输出的,因此还需要将GPIOB1配置为复用输出功能。PWM的输出比较极性设置为高。
4.代码:
1.PWM函数配置
#include "timer.h"
#include "led.h"
TIM_HandleTypeDef TIM3_Handler; //定时器句柄
TIM_OC_InitTypeDef TIM3_CH4Handler; //定时器3通道4句柄
//TIM3 PWM部分初始化
//PWM输出初始化
//arr:自动重装值
//psc:时钟预分频数
void TIM3_PWM_Init(u16 arr,u16 psc) //新增TIM3_PWM_Init函数,用于PWM输出
{
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_CH4Handler.OCMode=TIM_OCMODE_PWM1; //模式选择PWM1
TIM3_CH4Handler.Pulse=arr/2; //设置比较值,此值用来确定占空比,
//默认比较值为自动重装载值的一半,即占空比为50%
TIM3_CH4Handler.OCPolarity=TIM_OCPOLARITY_LOW; //输出比较极性为低
HAL_TIM_PWM_ConfigChannel(&TIM3_Handler,&TIM3_CH4Handler,TIM_CHANNEL_4);//配置TIM3通道4
HAL_TIM_PWM_Start(&TIM3_Handler,TIM_CHANNEL_4); //使能tim3,开启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时钟
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); //配置PB1复用映射为TIM3的PWM输出引脚
}
//设置TIM通道4的占空比
//compare:比较值
void TIM_SetTIM3Compare4(u32 compare)
{
TIM3->CCR4=compare;
}
采用PWM来控制舵机,就可以在主函数中调用TIM_SetTIM3Compare4();函数改变compare的值调节占空比来改变舵机输出角度了。
#include "sys.h"
#include "delay.h"
#include "usart.h"
#include "led.h"
#include "timer.h"
int main(void)
{
Cache_Enable(); //打开L1-Cache
HAL_Init(); //初始化HAL库
Stm32_Clock_Init(432,25,2,9); //设置时钟,216Mhz
delay_init(216); //延时初始化
uart_init(115200); //串口初始化
LED_Init(); //初始化LEd
TIM3_PWM_Init(20000-1,108-1);//自动重装载值设置为20000,及定时器每20000次触发一次中断
//定时器3使用的时钟为108MHz,这里进行108分频,定时器的预分频设置为1MHz
TIM_SetTIM3Compare4(1500); ///比较值设置为1500.使得定时器复位回中,舵机归位,每开始进入程序,舵机在中位
while(1)
{
TIM_SetTIM3Compare4(500); ///比较值设置为500,舵机反转90°
delay_ms(100);
TIM_SetTIM3Compare4(1000); ///比较值设置为1000,舵机反转45°
delay_ms(100);
TIM_SetTIM3Compare4(1500); ///比较值设置为1500.使得定时器复位回中,舵机归位
delay_ms(100);
}
}
ok了。。。。。舵机就可以转起来啦~~~~~主函数比较简单,大家可以自己调整。