STM32F407控制舵机
STM32F407控制舵机运行
使用STM32F407控制舵机,首先来看下舵机图片
[黑红白,黑线接GND,红线接VCC,信号线接白色线(有的舵机线的颜色不同,例如褐色红色橘色,仅颜色不同接法还如上述)]
舵机需要信号的周期为20ms,即频率为50Hz。
接下来正式操作:
步骤一:STM32F4程序(本次程序的PWM信号产生的周期频率由定时器TIM14通道1产生(TIM14_CH1),想要使用其它定时器也没关系下面会讲到)
#include "pwm.h"
void TIM14_CH1_PWM_Init(u16 per,u16 psc)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
TIM_OCInitTypeDef TIM_OCInitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOF,ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM14,ENABLE);//使能TIM14时钟
GPIO_PinAFConfig(GPIOF,GPIO_PinSource9,GPIO_AF_TIM14);//管脚复用
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF; //复用输出模式
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_9;//管脚设置
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_100MHz;//速度为100M
GPIO_InitStructure.GPIO_OType=GPIO_OType_PP;//推挽输出
GPIO_InitStructure.GPIO_PuPd=GPIO_PuPd_UP;//上拉
GPIO_Init(GPIOF,&GPIO_InitStructure); //初始化结构体
TIM_TimeBaseInitStructure.TIM_Period=per; //自动装载值
TIM_TimeBaseInitStructure.TIM_Prescaler=psc; //分频系数
TIM_TimeBaseInitStructure.TIM_ClockDivision=TIM_CKD_DIV1;
TIM_TimeBaseInitStructure.TIM_CounterMode=TIM_CounterMode_Up; //设置向上计数模式
TIM_TimeBaseInit(TIM14,&TIM_TimeBaseInitStructure);
TIM_OCInitStructure.TIM_OCMode=TIM_OCMode_PWM1;
TIM_OCInitStructure.TIM_OCPolarity=TIM_OCPolarity_Low;
TIM_OCInitStructure.TIM_OutputState=TIM_OutputState_Enable;
TIM_OC1Init(TIM14,&TIM_OCInitStructure); //输出比较通道1初始化
TIM_OC1PreloadConfig(TIM14,TIM_OCPreload_Enable); //使能TIMx在 CCR1 上的预装载寄存器
TIM_ARRPreloadConfig(TIM14,ENABLE);//使能预装载寄存器
TIM_Cmd(TIM14,ENABLE); //使能定时器
}
程序内将定时器14的初始化放在函数内方便在主程序内调用。
注意1:舵机需要PWM信号为500微妙到2500微秒,500对应舵机-90度,2500对应舵机+90度,那么1500微秒就是舵机的0度了(按我的理解不同型号舵机也是这样的数据控制,并且试验验证过)。
注意2:程序内的这条语句会影响到实验结果:
TIM_OCInitStructure.TIM_OCPolarity=TIM_OCPolarity_Low;
你可以选择等号后面写TIM_OCPolarity_Low,或者TIM_OCPolarity_High。
按照我程序里为TIM_OCPolarity_Low,那么主程序内赋给PWM函数的值如下TIM_SetCompare1(TIM14,500); //舵机-90度 delay_ms(2000);//延时2秒,好观察现象 TIM_SetCompare1(TIM14,1500); //舵机0度 delay_ms(2000); TIM_SetCompare1(TIM14,2500); //舵机+90度 delay_ms(2000);
如果等号后面写TIM_OCPolarity_High,
即TIM_OCInitStructure.TIM_OCPolarity=TIM_OCPolarity_High;
那么主程序内赋给PWM函数的值如下
TIM_SetCompare1(TIM14,19500);
delay_ms(2000);
TIM_SetCompare1(TIM14,18500);
delay_ms(2000);
TIM_SetCompare1(TIM14,17500);
delay_ms(2000);
下面看主程序。
#include "system.h"
#include "SysTick.h"
#include "pwm.h"
int main()
{
SysTick_Init(168);
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //中断优先级分组 分2组
TIM14_CH1_PWM_Init(20000-1,84-1); //50Hz
while(1)
{
TIM_SetCompare1(TIM14,500);
delay_ms(2000);
TIM_SetCompare1(TIM14,1500);
delay_ms(2000);
TIM_SetCompare1(TIM14,2500);
delay_ms(2000);
}
}
注意1:定时器14产生的PWM信号的周期即频率由:
TIM14_CH1_PWM_Init(20000-1,84-1); //50Hz来产生
先讲第二个参数,84-1,为84分频,(假如你是72-1,那就是72分频的意思),我的TIM14在APB1总线上,而我设置APB1总线上即为82MHz,(你要移植到你的程序里,参考你自己的PWM程序的分频数即可),82MHz分频82,即为1MHz,即为1微秒,那么第一个参数20000-1即为1微秒乘以20000的意思,那么就是20ms即50Hz了,那么PWM的周期频率就可以了(注意:大家必须调到20ms,50Hz)。
你需要通过之前的学习,和F4的rcc头文件来确定不同定时器挂接在哪个总线上,例如TIM14在我F4的stm32f4xx_rcc.h文件里如下:
#define RCC_APB1Periph_TIM2 ((uint32_t)0x00000001)
#define RCC_APB1Periph_TIM3 ((uint32_t)0x00000002)
#define RCC_APB1Periph_TIM4 ((uint32_t)0x00000004)
#define RCC_APB1Periph_TIM5 ((uint32_t)0x00000008)
#define RCC_APB1Periph_TIM6 ((uint32_t)0x00000010)
#define RCC_APB1Periph_TIM7 ((uint32_t)0x00000020)
#define RCC_APB1Periph_TIM12 ((uint32_t)0x00000040)
#define RCC_APB1Periph_TIM13 ((uint32_t)0x00000080)
#define RCC_APB1Periph_TIM14 ((uint32_t)0x00000100)
#define RCC_APB1Periph_WWDG ((uint32_t)0x00000800)
#define RCC_APB1Periph_SPI2 ((uint32_t)0x00004000)
#define RCC_APB1Periph_SPI3 ((uint32_t)0x00008000)
#define RCC_APB1Periph_USART2 ((uint32_t)0x00020000)
#define RCC_APB1Periph_USART3 ((uint32_t)0x00040000)
#define RCC_APB1Periph_UART4 ((uint32_t)0x00080000)
#define RCC_APB1Periph_UART5 ((uint32_t)0x00100000)
#define RCC_APB1Periph_I2C1 ((uint32_t)0x00200000)
#define RCC_APB1Periph_I2C2 ((uint32_t)0x00400000)
#define RCC_APB1Periph_I2C3 ((uint32_t)0x00800000)
#define RCC_APB1Periph_CAN1 ((uint32_t)0x02000000)
#define RCC_APB1Periph_CAN2 ((uint32_t)0x04000000)
#define RCC_APB1Periph_PWR ((uint32_t)0x10000000)
#define RCC_APB1Periph_DAC ((uint32_t)0x20000000)
#define RCC_APB1Periph_UART7 ((uint32_t)0x40000000)
#define RCC_APB1Periph_UART8 ((uint32_t)0x80000000)
#define IS_RCC_APB1_PERIPH(PERIPH) ((((PERIPH) & 0x09013600) == 0x00) && ((PERIPH) != 0x00))
/**
* @}
*/
/** @defgroup RCC_APB2_Peripherals
* @{
*/
#define RCC_APB2Periph_TIM1 ((uint32_t)0x00000001)
#define RCC_APB2Periph_TIM8 ((uint32_t)0x00000002)
#define RCC_APB2Periph_USART1 ((uint32_t)0x00000010)
#define RCC_APB2Periph_USART6 ((uint32_t)0x00000020)
#define RCC_APB2Periph_ADC ((uint32_t)0x00000100)
#define RCC_APB2Periph_ADC1 ((uint32_t)0x00000100)
#define RCC_APB2Periph_ADC2 ((uint32_t)0x00000200)
#define RCC_APB2Periph_ADC3 ((uint32_t)0x00000400)
#define RCC_APB2Periph_SDIO ((uint32_t)0x00000800)
#define RCC_APB2Periph_SPI1 ((uint32_t)0x00001000)
#define RCC_APB2Periph_SPI4 ((uint32_t)0x00002000)
#define RCC_APB2Periph_SYSCFG ((uint32_t)0x00004000)
#define RCC_APB2Periph_TIM9 ((uint32_t)0x00010000)
#define RCC_APB2Periph_TIM10 ((uint32_t)0x00020000)
#define RCC_APB2Periph_TIM11 ((uint32_t)0x00040000)
#define RCC_APB2Periph_SPI5 ((uint32_t)0x00100000)
#define RCC_APB2Periph_SPI6 ((uint32_t)0x00200000)
#define RCC_APB2Periph_SAI1 ((uint32_t)0x00400000)
#define RCC_APB2Periph_LTDC ((uint32_t)0x04000000)
可以看到TIM14在APB1总线上,如果你想用其它定时器如TIM2到TIM13,你就可以不用注意时钟频率问题,因为它们都是和TIM14一样在AHB1上的,你只需要在代码内将有TIM14的地方改成TIMx你想要的那个定时器。当然多个定时器一起用也行,只要配置起来就OK。
TIM14映射在PF9上,我们将PF9连接在舵机的数据线上(白色线),给STM32F4开发板烧录程序,就可以按照自己想法操作舵机了。按照主程序里的参数设置500,即-90度,1500,即0度,2500,即+90度。那么舵机就会90度的间断转动。头文件该添加函数名的不要忘记。