串口作為MCU的重要外部接口,同時也是軟件開發重要的調試手段,其重要性不言而喻。STM32的串口資源相當豐富的,功能也相當強勁。ALIENTEK戰艦STM32開發板所使用的STM32F103ZET6最多可提供5路串口,有分數波特率發生器、支持同步單線通信和半雙工單線通訊、支持LIN、支持調制解調器操作、智能卡協議和IrDASIRENDEC規范、具有DMA等。 用過單片機的人肯定都接觸過串口,設置串口無非就是設置波特率、數據位、停止位、奇偶校驗位。發送接收也就三種基本方式,輪詢、中斷和DMA。STM32F10x 的USART 模塊也不過如此。
STM32單片機的接收不定長度字節數據的方法。由于STM32單片機帶IDLE中斷,所以利用這個中斷,可以接收不定長字節的數據,由于STM32屬于ARM單片機,所以這篇文章的方法也適合其他的ARM單片機。
IDLE中斷什么時候發生?
IDLE就是串口收到一幀數據后,發生的中斷。什么是一幀數據呢?比如說給單片機一次發來1個字節,或者一次發來8個字節,這些一次發來的數據,就稱為一幀數據,也可以叫做一包數據。
如何判斷一幀數據結束,就是我們今天討論的問題。因為很多項目中都要用到這個,因為只有接收到一幀數據以后,你才可以判斷這次收了幾個字節和每個字節的內容是否符合協議要求。
看了前面IDLE中斷的定義,你就會明白了,一幀數據結束后,就會產生IDLE中斷。這個中斷真是太TMD有用了。省去了好多判斷的麻煩。
如何配置好IDLE中斷?
下面我們就配置好串口IDLE中斷吧。
這是串口CR1寄存器,其中,對bit4寫1開啟IDLE中斷,對bit5寫1開啟接收數據中斷。(注意:不同系列的STM32,對應的寄存器位可能不同)
(RXNE中斷和IDLE中斷的區別?
當接收到1個字節,就會產生RXNE中斷,當接收到一幀數據,就會產生IDLE中斷。比如給單片機一次性發送了8個字節,就會產生8次RXNE中斷,1次IDLE中斷。)
這是狀態寄存器,當串口接收到數據時,bit5就會自動變成1,當接收完一幀數據后,bit4就會變成1.
需要注意的是,在中斷函數里面,需要把對應的位清0,否則會影響下一次數據的接收。比如RXNE接收數據中斷,只要把接收到的一個字節讀出來,就會清除這個中斷。IDLE中斷,如何是F0系列的單片機,需要用ICR寄存器來清除,如果是F1系列的單片機,清除方法是“先讀SR寄存器,再讀DR寄存器”。(我怎么知道?手冊上寫的)
下面以STM32F103為例給出源程序。
我們先來看程序中的主要部分。
串口初始化函數片段
如果你原來的串口初始化函數具有打開串口接收中斷的話,實際上就是在初始化函數中多了一條打開空閑中斷的語句。
串口中斷函數
串口中斷函數里面,最重要的兩條語句,就是上圖中圈出來的兩條語句。第一條語句用來判斷是否接收到1個字節,第二條語句用來判斷是否接收到1幀數據。(是不是感覺超級方便?媽媽再也不用擔心我如何判斷是否接收完1幀數據了。)
主函數
我寫的這個主函數,是用來驗證接收的正確性的。RxCounter表示的是這一幀數據有幾個字節,接收完一幀數據,會在中斷函數里面把ReceiveState置1,然后,通過串口把接收到的數據發送回串口。這樣,既驗證了接收了多少字節的正確性,又驗證了接收到的數據是否正確。
上圖是結果驗證。
STM32串口接收不定長數據源程序
?
/**
******************************************************************************
* @file 串口接收不定長字節數據
******************************************************************************
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include “stm32f10x.h”
#include “uart.h”
volatile uint8_t aRxBuffer[100]={0x00};
volatile uint8_t RxCounter=0;
volatile uint8_t ReceiveState=0;
/**
* @brief Main program.
* @param None
* @retval None
*/
int main(void)
{
uint8_t i=0;
USART1_Init();
while (1)
{
if(ReceiveState==1)//如果接收到1幀數據
{
ReceiveState=0;
i=0;
while(RxCounter--)// 把接收到數據發送回串口
{
USART_SendData(USART1, aRxBuffer[i++]);
while (USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET);
}
RxCounter=0;
}
}
}
評論
查看更多