文章目錄
- 一、硬體連接
- 1.器件清單:
- 2.接線:
- 3.驅動電機
- 二、軟體驅動代碼撰寫
- 1.初始化代碼
- 2.電機驅動代碼
- 總結
- 大家好哇!我是小光,嵌入式愛好者,一個想要成為系統架構師的普通大學生,
- 進入正題,最近在做小車,目前已經可以跑起來了,然后就是加入各種各樣的傳感器,使得她的功能更加豐富,
- 本次就談談做小車中的第一步,也是最重要的一步:PWM驅動直流減速電機,也是就讓小車跑起來,
- 非常感謝大家的閱讀,如果有不對的地方歡迎指正
一、硬體連接
1.器件清單:
1.STM32F103C8T6最小系統板
2.直流減速電機
3.TB6612FNG驅動模塊
2.接線:

接線方式1(PWM驅動電機):
PWMA----PA11:接板子可設定PWM的IO口,
PWMA----PA2:接板子可設定PWM的IO口;
STBY------3.3v:使能;
AIN1-------PB12:普通IO口;
AIN2-------PB13:普通IO口;
BIN1-------PB14:普通IO口;
BIN2-------PB15:普通IO口;
VM---------12V電源正極:供電;
GND-------電源負極;
VCC--------板子5V;
GND--------板子GND;
A1(AO1)————電機1(無正負)
A2(AO2)————電機1(無正負,和正傳反轉有關)
B1(BO1)————電機2(無正負)
B2(BO2)————電機2(無正負,和正傳反轉有關)
注意:TB6612一定要和板子共地;
接線方式2(不空速):
不用接PWMA和PWMB就可以了,
3.驅動電機
現在就說說為什么這樣接線吧:

