功能介紹放開頭, 使用便捷無需愁。
這是全網(wǎng)最詳細、性價比最高的STM32實戰(zhàn)項目入門教程,通過合理的硬件設(shè)計和詳細的視頻筆記介紹,硬件使用STM32F103主控資料多方便學(xué)習(xí),通過3萬字筆記、12多個小時視頻、20多章節(jié)代碼手把手教會你如何開發(fā)和調(diào)試。讓你更快掌握嵌入式系統(tǒng)開發(fā)。
V1.5.0-STM32智能小車
V1.5.0:庫函數(shù)開發(fā)。功能:循跡、避障、跟隨、遙控、電池電壓顯示等。
視頻合集鏈接推薦觀看
[https://www.bilibili.com/video/BV1SY411L7rJ/?spm_id_from=333.337.search-card.all.click]
**V3.3.0-STM32智能小車 **
V3:HAL庫開發(fā)、功能:PID速度控制、PID循跡、PID跟隨、遙控、避障、PID角度控制、視覺控制、電磁循跡、RTOS等功能。
視頻合集鏈接推薦觀看
[https://www.bilibili.com/video/BV16x4y1M7EN/?spm_id_from=333.337.search-card.all.click]
超聲波測距
通過超聲波的硬件介紹我們知道
MCU給Trig腳一個大于10us的高電平脈沖;然后讀取Echo腳的高電平信號時間,通過公式:距離 = T *
聲速/2 就可以算出來距離。
軟件方面:10us高電平脈沖通過GPIO輸出實現(xiàn),高電平信號時間我們通過定時器的輸入捕獲來計算
的。
初始化脈沖引腳PA0
在led.c中的SR04初始化函數(shù)
void SR04_GPIO_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_SetBits(GPIOA,GPIO_Pin_0);
}
led.h有關(guān)宏定義和聲明
#define SR04 PAout(0) // PA0
void SR04_GPIO_Init(void);
?
初始化PA1輸入捕獲
查看數(shù)據(jù)手冊
初始化定時器2 通道2 輸入捕獲相關(guān)功能
//定時器2通道2輸入捕獲配置
TIM_ICInitTypeDef TIM2_ICInitStructure;
void TIM2_Cap_Init(u16 arr,u16 psc)
{
GPIO_InitTypeDef GPIO_InitStructure;
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); //使能TIM2時鐘
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //使能GPIOA時鐘
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1; //PA1 清除之前設(shè)置
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD; //PA1 輸入
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_ResetBits(GPIOA,GPIO_Pin_1); //PA1 下拉
//初始化定時器5 TIM5
TIM_TimeBaseStructure.TIM_Period = arr; //設(shè)定計數(shù)器自動重裝值
TIM_TimeBaseStructure.TIM_Prescaler =psc; //預(yù)分頻器
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; //設(shè)置時鐘分割:TDTS =
Tck_tim
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIM向上計數(shù)模式
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure); //根據(jù)TIM_TimeBaseInitStruct中
指定的參數(shù)初始化TIMx的時間基數(shù)單位
//初始化TIM5輸入捕獲參數(shù)
TIM2_ICInitStructure.TIM_Channel = TIM_Channel_2; // 選擇輸入端 IC2映射到TI2
上
TIM2_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising; //上升沿捕獲
TIM2_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI; //映射到TI2上
TIM2_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1; //配置輸入分頻,不分頻
TIM2_ICInitStructure.TIM_ICFilter = 0x00;//IC1F=0000 配置輸入濾波器 不濾波
TIM_ICInit(TIM2, &TIM2_ICInitStructure);
//中斷分組初始化
NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn; //TIM2中斷
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2; //先占優(yōu)先級2級
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; //從優(yōu)先級0級
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道被使能
NVIC_Init(&NVIC_InitStructure); //根據(jù)NVIC_InitStruct中指定的參數(shù)初始化外設(shè)NVIC
寄存器
TIM_ITConfig(TIM2,TIM_IT_Update|TIM_IT_CC2,ENABLE);//允許更新中斷 ,允許CC2IE捕獲
中斷
TIM_Cmd(TIM2,ENABLE ); //使能定時器2
}
u8 TIM5CH1_CAPTURE_STA=0; //輸入捕獲狀態(tài)
u16 TIM5CH1_CAPTURE_VAL; //輸入捕獲值
//定時器2中斷服務(wù)程序
void TIM2_IRQHandler(void)
{
if((TIM5CH1_CAPTURE_STA&0X80)==0)//還未成功捕獲
{
if (TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET)
{
if(TIM5CH1_CAPTURE_STA&0X40)//已經(jīng)捕獲到高電平了
{
if((TIM5CH1_CAPTURE_STA&0X3F)==0X3F)//高電平太長了
{
TIM5CH1_CAPTURE_STA|=0X80;//標(biāo)記成功捕獲了一次
TIM5CH1_CAPTURE_VAL=0XFFFF;
}else TIM5CH1_CAPTURE_STA++;
}
}
if (TIM_GetITStatus(TIM2, TIM_IT_CC2) != RESET)//捕獲2發(fā)生捕獲事件
{
if(TIM5CH1_CAPTURE_STA&0X40) //捕獲到一個下降沿
{
TIM5CH1_CAPTURE_STA|=0X80; //標(biāo)記成功捕獲到一次上升沿
TIM5CH1_CAPTURE_VAL=TIM_GetCapture2(TIM2);
TIM_OC2PolarityConfig(TIM2,TIM_ICPolarity_Rising); //CC2P=0 設(shè)置為
上升沿捕獲
}else //還未開始,第一次捕獲上升沿
{
TIM5CH1_CAPTURE_STA=0; //清空
TIM5CH1_CAPTURE_VAL=0;
TIM_SetCounter(TIM2,0);
TIM5CH1_CAPTURE_STA|=0X40; //標(biāo)記捕獲到了上升沿
TIM_OC2PolarityConfig(TIM2,TIM_ICPolarity_Falling); //CC2P=1
設(shè)置為下降沿捕獲
}
}
}
TIM_ClearITPendingBit(TIM2, TIM_IT_CC2|TIM_IT_Update); //清除中斷標(biāo)志位
}
?
在time 中聲明初始化函數(shù)
void TIM2_Cap_Init(u16 arr,u16 psc);
計算輸出距離
在main.c聲明變量
extern u8 TIM5CH1_CAPTURE_STA; //輸入捕獲狀態(tài)
extern u16 TIM5CH1_CAPTURE_VAL; //輸入捕獲值
定義變量
int Distance =0;
int time=0;
調(diào)用初始化函數(shù)
SR04_GPIO_Init();
TIM2_Cap_Init(0XFFFF,72-1); //以1Mhz的頻率計數(shù)
完成測距的函數(shù)
delay_ms(500);//加入延時
HC_SR04 =0;
delay_us(10);
HC_SR04 = 1;
if(TIM5CH1_CAPTURE_STA&0X80)//成功捕獲到了一次上升沿
{
time=TIM5CH1_CAPTURE_STA&0X3F;
time*=65536;//溢出時間總和
time+=TIM5CH1_CAPTURE_VAL;//得到總的高電平時間
printf("rnHIGH:%d usrn",time);//打印總的高點平時間
Distance = time*0.033/2;
printf("cm:%drn",Distance);
TIM5CH1_CAPTURE_STA=0;//開啟下一次捕獲
}
封裝一下方便調(diào)用
int TCRT5000_Dist(void)
{
HC_SR04 = 1;
delay_us(13);
HC_SR04=0;
if(TIM5CH1_CAPTURE_STA&0X80)//成功捕獲到了一次上升沿
{
time=TIM5CH1_CAPTURE_STA&0X3F;
time*=65536;//溢出時間總和
time+=TIM5CH1_CAPTURE_VAL;//得到總的高電平時間
printf("rnHIGH:%d usrn",time);//打印總的高點平時間
Distance = time*0.033/2;
printf("cm:%drn",Distance);
TIM5CH1_CAPTURE_STA=0;//開啟下一次捕獲
}
return Distance;
}
使用串口助手查看結(jié)果
練一練--編寫定距離跟隨功能
功能:根據(jù)根據(jù)超聲波測量距離跟隨前方物體
while(1){
HC_SR04 = 1;
delay_us(13);
HC_SR04=0;
if(TIM5CH1_CAPTURE_STA&0X80)//成功捕獲到了一次上
升沿
{
time=TIM5CH1_CAPTURE_STA&0X3F;
time*=65536;//溢出時間總和
time+=TIM5CH1_CAPTURE_VAL;//得到總的高電平時間
printf("rnHIGH:%d usrn",time);//打印總的高
點平時間
Distance = time*0.033/2;
printf("cm:%drn",Distance);
TIM5CH1_CAPTURE_STA=0;//開啟下一次捕獲
}
if(Distance >20)
{
Forward();
delay_ms(50);
}
if(Distance< 15)
{
Backward();
delay_ms(50);
}
AIN1 =0;
AIN2 = 0;
BIN1 = 0;
BIN2 =0;
}
練一練--結(jié)合舵機完成避障功能
功能:通過舵機旋轉(zhuǎn)不同角度,超聲波測量左右是否存在障礙物,控制小車運動。
測試舵機的轉(zhuǎn)角,不同占空比小車舵機的角度
TIM_SetCompare1(TIM3,80);
TIM_SetCompare1(TIM3,50);
TIM_SetCompare1(TIM3,110);
整體邏輯
if(Mode == 3)
{
//超聲波避障
TIM_SetCompare1(TIM3,80); //舵機向前 使超聲波朝前方
delay_ms(200);
if(TCRT5000_Dist() >25)// 前方無障礙物
{
Forward();
delay_ms(500);
}
if(TCRT5000_Dist()< 25) //向前有障礙物
{
TIM_SetCompare1(TIM3,50); //舵機向右邊轉(zhuǎn)大約30度
delay_ms(200);
if(TCRT5000_Dist() >25)//右側(cè)無障礙物判斷
{
Rightward();
delay_ms(700);
}
else { //右邊有障礙物
TIM_SetCompare1(TIM3,100); //舵機向左邊轉(zhuǎn)大
約30度
delay_ms(200);
if(TCRT5000_Dist() >25)//左側(cè)無障礙物
{
Leftward();
delay_ms(700);
}
else{
Backward();//后退
delay_ms(700);
Rightward(); //右轉(zhuǎn)
delay_ms(700);
}
}
}
} }
綜合一下-縫合上面練一練的功能
功能:
- 小車具有紅外對管循跡、藍牙遙控、定距離跟隨、避障運動模式
- 可以通過小車按鍵和APP進行切換小車的運動模式。
- APP與OLED顯示小車所處模式和超聲波測量值、電池電壓。
實現(xiàn)切換功能必須
** main中的循環(huán)**
while(1)
{
sprintf((char *)string,"Distance:%d ",TCRT5000_Dist());// 顯示距離信息
這里的 %d 需要幾個空格
OLED_ShowString(6,3,string,16);
sprintf((char *)string,"Mode:%d",Mode);//顯示小車模式
OLED_ShowString(6,6,string,16);
if(Mode == 1)
{
//定距離跟隨
TIM_SetCompare1(TIM3,80); //超聲波舵機向前
if(TCRT5000_Dist() >25)// 距離太遠
{
Forward();
delay_ms(200);
}
if(TCRT5000_Dist() < 20)//距離太近
{
Backward();
delay_ms(200);
}
AIN1 =0;//車輛暫定 如果不加 小車就會一直往前或者一直往后
AIN2 =0;
BIN1 =0;
BIN2 =0;
}
if(Mode == 2)
{
//藍牙控制小車
TIM_SetCompare1(TIM3,80); //超聲波舵機向前
if(g_USART3_FLAG1 == 1) //前進
{
g_USART3_FLAG1=0;
Forward();
delay_ms(500);
}
if(g_USART3_FLAG1 == 2) //向右
{
g_USART3_FLAG1=0;
Rightward();
delay_ms(500);
}
if(g_USART3_FLAG1 ==3) //向左
{
g_USART3_FLAG1=0;
Leftward();
delay_ms(500);
}
if(g_USART3_FLAG1 ==4) //向后
{
g_USART3_FLAG1=0;
Backward();
delay_ms(500);
}
if(g_USART3_FLAG1 ==5) //停止
{
g_USART3_FLAG1=0;
AIN1=0;
AIN2=0;
BIN1=0;
BIN2=0;
delay_ms(500);
}
}
if(Mode == 3)
{
//超聲波避障
TIM_SetCompare1(TIM3,80); //舵機向前
delay_ms(200);
if(TCRT5000_Dist() >25)// 前方無障礙物
{
Forward();
delay_ms(500);
}
if(TCRT5000_Dist()< 25) //向前有障礙物
{
TIM_SetCompare1(TIM3,50); //舵機右轉(zhuǎn)
delay_ms(200);
if(TCRT5000_Dist() >25)//右側(cè)無障礙物判斷
{
Rightward();
delay_ms(700);
}
else {
TIM_SetCompare1(TIM3,100); //舵機向左
delay_ms(200);
if(TCRT5000_Dist() >25)//左側(cè)無障礙物
{
Leftward();
delay_ms(700);
}
else{
Backward();
delay_ms(700);//后退
Rightward();
delay_ms(700);
}
}
}
}
if(Mode == 4)
{
//紅外循跡
TIM_SetCompare1(TIM3,80); //超聲波舵機向前
if(HW_1 == 0&&HW_2 == 0&&HW_3 == 0&&HW_4 == 0)//應(yīng)該
前進
{
Forward();
delay_ms(20);
}
if(HW_1 == 0&&HW_2 == 1&&HW_3 == 0&&HW_4 == 0)//應(yīng)該右邊
{
Rightward();
delay_ms(150);
}
if(HW_1 == 1&&HW_2 == 0&&HW_3 == 0&&HW_4 == 0)//應(yīng)該右邊
{
Rightward();
delay_ms(270);
}
if(HW_1 == 1&&HW_2 == 1&&HW_3 == 0&&HW_4 == 0)//應(yīng)該右邊
{
Rightward();
delay_ms(370);
}
if(HW_1 == 0&&HW_2 == 0&&HW_3 == 1&&HW_4 == 0)//應(yīng)該左邊
{
Leftward();
delay_ms(150);
}
if(HW_1 == 0&&HW_2 == 0&&HW_3 == 0&&HW_4 == 1)//應(yīng)該左邊
{
Leftward();
delay_ms(270);
}
if(HW_1 == 0&&HW_2 == 0&&HW_3 == 1&&HW_4 == 1)//應(yīng)該左邊
{
Leftward();
delay_ms(370);
}
}
if(Mode ==0)
{
delay_ms(1);
AIN1=0;
AIN2=0;
BIN1=0;
BIN2=0;
}
}
串口三中斷服務(wù)函數(shù)
//串口3 中斷處理函數(shù)
void USART3_IRQHandler (void)
{
u8 Res;
if(USART_GetITStatus(USART3, USART_IT_RXNE) != RESET)
{
Res =USART_ReceiveData(USART3); //讀取接收到的數(shù)據(jù)
if(Res == 'A') g_USART3_FLAG1 = 1 ; //根據(jù)接受的數(shù)據(jù) 置為標(biāo)志位
if(Res == 'B')g_USART3_FLAG1 = 2 ;
if(Res == 'C') g_USART3_FLAG1 = 3 ;
if(Res == 'D')g_USART3_FLAG1 = 4 ;
if(Res == 'E')g_USART3_FLAG1 = 5;
if(Res == 'F') Mode =1;
if(Res == 'G') Mode =2;
if(Res == 'H') Mode =3;
if(Res == 'I') Mode =4;
if(Res == 'J') Mode =0;
}
}
按鍵處理函數(shù)
void EXTI9_5_IRQHandler(void)//按鍵KEY_1 和KEY_2的中斷服務(wù)函數(shù)
{
delay_ms(10);//消抖
if(KEY_1 == 1) //判斷按鍵KEY_1 是否被按下
{
if(Mode == 4) Mode =1;
else
{
Mode = Mode + 1;
}
LED =! LED;
EXTI_ClearITPendingBit(EXTI_Line7); //清除LINE7上的中斷標(biāo)志位
}
}
void EXTI15_10_IRQHandler(void)//按鍵KEY_SW1 和KEY_SW2的中斷服務(wù)函數(shù)
{
delay_ms(10);//消抖
if(KEY_2 == 0) //判斷按鍵KEY_2 是否被按下
{
Mode = 0 ;
LED =! LED;
EXTI_ClearITPendingBit(EXTI_Line12); //清除LINE12上的中斷標(biāo)志位
}
}
手機APP-藍牙調(diào)試助手設(shè)置
審核編輯 黃宇
-
STM32
+關(guān)注
關(guān)注
2270文章
10900瀏覽量
356005 -
超聲波測距
+關(guān)注
關(guān)注
5文章
246瀏覽量
37924 -
避障小車
+關(guān)注
關(guān)注
1文章
24瀏覽量
19029 -
STM32F103C8T6
+關(guān)注
關(guān)注
108文章
160瀏覽量
83573 -
超聲波避障
+關(guān)注
關(guān)注
0文章
5瀏覽量
2877
發(fā)布評論請先 登錄
相關(guān)推薦
評論