嵌入式中缓冲区队列的实现

2019-07-13 06:56发布

class="markdown_views prism-github-gist"> 在串口,IIC或SPI以及CAN等通信中,往往需要一次性发送一帧完整的数据,由于硬件发送的速度问题,硬件不能及时发送出去,就会导致数据丢失等一系列问题。通常采用建立缓冲区解决。队列可以有效的利用缓冲区空间,并且保证数据在发送和接收过程中的时序问题。现在网上有公开的队列源码,其一般由入队,出队,查询队列成员数量,创建队列,销毁队列等组成,相对比较完善,但是在串口等环境中使用存在过多的调用函数等问题。所以就以上的情况做出了改善,编写了一个精简的缓冲队列,经过测试可以保证数据传输的完整性。

一、创建结构体

结构体主要由 缓冲区,队列头指针,队列尾指针,以及队列发送完成标志位组成。 /******* 数据发送缓冲区 结构体 *****/ typedef struct { u8 TxBuff[BUFFSIZE]; //缓冲区 u16 font; //头指针 u16 rear; //尾指针 u8 finished; //发送完成,0代表未发送完,1代表发送完成,发送终止 }TxBuffer;

二 入队函数

将发送的数据存入缓冲数组,并且移动相应长度的尾指针,检查发送标志位,判断是否需要启动硬件发送。主要有两个函数,一个为单字节发送个,另一个为多字节发送。 /* *函数名:UsartSendData *描述:串口发送数据,发送单字节 *输入:tx:发送接口 *输出:无 *调用:外部调用 */ void UsartSendData(ConnIFName tx,u8 data,USART_TypeDef* u) { TxBuffer* buff = GetTxBuffer(tx); //占用1字节用于判断是否到达缓冲区尾部 if(buff->rear == BUFFSIZE) buff->rear=0; buff->TxBuff[buff->rear++]=data; if(buff->finished == 1) { buff->finished=0; if(buff->font == BUFFSIZE) buff->font=0; USART_SendData(u,buff->TxBuff[buff->font]); buff->TxBuff[buff->font] = 0xFF; buff->font++; } } /* *函数名:MultitySend() *描述:串口发送数据,多字节发送 *输入:tx->发送接口 ;sendData[] 发送的数组;u->调用发送的硬件串口;len->发送的长度 *输出:无 *调用:外部调用 */ void MultitySend(ConnIFName tx,u8 data[],USART_TypeDef* u,u8 len) { u8 i=0; TxBuffer* buff = GetTxBuffer(tx); if(len<BUFFSIZE-buff->rear+buff->font) { for(i=0;iif(buff->rear == BUFFSIZE) buff->rear=0; buff->TxBuff[buff->rear++] = data[i]; } if(buff->finished !=0) { if(buff->font == BUFFSIZE) buff->font=0; USART_SendData(u,buff->TxBuff[buff->font++]); buff->finished =0; } } }

三 出队函数

读取队列中的数据并交由硬件发送,同时移动头指针到相应位置,根据情况操作标志位。这个函数一般由发送中断调用。 /* *函数名:TxBuffIRQ *描述:串口发送 *输入:tx:发送接口 *输出:无 *调用:中断调用 */ void TxBuffIRQ(ConnIFName tx,USART_TypeDef* u) { //取得该通信接口缓冲区指针 TxBuffer* buff = GetTxBuffer(tx); //判断缓冲区为NULL,则发送完成,停止发送 if(buff->font == buff->rear ) { buff->finished=1; //发送完成置位(缓冲区为空) }else { //判断是否到达队列尾部,如果到达则从头开始 /**防止由于时间差的问题导致中断重复发送缓冲区数据*****/ if(buff->font == BUFFSIZE ) buff->font=0; USART_SendData(u,buff->TxBuff[buff->font]); //0xff填充缓冲区 buff->TxBuff[buff->font] = 0xff; buff->font++; } }

四 获取队列函数

当多个队列共存时,需要由该函数传递对应队列的指针,以便操作队列。 /* *函数名:GetTxBuffer *描述:取得发送缓冲区指针 *输入:tx:取得哪个值 *输出:无 *调用:内部调用 */ TxBuffer* GetTxBuffer(ConnIFName tx) { switch (tx) { case DGUSIF: return &DgusTxBuff; case WKIF: return &WKTxBuff; case CK1IF: return &CKTxBuff; default: break; } return 0; }