性无码一区二区三区在线观看,少妇被爽到高潮在线观看,午夜精品一区二区三区,无码中文字幕人妻在线一区二区三区,无码精品国产一区二区三区免费

lihui710884923
認(rèn)證:VIP會(huì)員
所在專題目錄 查看專題
圖解STM32的4輸入 + 2 輸出 + 2 復(fù)用輸出8模式
開源之太陽能智能充電管理系統(tǒng)
嵌入式軟件底層開發(fā)的框架
嵌入式串口通訊處理機(jī)制(附FIFO源碼)
STM32 嵌入式平臺(tái)上的語音識(shí)別系統(tǒng)
STM32F767ZI 之人工智能(AI) 應(yīng)用
作者動(dòng)態(tài) 更多
物聯(lián)網(wǎng)專題之NB-IoT項(xiàng)目框架(二)
2024-07-25 11:53
物聯(lián)網(wǎng)專題之介紹(一)
2024-07-11 18:37
單片機(jī)RTC的中斷剖析
2024-03-09 15:28
串口通訊的來龍去脈
2024-02-14 17:32
stm32單片機(jī)的USB燒錄程序
2023-09-08 22:48

嵌入式串口通訊處理機(jī)制(附FIFO源碼)

    嵌入式串口通訊處理機(jī)制(附FIFO源碼),大家可以下載作為參考

      在嵌入式串口通訊中,串口通訊應(yīng)用幾乎是必須的,非常常用,做好串口的數(shù)據(jù)處理是非常關(guān)鍵的一步,這里再分享一下如何在裸機(jī)中對(duì)串口數(shù)據(jù)的有效處理,

比如一包數(shù)據(jù)0xaa,0x55,0xXX,0xXX,0x0a,0x0d,簡單介紹串口處理的方法

一.直接在接受中斷中判斷數(shù)據(jù)

先定義一個(gè)uint8_t Buff和一個(gè)uint8_t Table[10];

在接收中斷函數(shù)里用HAL_UART_Receive_IT(&UART1_Handler, &Buff, 1)這個(gè)函數(shù),每次在中斷里面都判斷Buff是不是0xaa,如果是則將數(shù)據(jù)存入到Table[0]中且繼續(xù)接收下面的數(shù)據(jù),都存入到Table的數(shù)組中,如果不是則繼續(xù)進(jìn)行判斷。然后對(duì)Table進(jìn)行判斷,首先判斷Table[0]和Table[1]分別為0xaa,0x55后,在進(jìn)行判斷Table[4]和Table[5]分別為0x0a,0x0d。在進(jìn)行判斷校驗(yàn)是否正確,正確后取出Table[2]的數(shù)據(jù)進(jìn)行處理。這種方法在數(shù)據(jù)傳輸慢的情況下,比較簡單方便,還可以,但是在數(shù)據(jù)快的時(shí)候,非常容易造成數(shù)據(jù)的丟失,還有就是要是第一次數(shù)據(jù)接收錯(cuò)誤,回不到初始化狀態(tài),必須復(fù)位操作

二.FIFO方式 超時(shí)接受

接收中斷函數(shù)里用HAL_UART_Receive_IT(&UART1_Handler, &Buff, 1)這個(gè)函數(shù)接收數(shù)據(jù)的時(shí)候不要做數(shù)據(jù)處理,而是忠實(shí)地接收原始字節(jié)流,只管接受入列,就是接受完數(shù)據(jù)0xaa,0x55,0xXX,0xXX,0x0a,0x0d后,超時(shí)時(shí)間RxTimeOut3到以后再對(duì)數(shù)據(jù)處理

/* 數(shù)據(jù)入隊(duì) */chfifo_in(&RxFifo, &Buff);

/* 清零超時(shí) */RxTimeOut3 = 0;

三.DMA+空閑中斷

就是接收到一幀數(shù)據(jù)0xaa,0x55,0xXX,0xXX,0x0a,0x0d后才觸發(fā)中斷接受,處理數(shù)據(jù)非常高效。

下邊具體介紹串口環(huán)形隊(duì)列 FIFO方式

