串口作為MCU的重要外部接口,同時(shí)也是軟件開(kāi)發(fā)重要的調(diào)試手段,其重要性不言而喻。STM32的串口資源相當(dāng)豐富的,功能也相當(dāng)強(qiáng)勁。ALIENTEK戰(zhàn)艦STM32開(kāi)發(fā)板所使用的STM32F103ZET6最多可提供5路串口,有分?jǐn)?shù)波特率發(fā)生器、支持同步單線通信和半雙工單線通訊、支持LIN、支持調(diào)制解調(diào)器操作、智能卡協(xié)議和IrDASIRENDEC規(guī)范、具有DMA等。 用過(guò)單片機(jī)的人肯定都接觸過(guò)串口,設(shè)置串口無(wú)非就是設(shè)置波特率、數(shù)據(jù)位、停止位、奇偶校驗(yàn)位。發(fā)送接收也就三種基本方式,輪詢、中斷和DMA。STM32F10x 的USART 模塊也不過(guò)如此。
STM32單片機(jī)的接收不定長(zhǎng)度字節(jié)數(shù)據(jù)的方法。由于STM32單片機(jī)帶IDLE中斷,所以利用這個(gè)中斷,可以接收不定長(zhǎng)字節(jié)的數(shù)據(jù),由于STM32屬于ARM單片機(jī),所以這篇文章的方法也適合其他的ARM單片機(jī)。
IDLE中斷什么時(shí)候發(fā)生?
IDLE就是串口收到一幀數(shù)據(jù)后,發(fā)生的中斷。什么是一幀數(shù)據(jù)呢?比如說(shuō)給單片機(jī)一次發(fā)來(lái)1個(gè)字節(jié),或者一次發(fā)來(lái)8個(gè)字節(jié),這些一次發(fā)來(lái)的數(shù)據(jù),就稱為一幀數(shù)據(jù),也可以叫做一包數(shù)據(jù)。
如何判斷一幀數(shù)據(jù)結(jié)束,就是我們今天討論的問(wèn)題。因?yàn)楹芏囗?xiàng)目中都要用到這個(gè),因?yàn)橹挥薪邮盏揭粠瑪?shù)據(jù)以后,你才可以判斷這次收了幾個(gè)字節(jié)和每個(gè)字節(jié)的內(nèi)容是否符合協(xié)議要求。
看了前面IDLE中斷的定義,你就會(huì)明白了,一幀數(shù)據(jù)結(jié)束后,就會(huì)產(chǎn)生IDLE中斷。這個(gè)中斷真是太TMD有用了。省去了好多判斷的麻煩。
如何配置好IDLE中斷?
下面我們就配置好串口IDLE中斷吧。
這是串口CR1寄存器,其中,對(duì)bit4寫1開(kāi)啟IDLE中斷,對(duì)bit5寫1開(kāi)啟接收數(shù)據(jù)中斷。(注意:不同系列的STM32,對(duì)應(yīng)的寄存器位可能不同)
?。≧XNE中斷和IDLE中斷的區(qū)別?
當(dāng)接收到1個(gè)字節(jié),就會(huì)產(chǎn)生RXNE中斷,當(dāng)接收到一幀數(shù)據(jù),就會(huì)產(chǎn)生IDLE中斷。比如給單片機(jī)一次性發(fā)送了8個(gè)字節(jié),就會(huì)產(chǎn)生8次RXNE中斷,1次IDLE中斷。)
這是狀態(tài)寄存器,當(dāng)串口接收到數(shù)據(jù)時(shí),bit5就會(huì)自動(dòng)變成1,當(dāng)接收完一幀數(shù)據(jù)后,bit4就會(huì)變成1.
需要注意的是,在中斷函數(shù)里面,需要把對(duì)應(yīng)的位清0,否則會(huì)影響下一次數(shù)據(jù)的接收。比如RXNE接收數(shù)據(jù)中斷,只要把接收到的一個(gè)字節(jié)讀出來(lái),就會(huì)清除這個(gè)中斷。IDLE中斷,如何是F0系列的單片機(jī),需要用ICR寄存器來(lái)清除,如果是F1系列的單片機(jī),清除方法是“先讀SR寄存器,再讀DR寄存器”。(我怎么知道?手冊(cè)上寫的)
下面以STM32F103為例給出源程序。
我們先來(lái)看程序中的主要部分。
串口初始化函數(shù)片段
如果你原來(lái)的串口初始化函數(shù)具有打開(kāi)串口接收中斷的話,實(shí)際上就是在初始化函數(shù)中多了一條打開(kāi)空閑中斷的語(yǔ)句。
串口中斷函數(shù)
串口中斷函數(shù)里面,最重要的兩條語(yǔ)句,就是上圖中圈出來(lái)的兩條語(yǔ)句。第一條語(yǔ)句用來(lái)判斷是否接收到1個(gè)字節(jié),第二條語(yǔ)句用來(lái)判斷是否接收到1幀數(shù)據(jù)。(是不是感覺(jué)超級(jí)方便?媽媽再也不用擔(dān)心我如何判斷是否接收完1幀數(shù)據(jù)了。)
主函數(shù)
我寫的這個(gè)主函數(shù),是用來(lái)驗(yàn)證接收的正確性的。RxCounter表示的是這一幀數(shù)據(jù)有幾個(gè)字節(jié),接收完一幀數(shù)據(jù),會(huì)在中斷函數(shù)里面把ReceiveState置1,然后,通過(guò)串口把接收到的數(shù)據(jù)發(fā)送回串口。這樣,既驗(yàn)證了接收了多少字節(jié)的正確性,又驗(yàn)證了接收到的數(shù)據(jù)是否正確。
上圖是結(jié)果驗(yàn)證。
STM32串口接收不定長(zhǎng)數(shù)據(jù)源程序
?
/**
******************************************************************************
* @file 串口接收不定長(zhǎng)字節(jié)數(shù)據(jù)
******************************************************************************
******************************************************************************
*/
/* 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幀數(shù)據(jù)
{
ReceiveState=0;
i=0;
while(RxCounter--)// 把接收到數(shù)據(jù)發(fā)送回串口
{
USART_SendData(USART1, aRxBuffer[i++]);
while (USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET);
}
RxCounter=0;
}
}
}
評(píng)論