stm32 hal uart_STM32 非阻塞HAL_UART_Receive_IT解析与实际应用
希望可以通過不同的視角能更好的總結(jié)分享如何使用HAL庫中的非阻塞UART。關(guān)于如何配置UART的問題本文不做具體介紹,需要這部分內(nèi)容的可以參考其他分享者的文章。另外,如希望在MacOS或Linux平臺優(yōu)雅的編寫、燒錄STM32代碼的可以參考我另外兩篇文章。Yume:MacOS在VSCode中優(yōu)雅的編寫STM32(HAL庫)?zhuanlan.zhihu.comYume:MacOS基于STM32CubeMX、Makefile和OpenOCD的Stm32交叉編譯環(huán)境搭建?zhuanlan.zhihu.com
1 通過STM32CubeMX初始化并生成工程目錄
通過STM32CubeMX可以很輕松的完成配置,網(wǎng)絡上也有很多很優(yōu)秀的分享者寫的教程。同時也可以參考我的另一篇文章(MacOS、Liunx用戶也可作為參考)進行相關(guān)的配置
Yume:MacOS基于STM32CubeMX、Makefile和OpenOCD的Stm32交叉編譯環(huán)境搭建?zhuanlan.zhihu.com2 通過CoolTerm與STM32通信
Roger Meier's Freeware?freeware.the-meiers.org具體使用方法,可以在網(wǎng)絡上找到很多教程,基本方法就是設置好對應的如波特率、有無奇偶校驗位等。需要特別指出的是,此軟件發(fā)送"ASCII"是原生發(fā)送,不會自動添加額外的結(jié)束符(也可能是我沒有配置)。
3 HAL庫中的非阻塞UART
可以在工程目錄"Drivers/CMSIS/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_uart.c"中看到所有關(guān)于UART的HAL庫函數(shù)使用方法。其中我們重點關(guān)注4個函數(shù)"UART_Receive_IT"、"HAL_UART_RxCpltCallback"、"HAL_UART_IRQHandler"、"HAL_UART_Receive_IT"
- HAL_UART_IRQHandler
此函數(shù)是request(響應中斷),即UART的RX中斷入口。當有數(shù)據(jù)發(fā)送時,就會進入到這個函數(shù)中。
HAL_UART_IRQHandler可以從HAL的UART庫文件看到該函數(shù)的描述與具體過程。正常情況下(即errorflags = RESET)將會調(diào)用"UART_Receive_IT"進入處理數(shù)據(jù)的部分。
- UART_Receive_IT
這個函數(shù)可以理解為RX接收數(shù)據(jù)處理的函數(shù)
UART_Receive_IT可以看到當進入到這個函數(shù)的時候,會判斷當前RX接收狀態(tài)(重要)。中間數(shù)據(jù)處理過程我們略過,大概知道就是將數(shù)據(jù)存入到一個特殊寄存器里。(想了解具體過程的,可以自行閱讀HAL庫相關(guān)文件)。再看看完成數(shù)據(jù)的轉(zhuǎn)存、狀態(tài)設置之類操作后會發(fā)生什么
UART_Receive_IT判斷條件"--huart->RxXferCount"就是判斷進來比特數(shù)是否到達指定的大小??梢钥吹疆敐M足條件是,將會關(guān)閉中斷響應,同時調(diào)用"HAL_UART_RxCpltCallback"函數(shù)。這個函數(shù)時給用戶的自定義的函數(shù),指定完成數(shù)據(jù)接收后的操作。
- HAL_UART_RxCpltCallback
上文已經(jīng)提到了,這是個給用戶在完成RX數(shù)據(jù)接收后自行決定怎么操作的函數(shù)。但我們還是看看在HAL庫文件中是怎么定義的
HAL_UART_RxCpltCallback可以看到void前面的"__weak"描述就是弱定義,指當用戶在進行定義時,可以理解為這個定義就失效了。所以我們可以在"main.c"再定義這個函數(shù),用于Rx完成接收后的操作。
那說到這,具體如何將Rx接收的數(shù)據(jù)進行轉(zhuǎn)存、處理等操作呢?
等等,是不是發(fā)現(xiàn)還有一個函數(shù)沒有說?
誒,通過從中斷入口層層進入,始終沒出現(xiàn)過"HAL_UART_Receive_IT"。那他究竟來干嘛的?還記得前面說到,在完成接收后"UART_Receive_IT"就會關(guān)閉中斷?,F(xiàn)在我們看看"HAL_UART_Receive_IT"
可以看到,該函數(shù)UART的RX為準備狀態(tài)后,就會將數(shù)據(jù)從接收數(shù)據(jù)的特殊寄存器"pRxBufferPtr"指針指向"pData"(用戶創(chuàng)建的寄存器)和一系列包括修改標志位等操作后,重新開啟UART的Receive中斷。
4 使用UART的HAL庫
那通過上面的一步一步從中斷入口走向出口。那我們也從入口開始,那就需要先打開入口(偽代碼形式)
uint8_t其中"huart1"是UART1的數(shù)據(jù)結(jié)構(gòu),STM32CubeMX配置時會幫我們完成,是全局變量;"rDataBuffer"是用戶自定義用于轉(zhuǎn)存RX接收數(shù)據(jù)的寄存器;后面的數(shù)字"1"表示接收數(shù)據(jù)為1比特(目的是接收到1比特數(shù)據(jù)就拿出來,實現(xiàn)通過結(jié)束符判斷數(shù)據(jù)接收完成,而不是指定的字節(jié)長度)。在main中編寫這段,就完成了打開中斷入口的操作,同時配置"huart1"數(shù)據(jù)結(jié)構(gòu)中關(guān)于RX接收信息,提供給中斷入口函數(shù)"HAL_UART_IRQHandler"。那為何在這里需要用while不斷循環(huán)檢測返回值呢?因為可能RX處于正忙狀態(tài)。如果在RX正忙狀態(tài)調(diào)用HAL_UART_Receive_IT,可能就會導致不是按預期執(zhí)行的。
當數(shù)據(jù)發(fā)送到RX時,觸發(fā)中斷,進入"HAL_UART_IRQHandler"。從第一步的到的RX接收信息可知,收到1Byte數(shù)據(jù)就會進入到"UART_Receive_IT"處理數(shù)據(jù)、關(guān)閉總斷入口。再進入到用戶自定義操作的函數(shù)"HAL_UART_RxCpltCallback"。所以我們需要在"main.c"中編寫這個函數(shù)(函數(shù)外定義的變量是全局變量)
uint8_t其中,全局變量"rData"用于存放接收到的數(shù)據(jù);"rDataBuffer"用于將接收到的數(shù)據(jù)從UART的RX特殊寄存器中轉(zhuǎn)移出來;"rDataCount"用于記錄收到的結(jié)束符之前(可以看到是通過"~"確認結(jié)束符,也可以根據(jù)需求自行定義)的數(shù)據(jù)字節(jié)數(shù);"rDataFlah"是通過一個符號表示完成RX的接收工作。當然,這些符號可以根據(jù)具體需求定義,并不是必須這么做的。
注意到的是,這里還有一個條件判斷"rDataBuffer[0]!=0x00",這么寫的目的首先是接收到"0"不處理,還有一個原因是因為在實踐過程中,不知道是什么原因,第一次發(fā)RX數(shù)據(jù)時,回顯數(shù)據(jù)顯示已經(jīng)進入過中斷,并進行RX數(shù)據(jù)接收轉(zhuǎn)存。如果不加判斷即使是沒接收到數(shù)據(jù)("0"=0x00)也判斷為有效數(shù)據(jù),那會出現(xiàn)第一次RX數(shù)據(jù)前面有幾字節(jié)為"0",不是預期的結(jié)果。我的判斷是可能在確認分隔幀時(大概就是取樣點),誤進入中斷導致的。但這不會影響后續(xù)RX的接收,所以及時不加也不會出現(xiàn)大問題。
然后接下來的判斷就是檢查是否收到RX接收結(jié)束符號,然后改變標志位,用于其他操作。
后面"while"就是重新打開UART的RX中斷,繼續(xù)接收數(shù)據(jù)。
5 結(jié)語
可以看出來,具體使用時其實就可以分為簡單的兩步:
但如何完全掌握,能在實際項目中變通運用UART。還需要仔細分析庫函數(shù)的層層套娃中摸出一條線來。
還有需要注意的是,本文所寫的沒有關(guān)注如寄存器溢出、出現(xiàn)錯誤如何處理等細節(jié)問題,這都需要更仔細的思考解決。
總結(jié)
以上是生活随笔為你收集整理的stm32 hal uart_STM32 非阻塞HAL_UART_Receive_IT解析与实际应用的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: python 循环触发一次_Python
- 下一篇: nacos enablediscover