0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

第18章-綜合以上功能 基于stm32的智能小車 基于stm32f103c8t6_HAL庫_CubeMX_超詳細(xì),包含代碼講解和原理圖

dfhjgfg ? 來源:dfhjgfg ? 作者:dfhjgfg ? 2024-08-20 17:15 ? 次閱讀

功能介紹放開頭, 使用便捷無需愁

這是全網(wǎng)最詳細(xì)、性價比最高的STM32實戰(zhàn)項目入門教程,通過合理的硬件設(shè)計和詳細(xì)的視頻筆記介紹,硬件使用STM32F103主控資料多方便學(xué)習(xí),通過3萬字筆記、12多個小時視頻、20多章節(jié)代碼手把手教會你如何開發(fā)和調(diào)試。讓你更快掌握嵌入式系統(tǒng)開發(fā)。

**V3.3.0-STM32智能小車 **

**視頻: **[https://www.bilibili.com/video/BV16x4y1M7EN/?spm_id_from=333.337.search-card.all.click]

V3:HAL庫開發(fā)、功能:PID速度控制、PID循跡、PID跟隨、遙控、避障、PID角度控制、視覺控制、電磁循跡、RTOS等功能。

第18章-綜合以上功能

18-按鍵和app按鈕切換功能

根據(jù)上面介紹,我們的模式可以有:

**OLED顯示模式: 速度、里程、電壓、超聲波數(shù)據(jù)、MPU6050俯仰角、橫滾角、航向角 數(shù)據(jù)顯示在OLED上和通過串口發(fā)送藍(lán)牙APP **

PID循跡模式:紅外對管PID循跡

手機遙控普通運動模式:遙控前、后、左、右加速運動

超聲波避障模式

PID跟隨模式:超聲波PID定距離跟隨

手機遙控角度閉環(huán)模式:MPU6050角度PID控制

可以設(shè)置標(biāo)志位通過按鍵改變標(biāo)志位,以實現(xiàn)功能切換。

定義一個全局變量,

uint8_t g_ucMode = 0; 
//小車運動模式標(biāo)志位 0:顯示功能、1:PID循跡模式、2:手機遙控普通運動模式、3.超聲波避障模式、4:PID跟隨模式、5:遙控角度閉環(huán)

在這里插入圖片描述

uint8_t g_ucMode = 0; //小車運動模式標(biāo)志位

在gpio.h聲明一下

在這里插入圖片描述

extern uint8_t g_ucMode ; //小車運動模式標(biāo)志位

按鍵中斷回調(diào)函數(shù)里面補充按下按鍵后的處理

先不進行消抖,如果后面KEY1 KEY2效果不好再消抖
在這里插入圖片描述

void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
if(GPIO_Pin == KEY1_Pin) //判斷一下那個引腳觸發(fā)中斷
{
//這里編寫觸發(fā)中斷后要執(zhí)行的程序
if(g_ucMode == 5) g_ucMode = 1;//g_ucMode模式是0 1 2 3 4 5 
else
{
g_ucMode+=1;
}
HAL_GPIO_TogglePin(LED_GPIO_Port,LED_Pin);
}
if(GPIO_Pin == KEY2_Pin) //判斷一下那個引腳觸發(fā)中斷
{
//這里編寫觸發(fā)中斷后要執(zhí)行的程序
g_ucMode=0;
HAL_GPIO_TogglePin(LED_GPIO_Port,LED_Pin);
}
}

然后主函數(shù)顯示當(dāng)前處于的模式

然后判斷當(dāng)前模式 執(zhí)行不同代碼

方法:一個功能一個功能的添加代碼,添加好一個調(diào)試測試一下,然后再添加下一個

下面這個就是我們主函數(shù)的代碼。

sprintf((char *)OledString," g_ucMode:%d",g_ucMode);//顯示g_ucMode 當(dāng)前模式
OLED_ShowString(0,6,OledString,12);//顯示在OLED上

