這個是全網(wǎng)最詳細的STM32項目教學(xué)視頻。
第一篇在這里:
視頻在這里
19.4-STM32接收數(shù)據(jù)-狀態(tài)顯示在屏幕
先通過串口上位機模擬發(fā)送、
STM32有視覺循跡模式、該模式下接收到數(shù)據(jù)根據(jù)狀態(tài)顯示在屏幕上,現(xiàn)在此狀態(tài)并不控制電機。
復(fù)制一下18在上面基礎(chǔ)改,命名成19-4_LED
可以先復(fù)制到桌面英文路徑,防止出現(xiàn)中文路徑兼容問題。
看原理圖攝像頭是預(yù)留什么引腳
PCB中可以看到接口位置
所以我們要初始化一下串口二,然后開啟串口接收中斷
串口2 開啟初始化
開啟串口中斷
生成代碼
打開代碼
如果發(fā)現(xiàn)18章代碼經(jīng)常出現(xiàn)黑屏,那可能就是6050的初始化卡住了,我們可以注釋掉一下MPU6050部分的代碼。
我們先定義一個串口二接收數(shù)據(jù)變量
uint8_t g_ucUsart2ReceiveData; //保存串口二接收的數(shù)據(jù)
開啟接收中斷
HAL_UART_Receive_IT(&huart2,&g_ucUsart2ReceiveData,1); //串口二接收數(shù)據(jù)
聲明一下變量
extern uint8_t g_ucUsart2ReceiveData; //保存串口二接收的數(shù)據(jù)
我們需要在串口中斷回調(diào)函數(shù)中加入我們對接收到數(shù)據(jù)的解析
if(huart == &huart2)//判斷中斷源 是否來自串口二
{
//這里增加解析函數(shù)
HAL_UART_Receive_IT(&huart2,&g_ucUsart2ReceiveData,1); //啟動串口二接收數(shù)據(jù)
}
在usart.c文件中定義一個函數(shù)
/*******************
* @brief 攝像頭串口協(xié)議解析函數(shù) 可以連接K210或openmv等
* @param data:串口接收到的每個字節(jié)
* @return
*
*******************/
void usartCamera_Receive_Data(uint8_t data)
{
static uint8_t state = 0;//定義靜態(tài)static 變量
if(state==0&&data==0xA5) //判斷第一個是不是幀頭0xA5
{
state=1;//是幀頭0xA5 賦值state=1 表示接收下一個數(shù)據(jù)
//數(shù)據(jù)存儲在數(shù)組中 "g_ucUsart2ReceivCounter++",這里是先用后加,比如g_ucUsart2ReceivCounter 初值為0,執(zhí)行這個是先g_ucaUsart2ReceiveBuffer[0]=data,然后g_ucUsart2ReceivCounter++,即后g_ucUsart2ReceivCounter = 1的
g_ucaUsart2ReceiveBuffer[g_ucUsart2ReceivCounter++] = data;
}
else if(state==1&&data==0xA6) //第二個是不是幀頭0xA6
{
state=2;//如果第二個是幀頭0xA6 賦值state=2 表示接收下一個數(shù)據(jù)
g_ucaUsart2ReceiveBuffer[g_ucUsart2ReceivCounter++] = data;//保存數(shù)據(jù)
}
else if(state==2)//然后確定開頭是0XA5 0XA6 就開始接收
{
g_ucaUsart2ReceiveBuffer[g_ucUsart2ReceivCounter++]=data;
if(g_ucUsart2ReceivCounter>9||data==0x5B) state=3; //接收大于9個或者接收到幀尾0X5B 就置位狀態(tài)三
}
else if(state==3) //狀態(tài)三
{
if(g_ucaUsart2ReceiveBuffer[g_ucUsart2ReceivCounter-1] == 0x5B) //確定 最后一個是不是0x5B幀尾 是幀尾0x5B 就認為通信正確 處理數(shù)據(jù)
{
state = 0; //這里就可以處理數(shù)據(jù)了、處理完記得清空數(shù)組和重置標志位與計數(shù)值
g_ucUsart2ReceivCounter = 0;//清零計數(shù)值
//比如根據(jù)數(shù)據(jù)設(shè)置紅外旋轉(zhuǎn)偏移狀態(tài)
//1.設(shè)置快速 慢速右邊 左邊 數(shù)字存儲的變量意義: [0]和[1]:幀頭、[2]:攝像頭左邊數(shù)第一個感興趣區(qū)域、[3]:左邊第二個、[4]:左邊第三個、[5]:左邊第四個、[6]:左邊第五個、[7]:幀尾
if(g_ucaUsart2ReceiveBuffer[6]==0&&g_ucaUsart2ReceiveBuffer[5]==0&&g_ucaUsart2ReceiveBuffer[3]==0&&g_ucaUsart2ReceiveBuffer[2]==0)
{
g_cThisState=0;//前進
g_lHW_State=22222;//設(shè)置這個顯示在OLED上方便調(diào)試 五個值 以此從左向右表示 從左向右的五個區(qū)域
}
if(g_ucaUsart2ReceiveBuffer[6]==0&&g_ucaUsart2ReceiveBuffer[5]==1&&g_ucaUsart2ReceiveBuffer[3]==0&&g_ucaUsart2ReceiveBuffer[2]==0)
{
g_cThisState=-1;//應(yīng)該右轉(zhuǎn)
g_lHW_State=22212; //表示右數(shù)第二個 識別到線
}
if(g_ucaUsart2ReceiveBuffer[6]==1&&g_ucaUsart2ReceiveBuffer[5]==0&&g_ucaUsart2ReceiveBuffer[3]==0&&g_ucaUsart2ReceiveBuffer[2]==0)
{g_cThisState=-2;//快速右轉(zhuǎn)
g_lHW_State=22221;
}
if(g_ucaUsart2ReceiveBuffer[6]==1&&g_ucaUsart2ReceiveBuffer[5]==1&&g_ucaUsart2ReceiveBuffer[3]==0&&g_ucaUsart2ReceiveBuffer[2]==0)
{g_cThisState=-3;//快速右轉(zhuǎn)
g_lHW_State=22211;
}
if(g_ucaUsart2ReceiveBuffer[6]==0&&g_ucaUsart2ReceiveBuffer[5]==0&&g_ucaUsart2ReceiveBuffer[3]==1&&g_ucaUsart2ReceiveBuffer[2]==0)
{g_cThisState=1;//應(yīng)該左轉(zhuǎn)
g_lHW_State=21222;
}
if(g_ucaUsart2ReceiveBuffer[6]==0&&g_ucaUsart2ReceiveBuffer[5]==0&&g_ucaUsart2ReceiveBuffer[3]==0&&g_ucaUsart2ReceiveBuffer[2]==1)
{g_cThisState=2;//快速左轉(zhuǎn)
g_lHW_State=12222;
}
if(g_ucaUsart2ReceiveBuffer[6]==0&&g_ucaUsart2ReceiveBuffer[5]==0&&g_ucaUsart2ReceiveBuffer[3]==1&&g_ucaUsart2ReceiveBuffer[2]==1)
{g_cThisState=3;//快速左轉(zhuǎn)
g_lHW_State=11222;
}
//2.然后清空數(shù)組
for(int i=0;i<10;i++) g_ucaUsart2ReceiveBuffer[i]=0x00;//清空數(shù)組
}
else //不是幀尾說明通信錯誤重新開始接收
{
state=0;
g_ucUsart2ReceivCounter =0;
for(int i=0;i<10;i++) g_ucaUsart2ReceiveBuffer[i]=0x00;//清空數(shù)組
}
}
else
{ //其他異常清空
state=0;
g_ucUsart2ReceivCounter =0;
for(int i=0;i<10;i++) g_ucaUsart2ReceiveBuffer[i]=0x00;//清空數(shù)組
}
}
然后聲明一下變量
extern int8_t g_cThisState ;//這次狀態(tài)
定義一個變量 并且在main文件中聲明一下
int g_lHW_State = 0;//幫助視覺調(diào)試 用于表示紅外對管或者視覺攝像頭識別狀態(tài)
聲明一下
extern int g_lHW_State;//幫助視覺調(diào)試 用于表示紅外對管或者視覺攝像頭識別狀態(tài)
我們需要再定義模式,這個模式是視覺循跡模式
視覺模式下 我們顯示一下,我們之前賦值的變量 以測試我們接收的數(shù)據(jù)是否正確。
//這里編寫觸發(fā)中斷后要執(zhí)行的程序
if(g_ucMode == 6) g_ucMode = 1;//g_ucMode模式是0 1 2 3 4 5 6
else
{
g_ucMode+=1;
}
增加模式6,的功能,我們先只顯示視覺識別結(jié)果
if(g_ucMode == 6)
{
sprintf((char*)OledString, "lHW:%d ", g_lHW_State);//視覺識別結(jié)果
OLED_ShowString(0,0,OledString,12);//這個是oled驅(qū)動里面的,是顯示位置的一個函數(shù),
motorPidSetSpeed(0,0);//停住電機防止亂跑 方便調(diào)試
}
別忘記我們的解析函數(shù),加到串口中斷處理函數(shù)中
usartCamera_Receive_Data(g_ucUsart2ReceiveData);
修改上面程序經(jīng)過測試,單片機
編譯上面程序,并燒錄到我們的單片機、單片機連接到電腦、然后電腦模擬openmv發(fā)送正確格式的數(shù)據(jù),手動點擊SSCOM發(fā)送數(shù)據(jù)、單片機可以接收到數(shù)據(jù)并顯示在OLED上(觀察的是OLED的第一行數(shù)值變化)、當(dāng)我們設(shè)置每1ms發(fā)送一次數(shù)據(jù)時候,單片機的OLED有時候會出現(xiàn)卡死的情況。所以是單片機串口接收大量數(shù)據(jù)卡死的情況,經(jīng)過網(wǎng)上搜索發(fā)現(xiàn)解決問題的辦法。
**這個博客是搜索到可以解決問題的鏈接:**https://blog.csdn.net/qq_44629109/article/details/131002223
參考博客如下部分:
所以我們要更改如下代碼:
__HAL_UART_ENABLE_IT(&huart2, UART_IT_ERR);// 啟用UART2的錯誤中斷功能
在USART.C 中添加如下代碼
/* UART 錯誤回調(diào)函數(shù) 處理串口錯誤 */
void HAL_UART_ErrorCallback(UART_HandleTypeDef *huart)
{
if(__HAL_UART_GET_FLAG(huart,UART_FLAG_ORE) != RESET) //使用__HAL_UART_GET_FLAG宏檢查UART的overrun錯誤標志位是否被置位。如果返回值不等于RESET,表示overrun錯誤標志位被置位,即發(fā)生了overrun錯誤
{
__HAL_UART_CLEAR_OREFLAG(huart);//使用__HAL_UART_CLEAR_OREFLAG宏清除UART的overrun錯誤標志位
HAL_UART_Receive_IT(&huart2,&g_ucUsart2ReceiveData,1); //使用HAL庫函數(shù)啟動UART2接收中斷,并設(shè)置接收緩沖區(qū)的大小為1字節(jié)
}
}
添加串口2接收變量的聲明
extern uint8_t g_ucUsart2ReceiveData; //保存串口二接收的數(shù)據(jù)
讓單片機處于模式6(按六下 KEY1)
上面我們測試通過上位機發(fā)送數(shù)據(jù),然后觀察屏幕。
然后我們把STM32底板接到openmv,openmv連接電腦,openmv使用的程序是19章3節(jié)的程序19-3-openmv
然后上面如果沒有問題,就可以把openmv 程序通過"將打開的腳本保存到openmv Cam(作為main.py)"
接法如下:
這里就說明了如何接受的數(shù)據(jù),后面的19.5講解利用數(shù)據(jù)
聯(lián)系:Q,1930299709