新聞中心

EEPW首頁 > 嵌入式系統(tǒng) > 設計應用 > 關于STM32串口的理解

關于STM32串口的理解

作者: 時間:2016-11-18 來源:網絡 收藏

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

本文引用地址:http://butianyuan.cn/article/201611/315877.htm

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

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

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

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

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

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

對于第一種情況,其程序可以這么寫:其中TXS是保存了要發(fā)送數據的字符串,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ā)送完成后關閉TXE中斷,
{ USART_ITConfig(USART1,USART_IT_TXE,DISABLE);}
}
}

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

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

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

在使用時,只要將TXS指向要發(fā)送的字符串或者數組,設置TxLen為要發(fā)送的數據長度,然后執(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; //復位索引值
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);

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




關鍵詞: STM32串

評論


技術專區(qū)

關閉