環(huán)形緩沖區(qū)(FIFO)就是一個(gè)帶“頭指針”和“尾指針”的數(shù)組。“頭指針”指向環(huán)形緩沖區(qū)中可讀的數(shù)據(jù),“尾指針”指向環(huán)形緩沖區(qū)中可寫的緩沖空間。通過移動(dòng)“頭指針”和“尾指針”就可以實(shí)現(xiàn)緩沖區(qū)的數(shù)據(jù)讀取和寫入。在通常情況下,應(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)“尾指針”超過數(shù)組大小,則“尾指針”重新指向數(shù)組的首元素,從而形成“環(huán)形緩沖區(qū)”!,有效數(shù)據(jù)區(qū)域在“頭指針”和“尾指針”之間。如下圖所示。

當(dāng)然,環(huán)形緩沖區(qū)的“頭指針”和“尾指針”可以用“頭變量”和“尾變量”來代替,因?yàn)榍袚Q數(shù)組的元素空間,除了可以用“指針偏移法”之外,還可以用“素組下標(biāo)偏移法”。當(dāng)串口接收到新的數(shù)組,則將數(shù)組保存到環(huán)形緩沖區(qū)中,同時(shí)將“尾變量”加一,以保存下一個(gè)數(shù)據(jù);應(yīng)用程序在讀取數(shù)據(jù)時(shí),“頭變量”加一,以讀取下一個(gè)數(shù)據(jù)。

 

“環(huán)形緩沖區(qū)”數(shù)據(jù)接收處理機(jī)制的好處在于:利用了隊(duì)列的特點(diǎn),一頭進(jìn),一頭出,互不影響,在數(shù)據(jù)進(jìn)去(往里存)的時(shí)候,另一邊也可以把數(shù)據(jù)讀出來,而讀出來的數(shù)據(jù),留下的空位,又可以增加多的存儲(chǔ)空間,從而避免一邊接收數(shù)據(jù)且一邊處理數(shù)據(jù)會(huì)在數(shù)據(jù)量密集的時(shí)候而導(dǎo)致的丟掉數(shù)據(jù)或者數(shù)據(jù)產(chǎn)生沖突的問題。

 

  如果僅有一個(gè)線程讀取環(huán)形緩沖區(qū)的數(shù)據(jù),只有一個(gè)串口往環(huán)形緩沖區(qū)寫入數(shù)據(jù),則不需要添加互斥保護(hù)機(jī)制就可以保證數(shù)據(jù)的正確性。

 

  需要注意的是,如果串口每接收x個(gè)字節(jié)的數(shù)據(jù)才處理一次,則環(huán)形緩沖區(qū)的緩沖數(shù)組的大小必須是x的N倍,具體N為多少,需要結(jié)合具體的數(shù)據(jù)接收速率以及處理速率,適當(dāng)調(diào)節(jié)。這就好比喻,水壺永遠(yuǎn)大于水杯,這樣子水壺才能存放很多杯水。

 

如果覺得前文隱晦難懂,那么下面我們來一起討論一下環(huán)形隊(duì)列的具體狀態(tài)以及實(shí)現(xiàn)。下文構(gòu)建的環(huán)形隊(duì)列采用的是“頭變量”“尾變量”來控制隊(duì)列的存儲(chǔ)和讀取。

首先,我們會(huì)構(gòu)造一個(gè)結(jié)構(gòu)體,并定義一個(gè)結(jié)構(gòu)變量。

 

#define MAX_SIZE  12               //緩沖區(qū)大小

 

typedef struct 

{

  unsigned char head;        //緩沖區(qū)頭部位置

  unsigned char tail;         //緩沖區(qū)尾部位置

  unsigned char ringBuf[MAX_SIZE]; //緩沖區(qū)數(shù)組

} ringBuffer_t;

 

ringBuffer_t buffer;                 //定義一個(gè)結(jié)構(gòu)體

 

定義一個(gè)結(jié)構(gòu)頭體則表示新的消息隊(duì)列已經(jīng)創(chuàng)建完成。新建創(chuàng)建的隊(duì)列,頭指針head和尾指針tail都是指向數(shù)組的元素0。如下圖所示,此時(shí)的消息隊(duì)列是“空隊(duì)列”。

