1.1 環(huán)形緩沖區(qū)的實(shí)現(xiàn)思路
單片機(jī)程序開(kāi)發(fā)一般都會(huì)用到UART串口通信,通過(guò)通信來(lái)實(shí)現(xiàn)上位機(jī)和單片機(jī)程序的數(shù)據(jù)交互。通信中為了實(shí)現(xiàn)正常的收發(fā),一般都會(huì)有對(duì)應(yīng)的發(fā)送和接收緩存來(lái)暫存通信數(shù)據(jù)。這里使用環(huán)形緩沖區(qū)的方式來(lái)設(shè)計(jì)數(shù)據(jù)收發(fā)的緩存,即緩沖區(qū)溢出后,從緩沖區(qū)數(shù)組的起始索引處重新進(jìn)行數(shù)據(jù)的存儲(chǔ),這樣可以比較高效地使用緩沖區(qū)。
核心思路摘抄如下。規(guī)定以下所有方案,在緩沖區(qū)滿時(shí)不可再寫(xiě)入數(shù)據(jù),緩沖區(qū)空時(shí)不能讀數(shù)據(jù)。
常規(guī)數(shù)組環(huán)形緩沖區(qū)思路:
設(shè)緩沖區(qū)大小為N,隊(duì)頭out,隊(duì)尾in,out、in均是下標(biāo)表示。
- 初始時(shí),in = out = 0
- 隊(duì)頭隊(duì)尾的更新用取模操作,out = (out + 1) % N,in = (in + 1) % N
- out == in表示緩沖區(qū)空,(in + 1) % N == out表示緩沖區(qū)滿
- 入隊(duì)que[in] = value; in = (in + 1) % N;
- 出隊(duì)ret = que[out]; out = (out + 1) % N;
- 數(shù)據(jù)長(zhǎng)度 len = (in - out + N) % N
改進(jìn)版數(shù)組環(huán)形緩沖區(qū)思路:
同樣假設(shè)緩沖區(qū)大小為N,隊(duì)頭out,隊(duì)尾in,out、in為數(shù)組下標(biāo),但數(shù)據(jù)類型為unsigned int。
- 初始時(shí),in = out = 0
- 上調(diào)緩沖區(qū)大小N為2的冪,假設(shè)為M
- 隊(duì)頭隊(duì)尾更新不再取模,直接++out,++in
- out == in表示緩沖區(qū)空,(in - out) == M表示緩沖區(qū)滿
- 入隊(duì)que[in & (M - 1)] = value; ++in;
- 出隊(duì)ret = que[out & (M - 1)] ; ++out;
- in - out表示數(shù)據(jù)長(zhǎng)度
1.2 環(huán)形緩沖區(qū)的代碼實(shí)現(xiàn)
本文對(duì)應(yīng)的工程代碼鏈接如下。該工程基于eclipse IDE開(kāi)發(fā),編譯器使用arm-none-eabi-gcc,使用的硬件是STM32F429I-DISCO開(kāi)發(fā)板。
https://download.csdn.net/download/goodrenze/85163032
根據(jù)以上的環(huán)形緩沖區(qū)設(shè)計(jì)思路,先定義緩存對(duì)應(yīng)的結(jié)構(gòu)體類型如下。
typedef struct _UartBuf_t
{
#if UART_RECORD_LOST_NUM
uint32_t TxLostNum;
#endif
uint8_t* TxBuf;
#if UART_BUF_SIZE_IS_2POW
uint16_t TxIn;
uint16_t TxOut;
uint16_t TxSize;
#else
int16_t TxIn;
int16_t TxOut;
int16_t TxSize;
#endif
#if UART_RECORD_LOST_NUM
uint32_t RxLostNum;
#endif
uint8_t* RxBuf;
#if UART_BUF_SIZE_IS_2POW
uint16_t RxIn;
uint16_t RxOut;
uint16_t RxSize;
#else
int16_t RxIn;
int16_t RxOut;
int16_t RxSize;
#endif
}UartBuf_t;
以上結(jié)構(gòu)體中,UART_RECORD_LOST_NUM宏定義用于設(shè)置是否記錄丟失的數(shù)據(jù)個(gè)數(shù),UART_BUF_SIZE_IS_2POW宏定義用于設(shè)置收發(fā)緩存的長(zhǎng)度是否是2的冪,如果緩存長(zhǎng)度是2的冪,則緩存索引和長(zhǎng)度使用無(wú)符號(hào)數(shù),否則使用有符號(hào)數(shù)。TxBuf和RxBuf指針用于指向?qū)?yīng)的發(fā)送和接收的緩存數(shù)組。
本例程的UART串口發(fā)送和接收都是用串口中斷來(lái)實(shí)現(xiàn)的,串口中斷處理函數(shù)的代碼實(shí)現(xiàn)如下,只需要在對(duì)應(yīng)的串口中斷入口函數(shù)中調(diào)用該函數(shù)進(jìn)行串口數(shù)據(jù)的收發(fā)處理即可。
// 以下環(huán)形緩沖區(qū)的設(shè)計(jì)思路參考以下鏈接:
// https://www.cnblogs.com/zengzy/p/5139582.html
void UartIrqService(USART_TypeDef* UartX, UartBuf_t* Buf)
{
uint32_t SR = UartX->SR;
uint32_t CR1 = UartX->CR1;
uint32_t CR3 = UartX->CR3;
UNUSED(CR3);
while(SR & USART_SR_RXNE)
{
#if UART_RECORD_LOST_NUM
if(SR & USART_SR_ORE)
{
Buf->RxLostNum++;
}
#endif
#if UART_BUF_SIZE_IS_2POW
if ((Buf->RxIn - Buf->RxOut) != Buf->RxSize)
{
Buf->RxBuf[Buf->RxIn & (Buf->RxSize - 1)] = (uint8_t)(UartX->DR & (uint8_t)0x00FF);
Buf->RxIn++;
}
#else
if (((Buf->RxIn + 1) % Buf->RxSize) != Buf->RxOut)
{
Buf->RxBuf[Buf->RxIn++] = (uint8_t)(UartX->DR & (uint8_t)0x00FF);
Buf->RxIn %= Buf->RxSize;
}
#endif
else
{
Buf->RxBuf[Buf->RxIn] = (uint8_t)(UartX->DR & (uint8_t)0x00FF);
#if UART_RECORD_LOST_NUM
Buf->RxLostNum++;
#endif
}
SR = UartX->SR;
}
if((SR & USART_SR_TXE) && (CR1 & USART_CR1_TXEIE))
{
if(Buf->TxIn != Buf->TxOut)
{
#if UART_BUF_SIZE_IS_2POW
UartX->DR = (uint8_t)(Buf->TxBuf[Buf->TxOut & (Buf->TxSize - 1)] & (uint8_t)0x00FF);
Buf->TxOut++;
#else
UartX->DR = (uint8_t)(Buf->TxBuf[Buf->TxOut++] & (uint8_t)0x00FF);
Buf->TxOut %= Buf->TxSize;
#endif
}
else
{
CLEAR_BIT(UartX->CR1, USART_CR1_TXEIE);
}
}
}
以上代碼就是上面提到的環(huán)形緩沖區(qū)思路的具體實(shí)現(xiàn)。當(dāng)緩沖區(qū)的數(shù)據(jù)長(zhǎng)度是2的冪的時(shí)候,可以省去求余的運(yùn)算,可以提高代碼的執(zhí)行速度。所以如果要求代碼的執(zhí)行時(shí)間盡量短,可以考慮將緩沖區(qū)的長(zhǎng)度設(shè)置成2的冪。
-
單片機(jī)
+關(guān)注
關(guān)注
6067文章
44989瀏覽量
650362 -
緩沖區(qū)
+關(guān)注
關(guān)注
0文章
36瀏覽量
9365 -
程序
+關(guān)注
關(guān)注
117文章
3826瀏覽量
82967 -
uart
+關(guān)注
關(guān)注
22文章
1276瀏覽量
103917 -
串口通信
+關(guān)注
關(guān)注
34文章
1639瀏覽量
56806
發(fā)布評(píng)論請(qǐng)先 登錄
STM32進(jìn)階之串口環(huán)形緩沖區(qū)實(shí)現(xiàn)
MCU進(jìn)階之串口環(huán)形緩沖區(qū)實(shí)現(xiàn)
STM32串口環(huán)形緩沖區(qū)的實(shí)現(xiàn)
環(huán)形緩沖區(qū)的設(shè)計(jì)分享!
環(huán)形緩沖區(qū)簡(jiǎn)介
請(qǐng)問(wèn)串口的DMA接收緩沖區(qū)是不是環(huán)形緩沖區(qū)
rtt的環(huán)形緩沖區(qū)讀完就丟棄了?
環(huán)形緩沖區(qū)讀寫(xiě)操作的分析與實(shí)現(xiàn)
環(huán)形緩沖區(qū)的實(shí)現(xiàn)原理

緩沖區(qū)是啥意思 STM32串口數(shù)據(jù)接收之環(huán)形緩沖區(qū)
STM32串口數(shù)據(jù)接收 --環(huán)形緩沖區(qū)

C++環(huán)形緩沖區(qū)設(shè)計(jì)與實(shí)現(xiàn)

評(píng)論