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

物联沃分享整理
物联沃-IOTWORD物联网 » STM32 PWM控制舵机转向详解

发表回复