日韩无码专区无码一级三级片|91人人爱网站中日韩无码电影|厨房大战丰满熟妇|AV高清无码在线免费观看|另类AV日韩少妇熟女|中文日本大黄一级黄色片|色情在线视频免费|亚洲成人特黄a片|黄片wwwav色图欧美|欧亚乱色一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時(shí)間:8:30-17:00
你可能遇到了下面的問(wèn)題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營(yíng)銷(xiāo)解決方案
STM32串口開(kāi)發(fā)之環(huán)形緩沖區(qū)

01簡(jiǎn)介

在之前的文章《stm32 串口詳解》中,我們講解了串口的基本應(yīng)用,使用串口中斷接收數(shù)據(jù),串口中斷發(fā)送回包(一般可以使用非中斷形式發(fā)送回包,在數(shù)據(jù)接收不頻繁的應(yīng)用中。串口接收中斷保證串口數(shù)據(jù)及時(shí)響應(yīng),使用非中斷方式發(fā)送回包即可)。

創(chuàng)新互聯(lián)公司自2013年起,先為寧縣等服務(wù)建站,寧縣等地企業(yè),進(jìn)行企業(yè)商務(wù)咨詢服務(wù)。為寧縣企業(yè)網(wǎng)站制作PC+手機(jī)+微官網(wǎng)三網(wǎng)同步一站式服務(wù)解決您的所有建站問(wèn)題。

后面的文章《STM32使用DMA接收串口數(shù)據(jù)》和《STM32使用DMA發(fā)送串口數(shù)據(jù)》講解了如何使用DMA輔助串口收發(fā)數(shù)據(jù),使用DMA的好處在于不用CPU即可完成串口收發(fā)數(shù)據(jù),減輕CPU負(fù)擔(dān),在串口通信頻繁且不想頻繁中斷的應(yīng)用中非常有用。

除了上述兩種場(chǎng)景,還有一種應(yīng)用場(chǎng)景:串口接收數(shù)據(jù)長(zhǎng)度位置,頻率未知,不要求實(shí)時(shí)處理的場(chǎng)景。如果采用上述方案,接收一幀數(shù)據(jù)立即處理,那么在處理的時(shí)候來(lái)的數(shù)據(jù)包就“丟失”了。這個(gè)時(shí)候就需要緩沖隊(duì)列來(lái)解決這個(gè)問(wèn)題。

02緩沖區(qū)

緩沖區(qū)看名字就知道,是緩沖數(shù)據(jù)用的。實(shí)現(xiàn)緩沖區(qū)最簡(jiǎn)單的辦法時(shí),定義多個(gè)數(shù)組,接收一包數(shù)據(jù)到數(shù)組A,就把接收數(shù)據(jù)的地址換成數(shù)組B,每個(gè)數(shù)據(jù)有個(gè)標(biāo)記字節(jié)用于表示這個(gè)數(shù)組是否收到數(shù)據(jù),收到數(shù)據(jù)是否處理完成。

上述方案是完全可行的,但有缺點(diǎn):

①緩沖數(shù)據(jù)組數(shù)一定,且有多變量,代碼結(jié)構(gòu)不太清晰。

②接收數(shù)據(jù)長(zhǎng)度可能大于數(shù)組大小,也可能小于數(shù)組大小。不靈活,需要接收數(shù)據(jù)很長(zhǎng)時(shí)容易出錯(cuò),且內(nèi)存利用率低。

解決這個(gè)問(wèn)題的好辦法是:環(huán)形緩沖區(qū)。