sprintf((char *)Usart3String," g_ucMode:%d",g_ucMode);//藍(lán)牙APP顯示
HAL_UART_Transmit(&huart3,( uint8_t *)Usart3String,strlen(( const  char  *)Usart3String),50);//阻塞式發(fā)送通過串口三輸出字符 strlen:計算字符串大小

if(g_ucMode == 0)
{
//0LED顯示功能
sprintf((char*)OledString, "V1:%.2fV2:%.2f", Motor1Speed,Motor2Speed);//顯示速度
OLED_ShowString(0,0,OledString,12);//這個是oled驅(qū)動里面的,是顯示位置的一個函數(shù),

sprintf((char*)OledString, "Mileage:%.2f", Mileage);//顯示里程
OLED_ShowString(0,1,OledString,12);//這個是oled驅(qū)動里面的,是顯示位置的一個函數(shù),

sprintf((char*)OledString, "U:%.2fV", adcGetBatteryVoltage());//顯示電池電壓
OLED_ShowString(0,2,OledString,12);//這個是oled驅(qū)動里面的,是顯示位置的一個函數(shù),

sprintf((char *)OledString,"HC_SR04:%.2fcmrn",HC_SR04_Read());//顯示超聲波數(shù)據(jù)
OLED_ShowString(0,3,OledString,12);//這個是oled驅(qū)動里面的,是顯示位置的一個函數(shù),

sprintf((char *)OledString,"p:%.2f r:%.2f rn",pitch,roll);//顯示6050數(shù)據(jù) 俯仰角 橫滾角
OLED_ShowString(0,4,OledString,12);//這個是oled驅(qū)動里面的,是顯示位置的一個函數(shù),

sprintf((char *)OledString,"y:%.2f  rn",yaw);//顯示6050數(shù)據(jù)  航向角
OLED_ShowString(0,5,OledString,12);//這個是oled驅(qū)動里面的,是顯示位置的一個函數(shù),

//藍(lán)牙APP顯示
sprintf((char*)Usart3String, "V1:%.2fV2:%.2f", Motor1Speed,Motor2Speed);//顯示速度
HAL_UART_Transmit(&huart3,( uint8_t *)Usart3String,strlen(( const  char  *)Usart3String),50);//阻塞式發(fā)送通過串口三輸出字符 strlen:計算字符串大小
//阻塞方式發(fā)送可以保證數(shù)據(jù)發(fā)送完畢,中斷發(fā)送不一定可以保證數(shù)據(jù)已經(jīng)發(fā)送完畢才啟動下一次發(fā)送
sprintf((char*)Usart3String, "Mileage:%.2f", Mileage);//顯示里程
HAL_UART_Transmit(&huart3,( uint8_t *)Usart3String,strlen(( const  char  *)Usart3String),50);//阻塞式發(fā)送通過串口三輸出字符 strlen:計算字符串大小

sprintf((char*)Usart3String, "U:%.2fV", adcGetBatteryVoltage());//顯示電池電壓
HAL_UART_Transmit(&huart3,( uint8_t *)Usart3String,strlen(( const  char  *)Usart3String),50);//阻塞式發(fā)送通過串口三輸出字符 strlen:計算字符串大小

sprintf((char *)Usart3String,"HC_SR04:%.2fcmrn",HC_SR04_Read());//顯示超聲波數(shù)據(jù)
HAL_UART_Transmit(&huart3,( uint8_t *)Usart3String,strlen(( const  char  *)Usart3String),50);//阻塞式發(fā)送通過串口三輸出字符 strlen:計算字符串大小

sprintf((char *)Usart3String,"p:%.2f r:%.2f rn",pitch,roll);//顯示6050數(shù)據(jù) 俯仰角 橫滾角
HAL_UART_Transmit(&huart3,( uint8_t *)Usart3String,strlen(( const  char  *)Usart3String),50);//阻塞式發(fā)送通過串口三輸出字符 strlen:計算字符串大小

sprintf((char *)Usart3String,"y:%.2f  rn",yaw);//顯示6050數(shù)據(jù)  航向角
HAL_UART_Transmit(&huart3,( uint8_t *)Usart3String,strlen(( const  char  *)Usart3String),50);//阻塞式發(fā)送通過串口三輸出字符 strlen:計算字符串大小

//獲得6050數(shù)據(jù)
while(mpu_dmp_get_data(&pitch,&roll,&yaw)!=0){}  //這個可以解決經(jīng)常讀不出數(shù)據(jù)的問題

//顯示模式電機停轉(zhuǎn)
motorPidSetSpeed(0,0);
}
if(g_ucMode == 1)
{
///****    紅外PID循跡功能******************/
g_ucaHW_Read[0] = READ_HW_OUT_1;//讀取紅外對管狀態(tài)、這樣相比于寫在if里面更高效
g_ucaHW_Read[1] = READ_HW_OUT_2;
g_ucaHW_Read[2] = READ_HW_OUT_3;
g_ucaHW_Read[3] = READ_HW_OUT_4;
?
if(g_ucaHW_Read[0] == 0&&g_ucaHW_Read[1] == 0&&g_ucaHW_Read[2] == 0&&g_ucaHW_Read[3] == 0 )
{
//printf("應(yīng)該前進rn");//注釋掉更加高效,減少無必要程序執(zhí)行
g_cThisState = 0;//前進
}
else if(g_ucaHW_Read[0] == 0&&g_ucaHW_Read[1] == 1&&g_ucaHW_Read[2] == 0&&g_ucaHW_Read[3] == 0 )//使用else if更加合理高效
{
//printf("應(yīng)該右轉(zhuǎn)rn");
g_cThisState = -1;//應(yīng)該右轉(zhuǎn)
}
else if(g_ucaHW_Read[0] == 1&&g_ucaHW_Read[1] == 0&&g_ucaHW_Read[2] == 0&&g_ucaHW_Read[3] == 0 )
{
//printf("快速右轉(zhuǎn)rn");
g_cThisState = -2;//快速右轉(zhuǎn)
}
else if(g_ucaHW_Read[0] == 1&&g_ucaHW_Read[1] == 1&&g_ucaHW_Read[2] == 0&&g_ucaHW_Read[3] == 0)
{
//printf("快速右轉(zhuǎn)rn");
g_cThisState = -3;//快速右轉(zhuǎn)
}
else if(g_ucaHW_Read[0] == 0&&g_ucaHW_Read[1] == 0&&g_ucaHW_Read[2] == 1&&g_ucaHW_Read[3] == 0 )
{
//printf("應(yīng)該左轉(zhuǎn)rn");
g_cThisState = 1;//應(yīng)該左轉(zhuǎn)
}
else if(g_ucaHW_Read[0] == 0&&g_ucaHW_Read[1] == 0&&g_ucaHW_Read[2] == 0&&g_ucaHW_Read[3] == 1 )
{
//printf("快速左轉(zhuǎn)rn");
g_cThisState = 2;//快速左轉(zhuǎn)
}
else if(g_ucaHW_Read[0] == 0&&g_ucaHW_Read[1] == 0&&g_ucaHW_Read[2] == 1&&g_ucaHW_Read[3] == 1)
{
//    printf("快速左轉(zhuǎn)rn");
g_cThisState = 3;//快速左轉(zhuǎn)
}
g_fHW_PID_Out = PID_realize(&pidHW_Tracking,g_cThisState);//PID計算輸出目標(biāo)速度 這個速度,會和基礎(chǔ)速度加減
?
g_fHW_PID_Out1 = 3 + g_fHW_PID_Out;//電機1速度=基礎(chǔ)速度+循跡PID輸出速度
g_fHW_PID_Out2 = 3 - g_fHW_PID_Out;//電機1速度=基礎(chǔ)速度-循跡PID輸出速度
if(g_fHW_PID_Out1 >5) g_fHW_PID_Out1 =5;//進行限幅 限幅速度在0-5之間
if(g_fHW_PID_Out1 < 0) g_fHW_PID_Out1 =0;
if(g_fHW_PID_Out2 >5) g_fHW_PID_Out2 =5;
if(g_fHW_PID_Out2 < 0) g_fHW_PID_Out2 =0;
if(g_cThisState != g_cLastState)//如何這次狀態(tài)不等于上次狀態(tài)、就進行改變目標(biāo)速度和控制電機、在定時器中依舊定時控制電機
{
motorPidSetSpeed(g_fHW_PID_Out1,g_fHW_PID_Out2);//通過計算的速度控制電機
}

g_cLastState = g_cThisState;//保存上次紅外對管狀態(tài)
?
}
if(g_ucMode == 2)
{
//***************遙控模式***********************//
//遙控模式的控制在串口三的中斷里面
}
if(g_ucMode == 3)
{
//******超聲波避障模式*********************//
////避障邏輯
if(HC_SR04_Read() > 25)//前方無障礙物
{
motorPidSetSpeed(1,1);//前運動
HAL_Delay(100);
}
else{//前方有障礙物
motorPidSetSpeed(-1,1);//右邊運動 原地
HAL_Delay(500);
if(HC_SR04_Read() > 25)//右邊無障礙物
{
motorPidSetSpeed(1,1);//前運動
HAL_Delay(100);
}
else{//右邊有障礙物
motorPidSetSpeed(1,-1);//左邊運動 原地
HAL_Delay(1000);
if(HC_SR04_Read() >25)//左邊無障礙物
{
 motorPidSetSpeed(1,1);//前運動
HAL_Delay(100);
}
else{
motorPidSetSpeed(-1,-1);//后運動
HAL_Delay(1000);
motorPidSetSpeed(-1,1);//右邊運動
HAL_Delay(50);
}
}
}
}
if(g_ucMode == 4)
{
//**********PID跟隨功能***********//
g_fHC_SR04_Read=HC_SR04_Read();//讀取前方障礙物距離
if(g_fHC_SR04_Read < 60){  //如果前60cm 有東西就啟動跟隨
g_fFollow_PID_Out = PID_realize(&pidFollow,g_fHC_SR04_Read);//PID計算輸出目標(biāo)速度 這個速度,會和基礎(chǔ)速度加減
if(g_fFollow_PID_Out > 6) g_fFollow_PID_Out = 6;//對輸出速度限幅
if(g_fFollow_PID_Out < -6) g_fFollow_PID_Out = -6;
motorPidSetSpeed(g_fFollow_PID_Out,g_fFollow_PID_Out);//速度作用與電機上
}
else motorPidSetSpeed(0,0);//如果前面60cm 沒有東西就停止
HAL_Delay(10);//讀取超聲波傳感器不能過快
}
if(g_ucMode == 5)
{
//*************MPU6050航向角 PID轉(zhuǎn)向控制*****************//
?
sprintf((char *)Usart3String,"pitch:%.2f roll:%.2f yaw:%.2frn",pitch,roll,yaw);//顯示6050數(shù)據(jù) 俯仰角 橫滾角 航向角
HAL_UART_Transmit(&huart3,( uint8_t *)Usart3String,strlen(( const  char  *)Usart3String),0xFFFF);//通過串口三輸出字符 strlen:計算字符串大小
   
   //mpu_dmp_get_data(&pitch,&roll,&yaw);//返回值:0,DMP成功解出歐拉角
while(mpu_dmp_get_data(&pitch,&roll,&yaw)!=0){}  //這個可以解決經(jīng)常讀不出數(shù)據(jù)的問題


g_fMPU6050YawMovePidOut = PID_realize(&pidMPU6050YawMovement,yaw);//PID計算輸出目標(biāo)速度 這個速度,會和基礎(chǔ)速度加減
?
g_fMPU6050YawMovePidOut1 = 1.5 + g_fMPU6050YawMovePidOut;//基礎(chǔ)速度加減PID輸出速度
g_fMPU6050YawMovePidOut2 = 1.5 - g_fMPU6050YawMovePidOut;
if(g_fMPU6050YawMovePidOut1 >3.5) g_fMPU6050YawMovePidOut1 =3.5;//進行限幅
if(g_fMPU6050YawMovePidOut1 < 0) g_fMPU6050YawMovePidOut1 =0;
if(g_fMPU6050YawMovePidOut2 >3.5) g_fMPU6050YawMovePidOut2 =3.5;
if(g_fMPU6050YawMovePidOut2 < 0) g_fMPU6050YawMovePidOut2 =0;
motorPidSetSpeed(g_fMPU6050YawMovePidOut1,g_fMPU6050YawMovePidOut2);

}

