新聞中心

STM32的串口中斷

作者: 時間:2016-12-02 來源:網(wǎng)絡(luò) 收藏

總的來說,STM32單片機的串口還是很好理解的,編程也不算復(fù)雜。當(dāng)然我更愿意希望其中斷系統(tǒng)51單片機一樣的簡單。

本文引用地址:http://butianyuan.cn/article/201612/325043.htm

對于接收終端,就是RXNE了,這只在接收完成后才產(chǎn)生,在執(zhí)行USART_ITConfig(USART1, USART_IT_RXNE, ENABLE)代碼時不會進(jìn)入ISR。但麻煩的就是發(fā)送有關(guān)的中斷了:TXE或者TC,根據(jù)資料和測試的結(jié)果,TXE在復(fù)位后就是置1的,即在執(zhí)行USART_ITConfig(USART1, USART_IT_TXE, ENABLE)后會立即產(chǎn)生中斷請求。因此這造成一個麻煩的問題:如果沒有真正的發(fā)送數(shù)據(jù),TXE中斷都會發(fā)生,而且沒有休止,這將占用很大部分的CPU時間,甚至影響其他程序的運行!

因此建議的是在初始化時不好啟用TXE中斷,只在要發(fā)送數(shù)據(jù)(尤其是字符串、數(shù)組這樣的系列數(shù)據(jù))時才啟用TXE。在發(fā)送完成后立即將其關(guān)閉,以免引起不必要的麻煩。

對于發(fā)送,需要注意TXE和TC的差別——這里簡單描述一下,假設(shè)串口數(shù)據(jù)寄存器是DR、串口移位寄存器是SR以及TXD引腳TXDpin,其關(guān)系是DR->SR->TXDpin。當(dāng)DR中的數(shù)據(jù)轉(zhuǎn)移到SR中時TXE置1,如果有數(shù)據(jù)寫入DR時就能將TXE置0;如果SR中的數(shù)據(jù)全部通過TXDpin移出并且沒有數(shù)據(jù)進(jìn)入DR,則TC置1。并且需要注意TXE只能通過寫DR來置0,不能直接將其清零,而TC可以直接將其寫1清零。

對于發(fā)送單個字符可以考慮不用中斷,直接以查詢方式完成。

對于發(fā)送字符串/數(shù)組類的數(shù)據(jù),唯一要考慮的是只在最后一個字符發(fā)送后關(guān)閉發(fā)送中斷,這里可以分為兩種情況:對于發(fā)送可顯示的字符串,其用0x00作為結(jié)尾的,因此在ISR中就用0x00作為關(guān)閉發(fā)送中斷(TXE或者TC)的條件;第二種情況就是發(fā)送二進(jìn)制數(shù)據(jù),那就是0x00~0xFF中間的任意數(shù)據(jù),就不能用0x00來判斷結(jié)束了,這時必須知道數(shù)據(jù)的具體長度。

這里簡單分析上面代碼的執(zhí)行過程:TXE中斷產(chǎn)生于前一個字符從DR送入SR,執(zhí)行效果是后一個字符送入DR。對于第一種情況,如果是可顯示字符,就執(zhí)行USART_SendData來寫DR(也就清零了TXE),當(dāng)最后一個可顯示的字符從DR送入SR之后,產(chǎn)生的TXE中斷發(fā)現(xiàn)要送入DR的是字符是0x00——這當(dāng)然不行——此時就關(guān)閉TXE中斷,字符串發(fā)送過程就算結(jié)束了。當(dāng)然這時不能忽略一個隱含的結(jié)果:那就是最后一個可顯示字符從DR轉(zhuǎn)入SR后TXE是置1的,但關(guān)閉了TXE中斷,因此只要下次再開啟TXE中斷就會立即進(jìn)入ISR。對于第二種情況,其結(jié)果和第一種的相同。

對于第一種情況,其程序可以這么寫:其中TXS是保存了要發(fā)送數(shù)據(jù)的字符串,TxCounter1是索引值:

extern __IO uint8_t TxCounter1;
extern uint8_t *TXS;
extern __IO uint8_t TxLen;

void USART1_IRQHandler(void)
{
if(USART_GetITStatus(USART1, USART_IT_TXE) != RESET)
{
if(TXS[TxCounter1]) //如果是可顯示字符
{ USART_SendData(USART1,TXS[TxCounter1++]);}
else //發(fā)送完成后關(guān)閉TXE中斷,
{ USART_ITConfig(USART1,USART_IT_TXE,DISABLE);}
}
}

對于第二種情況,和上面的大同小異,其中TXLen表示要發(fā)送的二進(jìn)制數(shù)據(jù)長度:

void USART1_IRQHandler(void)
{
if(USART_GetITStatus(USART1, USART_IT_TXE) != RESET) //對USART_DR的寫操作,將該位清零。
{
if(TxCounter1 { USART_SendData(USART1,TXS[TxCounter1++]);}
else //發(fā)送完成后關(guān)閉TXE中斷
{ USART_ITConfig(USART1,USART_IT_TXE,DISABLE);}
}
}

事實上第一種情況是第二種的特殊形式,就是說可以用第二種情況去發(fā)送可顯示的字符——當(dāng)然沒人有閑心去數(shù)一句話里有多少個字母空格和標(biāo)點符號!

在使用時,只要將TXS指向要發(fā)送的字符串或者數(shù)組,設(shè)置TxLen為要發(fā)送的數(shù)據(jù)長度,然后執(zhí)行USART_ITConfig(USART1, USART_IT_TXE,ENABLE)就立即開始發(fā)送過程。用戶可以檢查TxCounter1來確定發(fā)送了多少字節(jié)。比如以第二種情況為例:

uint32_t *TXS;
uint8_t TxBuffer1[]="0123456789ABCDEF";
uint8_t DST2[]="ASDFGHJKL";
__IO uint8_t TxLen = 0x00;

TxLen=8; //發(fā)送8個字符,最終發(fā)送的是01234567
TXS=(uint32_t *)TxBuffer1; //將TXS指向字符串TxBuffer1
TxCounter1=0; //復(fù)位索引值
USART_ITConfig(USART1, USART_IT_TXE,ENABLE); //啟用TXE中斷,即開始發(fā)送過程
while(TxCounter1!=TxLen); //等待發(fā)送完成
TXS=(uint32_t *)TxBuffer2; //同上,最終發(fā)送的是ASDFGHJK
TxCounter1=0;
USART_ITConfig(USART1, USART_IT_TXE,ENABLE);
while(TxCounter1!=TxLen);

以上就是我認(rèn)為的最佳方案,但串口中斷方式數(shù)據(jù)有多長就中斷多少次,我認(rèn)為還是占用不少CPU時間,相比之下DMA方式就好多了,因為DMA發(fā)送字符串時最多中斷兩次(半傳輸完成,全傳輸完成),并且將串口變成類似16C550的器件。關(guān)于DMA方式的這里就不介紹了,有空再說。



關(guān)鍵詞: STM32串口中

評論


技術(shù)專區(qū)

關(guān)閉