環(huán)形緩沖區(qū)就是一個(gè)帶“頭指針”和“尾指針”的數(shù)組?!邦^指針”指向環(huán)形緩沖區(qū)中可讀的數(shù)據(jù),“尾指針”指向環(huán)形緩沖區(qū)中可寫(xiě)的緩沖空間。通過(guò)移動(dòng)“頭指針”和“尾指針”就可以實(shí)現(xiàn)緩沖區(qū)的數(shù)據(jù)讀取和寫(xiě)入。在通常情況下,應(yīng)用程序讀取環(huán)形緩沖區(qū)的數(shù)據(jù)僅僅會(huì)影響“頭指針”,而串口接收數(shù)據(jù)僅僅會(huì)影響“尾指針”。當(dāng)串口接收到新的數(shù)組,則將數(shù)組保存到環(huán)形緩沖區(qū)中,同時(shí)將“尾指針”加1,以保存下一個(gè)數(shù)據(jù);應(yīng)用程序在讀取數(shù)據(jù)時(shí),“頭指針”加1,以讀取下一個(gè)數(shù)據(jù)。當(dāng)“尾指針”超過(guò)數(shù)組大小,則“尾指針”重新指向數(shù)組的首元素,從而形成“環(huán)形緩沖區(qū)”!,有效數(shù)據(jù)區(qū)域在“頭指針”和“尾指針”之間。如下圖

如上面說(shuō)的,環(huán)形緩沖區(qū)其實(shí)就是一個(gè)數(shù)組,將其“剪開(kāi)”,然后“拉直”后如下圖

環(huán)形緩沖區(qū)的特性

1、先進(jìn)新出。

2、當(dāng)緩沖區(qū)被使用完,且又有新的數(shù)據(jù)需要存儲(chǔ)時(shí),丟掉歷史最久的數(shù)據(jù),保存最新數(shù)據(jù)。

03代碼實(shí)現(xiàn)

環(huán)形緩沖區(qū)的實(shí)現(xiàn)很簡(jiǎn)單,只需要簡(jiǎn)單的幾個(gè)接口即可。

首先需要?jiǎng)?chuàng)建一個(gè)環(huán)形緩沖區(qū)

 
 
 
 
  1. #define  RINGBUFF_LEN          (500)     //定義最大接收字節(jié)數(shù) 500 
  2. #define  RINGBUFF_OK           1      
  3. #define  RINGBUFF_ERR          0    
  4. typedef struct 
  5.     uint16_t Head;            
  6.     uint16_t Tail; 
  7.     uint16_t Lenght; 
  8.     uint8_t  Ring_data[RINGBUFF_LEN]; 
  9. }RingBuff_t; 
  10. RingBuff_t ringBuff;//創(chuàng)建一個(gè)ringBuff的緩沖區(qū) 

當(dāng)我們發(fā)現(xiàn)環(huán)形緩沖區(qū)被“沖爆”時(shí),也就是緩沖區(qū)滿了,但是還有待緩沖的數(shù)據(jù)時(shí),只需要修改RINGBUFF_LEN的宏定義,增大緩沖區(qū)間即可。

環(huán)形緩沖區(qū)的初始化

 
 
 
 
  1. /** 
  2. * @brief  RingBuff_Init 
  3. * @param  void 
  4. * @return void 
  5. * @note   初始化環(huán)形緩沖區(qū) 
  6. */ 
  7. void RingBuff_Init(void) 
  8.   //初始化相關(guān)信息 
  9.   ringBuff.Head = 0; 
  10.   ringBuff.Tail = 0; 
  11.   ringBuff.Lenght = 0; 

主要是將環(huán)形緩沖區(qū)的頭,尾和長(zhǎng)度清零,表示沒(méi)有任何數(shù)據(jù)存入。

環(huán)形緩沖區(qū)的寫(xiě)入

 
 
 
 
  1. /** 
  2. * @brief  Write_RingBuff 
  3. * @param  uint8_t data 
  4. * @return FLASE:環(huán)形緩沖區(qū)已滿,寫(xiě)入失敗;TRUE:寫(xiě)入成功 
  5. * @note   往環(huán)形緩沖區(qū)寫(xiě)入uint8_t類(lèi)型的數(shù)據(jù) 
  6. */ 
  7. uint8_t Write_RingBuff(uint8_t data) 
  8.   if(ringBuff.Lenght >= RINGBUFF_LEN) //判斷緩沖區(qū)是否已滿 
  9.   { 
  10.     return RINGBUFF_ERR; 
  11.   } 
  12.   ringBuff.Ring_data[ringBuff.Tail]=data; 
  13.   ringBuff.Tail = (ringBuff.Tail+1)%RINGBUFF_LEN;//防止越界非法訪問(wèn) 
  14.   ringBuff.Lenght++; 
  15.   return RINGBUFF_OK; 

