01
前言
在嵌入式軟件的開發中,串口是十分常用且基礎的功能。在需要批量發送數據的場合,可以使用while循環等待發送完成標志位的方式,但是這種方式會占據主循環,影響效率。也可以采用dma的方式,但是dma在發送數據時非常高效,但是批量接收數據時,就很不靈活,特別是一些在串口數據中解析某種協議格式時,很不方便。下面介紹一種利用串口中斷結合FIFO隊列的串口數據收發方法,結合了不阻塞批量發與靈活接收的優點,特別適用于串口協議收發的使用場景。
02
FIFO隊列
FIFO是英文First In First Out 的縮寫,是一種先進先出的數據緩存器,順序寫入數據,順序的讀出數據,其數據地址由內部讀寫指針自動加1完成。相比于一個同等緩存大小的數值,FIFO就是多管理了一個先進先出的功能,方便串口數據的存入和讀出。
Fifo在帶操作系統的嵌入式軟件中都有現成的實現,但是在基礎的嵌入軟件中,我們可以自己實現一個。
#define UART1_IN_FIFO_SIZE 100 //接收串口隊列的深度#define UART1_OUT_FIFO_SIZE 250 //發送串口隊列的深度 //頭文件函數列表FIFO_EXT u8 uart1infifo_data[UART1_IN_FIFO_SIZE];#define uart1infifo_count (uart1infifo_GetCount())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接收隊列緩存數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接收隊列入數據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接收隊列出數據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); }}
為了節省篇幅,串口1發送隊列就不詳細描述了,在接收隊列的基礎上稍加修改即可。
03
中斷收發串口
//串口發送函數 void SendDataToUart1(u8 * pData, u16 len){ u8i; //串口發送隊列將慢,等待一下數據發送 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);} //串口處理函數void USART1_IRQHandler(void){ if (USART_GetFlagStatus(USART1, USART_FLAG_RXNE)) { uart1infifo_DataIn(USART_ReceiveData(USART1));//接收數據并放入串口接收隊列 //串口數據處理flag } else if (USART_GetFlagStatus(USART1, USART_FLAG_TXE)) { if (uart1outfifo_count > 0) { USART_SendData(USART1, uart1outfifo_DataOut());//發隊列取出數據放入串口發送寄存器}else { USART_ITConfig(USART1, USART_IT_TXE, DISABLE); } }}
04
串口數據處理
不定長數據包超時處理
在上節的“串口數據處理flag”處,加入超時的標記g_uartTimeOut = n;并在定時器中斷中倒計時g_uartTimeOut,減到0后,產生數據包處理標志gb_needDealUartPkg = 1。主循環掃到gb_needDealUartPkg是1后,讀出uart1infifo中的全部數據進行解包處理。
不定長數據包按內容格式處理
?在上節的“串口數據處理flag”處,加入比對數據包格式的函數,當格式滿足要求時,將整個數據包存入數據包隊列(參照前面的串口數據接收函數,寫一個接收隊列,接收的數據為數據包結構體)。主循環掃描數據包隊列的緩存數,有就去處理。
定長數據包處理
主循環中掃描uart1infifo_count,當達到定長后,讀出uart1infifo中的定長數據進行解包處理。
原文標題:嵌入式軟件中的串口收發隊列設計方法
文章出處:【微信公眾號:FPGA之家】歡迎添加關注!文章轉載請注明出處。
-
操作系統
+關注
關注
37文章
6889瀏覽量
123603 -
fifo
+關注
關注
3文章
389瀏覽量
43815 -
串口數據
+關注
關注
0文章
33瀏覽量
13916
原文標題:嵌入式軟件中的串口收發隊列設計方法
文章出處:【微信號:zhuyandz,微信公眾號:FPGA之家】歡迎添加關注!文章轉載請注明出處。
發布評論請先 登錄
相關推薦
評論