STM32串口通迅–使用中斷方式
在上一節(jié)串口通訊中使用了查詢方式, 在少量數(shù)據(jù)傳輸應(yīng)用中, 這種方法基本可行, 但如果通迅數(shù)據(jù)量比較大的話會(huì)對(duì)系統(tǒng)實(shí)時(shí)性造成很大的影響, 所以在實(shí)際工程運(yùn)用中, 查詢的方法并不多見.
一個(gè)較好的方法就是利用空間換時(shí)間, 用一個(gè)緩存區(qū)加中斷進(jìn)行數(shù)據(jù)發(fā)送和接收, 以減少不必要的等待的時(shí)間, 提高系統(tǒng)的實(shí)時(shí)性.
為了提高空間利用率, 最常用的方法是采用一個(gè)環(huán)形隊(duì)列做為接收/發(fā)送緩存, 配合中斷, 可很好的完成數(shù)據(jù)接收/傳送, 在時(shí)間和空間中取得一個(gè)平衡. 有關(guān)環(huán)形隊(duì)列的知識(shí), 這里不多做介紹, 可參考相關(guān)資料.
使用環(huán)形隊(duì)列做為緩存.
發(fā)送邏輯: 當(dāng)有一個(gè)字符串要發(fā)送時(shí), 待發(fā)送的字符串送入FIFO緩存, 然后打開串口中斷, 在中斷服務(wù)函數(shù)中從FIFO取出數(shù)據(jù), 逐一發(fā)送.
STM32的USART中斷.
在STM32中, 每個(gè)USART有多個(gè)中斷事件, 共用一個(gè)中斷向量. 其中比較常用的事件標(biāo)志有三個(gè): TXE, TC, RXNE.
數(shù)據(jù)發(fā)送的過程: 待發(fā)送的數(shù)據(jù)被寫入U(xiǎn)SART_DR(數(shù)據(jù)寄存器), 然后硬件將數(shù)據(jù)從USART_DR移動(dòng)到發(fā)送移位寄存器, 隨著時(shí)鐘逐位稱到Tx引腳.
TXE:發(fā)送數(shù)據(jù)寄存器空 (Transmit data register empty).
當(dāng)TDR寄存器中的數(shù)據(jù)被硬件轉(zhuǎn)移到移位寄存器的時(shí)候,該位被硬件置位。如果USART_CR1 寄存器中的TXEIE為1,則產(chǎn)生中斷。對(duì)USART_DR的寫操作,將該位清零。
0:數(shù)據(jù)還沒有被轉(zhuǎn)移到移位寄存器;
1:數(shù)據(jù)已經(jīng)被轉(zhuǎn)移到移位寄存器。
TC:發(fā)送完成 (Transmission complete)
當(dāng)包含有數(shù)據(jù)的一幀發(fā)送完成后, 并且TXE=1時(shí), 由硬件將該位置’1′. 如果USART_CR1中的 TCIE為’1′,則產(chǎn)生中斷. 由軟件序列清除該位(先讀USART_SR,然后寫入U(xiǎn)SART_DR). TC 位也可以通過寫入’0′來清除,只有在多緩存通訊中才推薦這種清除程序。
0:發(fā)送還未完成;
1:發(fā)送完成。
RXNE:讀數(shù)據(jù)寄存器非空 (Read data register not empty)
當(dāng)RDR移位寄存器中的數(shù)據(jù)被轉(zhuǎn)移到USART_DR寄存器中,該位被硬件置位。如果 USART_CR1寄存器中的RXNEIE為1,則產(chǎn)生中斷。對(duì)USART_DR的讀操作可以將該位清 零。RXNE位也可以通過寫入0來清除,只有在多緩存通訊中才推薦這種清除程序。
0:數(shù)據(jù)沒有收到;
1:收到數(shù)據(jù),可以讀出。
USART的初始化同上一節(jié)一樣, 唯一的區(qū)別就是因?yàn)槭褂昧酥袛? 要配置NVIC.
有關(guān)NVIC的相關(guān)知識(shí)見 STM32中斷與NVIC概覽
NVIC的配置:
void NVIC_Config(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
// 2位搶占優(yōu)先級(jí), 兩位響應(yīng)優(yōu)先級(jí)
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
// 中斷通道
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
// 搶占優(yōu)先級(jí)
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;
// 響應(yīng)優(yōu)先級(jí)
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;
// 使能中斷
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
return;
}
字符串發(fā)送函數(shù):
BOOL USART1_Puts(const uint8_t *str)
{
// 獲取字符串長度
size_t str_len = strlen((const char *)str);
// FIFO不足以容納字符串, 發(fā)送失敗
if (str_len > FIFO_get_free(&USART1_tx_fifo))
{
return FALSE;
}
while (*str != '