這個(gè)接口是寫(xiě)入一個(gè)字節(jié)到環(huán)形緩沖區(qū)。這里注意:大家可以根據(jù)自己的實(shí)際應(yīng)用修改為一次緩沖多個(gè)字節(jié)。并且這個(gè)做了緩沖區(qū)滿時(shí)報(bào)錯(cuò)且防止非法越界的處理,大家可以自行修改為緩沖區(qū)滿時(shí)覆蓋最早的數(shù)據(jù)。

環(huán)形緩沖區(qū)的讀取

 
 
 
 
  1. /** 
  2. * @brief  Read_RingBuff 
  3. * @param  uint8_t *rData,用于保存讀取的數(shù)據(jù) 
  4. * @return FLASE:環(huán)形緩沖區(qū)沒(méi)有數(shù)據(jù),讀取失敗;TRUE:讀取成功 
  5. * @note   從環(huán)形緩沖區(qū)讀取一個(gè)u8類(lèi)型的數(shù)據(jù) 
  6. */ 
  7. uint8_t Read_RingBuff(uint8_t *rData) 
  8.   if(ringBuff.Lenght == 0)//判斷非空 
  9.   { 
  10.     return RINGBUFF_ERR; 
  11.   } 
  12.   *rData = ringBuff.Ring_data[ringBuff.Head];//先進(jìn)先出FIFO,從緩沖區(qū)頭出 
  13.   ringBuff.Head = (ringBuff.Head+1)%RINGBUFF_LEN;//防止越界非法訪問(wèn) 
  14.   ringBuff.Lenght--; 
  15.   return RINGBUFF_OK; 

讀取的話也很簡(jiǎn)單,同樣是讀取一個(gè)字節(jié),大家可以自行修改為讀取多個(gè)字節(jié)。

04驗(yàn)證

光說(shuō)不練假把式,下面我們就來(lái)驗(yàn)證上面的代碼可行性。

串口中斷函數(shù)中緩沖數(shù)據(jù)

 
 
 
 
  1. void USART1_IRQHandler(void) 
  2.   if(USART_GetFlagStatus(USART1, USART_FLAG_RXNE)) 
  3.   { 
  4.     Write_RingBuff(USART_ReceiveData(USART1)); 
  5.     USART_ClearFlag(USART1, USART_FLAG_RXNE); 
  6.   } 

在主循環(huán)中,讀取緩沖區(qū)的數(shù)據(jù),然后發(fā)送出去,因?yàn)槭呛?jiǎn)單的demo,添加了延時(shí)模擬CPU處理其他任務(wù)。

 
 
 
 
  1. while (1) 
  2.   { 
  3.     if(Read_RingBuff(&data))            //從環(huán)形緩沖區(qū)中讀取數(shù)據(jù) 
  4.     { 
  5.       USART_SendData(USART1, data); 
  6.     } 
  7.     SysCtlDelay(1*(SystemCoreClock/3000)); 
  8.   } 

驗(yàn)證,間隔100ms發(fā)送數(shù)據(jù)。

結(jié)果顯示沒(méi)有出現(xiàn)丟包問(wèn)題。如果你的應(yīng)用場(chǎng)景串口通信速率快,數(shù)據(jù)量大或處理速度慢導(dǎo)致丟包,建議增大RINGBUFF_LEN的宏定義,增大緩沖區(qū)間即可。

本文轉(zhuǎn)載自微信公眾號(hào)「 知曉編程」,可以通過(guò)以下二維碼關(guān)注。轉(zhuǎn)載本文請(qǐng)聯(lián)系 知曉編程公眾號(hào)。


本文題目:STM32串口開(kāi)發(fā)之環(huán)形緩沖區(qū)
文章源于:http://www.5511xx.com/article/djipsig.html