STM32 PWM控制舵机转向详解
一 前言
我们在本章学习的时候,顺序是定时器 -> pwm ->舵机
定时器相关配置
舵机的标准脉冲信号为50Hz(20ms),所以定时器的值我们要一个周期时间配置成20ms
一般来说,stm32f103系列的芯片时钟信号频率为72MHz,经过一个预分频器(配置成7200-1),也就是将72MHz的信号变成了1MHz,进入计数器开始数数。
自动重装载寄存器值=定时器时钟频率 * PWM周期=1 *10^6 Hz* 20*10^(-3)seconds=200
所以我们在定时器配置的时候,要将自动重装载寄存器配置成200、预分频器配置成7200,配置如下:
TIM_Motorinit.TIM_Period =200-1;//自动重装载寄存器的值
TIM_Motorinit.TIM_Prescaler =7200-1;//预分频值
对于SG90舵机,推荐的 PWM 信号频率是 50Hz。这意味着每个周期的时间 T 是 20ms (因为 T=1/50Hz=20ms)。这两行代码就实现了SG90舵机的脉冲信号,这是基本定时器的工作,配置舵机的脉冲信号,也就是20ms
关于定时器的其他配置的相关代码:
1、向上计数模式 TIM_Motorinit.TIM_CounterMode = TIM_CounterMode_Up;
2、时钟分割为不分频 TIM_Motorinit.TIM_ClockDivision = TIM_CKD_DIV1;
以上就是定时器需要注意的配置,具体的代码还请往下看!
PWM
PWM周期
PWM(脉宽调制)信号的周期是指从一个高电平开始到下一个高电平开始的总时间。这是官方术语,通俗的来讲,它是由芯片内部产生的时钟信号方波,一高一低为一个周期。
周期反映了PWM信号的频率,周期 T 和频率 f 之间的关系如下:
T=1/f
PWM控制舵机角度
控制舵机角度的实际并不是占空比,而是脉宽的绝对时长,舵机输出轴转角只跟脉宽时长绝对值有关系,跟频率和占空比只是间接的关系。一般舵机是用0.5~2.5ms的脉宽来控制舵机角度,如图不同的脉宽控制不同的角度,同学们可以记一下
调节比较值,就能调节PWM的脉冲宽度
举个例子:告诉一下大家怎么计算出这个时间,比如我现在想让舵机一开始就转到45°,那么我现在该怎么算得到这个1ms?
解析:以下是需要用到的公式和思路,大家可以跟着捋一下
脉宽时长=PWM周期*占空比
占空比(%)=信号处于高电平的时间/信号从开始到结束的时间一个完整的脉冲周期。
PWM周期我们一般都设为20ms,这个20ms是我们计算0.5ms、1ms、1.5ms、2ms、2.5ms的基础前提,前面我也教大家配置好了。
我们可以将比较寄存器的值设为190,自动重装载寄存器标为200,假设在PWM模式1下,有效电平设为低电平时,计数模式为向上计数 。
来捋一下,当我们初始值比较寄存器就为190的时候,这时在PWM模式1,向上计数模式下,计数器要大于等于比较寄存器时,输入无效电平(高电平),所以在190~200这个范围都是高电平。
所以脉宽时长=20ms*(10/200)=1ms。我们就得到了我们所需的秒数1ms,这样舵机一开始就转到45°了。
以下是不同PWM模式下不同计数方式下的定义,同学们可自行记忆
舵机
舵机是一种位置伺服驱动器,并且是一种根据输入PWM信号占空比来控制输出角度的装置,一般舵机转动的角度是0~180°,高级的是0~360°,但这我只给大家介绍转动的角度是0~180°舵机的配置。
图片中的舵机具有三根输入线:电源线,地线和信号线,PWM就是输入到信号线来控制舵机。
以下接线位置发给大家自行观看,有时候那个负极线是黑色,提示大家一下。
二、代码配置
要实现一个项目:
在PWM2模式下,输出有效电平为高电平时,每隔500ms转动90°,实现舵机从0°-90°-180°。
motor.c文件
#include "stm32f10x.h"
#include "motor.h"
void motor_config(void)
{
GPIO_InitTypeDef GPIO_Motorinit;//GPIO结构体
TIM_TimeBaseInitTypeDef TIM_Motorinit;//基本配置的定时器结构体
TIM_OCInitTypeDef TIMPWM_Motorinit;//定时器输出比较结构体
RCC_APB2PeriphResetCmd( RCC_APB2Periph_GPIOB, ENABLE );//GPIOB时钟
RCC_APB1PeriphResetCmd( RCC_APB1Periph_TIM3, ENABLE );//定时器时钟
RCC_APB2PeriphResetCmd( RCC_APB2Periph_AFIO, ENABLE );//复用引脚的时钟
GPIO_PinRemapConfig( GPIO_PartialRemap_TIM3,ENABLE );//TIM3的部分引脚复用。这里是将
//PB5引脚复用为TIM3的输出引脚,用于产生PWM信号。
GPIO_Motorinit.GPIO_Mode =GPIO_Mode_AF_PP;//复用推挽输出模式,来输出定时信号(PWM波)
GPIO_Motorinit.GPIO_Pin =GPIO_Pin_5;//选择GPIOB的第5引脚。
GPIO_Motorinit.GPIO_Speed =GPIO_Speed_50MHz;//设置引脚的输出速度为50MHz。
GPIO_Init(GPIOB, &GPIO_Motorinit );//初始化GPIOB的配置
TIM_Motorinit.TIM_ClockDivision = TIM_CKD_DIV1;//设置时钟分割,不分频
TIM_Motorinit.TIM_CounterMode = TIM_CounterMode_Up;//向上计数模式
TIM_Motorinit.TIM_Period =200-1;//设置自动重装载值,意味着PWM周期为200个计时单位。
TIM_Motorinit.TIM_Prescaler =7200-1;//预分频值
TIM_TimeBaseInit(TIM3,&TIM_Motorinit);//初始化定时器3
TIMPWM_Motorinit.TIM_OCMode = TIM_OCMode_PWM2;//选择pwm模式2
TIMPWM_Motorinit.TIM_OutputState = TIM_OutputState_Enable;//比较输出使能
TIMPWM_Motorinit.TIM_OCPolarity = TIM_OCNPolarity_High;//选择有效电平为高电平
TIM_OC2Init( TIM3,&TIMPWM_Motorinit);//选择定时器3通道2
TIM_OC2PreloadConfig(TIM3, TIM_OCPreload_Enable);//使能TIM3通道2的预装载功能。预装载
//功能可以在更新时加载新的比较值,从而使PWM信号输出更为平滑。
TIM_Cmd( TIM3, ENABLE );//定时器3使能
}
在这个文件当中我们配置三个结构体,按照我配置的顺序,先配置GPIO结构体,再配置基本的定时器结构体,最后配置定时器输出比较结构体。配置GPIO结构体是因为PWM信号线要接到PB5上,注意我们要写复用时钟,并且要TIM3的部分引脚复用。这里是将 PB5引脚复用为TIM3的输出引脚,用于产生PWM信号。写GPIO_PinRemapConfig(GPIO_PartialRemap_TIM3,ENABLE );
易错点
配置基本的定时器结构体时,预分频器值和自动重装载寄存器值记得都要-1(因为都是从0开始计数的);
配置定时器输出比较结构体时,选择PWM模式,计数模式,以及有效电平是高还是低;根据这些自己要去计算角度关系。
最后三行代码大家一定也要记得输入,选择定时器通道,使能定时器3通道2的预装载功能,定时器3使能。
main.c文件
#include "stm32f10x.h"
#include "main.h"
#include "tim.h"
#include "motor.h"
void delay(uint16_t time)
{
uint16_t i=0;
while(time--)
{
i=12000;
while(i--);
}
}
int main()
{
uint16_t pwmval =155;
motor_config();
while(1)
{
for(pwmval=195;pwmval>=175;pwmval-=10)
{TIM_SetCompare2(TIM3, pwmval);
delay(500);
}
}
}
这里我想实现的效果,主要体现在for循环里有没有写对了。
for循环的整体思路
我讲一下for循环里的思路,首先直接看pwmval=195,它执行第二个语句(pwmval>=175),满足条件向下执行,更新PWM的值{TIM_SetCompare2(TIM3, pwmval);},此时PWM=195,舵机转到0度(20ms*(5/200)=0.5ms,等待500ms。执行完后返回到for括号中,执行第三个语句(pwmval-=10)此时pwmval=185,满足第二个语句大于等于175,又继续向下执行{TIM_SetCompare2(TIM3, pwmval);},此时PWM=185,舵机转到45度(20ms*(15/200)=1.5ms),等待500ms。执行完后返回到for括号中,执行第三个语句(pwmval-=10)此时pwmval=175,满足第二个语句大于等于175,又继续向下执行{TIM_SetCompare2(TIM3, pwmval);},此时PWM=175,舵机转到180度(20ms*(25/200)=2.5ms),等待500ms。执行完后返回到for括号中,执行第三个语句(pwmval-=10)此时pwmval=165,不满足第二个语句大于等于175。语句结束,舵机转动结束,完成项目(每隔500ms转动90°,实现舵机从0°-90°-180°)。
作者:most diligent