簡介
- 小車的動力部分由4個帶減速箱的電機,和兩個L298N電機驅動模塊組成。
- 通過STM32核心板控制電機驅動模塊,JDY-31藍牙模塊與手機通訊。
- 總共三塊電池,一塊專門給單片機供電,另外兩塊串聯(lián)在一起同時給電機驅動模塊供電(為什么選擇分別供電后面的電源硬件部分有說)。
- 源碼下載,提取碼:nxo3
硬件
硬件的基本介紹
- 電機的位置很重要,因為電機驅動模塊一個可以分別控制兩個電機,而且程序里面也是分別控制單個電機的動作。
- 如果電機的和自己想要的運動方向不一樣的話,交換一下接線端的兩個線就好了。程序里面小車前進默認是電機1、2CW(順時針),電機3、4CCW(逆時針)。
L298N電機驅動模塊
電機驅動模塊這里不細講,網上有很多資料,很簡單的。
下面這個是右邊的驅動板,控制電機1、2。
下面是左邊的驅動板,控制電機3、4。
- 兩個驅動板是并聯(lián)的,供電時應選擇粗一點的導線給驅動板供電,最好就不要使用杜邦線,如果使用杜邦線有可能會電壓不夠。
- 有的時候電機可能要用手轉一下才能動,那是因為電壓太小了,可以串聯(lián)幾個電池。我是用一個小米充電寶和4節(jié)干電池,電 壓應該在10V左右。
- 注意不能串聯(lián)太多充電寶,因為充電寶上面有過電流保護,電流太大充電寶可能會斷電,甚至有可能會直接弄壞充電寶。
- 如果是雙電源的話,單片機要和兩個驅動板共地。
- 電機驅動模塊上面的電機使能端的跳帽要拔掉,因為程序是用PWM來控制使能引腳的通點時長來讓小車轉彎的。
藍牙模塊JDY-31
我使用的是透傳藍牙模塊,簡單來說就是手機連接后給藍牙發(fā)送什么數(shù)據(jù),然后藍牙模塊再原封不動的通過串口發(fā)給單片機,所以只要懂串口的基本通信就好了。
- 0V和3.3V是從單片機上取電的,驅動板取電的話有可能會有干擾。
- PA2、PA3是單片機的串口2引腳。本來我想用串口1通訊的,但是好像串口1只能接受到單片機發(fā)出來的數(shù)據(jù),不能用手機發(fā)送進去給單片機(有可能是因為串口1的時鐘頻率太高),而且串口1正好留出來下載程序,所以就選擇了串口2。
- 藍牙模塊的默認波特率是9600,為了方便我也將串口的波特率也初始化成了9600。
- 藍牙模塊的STATE引腳是藍牙的連接狀態(tài)引腳,連接成功會變成高電平。該引腳我用來給小車做緊急剎車,當藍牙沒有連接或是斷開小車會自動剎車,以免藍牙突然斷開時小車失控的運動。
電源
小車采用雙電源供電
- 這里我選擇用兩個電源分別給單片機和驅動板供電的原因
電機啟動會有很大的啟動電流會在一瞬間將電流全部拉走,使得單片機斷電,如果藍牙模塊也是從單片機上取點也會斷電。
直接電機的電刷會產生火花對通訊有干擾,有些質量好的電機可能沒有(不太確定是不是這個原因,但同電源時通訊確實有干擾,藍牙會接收一些奇怪的數(shù)據(jù))。 - 驅動板的兩塊電源串聯(lián)連接,然后連接到驅動板的電源接線端。
程序
程序只要按照上面的連接都是可以直接使用,如果硬件有改動我也有定義宏可以直接做更改。
代碼里面的注釋比較詳細,這里只是將重要的代碼放上來,稍作講解,最好是直接下載來看。
下載地址,提取碼:qsmu
main.c
#include "stm32f10x.h" // Device header
#include "MTR_GPIO.h"
#include "USART.h"
#include "LED.h"
#include "blueTooth.h"
#include "PWM_GeneralTim.h"int main(void){USART_Config();//串口MTR_GPIOInit();//電機引腳GENERAL_TIM_Init();//定時器PWM初始化,用于小車轉向blueToothInit();//藍牙初始化LEDInit();printf("-----指令-----\n\0x01:小車后退\n\0x02:小車向左\n\0x03:小車向右\n\0x04:小車前進\n\0x05:小車剎車\n\0x06:電機停止\n\0x07:小車逆時針\n\0x08:小車轉向停止\n\0x09:小車順時針\n");while(1){//如果藍牙斷開,小車會一直在剎車狀態(tài)if(BLUE_TOOTH_STATE != Bit_SET){MTR_CarBrakeAll();}}
}
stm32f10x_it.c
void DEBUG_USART_IRQHandler(void){uint8_t CMD = 0;//接收的命令if(USART_GetITStatus(DEBUG_USARTx,USART_IT_RXNE)!=RESET){LED1_ON;CMD = USART_ReceiveData(DEBUG_USARTx);//讀取一個switch(CMD){case 0x06://電機停止MTR_CarBrakeAll();printf("0x06");break;case 0x08://小車轉向停止PWM_CarMaxGo();printf("0x08");break;case 0x05://小車剎車MTR_CarBrakeAll();printf("0x05");break;case 0x02://小車向左PWM_CarLeft();printf("0x02");break;case 0x03://小車向右PWM_CarRight();printf("0x03");break;case 0x04://小車前進MTR_CarGo();printf("0x04");break;case 0x01://小車后退MTR_CarBackGo();printf("0x01");break;case 0x07://小車逆時針MTR_CarCCW();printf("0x07");break;case 0x09://小車順時針MTR_CarCW();printf("0x09");break;}LED1_OFF;//讓LED閃爍來表示數(shù)據(jù)的接收}USART_ClearFlag(DEBUG_USARTx,USART_FLAG_RXNE);
}
- 串口通過接收十六進制的指令來控制驅動板。
- 接收到特定的指令后,單片機會將小車執(zhí)行的指令再發(fā)送回給藍牙。
MTR_GPIO.c
#include "MTR_GPIO.h"//剎車
void MTR_CarBrakeAll(void){MTR1_BRAKE;MTR2_BRAKE;MTR3_BRAKE;MTR4_BRAKE;
}//前進
void MTR_CarGo(void){MTR1_CW;MTR2_CW;MTR3_CCW;MTR4_CCW;
}//后退
void MTR_CarBackGo(void){MTR1_CCW;MTR2_CCW;MTR3_CW;MTR4_CW;
}//順時針
void MTR_CarCW(void){MTR1_CCW;MTR2_CCW;MTR3_CCW;MTR4_CCW;
}//逆時針
void MTR_CarCCW(void){MTR1_CW;MTR2_CW;MTR3_CW;MTR4_CW;
}void MTR_GPIOInit(void){GPIO_InitTypeDef GPIO_InitStructure;RCC_APB2PeriphClockCmd(MTR1_GPIO_CLK|MTR2_GPIO_CLK|MTR3_GPIO_CLK|MTR4_GPIO_CLK,ENABLE);//時鐘GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;//推挽輸出//電機1GPIO_InitStructure.GPIO_Pin = MTR1_GPIO_PIN;GPIO_Init(MTR1_GPIO_PORT, &GPIO_InitStructure);//電機2GPIO_InitStructure.GPIO_Pin = MTR2_GPIO_PIN;GPIO_Init(MTR2_GPIO_PORT, &GPIO_InitStructure);//電機3GPIO_InitStructure.GPIO_Pin = MTR3_GPIO_PIN;GPIO_Init(MTR3_GPIO_PORT, &GPIO_InitStructure);//電機4GPIO_InitStructure.GPIO_Pin = MTR4_GPIO_PIN;GPIO_Init(MTR4_GPIO_PORT, &GPIO_InitStructure);//小車剎車MTR_CarBrakeAll();
}
注意:因為單片機是控制驅動板從而間接的控制電機,為了簡單我直接把控制驅動板的引腳看成是控制電機的。
- 電機的引腳初始化。
- 小車前進、后退、原地旋轉和剎車的函數(shù)封裝。
MTR_GPIO.h
#ifndef __MTR_GPIO_H
#define __MTR_GPIO_H#include "stm32f10x.h"/*小車四輪驅動電機1:右上電機2:右下電機3:左上電機4:左下
*/
#define MTR1_GPIO_PORT GPIOB
#define MTR1_GPIO_CLK RCC_APB2Periph_GPIOB
#define MTR1_GPIO_PIN GPIO_Pin_6|GPIO_Pin_7
#define MTR1_CW {GPIO_ResetBits(MTR1_GPIO_PORT,GPIO_Pin_6);GPIO_SetBits(MTR1_GPIO_PORT,GPIO_Pin_7);}//順時針
#define MTR1_CCW {GPIO_SetBits(MTR1_GPIO_PORT,GPIO_Pin_6);GPIO_ResetBits(MTR1_GPIO_PORT,GPIO_Pin_7);}//逆時針
#define MTR1_BRAKE GPIO_ResetBits(MTR1_GPIO_PORT,MTR1_GPIO_PIN);#define MTR2_GPIO_PORT GPIOB
#define MTR2_GPIO_CLK RCC_APB2Periph_GPIOB
#define MTR2_GPIO_PIN GPIO_Pin_8|GPIO_Pin_9
#define MTR2_CW {GPIO_ResetBits(MTR2_GPIO_PORT,GPIO_Pin_8);GPIO_SetBits(MTR2_GPIO_PORT,GPIO_Pin_9);}//順時針
#define MTR2_CCW {GPIO_SetBits(MTR2_GPIO_PORT,GPIO_Pin_8);GPIO_ResetBits(MTR2_GPIO_PORT,GPIO_Pin_9);}//逆時針
#define MTR2_BRAKE GPIO_ResetBits(MTR2_GPIO_PORT,MTR2_GPIO_PIN);#define MTR3_GPIO_PORT GPIOB
#define MTR3_GPIO_CLK RCC_APB2Periph_GPIOB
#define MTR3_GPIO_PIN GPIO_Pin_12|GPIO_Pin_13
#define MTR3_CW {GPIO_ResetBits(MTR3_GPIO_PORT,GPIO_Pin_12);GPIO_SetBits(MTR3_GPIO_PORT,GPIO_Pin_13);}//順時針
#define MTR3_CCW {GPIO_SetBits(MTR3_GPIO_PORT,GPIO_Pin_12);GPIO_ResetBits(MTR3_GPIO_PORT,GPIO_Pin_13);}//逆時針
#define MTR3_BRAKE GPIO_ResetBits(MTR3_GPIO_PORT,MTR3_GPIO_PIN);#define MTR4_GPIO_PORT GPIOB
#define MTR4_GPIO_CLK RCC_APB2Periph_GPIOB
#define MTR4_GPIO_PIN GPIO_Pin_14|GPIO_Pin_15
#define MTR4_CW {GPIO_ResetBits(MTR4_GPIO_PORT,GPIO_Pin_14);GPIO_SetBits(MTR4_GPIO_PORT,GPIO_Pin_15);}//順時針
#define MTR4_CCW {GPIO_SetBits(MTR4_GPIO_PORT,GPIO_Pin_14);GPIO_ResetBits(MTR4_GPIO_PORT,GPIO_Pin_15);}//逆時針
#define MTR4_BRAKE GPIO_ResetBits(MTR4_GPIO_PORT,MTR4_GPIO_PIN);void MTR_CarBrakeAll(void); //小車剎車
void MTR_CarGo(void); //小車前進
void MTR_CarBackGo(void); //小車后退
void MTR_CarCW(void); //小車順時針轉
void MTR_CarCCW(void); //小車逆時針轉
void MTR_GPIOInit(void);#endif
PWM_GeneralTim.c
#include "PWM_GeneralTim.h" static void GENERAL_TIM_GPIO_Config(void)
{GPIO_InitTypeDef GPIO_InitStructure;// 輸出比較通道1 GPIO 初始化RCC_APB2PeriphClockCmd(GENERAL_TIM_CH1_GPIO_CLK, ENABLE);GPIO_InitStructure.GPIO_Pin = GENERAL_TIM_CH1_PIN;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GENERAL_TIM_CH1_PORT, &GPIO_InitStructure);// 輸出比較通道2 GPIO 初始化RCC_APB2PeriphClockCmd(GENERAL_TIM_CH2_GPIO_CLK, ENABLE);GPIO_InitStructure.GPIO_Pin = GENERAL_TIM_CH2_PIN;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GENERAL_TIM_CH2_PORT, &GPIO_InitStructure);// 輸出比較通道3 GPIO 初始化RCC_APB2PeriphClockCmd(GENERAL_TIM_CH3_GPIO_CLK, ENABLE);GPIO_InitStructure.GPIO_Pin = GENERAL_TIM_CH3_PIN;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GENERAL_TIM_CH3_PORT, &GPIO_InitStructure);// 輸出比較通道4 GPIO 初始化RCC_APB2PeriphClockCmd(GENERAL_TIM_CH4_GPIO_CLK, ENABLE);GPIO_InitStructure.GPIO_Pin = GENERAL_TIM_CH4_PIN;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GENERAL_TIM_CH4_PORT, &GPIO_InitStructure);
}///*
// * 注意:TIM_TimeBaseInitTypeDef結構體里面有5個成員,TIM6和TIM7的寄存器里面只有
// * TIM_Prescaler和TIM_Period,所以使用TIM6和TIM7的時候只需初始化這兩個成員即可,
// * 另外三個成員是通用定時器和高級定時器才有.
// *-----------------------------------------------------------------------------
// *typedef struct
// *{ TIM_Prescaler 都有
// * TIM_CounterMode TIMx,x[6,7]沒有,其他都有
// * TIM_Period 都有
// * TIM_ClockDivision TIMx,x[6,7]沒有,其他都有
// * TIM_RepetitionCounter TIMx,x[1,8,15,16,17]才有
// *}TIM_TimeBaseInitTypeDef;
// *-----------------------------------------------------------------------------
// *//* ---------------- PWM信號 周期和占空比的計算--------------- */
// ARR :自動重裝載寄存器的值
// CLK_cnt:計數(shù)器的時鐘,等于 Fck_int / (psc+1) = 72M/(psc+1)
// PWM 信號的周期 T = ARR * (1/CLK_cnt) = ARR*(PSC+1) / 72M
// 占空比P=CCR/(ARR+1)static void GENERAL_TIM_Mode_Config(void)
{TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;TIM_OCInitTypeDef TIM_OCInitStructure;// 開啟定時器時鐘,即內部時鐘CK_INT=72MGENERAL_TIM_APBxClock_FUN(GENERAL_TIM_CLK,ENABLE);/*--------------------時基結構體初始化-------------------------*/// 配置周期// 自動重裝載寄存器的值,累計TIM_Period+1個頻率后產生一個更新或者中斷TIM_TimeBaseStructure.TIM_Period=GENERAL_TIM_Period; // 驅動CNT計數(shù)器的時鐘 = Fck_int/(psc+1)TIM_TimeBaseStructure.TIM_Prescaler= GENERAL_TIM_Prescaler; // 時鐘分頻因子 ,配置死區(qū)時間時需要用到TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1; // 計數(shù)器計數(shù)模式,設置為向上計數(shù)TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up; // 重復計數(shù)器的值,沒用到不用管TIM_TimeBaseStructure.TIM_RepetitionCounter=0; // 初始化定時器TIM_TimeBaseInit(GENERAL_TIM, &TIM_TimeBaseStructure);/*--------------------輸出比較結構體初始化-------------------*/ // 配置為PWM模式TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2;// 輸出使能TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;// 輸出通道電平極性配置 TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;// 輸出比較通道 1TIM_OCInitStructure.TIM_Pulse = 0;TIM_OC1Init(GENERAL_TIM, &TIM_OCInitStructure);TIM_OC1PreloadConfig(GENERAL_TIM, TIM_OCPreload_Enable);// 輸出比較通道 2TIM_OCInitStructure.TIM_Pulse = 0;TIM_OC2Init(GENERAL_TIM, &TIM_OCInitStructure);TIM_OC2PreloadConfig(GENERAL_TIM, TIM_OCPreload_Enable);// 輸出比較通道 3TIM_OCInitStructure.TIM_Pulse = 0;TIM_OC3Init(GENERAL_TIM, &TIM_OCInitStructure);TIM_OC3PreloadConfig(GENERAL_TIM, TIM_OCPreload_Enable);// 輸出比較通道 4TIM_OCInitStructure.TIM_Pulse = 0;TIM_OC4Init(GENERAL_TIM, &TIM_OCInitStructure);TIM_OC4PreloadConfig(GENERAL_TIM, TIM_OCPreload_Enable);// 使能計數(shù)器TIM_Cmd(GENERAL_TIM, ENABLE);
}void GENERAL_TIM_Init(void)
{GENERAL_TIM_GPIO_Config();GENERAL_TIM_Mode_Config();
}//小車左轉
void PWM_CarLeft(void){TIM_SetCompare1(GENERAL_TIM,0);TIM_SetCompare2(GENERAL_TIM,0);TIM_SetCompare3(GENERAL_TIM,4000);TIM_SetCompare4(GENERAL_TIM,4000);
}//小車右轉
void PWM_CarRight(void){TIM_SetCompare1(GENERAL_TIM,4000);TIM_SetCompare2(GENERAL_TIM,4000);TIM_SetCompare3(GENERAL_TIM,0);TIM_SetCompare4(GENERAL_TIM,0);
}//小車最大速度
void PWM_CarMaxGo(void){TIM_SetCompare1(GENERAL_TIM,0);TIM_SetCompare2(GENERAL_TIM,0);TIM_SetCompare3(GENERAL_TIM,0);TIM_SetCompare4(GENERAL_TIM,0);
}/*********************************************END OF FILE**********************/
- 小車轉向的原理是跟坦克的一樣,通過降低轉向邊的輪子速度來實現(xiàn)。而控制轉速就要用到PWM波來減少或增多電機的通斷時間(其實是驅動板的電機使能引腳)。
- 轉向函數(shù)的封裝
PS:完整的程序太多了,最好下載下來慢慢看。
藍牙遙控器
做到這里就剩只藍牙遙控器的配置了,軟件呢隨便哪個都行,只要能收發(fā)數(shù)據(jù)就行。
不過我推薦用我這個,因為長得好看。
下載地址,提取碼:kvar。此軟件為安卓,ios沒有
查看指令
單片機復位的時候會通過藍牙發(fā)送這些數(shù)據(jù),用手機連上藍牙然后復位單片機就可以看到了。
printf("-----指令-----\n
0x01:小車后退\n
0x02:小車向左\n
0x03:小車向右\n
0x04:小車前進\n
0x05:小車剎車\n
0x06:電機停止\n
0x07:小車逆時針\n
0x08:小車轉向停止\n
0x09:小車順時針\n");
- 單片機就是通過這些十六進制的數(shù)據(jù)來控制小車的運動,只要將遙控器上的按鍵對應這些數(shù)據(jù)就行了。
按鍵說明
按鍵配置
按鍵配置簡單,只要根據(jù)指令來配置就好了,我就舉幾個例子。
- 前進
- 左轉
- 剎車
- 原地順時針 接下來可以開車上路了
祝你好運!!!
總結
以上是生活随笔為你收集整理的STM32智能遥控小车,超详细-附下载直接可以用,双电源跑贼快!的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。