當(dāng)如果l加入隊(duì)列,則緩沖隊(duì)列處于滿載狀態(tài),如下圖所示:如果此時(shí),接收到新的數(shù)據(jù)并需要保存,則tail需要?dú)w零,將接收到的數(shù)據(jù)存到數(shù)組的第一個(gè)元素空間,如果尚未讀取緩沖數(shù)組的一個(gè)元素空間的數(shù)據(jù),則此數(shù)據(jù)會(huì)被新接收的數(shù)據(jù)覆蓋。同時(shí)head需要增加1,修改頭節(jié)點(diǎn)偏移位置丟棄早期數(shù)據(jù)。

當(dāng)消息隊(duì)列中的所有數(shù)據(jù)都讀取出來后,此時(shí)環(huán)形隊(duì)列是空的,狀態(tài)如下圖所示。從圖可以總結(jié)得知,如果tail和head相等,則表示緩沖隊(duì)列是空的。

1.3.1 ringBuffer.c

1. 構(gòu)造環(huán)形緩沖區(qū)

/**********************************************************************************************
描述   :      環(huán)形緩沖讀寫
作者   :      Jahol Fan
版本   :      V1.0
修改   :      
完成日期: 
Notice    :本程序只供學(xué)習(xí)使用,未經(jīng)作者許可,不得用于其它任何用途。版權(quán)所有,盜版必究
***********************************************************************************************/
#include "ringbuffer.h"

#define BUFFER_MAX  36               //緩沖區(qū)大小

typedef struct 
{
  unsigned char headPosition;        //緩沖區(qū)頭部位置
  unsigned char tailPositon;         //緩沖區(qū)尾部位置
  unsigned char ringBuf[BUFFER_MAX]; //緩沖區(qū)數(shù)組
} ringBuffer_t;

ringBuffer_t buffer; //定義一個(gè)結(jié)構(gòu)體

首先,需要構(gòu)建一個(gè)結(jié)構(gòu)體ringBuffer_t,如果定義一個(gè)結(jié)構(gòu)體變量buffer,則意味著創(chuàng)建一個(gè)環(huán)形緩沖區(qū)。

2. 往環(huán)形緩沖區(qū)存數(shù)據(jù)

/**
* @brief 寫一個(gè)字節(jié)到環(huán)形緩沖區(qū)
* @param data:待寫入的數(shù)據(jù)
* @return none
*/
void RingBuf_Write(unsigned char data)
{
  buffer.ringBuf[buffer.tailPositon]=data;     //從尾部追加
  if(++buffer.tailPositon>=BUFFER_MAX)         //尾節(jié)點(diǎn)偏移
    buffer.tailPositon=0;                      //大于數(shù)組最大長度 歸零 形成環(huán)形隊(duì)列
  if(buffer.tailPositon == buffer.headPosition)//如果尾部節(jié)點(diǎn)追到頭部節(jié)點(diǎn),則修改頭節(jié)點(diǎn)偏移位置丟棄早期數(shù)據(jù)
    if(++buffer.headPosition>=BUFFER_MAX)
      buffer.headPosition=0;
}

8行:將數(shù)據(jù)存放到tailPosition所指向的元素空間。

9行:tailPosition變量自增1,并且判斷,如果大于最大緩沖,則將tailPosition歸零。

11行:如果tailPositon與headPosition相等,則表示,數(shù)據(jù)存入速度大于數(shù)據(jù)取出速度,從到導(dǎo)致“追尾”。此時(shí)headPosition需要自增1,以丟棄早期數(shù)據(jù),這也就是數(shù)據(jù)“覆蓋現(xiàn)象”,這種現(xiàn)象是不允許存在的,解決這種現(xiàn)象的辦法是將緩沖隊(duì)列的空間再開大點(diǎn)。

13行:如果headPosition也大于最大數(shù)組,則需要將headPosition清零。

3. 讀取環(huán)形緩沖區(qū)的數(shù)據(jù)

/**
* @brief 讀取環(huán)形緩沖區(qū)的一個(gè)字節(jié)的數(shù)據(jù)
* @param *pData:指針,用于保存讀取到的數(shù)據(jù)
* @return 1表示緩沖區(qū)是空的,0表示讀取數(shù)據(jù)成功
*/
u8 RingBuf_Read(unsigned char* pData)
{
  if(buffer.headPosition == buffer.tailPositon)    //如果頭尾接觸表示緩沖區(qū)為空
    {
            return 1;   //返回1,環(huán)形緩沖區(qū)是空的
    }
  else
  {
    *pData=buffer.ringBuf[buffer.headPosition];    //如果緩沖區(qū)非空則取頭節(jié)點(diǎn)值并偏移頭節(jié)點(diǎn)
    if(++buffer.headPosition>=BUFFER_MAX)
      buffer.headPosition=0;
    return 0;     //返回0,表示讀取數(shù)據(jù)成功
  }
}