可以測試上面的代碼 然后沒有問題后,我們添加一個通過藍(lán)牙APP按鈕切換模式代碼
在這里插入圖片描述

if(g_ucUsart3ReceiveData == 'J') //改變模式
{
if(g_ucMode == 5) g_ucMode = 1;//g_ucMode模式是0 1 2 3 4 5 
else
{
g_ucMode+=1;
}
}
if(g_ucUsart3ReceiveData == 'K') g_ucMode=0;//設(shè)置為顯示模式

然后對應(yīng)APP也要添加 按鈕設(shè)置
在這里插入圖片描述
我們
按鍵沒有消抖效果不好,我們消抖一下
在這里插入圖片描述
我們增加了 HAL延時和再次判斷電平

void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
if(GPIO_Pin == KEY1_Pin) //判斷一下那個引腳觸發(fā)中斷
{
HAL_Delay(10);//延時消抖 主要
if(HAL_GPIO_ReadPin(KEY1_GPIO_Port, KEY1_Pin) == GPIO_PIN_SET)//判斷KEY1引腳仍為高電平
{
//這里編寫觸發(fā)中斷后要執(zhí)行的程序
if(g_ucMode == 5) g_ucMode = 1;//g_ucMode模式是0 1 2 3 4 5 
else
{
g_ucMode+=1;
}
HAL_GPIO_TogglePin(LED_GPIO_Port,LED_Pin);
}
}
if(GPIO_Pin == KEY2_Pin) //判斷一下那個引腳觸發(fā)中斷
{
HAL_Delay(10);//延時消抖
if(HAL_GPIO_ReadPin(KEY2_GPIO_Port, KEY2_Pin) == GPIO_PIN_RESET)//判斷KEY2引腳仍為低電平
{
//這里編寫觸發(fā)中斷后要執(zhí)行的程序
g_ucMode=0;
HAL_GPIO_TogglePin(LED_GPIO_Port,LED_Pin);
}
}
}
?

