?一、簡介
上一節課主要學習了輸出比較和PWM的基本原理和結構,本節課就主要以實踐為主通過STM32最小系統板和驅動器控制舵機和直流電機。
上一節課的坐標?初學者STM32—輸出比較與PWM-CSDN博客
二、舵機
舵機是一種根據輸入PWM信號占空比來控制輸出角度的裝置
輸入PWM信號要求:周期為20ms,對應50Hz,高電平寬度為0.5ms~2.5ms
根據上圖所示,舵機內部是由直流電機驅動的,還有一個控制電路版,PWM輸入某個信號,它就會以某種角度轉動。根據最右邊的圖可知,我們這個舵機是180度的舵機,當給予的PWM脈沖信號不同寬度的時候就會以不同的角度進行旋轉。舵機在很多領域都會用上,比如遙控車的轉彎、機械臂的關節等等。
上圖是舵機的電路結構,主要由三根線組成,電源、地線和PWM信號線
不同顏色的舵機接線:
第一種????????黑色:GND????????紅色:+5V????????黃色:信號線
第二種????????棕色 :GND???????紅色:+5V????????橙色:信號線
三、直流電機驅動
直流電機是一種將電能轉換為機械能的裝置,有兩個電極,當電極正接時,電機正轉,當電極反接時,電機反轉
直流電機屬于大功率器件,GPIO口無法直接驅動,需要配合電機驅動電路來操作
TB6612是一款雙路H橋型的直流電機驅動芯片,可以驅動兩個直流電機并且控制其轉速和方向
我們通過看原理圖:電機接O1和O2,當左上和右下形成兩路推挽電路就會導通驅動電機旋轉,當右上和左下兩路導通的時候電機就以另一個方向旋轉。?
?
上圖為電機的驅動芯片和引腳定義圖。我們可以通過引腳定義圖知道如何輸入信號控制電機。
根據定義圖所示:PWM給與的信號按照一定頻率的高低運行就能實現電機的運行而且還能根據電平的時間實現速讀的變化。
注意:VM必須要和驅動電壓一致? ? ? ? H:高電平? ? ? ? L:低電平
四、PWM控制舵機
時鐘源連接著時基單元,我們通過配置好時基單元后計數器就會根據已經配置好的模式進行輸出控制,前面講過用輸出控制寄存器配置,通過配置好的參考電平,使能時候就可以控制GPIO口輸出相應的PWM了。
但是GPIO控制PWM的時候必須要配置成復用推挽輸出,我們參考下圖復用功能,當我們配置了復用推挽輸出,輸出數據寄存器就會斷開,片上外設就能夠連接上輸出控制然后才能夠輸出PWM波形。
代碼部分
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP;//復用推挽輸出GPIO_InitStructure.GPIO_Pin=GPIO_Pin_7;GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;GPIO_Init(GPIOA,&GPIO_InitStructure); TIM_InternalClockConfig(TIM3);
首先第一步就是打開總線APB1和APB2,TIM3是在APB1中,GPIO在APB2中
配置GPIO,注意這里輸出配置為復用推挽,上面說出了原因
開啟GPIO_Pin_7(TIM3在PA7引腳)(后面要考)
開啟TIM3的時基單元時鐘
TIM_TimeBaseInitTypeDef TIM_TimeBAseInitStructure;TIM_TimeBAseInitStructure.TIM_ClockDivision =TIM_CKD_DIV1; //分頻模式TIM_TimeBAseInitStructure.TIM_CounterMode =TIM_CounterMode_Up; //計數模式向上計數TIM_TimeBAseInitStructure.TIM_Period =20000 - 1; //重裝器的值ARRTIM_TimeBAseInitStructure.TIM_Prescaler =72 - 1; //預分頻器的值PSCTIM_TimeBAseInitStructure.TIM_RepetitionCounter = 0; //重復計數器的值TIM_TimeBaseInit(TIM3,&TIM_TimeBAseInitStructure);
然后配置時基單元?
這個配置按照平常配置,但是ARR和PSC必須要滿足舵機運行的頻率
PWM頻率:? Freq = CK_PSC / (PSC + 1) / (ARR + 1) = 50Hz
PWM占空比:? Duty = CCR / (ARR + 1)
PWM分辨率:? Reso = 1 / (ARR + 1)
這里設置的是20000的ARR 和 72的PSC,而后面的CCR的值是可變的,我設置為500到2500,這樣占空比就能在0.005~0.025(對應高電平寬度0.5ms~2.5ms)滿足舵機0~180度
TIM_OCInitTypeDef TIM_OCInitStructure;TIM_OCStructInit(&TIM_OCInitStructure);TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;//高級性TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;//使能端TIM_OCInitStructure.TIM_Pulse=0; //CCR TIM_OC2Init(TIM3,&TIM_OCInitStructure);TIM_Cmd(TIM3,ENABLE);
然后配置輸出比較的參數,同樣也是用結構體配置的?
TIM_OCPolarity :極性選擇為 高 ,當輸出REF為高電平時就是高電平,反之
然后輸出使能:TIM_OutputState_Enable
CCR:0(后面通過函數自己配置)
最后填入OC2Init中
由于我選擇的是TIM3的通道2(CH2),所以配置的是OC2Init
?上圖是通用定時器的部分結構,OC2Init中的OC2就是CH2通道,當然也可以選擇其他通道,這里只是舉個例子。因為每個通用定時器都能輸出四路PWM。
void PWM_SetCompare2(uint16_t Compare)
{TIM_SetCompare2(TIM3,Compare);
}void Servo_SetAngle(float Angle)
{PWM_SetCompare2(Angle / 180 * 2000 + 500);
}
TIM_SetCompare2這個函數也是因為用了OC2通道所以是TIM_SetCompare?2?而不是1或者其他
最后我們通過這個函數來填寫CCR的值,其中Compare是一個變量,在500~2500之間,實現了舵機從0~180度的控制。
五、直流電機的控制
由于直流電機的控制和舵機控制相似,就省略講解,但是也會重點講解時基單元的配置和方向控制
時基單元的配置
TIM_TimeBaseInitTypeDef TIM_TimeBAseInitStructure;TIM_TimeBAseInitStructure.TIM_ClockDivision =TIM_CKD_DIV1; //分頻模式TIM_TimeBAseInitStructure.TIM_CounterMode =TIM_CounterMode_Up; //計數模式向上計數TIM_TimeBAseInitStructure.TIM_Period =100 - 1; //重裝器的值ARRTIM_TimeBAseInitStructure.TIM_Prescaler =36 - 1; //預分頻器的值PSCTIM_TimeBAseInitStructure.TIM_RepetitionCounter = 0; //重復計數器的值TIM_TimeBaseInit(TIM2,&TIM_TimeBAseInitStructure);
PWM頻率:? Freq = CK_PSC / (PSC + 1) / (ARR + 1) = 20KHz?
為什么要這個頻率呢?因為頻率太低當我們捂住電機的時候會發現有嗚嗚聲,這樣就會產生噪音。我們將頻率提高到20KHz超出了讓人耳能聽到的頻率就不會聽到這個噪音。?
#include "stm32f10x.h" // Device header
#include "PWM.h"
void Motor_init(void)
{RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;GPIO_InitStructure.GPIO_Pin=GPIO_Pin_4 | GPIO_Pin_5;GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;GPIO_Init(GPIOA,&GPIO_InitStructure);PWM_Init();
}
void Motor_SetSpeed(int8_t Speed)
{if(Speed >= 0){GPIO_SetBits(GPIOA,GPIO_Pin_4);GPIO_ResetBits(GPIOA,GPIO_Pin_5);PWM_SetCompare3(Speed);}else{GPIO_ResetBits(GPIOA,GPIO_Pin_4);GPIO_SetBits(GPIOA,GPIO_Pin_5);PWM_SetCompare3(-Speed); }
}
GPIO_SetBits置1????????GPIO_ResetBits置0
他們分別連接TB6612的AO1和AO2,當參數speed大于0就是正轉,小于0就是反轉
六、完整代碼(按鍵控制舵機)
main.c
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "OLED.h"
#include "Servo.h"
#include "Key.h"uint8_t KeyNum;
float Angle;
int main(void)
{Key_Init();OLED_Init();Servo_Init();OLED_ShowString(1,1,"Angle:");while(1){KeyNum=Key_GetNum();if(KeyNum == 2){Angle+=30;if(Angle > 180){Angle = 0;}}Servo_SetAngle(Angle);OLED_ShowNum(1,7,Angle,3);}}
Servo.c
#include "stm32f10x.h" // Device header
#include "PWM.h"void Servo_Init(void)
{PWM_Init();
}
void Servo_SetAngle(float Angle)
{PWM_SetCompare2(Angle / 180 * 2000 + 500);
}
?PWM.c
#include "stm32f10x.h" // Device headervoid PWM_Init(void)
{RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP;//復用推挽輸出GPIO_InitStructure.GPIO_Pin=GPIO_Pin_2;GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;GPIO_Init(GPIOA,&GPIO_InitStructure); TIM_InternalClockConfig(TIM2); //上電默認是這個內部時鐘TIM_TimeBaseInitTypeDef TIM_TimeBAseInitStructure;TIM_TimeBAseInitStructure.TIM_ClockDivision =TIM_CKD_DIV1; //分頻模式TIM_TimeBAseInitStructure.TIM_CounterMode =TIM_CounterMode_Up; //計數模式向上計數TIM_TimeBAseInitStructure.TIM_Period =100 - 1; //重裝器的值ARRTIM_TimeBAseInitStructure.TIM_Prescaler =36 - 1; //預分頻器的值PSCTIM_TimeBAseInitStructure.TIM_RepetitionCounter = 0; //重復計數器的值TIM_TimeBaseInit(TIM2,&TIM_TimeBAseInitStructure);TIM_OCInitTypeDef TIM_OCInitStructure;TIM_OCStructInit(&TIM_OCInitStructure);TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;//高級性TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;//使能端TIM_OCInitStructure.TIM_Pulse=0; //CCR的值TIM_OC3Init(TIM2,&TIM_OCInitStructure);TIM_Cmd(TIM2,ENABLE);
}
void PWM_SetCompare3(uint16_t Compare)
{TIM_SetCompare3(TIM2,Compare);
}
PWM.h?
#ifndef __PWM_H
#define __PWM_Hvoid PWM_Init(void);
void PWM_SetCompare2(uint16_t Compare);
#endif
Servo.c?
#ifndef __SERVO_H
#define __SERVO_Hvoid Servo_Init(void);
void Servo_SetAngle(float Angle);#endif
Key.c?
#include "stm32f10x.h" // Device header
#include "Delay.h"
void Key_Init(void)
{RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IPU;GPIO_InitStructure.GPIO_Pin=GPIO_Pin_1;GPIO_Init(GPIOB,&GPIO_InitStructure);
}
uint8_t Key_GetNum(void)
{uint8_t KeyNum=0; if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_1)==0){Delay_ms(20);while(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_1)==0)Delay_ms(20);KeyNum=1;}return KeyNum;
}
Key.h?
#ifndef __KEY_H
#define __KEY_Hvoid Key_Init(void);
uint8_t Key_GetNum(void);#endif
這段完整代碼實現的效果:當按鍵按下的時候?舵機運動30度,加滿180度的時候就會重新歸位0度
七、完整代碼(按鍵控制電機速度)
main.c
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "OLED.h"
#include "Motor.h"
#include "Key.h"
uint8_t KeyNum;
int8_t Speed;
int main(void)
{Key_Init();OLED_Init();Motor_init();OLED_ShowString(1,1,"Speed:");while(1){KeyNum=Key_GetNum();if(KeyNum == 1){Speed+=20;if(Speed>100)Speed=0;}Motor_SetSpeed(Speed);OLED_ShowSignedNum(1,7,Speed,3);}
}
??Motor.c
#include "stm32f10x.h" // Device header
#include "PWM.h"
void Motor_init(void)
{RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;GPIO_InitStructure.GPIO_Pin=GPIO_Pin_4 | GPIO_Pin_5;GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;GPIO_Init(GPIOA,&GPIO_InitStructure);PWM_Init();
}
void Motor_SetSpeed(int8_t Speed)
{if(Speed >= 0){GPIO_SetBits(GPIOA,GPIO_Pin_4);GPIO_ResetBits(GPIOA,GPIO_Pin_5);PWM_SetCompare3(Speed);}else{GPIO_ResetBits(GPIOA,GPIO_Pin_4);GPIO_SetBits(GPIOA,GPIO_Pin_5);PWM_SetCompare3(-Speed); }
}
?Motor.h
#ifndef __MOTOR_H
#define __MOTOR_Hvoid Motor_init(void);
void Motor_SetSpeed(int8_t Speed);#endif
Key.c與Key.h和上面(按鍵控制舵機)的Key函數一樣
最后實現的效果:按鍵每按一次,電機就會以百分之20的比例進行增速最后增到100,再次按下就會歸零。