當(dāng)前位置:首頁 > 單片機(jī) > 單片機(jī)
[導(dǎo)讀]在上一節(jié)串口通訊中使用了查詢方式, 在少量數(shù)據(jù)傳輸應(yīng)用中, 這種方法基本可行, 但如果通迅數(shù)據(jù)量比較大的話會(huì)對(duì)系統(tǒng)實(shí)時(shí)性造成很大的影響, 所以在實(shí)際工程運(yùn)用中, 查詢的方法并不多見.一個(gè)較好的方法就是利用空間換時(shí)

在上一節(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 != '