🌈個人主頁:羽晨同學
💫個人格言:“成為自己未來的主人~”?
在我們的這篇文章當中,我們主要想要實現的功能的是電機調速功能。在我們的這篇文章中,主要實現的是開環的功能,而非閉環,也就是不加入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_PPRCC_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和PB7RCC_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_PPRCC_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_PPGPIO_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和PB7RCC_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_PPGPIO_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,負數, - 1if(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,負數, - 1if(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);
}