嵌入式軟件中的串口收發(fā)隊列設計方法
點擊上方藍字關注我哦~
01
前言
在嵌入式軟件的開發(fā)中,串口是十分常用且基礎的功能。在需要批量發(fā)送數(shù)據(jù)的場合,可以使用while循環(huán)等待發(fā)送完成標志位的方式,但是這種方式會占據(jù)主循環(huán),影響效率。也可以采用dma的方式,但是dma在發(fā)送數(shù)據(jù)時非常高效,但是批量接收數(shù)據(jù)時,就很不靈活,特別是一些在串口數(shù)據(jù)中解析某種協(xié)議格式時,很不方便。下面介紹一種利用串口中斷結合FIFO隊列的串口數(shù)據(jù)收發(fā)方法,結合了不阻塞批量發(fā)與靈活接收的優(yōu)點,特別適用于串口協(xié)議收發(fā)的使用場景。
02
FIFO隊列
FIFO是英文First In First Out 的縮寫,是一種先進先出的數(shù)據(jù)緩存器,順序?qū)懭霐?shù)據(jù),順序的讀出數(shù)據(jù),其數(shù)據(jù)地址由內(nèi)部讀寫指針自動加1完成。相比于一個同等緩存大小的數(shù)值,F(xiàn)IFO就是多管理了一個先進先出的功能,方便串口數(shù)據(jù)的存入和讀出。
Fifo在帶操作系統(tǒng)的嵌入式軟件中都有現(xiàn)成的實現(xiàn),但是在基礎的嵌入軟件中,我們可以自己實現(xiàn)一個。
//頭文件函數(shù)列表
FIFO_EXT u8 uart1infifo_data[UART1_IN_FIFO_SIZE];
FIFO_EXT u16 uart1infifo_front;
FIFO_EXT u16 uart1infifo_rear;
FIFO_EXT void uart1infifo_Clear(void);
FIFO_EXT void uart1infifo_DataIn(u8 d);
FIFO_EXT u8 uart1infifo_DataOut(void);
FIFO_EXT u16 uart1infifo_GetSpace(void);
FIFO_EXT u16 uart1infifo_GetCount(void);
//獲取串口1接收隊列緩存數(shù)
u16 uart1infifo_GetCount(void)
{
u16 countR,countF;
countR = uart1infifo_rear;
countF = uart1infifo_front;
if (countR >= countF)
{
return(countR - countF);
}
else
{
return(UART1_IN_FIFO_SIZE + countR - countF);
}
}
//清空串口1接收隊列
void uart1infifo_Clear(void)
{
uart1infifo_front = UART1_IN_FIFO_SIZE -1;
uart1infifo_rear = uart1infifo_front;
// uart1infifo_count = 0;
}
//串口1接收隊列入數(shù)據(jù)
void uart1infifo_DataIn(u8 d)
{
if (uart1infifo_count < UART1_IN_FIFO_SIZE)
{
uart1infifo_rear = (uart1infifo_rear +1) % UART1_IN_FIFO_SIZE;
uart1infifo_data[uart1infifo_rear] = d;
}
}
//串口1接收隊列出數(shù)據(jù)
u8 uart1infifo_DataOut(void)
{
if (uart1infifo_rear != uart1infifo_front)
{
uart1infifo_front = (uart1infifo_front +1) % UART1_IN_FIFO_SIZE;
return(uart1infifo_data[uart1infifo_front]);
}
else
{
return(0xff);
}
}
為了節(jié)省篇幅,串口1發(fā)送隊列就不詳細描述了,在接收隊列的基礎上稍加修改即可。
03
中斷收發(fā)串口
//串口發(fā)送函數(shù)
void SendDataToUart1(u8 * pData, u16 len)
{
u8 i;
//串口發(fā)送隊列將慢,等待一下數(shù)據(jù)發(fā)送
while (1)
{
if (uart1outfifo_GetSpace() > len+5)
{
break;
}
else
{
i = 0;
}
}
USART_ITConfig(USART1, USART_IT_TXE, DISABLE); //關閉中斷,防止隊列的進出會同時進行
while (len --)
{
uart1outfifo_DataIn(*pData);
pData ++;
}
USART_ITConfig(USART1, USART_IT_TXE, ENABLE);
}
//串口處理函數(shù)
void USART1_IRQHandler(void)
{
if (USART_GetFlagStatus(USART1, USART_FLAG_RXNE))
{
uart1infifo_DataIn(USART_ReceiveData(USART1));//接收數(shù)據(jù)并放入串口接收隊列
//串口數(shù)據(jù)處理flag
}
else if (USART_GetFlagStatus(USART1, USART_FLAG_TXE))
{
if (uart1outfifo_count > 0)
{
USART_SendData(USART1, uart1outfifo_DataOut());//發(fā)隊列取出數(shù)據(jù)放入串口發(fā)送寄存器
}
else
{
USART_ITConfig(USART1, USART_IT_TXE, DISABLE);
}
}
}
04
串口數(shù)據(jù)處理
不定長數(shù)據(jù)包超時處理
在上節(jié)的“串口數(shù)據(jù)處理flag”處,加入超時的標記g_uartTimeOut = n;并在定時器中斷中倒計時g_uartTimeOut,減到0后,產(chǎn)生數(shù)據(jù)包處理標志gb_needDealUartPkg = 1。主循環(huán)掃到gb_needDealUartPkg是1后,讀出uart1infifo中的全部數(shù)據(jù)進行解包處理。
不定長數(shù)據(jù)包按內(nèi)容格式處理
?在上節(jié)的“串口數(shù)據(jù)處理flag”處,加入比對數(shù)據(jù)包格式的函數(shù),當格式滿足要求時,將整個數(shù)據(jù)包存入數(shù)據(jù)包隊列(參照前面的串口數(shù)據(jù)接收函數(shù),寫一個接收隊列,接收的數(shù)據(jù)為數(shù)據(jù)包結構體)。主循環(huán)掃描數(shù)據(jù)包隊列的緩存數(shù),有就去處理。
定長數(shù)據(jù)包處理
主循環(huán)中掃描uart1infifo_count,當達到定長后,讀出uart1infifo中的定長數(shù)據(jù)進行解包處理。
/ The End /
本文由【嵌入式案例Show】原創(chuàng)出品,未經(jīng)許可,請勿轉(zhuǎn)載
掃碼關注我們
看更多嵌入式案例
喜歡本篇內(nèi)容請給我們點個在看
免責聲明:本文內(nèi)容由21ic獲得授權后發(fā)布,版權歸原作者所有,本平臺僅提供信息存儲服務。文章僅代表作者個人觀點,不代表本平臺立場,如有問題,請聯(lián)系我們,謝謝!