平衡车 - 电机调速
这个是电机控制的具体的引脚图,我们可以看到在这个H桥的结构当中,AIN1为正,AIN2为负的时候,是正转,否则反转,所以,我们可以通过控制AIN1和AIN2来控制电机转动的方向,通过PWMA和PWMB来控制速度,而对应的AIN1和AIN2为PA10和PA9,同理,BIN1和BIN2为PB5和PB7,所以,首先,我们需要对这些引脚进行初始化。我们需要将STBY引脚设置为高电平,因为STBY为休眠引脚
🌈个人主页:羽晨同学
💫个人格言:“成为自己未来的主人~”
在我们的这篇文章当中,我们主要想要实现的功能的是电机调速功能。在我们的这篇文章中,主要实现的是开环的功能,而非闭环,也就是不加入PID对电机速度进行控制。
首先,我们需要将STBY引脚设置为高电平,因为STBY为休眠引脚,当STBY为低电平的时候,电机处于休眠状态,此时电机是不会进行运动的。
由电路图可知,STBY引脚,也就是PA1引脚,所以,我们需要将PA1设置为高电平。
在这个之前,我们先实现按键的功能,通过按键控制电机速度。
static Button_TypeDef userKey;//用户按钮
static void OnUserKey_Clicked(uint8_t clicks);
//
// @简介: 按键任务的初始化函数
//
void App_Button_Init(void)
{
Button_InitTypeDef Button_InitStruct = {0};
Button_InitStruct.GPIOx = GPIOA;
Button_InitStruct.GPIO_Pin = GPIO_Pin_11;
My_Button_Init(&userKey,&Button_InitStruct);
My_Button_SetClickCb(&userKey,OnUserKey_Clicked);
}
通过回调函数来控制按键按下之后的操作。
//
// @简介: 按键回调函数
//
static void OnUserKey_Clicked(uint8_t clicks)
{
}
所以,接下来,我们通过回调函数来实现对应的功能
首先,我们先设置STBY,来控制是休眠状态还是启动状态,也就是说,我们需要先配置PA1引脚。
//
// @简介: 初始化STBY引脚 PA1 -- Out -PP
//
static void STBY_Pin_Init(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
GPIO_InitTypeDef GPIO_InitStruct = {0};
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_1;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_2MHz;
GPIO_Init(GPIOA,&GPIO_InitStruct);
}
然后,我们设置一个函数来控制STBY的状态
//
// @简介: 控制TB6612进入休眠状态或者活动状态
// @参数: on 0 - 休眠状态,向STBY写L
// 非零 - 活动状态,向STBY写H
//
void App_Pwm_Cmd(uint8_t on)
{
if(on == 0)
{
GPIO_WriteBit(GPIOA,GPIO_Pin_1,Bit_RESET);//休眠
}
else
{
GPIO_WriteBit(GPIOA,GPIO_Pin_1,Bit_SET);//觉醒
}
}
这样的话,我们就可以在按键回调函数当中,通过按下按键来改变对应的状态
//
// @简介: 按键回调函数
//
static void OnUserKey_Clicked(uint8_t clicks)
{
if(clicks == 1)
{
pwm_on^=1;
App_Pwm_Cmd(pwm_on);
}
}
所以,这个时候来说,我们就实现了,只要按下按键,就可以控制STBY的状态。
然后,我们在main中对PWM进行初始化
#include "stm32f10x.h"
#include "delay.h"
#include "app_bat.h"
#include "app_button.h"
int main(void)
{
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);
App_Bat_Init();
App_Button_Init();
App_Pwm_Init();
while(1)
{
App_Bat_Proc();
App_Button_Proc();
}
}
这样,就可以实现通过按键来控制STBY的状态了。
接下来,我们就来实现电机调速的具体功能。
这个是电机控制的具体的引脚图,我们可以看到在这个H桥的结构当中,AIN1为正,AIN2为负的时候,是正转,否则反转,所以,我们可以通过控制AIN1和AIN2来控制电机转动的方向,通过PWMA和PWMB来控制速度,而对应的AIN1和AIN2为PA10和PA9,同理,BIN1和BIN2为PB5和PB7,所以,首先,我们需要对这些引脚进行初始化。
//
// @简介: 左电机的初始化
//
static void Motor_L_Init(void)
{
//初始化 PA9 PA10为Out_PP
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
GPIO_InitTypeDef GPIO_InitStruct = {0};
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_9 | GPIO_Pin_10;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_2MHz;
GPIO_Init(GPIOA,&GPIO_InitStruct);
}
//
// @简介: 右电机初始化
//
static void Motor_R_Init(void)
{
//初始化PB5和PB7
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
GPIO_InitTypeDef GPIO_InitStruct = {0};
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_7;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_2MHz;
GPIO_Init(GPIOB,&GPIO_InitStruct);
}
这样,我们就对对应的引脚进行了初始化
接下来,我们需要对对应的PWM进行初始化,一个是PA8一个是PB6,我们应该设置为AF_PP模式,因为PA8和PB6均被定时器所占用,所以为复用模式,又因为要输出高低电平,所以为推挽模式。
//
// @简介: 左电机的初始化
//
static void Motor_L_Init(void)
{
//初始化 PA9 PA10为Out_PP
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
GPIO_InitTypeDef GPIO_InitStruct = {0};
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_9 | GPIO_Pin_10;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_2MHz;
GPIO_Init(GPIOA,&GPIO_InitStruct);
//对PWM进行初始化,PA8 - AF_PP
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_8;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_2MHz;
GPIO_Init(GPIOA,&GPIO_InitStruct);
}
//
// @简介: 右电机初始化
//
static void Motor_R_Init(void)
{
//初始化PB5和PB7
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
GPIO_InitTypeDef GPIO_InitStruct = {0};
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_7;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_2MHz;
GPIO_Init(GPIOB,&GPIO_InitStruct);
//对PWM进行初始化,PB6 - AF_PP
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_6;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_2MHz;
GPIO_Init(GPIOB,&GPIO_InitStruct);
}
初始化完成之后,接下来,让我们完成对应的PWM的操作
这个是定时器内部的结构框图。
我们先来完成时基单元的参数设置,我们想要实现的效果为1000级可调,我们输入的是72MHz,为了让周期尽可能的小,所以我们的PSC为0,为了实现1000级可调,PWM是由CCR寄存器实现的,它的范围是0-ARR寄存器,所以,ARR应该为999,重复计数器RCR为0就好了,接下来,我们在代码中实现这个功能:
所以,我们对定时器进行初始化
//对定时器1进行初始化
RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1,ENABLE);
//设置时基单元的参数
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct = {0};
TIM_TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInitStruct.TIM_Period = 999;
TIM_TimeBaseInitStruct.TIM_Prescaler = 0;
TIM_TimeBaseInitStruct.TIM_RepetitionCounter = 0;
TIM_TimeBaseInit(TIM1,&TIM_TimeBaseInitStruct);
//设置时基单元的参数
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct = {0};
TIM_TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInitStruct.TIM_Period = 999;
TIM_TimeBaseInitStruct.TIM_Prescaler = 0;
TIM_TimeBaseInitStruct.TIM_RepetitionCounter = 0;
TIM_TimeBaseInit(TIM4,&TIM_TimeBaseInitStruct);
初始化时钟之后,我们对PWM进行设置,PWM是在CCR中进行设置,通过输出比较产生PWM波
//配置输出比较
TIM_OCInitTypeDef TIM_OCInitStruct = {0};
TIM_OCInitStruct.TIM_OCMode = TIM_OCMode_PWM1;
TIM_OCInitStruct.TIM_OCPolarity = TIM_OCPolarity_High;
TIM_OCInitStruct.TIM_OutputState = ENABLE;
TIM_OCInitStruct.TIM_Pulse = 0;
TIM_OC1Init(TIM1,&TIM_OCInitStruct);
//配置MOE的开关
TIM_CtrlPWMOutputs(TIM1,ENABLE);
//闭合定时器的总开关
TIM_Cmd(TIM1,ENABLE);
//配置输出比较
TIM_OCInitTypeDef TIM_OCInitStruct = {0};
TIM_OCInitStruct.TIM_OCMode = TIM_OCMode_PWM1;
TIM_OCInitStruct.TIM_OCPolarity = TIM_OCPolarity_High;
TIM_OCInitStruct.TIM_OutputState = ENABLE;
TIM_OCInitStruct.TIM_Pulse = 0;
TIM_OC1Init(TIM4,&TIM_OCInitStruct);
//配置MOE的开关
TIM_CtrlPWMOutputs(TIM4,ENABLE);
//闭合定时器的总开关
TIM_Cmd(TIM4,ENABLE);
接下来,我们来设置左右电机的占空比
//
// @简介: 控制左电机的PWM
// @参数: duty 占空比的具体指,-100.0f - 100.0f
//
void App_Pwm_Set_L(float duty)
{
float sign;//符号,正数 - +1,负数, - 1
if(duty >= 0) sign = 1;
else sign = -1;
duty = fabs(duty);
if(sign >= 0)//正传
{
GPIO_WriteBit(GPIOA,GPIO_Pin_9,Bit_SET);// AIN1 - 高
GPIO_WriteBit(GPIOA,GPIO_Pin_10,Bit_RESET);//AIN2 - 低
}
else//反转
{
GPIO_WriteBit(GPIOA,GPIO_Pin_10,Bit_SET);// AIN1 - 高
GPIO_WriteBit(GPIOA,GPIO_Pin_9,Bit_RESET);//AIN2 - 低
}
uint16_t ccr = duty/100.0f*999;
TIM_SetCompare1(TIM1,ccr);
}
//
// @简介: 控制右电机的PWM
// @参数: duty 占空比的具体指,-100.0f - 100.0f
//
void App_Pwm_Set_R(float duty)
{
float sign;//符号,正数 - +1,负数, - 1
if(duty >= 0) sign = 1;
else sign = -1;
duty = fabs(duty);
if(sign >= 0)//正传
{
GPIO_WriteBit(GPIOB,GPIO_Pin_5,Bit_SET);// AIN1 - 高
GPIO_WriteBit(GPIOB,GPIO_Pin_7,Bit_RESET);//AIN2 - 低
}
else//反转
{
GPIO_WriteBit(GPIOB,GPIO_Pin_7,Bit_SET);// AIN1 - 高
GPIO_WriteBit(GPIOB,GPIO_Pin_5,Bit_RESET);//AIN2 - 低
}
uint16_t ccr = duty/100.0f*999;
TIM_SetCompare1(TIM4,ccr);
}
更多推荐
所有评论(0)