8行:首先判斷headPosition是否等于tailPositon,如果相等,則表明,此時(shí)緩沖區(qū)是空的。

10行:緩沖區(qū)為空,則直接返回,不執(zhí)行后面的程序

12行:如果緩沖區(qū)不為空,則條件成立并執(zhí)行

14行:讀取headPosition所指向的環(huán)形緩沖隊(duì)列的元素空間的數(shù)據(jù)。

15行:headPosition自增1以讀取下一個(gè)數(shù)據(jù)。如果headPosition大于最大值BUFFER_MAX,則將headPosition歸零。

17行:返回0,表示讀取數(shù)據(jù)成功。

看串口中斷函數(shù) ,數(shù)據(jù)接收成功,則將數(shù)據(jù)存入環(huán)形緩沖隊(duì)列

/**
* @brief 串口1中斷函數(shù)
* @param none
* @return none
*/
void USART1_IRQHandler(void)
{
  if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)  //判斷接收標(biāo)志位是否為1
  {         
        USART_ClearITPendingBit(USART1,USART_IT_RXNE);       //清楚標(biāo)志位
        RingBuf_Write(USART_ReceiveData(USART1));
        //阻塞等待直到傳輸完成
        while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);
    
    }
}

主函數(shù)就是解析數(shù)據(jù)

if(0 == RingBuf_Read(&data))//從環(huán)形緩沖區(qū)中讀取數(shù)據(jù)   

{         

            user code   //讀取接收到的數(shù)據(jù)并回發(fā)數(shù)據(jù)        

}

聲明:本內(nèi)容為作者獨(dú)立觀點(diǎn),不代表電子星球立場。未經(jīng)允許不得轉(zhuǎn)載。授權(quán)事宜與稿件投訴,請(qǐng)聯(lián)系:editor@netbroad.com
本篇所含全部資料,點(diǎn)擊此處留下郵箱我會(huì)發(fā)給你
資料明細(xì):這個(gè)是一個(gè)wifi控制的小車程序,單片機(jī)通過串口和wifi模塊通訊
覺得內(nèi)容不錯(cuò)的朋友,別忘了一鍵三連哦!
贊 10
收藏 13
關(guān)注 210
成為作者 賺取收益
全部留言
0/200
  • sdll825 2023-03-16 14:48
    老師,能不能發(fā)我一下資料,謝謝! sd****@****.com
    回復(fù)
  • 熊紅 2021-10-17 01:23
    老師,能不能發(fā)我一下資料,謝謝! m1****@****.com
    回復(fù) 1條回復(fù)
  • dy-A9JA8Jst 2021-04-08 09:22
    謝謝老師 xg****@****.com
    回復(fù) 1條回復(fù)
  • 小董 2021-03-08 17:51
    對(duì)我很有幫助
    回復(fù)
  • dy-blNlwnWV 2021-02-24 23:11
    圍觀學(xué)習(xí)
    回復(fù)
  • 魚鷹單片機(jī) 2021-01-13 17:54
    老師,能不能發(fā)我一下資料,謝謝! ya****@****.com
    回復(fù) 1條回復(fù)
  • 程序員小哈 2021-01-05 12:19
    老師,能不能發(fā)我一下資料,謝謝! ju****@****.com
    回復(fù) 1條回復(fù)
  • 星球居民-YBPLIKJ1 2020-12-19 09:07
    通用的
    回復(fù)
  • 喂,你好 2020-12-16 12:23
    大開眼界,真是好文
    回復(fù)
  • keyhei66 2020-12-16 06:39
    精彩,很多東西還沒接觸到
    回復(fù)
  • 米修兒 2020-12-11 17:54
    不錯(cuò)
    回復(fù)
  • heiha88 2020-12-09 07:42
    下載看看
    回復(fù)