我們只需要讓四個IO輸出相應的高低電平,然后通過PWM調速,就可以讓小車動起來了,是不是很簡單(狗頭保命),好了,下面開始講解軟體部分,
二、軟體驅動代碼撰寫
1.初始化代碼
代碼示例:
void Motor_Init(u16 arr,u16 psc)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); //使能PB埠時鐘
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12 | GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15; //埠配置
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推挽輸出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //50M
GPIO_Init(GPIOB, &GPIO_InitStructure); //根據設定引數初始化GPIOB
PWM_Init(arr,psc);
}
這就是很簡單的GPIO初始化啦,然后就是PWM初始化:
/**************************************************************************
函式功能:控制電機的兩路PWM初始化
入口引數:無
回傳 值:無
**************************************************************************/
void PWM_Init(u16 arr,u16 psc)
{
GPIO_InitTypeDef GPIO_InitStructure;
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_OCInitTypeDef TIM_OCInitStructure;
//使能GPIO和定時器時鐘
RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE); //
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA , ENABLE); //使能GPIO外設時鐘使能
//設定該引腳為復用輸出功能,輸出TIM1 CH4和TIM2 CH3的PWM脈沖波形
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2|GPIO_Pin_11; //TIM_CH1 //TIM_CH4
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //復用推挽輸出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
//初始化定時器arr、psc
TIM_TimeBaseStructure.TIM_Period = arr; //設定在下一個更新事件裝入活動的自動重裝載暫存器周期的值
TIM_TimeBaseStructure.TIM_Prescaler =psc; //設定用來作為TIMx時鐘頻率除數的預分頻值 不分頻
TIM_TimeBaseStructure.TIM_ClockDivision = 0; //設定時鐘分割:TDTS = Tck_tim
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIM向上計數模式
TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure); //根據TIM_TimeBaseInitStruct中指定的引數初始化TIMx的時間基數單位
//初始化比較引數
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; //選擇定時器模式:TIM脈沖寬度調制模式1
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //比較輸出使能
TIM_OCInitStructure.TIM_Pulse = 0; //設定待裝入捕獲比較暫存器的脈沖值
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //輸出極性:TIM輸出比較極性高
TIM_OC4Init(TIM1, &TIM_OCInitStructure); //根據TIM_OCInitStruct中指定的引數初始化外設TIMx
//MOE 主輸出使能
TIM_CtrlPWMOutputs(TIM1,ENABLE);
//CH4預裝載使能
TIM_OC4PreloadConfig(TIM1, TIM_OCPreload_Enable);
//使能TIMx在ARR上的預裝載暫存器
TIM_ARRPreloadConfig(TIM1, ENABLE);
//使能TIM1
TIM_Cmd(TIM1, ENABLE);
//TIM2_CH3
TIM_TimeBaseStructure.TIM_Period = arr; //設定在下一個更新事件裝入活動的自動重裝載暫存器周期的值
TIM_TimeBaseStructure.TIM_Prescaler =psc; //設定用來作為TIMx時鐘頻率除數的預分頻值 不分頻
TIM_TimeBaseStructure.TIM_ClockDivision = 0; //設定時鐘分割:TDTS = Tck_tim
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIM向上計數模式
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure); //根據TIM_TimeBaseInitStruct中指定的引數初始化TIMx的時間基數單位
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; //選擇定時器模式:TIM脈沖寬度調制模式1
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //比較輸出使能
TIM_OCInitStructure.TIM_Pulse = 0; //設定待裝入捕獲比較暫存器的脈沖值
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //輸出極性:TIM輸出比較極性高
TIM_OC3Init(TIM2, &TIM_OCInitStructure); //根據TIM_OCInitStruct中指定的引數初始化外設TIMx
TIM_CtrlPWMOutputs(TIM2,ENABLE); //MOE 主輸出使能
TIM_OC3PreloadConfig(TIM2, TIM_OCPreload_Enable); //CH3預裝載使能
TIM_ARRPreloadConfig(TIM2, ENABLE); //使能TIMx在ARR上的預裝載暫存器
TIM_Cmd(TIM2, ENABLE); //使能TIM2
}
大家可以仔細看看注釋,這里我用的是PA11(TIM1 CH4)和 PA2(TIM2 CH3),這樣我們就初始化完了,
2.電機驅動代碼
.h檔案:
//位帶操作,實作51類似的GPIO控制功能
//具體實作思想,參考<<CM3權威指南>>第五章(87頁~92頁).
//IO口操作宏定義
#define BITBAND(addr, bitnum) ((addr & 0xF0000000)+0x2000000+((addr &0xFFFFF)<<5)+(bitnum<<2))
#define MEM_ADDR(addr) *((volatile unsigned long *)(addr))
#define BIT_ADDR(addr, bitnum) MEM_ADDR(BITBAND(addr, bitnum))
//IO口地址映射
#define GPIOA_ODR_Addr (GPIOA_BASE+12) //0x4001080C
#define GPIOB_ODR_Addr (GPIOB_BASE+12) //0x40010C0C
#define GPIOA_IDR_Addr (GPIOA_BASE+8) //0x40010808
#define GPIOB_IDR_Addr (GPIOB_BASE+8) //0x40010C08
//IO口操作,只對單一的IO口!
//確保n的值小于16!
#define PAout(n) BIT_ADDR(GPIOA_ODR_Addr,n) //輸出
#define PAin(n) BIT_ADDR(GPIOA_IDR_Addr,n) //輸入
#define PBout(n) BIT_ADDR(GPIOB_ODR_Addr,n) //輸出
#define PBin(n) BIT_ADDR(GPIOB_IDR_Addr,n) //輸入
#define PWMA TIM2->CCR3 //PA2
#define AIN2 PBout(15)
#define AIN1 PBout(14)
#define BIN1 PBout(13)
#define BIN2 PBout(12)
#define PWMB TIM1->CCR4 //PA11
void Set_Pwm(int moto1,int moto2);
int myabs(int a);
這里我用了PB12-15作為輸入的引腳,大家也可以用其他的引腳,只是需要把宏定義改一下就可以了
.c檔案:
/**************************************************************************
函式功能:賦值給PWM暫存器
入口引數:左輪PWM、右輪PWM
回傳 值:無
**************************************************************************/
void Set_Pwm(int motorLeft,int motorRight)
{
if(motorLeft>0) AIN2=0, AIN1=1;
else if(motorLeft == 0) AIN2=0, AIN1=0;
else AIN2=1, AIN1=0;
PWMA=myabs(motorLeft);
if(motorRight>0) BIN1=0, BIN2=1;
else if(motorRight == 0) BIN1=0, BIN2=0;
else BIN1=1, BIN2=0;
PWMB=myabs(motorRight);
}
/**************************************************************************
函式功能:絕對值函式
入口引數:int
回傳 值:unsigned int
**************************************************************************/
int myabs(int a)
{
int temp;
if(a<0)
temp=-a;
else
temp=a;
return temp;
}
這個函式void Set_Pwm(int motorLeft,int motorRight)就是根據TB6612驅動電機的原理撰寫的代碼,方便我們控制電機,
我們呼叫時直接SetPwm(LeftSpeed,RightSpeed);就可以了,是不是很簡單呢?(狗頭保命);
總結
本文僅僅簡單介紹了TB6612控制直流電機的原理和驅動代碼的撰寫,這樣就完成了智能小車的第一步,后面會加上更多傳感器如:超聲波,紅外避障,紅外遙控,超聲波,手勢傳感器等等,去實作更多的功能,感謝閱讀,如果覺得我的文章對你有幫助的話,就點個贊吧!愛了愛了轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/382966.html
標籤:其他
上一篇:亞康萬瑋使用HyperMotion對多服務單位實施分批次自助式遷移,提前完成資料遷移目標
下一篇:嵌入式實時作業系統5——就緒表