但是測試不能執(zhí)行中斷,程序異??ㄋ懒?/strong>

原因是HAL_Delay使用的是sysTick 中斷優(yōu)先級在軟件初始化是默認(rèn)最低的,比外部中斷優(yōu)先級低,所以HAL_Delay不能在外部中斷服務(wù)函數(shù)中調(diào)用。

所以我們可以通過提高sysTick 中斷的優(yōu)先級,提高的比HAL_Delay高。
在這里插入圖片描述
然后我們提高至 如下圖
在這里插入圖片描述
然后編譯燒錄測試按鍵是否更加穩(wěn)定。
下面的章節(jié)我們講解視覺,RTOS系統(tǒng),電磁循跡等功能

審核編輯 黃宇

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴
  • 物聯(lián)網(wǎng)
    +關(guān)注

    關(guān)注

    2911

    文章

    44841

    瀏覽量

    375260
  • 單片機
    +關(guān)注

    關(guān)注

    0

    文章

    217

    瀏覽量

    16658
收藏 人收藏

    評論

    相關(guān)推薦

    stm32f103c8t6封裝及最小系統(tǒng)原理圖

    系統(tǒng)原理圖。 STM32F103C8T6封裝 STM32F103C8T6封裝為LQFP48-48引腳小外形四方扁平封裝外形,如下圖: STM32F103C8T6最小系統(tǒng)
    發(fā)表于 11-23 15:50 ?35.2w次閱讀

    stm32f103c8t6原理圖及最小系統(tǒng)

    stm32f103c8t6原理圖
    發(fā)表于 06-10 08:00 ?786次下載

    STM32F103C8T6-Board詳細(xì)原理圖資料免費下載

    本文檔的主要內(nèi)容詳細(xì)介紹的是STM32F103C8T6-Board詳細(xì)原理圖資料免費下載。
    發(fā)表于 09-28 08:00 ?96次下載
    <b class='flag-5'>STM32F103C8T6</b>-Board<b class='flag-5'>詳細(xì)</b><b class='flag-5'>原理圖</b>資料免費下載

    STM32F103C8T6開發(fā)板的電路原理圖免費下載

    本文檔的主要內(nèi)容詳細(xì)介紹的是STM32F103C8T6開發(fā)板的電路原理圖免費下載。
    發(fā)表于 12-24 11:57 ?414次下載
    <b class='flag-5'>STM32F103C8T6</b>開發(fā)板的電路<b class='flag-5'>原理圖</b>免費下載

    STM32F103C8T6 Board的電路原理圖免費下載

    本文檔的主要內(nèi)容詳細(xì)介紹的是STM32F103C8T6 Board的電路原理圖免費下載。
    發(fā)表于 03-12 08:00 ?10次下載
    <b class='flag-5'>STM32F103C8T6</b> Board的電路<b class='flag-5'>原理圖</b>免費下載

    STM32F103C8T6核心板的原理圖免費下載

    本文檔的主要內(nèi)容詳細(xì)介紹的是STM32F103C8T6核心板的電路原理圖免費下載。
    發(fā)表于 03-14 08:00 ?91次下載
    <b class='flag-5'>STM32F103C8T6</b>核心板的<b class='flag-5'>原理圖</b>免費下載

    STM32F103C8T6核心板的資料合集免費下載

    ),STM32F103C8T6原理圖,STM32F103C8T6核心板尺寸,STM32F103C8T6.SCHLIB,和STM32F103x8
    發(fā)表于 06-04 08:00 ?726次下載
    <b class='flag-5'>STM32F103C8T6</b>核心板的資料合集免費下載

    STM32F103C8T6原理圖

    STM32F103C8T6原理圖免費下載。
    發(fā)表于 06-02 10:01 ?185次下載

    使用STM32F103C8T6控制L298N電機驅(qū)動麥克納姆輪小車HAL

    使用STM32F103C8T6控制L298N電機驅(qū)動麥克納姆輪小車HAL
    發(fā)表于 11-23 17:36 ?56次下載
    使用<b class='flag-5'>STM32F103C8T6</b>控制L298N電機驅(qū)動麥克納姆輪<b class='flag-5'>小車</b>(<b class='flag-5'>HAL</b><b class='flag-5'>庫</b>)

    STM32F103C8T6原理圖(高清PDF版)

    STM32F103C8T6原理圖(高清PDF版)免費下載。
    發(fā)表于 07-28 16:25 ?0次下載

    STM32F103C8T6核心板原理圖

    STM32F103C8T6核心板原理圖免費下載。
    發(fā)表于 04-23 09:47 ?411次下載

    使用stm32f103c8t6設(shè)計的藍(lán)牙小車

    使用stm32f103c8t6設(shè)計的藍(lán)牙小車,具有前進后退,左轉(zhuǎn)右轉(zhuǎn)等功能
    發(fā)表于 08-07 16:08 ?32次下載

    分享STM32F103C8T6原理圖

    STM32F103C8T6最小系統(tǒng)原理圖
    發(fā)表于 08-29 15:52 ?109次下載

    STM32平衡小車原理圖

    STM32f103c8t6平衡小車原理圖
    發(fā)表于 07-05 10:54 ?1次下載

    12-ADC采集電壓和顯示 基于STM32的ADC—電壓采集(詳細(xì)講解+HAL

    12-ADC采集電壓和顯示 基于STM32的ADC—電壓采集(詳細(xì)講解+HAL
    的頭像 發(fā)表于 08-21 16:31 ?2823次閱讀
    <b class='flag-5'>第</b>12<b class='flag-5'>章</b>-ADC采集電壓和顯示 基于<b class='flag-5'>STM32</b>的ADC—電壓采集(<b class='flag-5'>詳細(xì)</b><b class='flag-5'>講解</b>+<b class='flag-5'>HAL</b><b class='flag-5'>庫</b>)