class="markdown_views prism-github-gist">
在串口,IIC或SPI以及CAN等通信中,往往需要一次性发送一帧完整的数据,由于硬件发送的速度问题,硬件不能及时发送出去,就会导致数据丢失等一系列问题。通常采用建立缓冲区解决。队列可以有效的利用缓冲区空间,并且保证数据在发送和接收过程中的时序问题。现在网上有公开的队列源码,其一般由入队,出队,查询队列成员数量,创建队列,销毁队列等组成,相对比较完善,但是在串口等环境中使用存在过多的调用函数等问题。所以就以上的情况做出了改善,编写了一个精简的缓冲队列,经过测试可以保证数据传输的完整性。
一、创建结构体
结构体主要由 缓冲区,队列头指针,队列尾指针,以及队列发送完成标志位组成。
/*******
数据发送缓冲区 结构体
*****/
typedef struct
{
u8 TxBuff[BUFFSIZE];
u16 font;
u16 rear;
u8 finished;
}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;
}
}
}
三 出队函数
读取队列中的数据并交由硬件发送,同时移动头指针到相应位置,根据情况操作标志位。这个函数一般由发送中断调用。
void TxBuffIRQ(ConnIFName tx,USART_TypeDef* u)
{
TxBuffer* buff = GetTxBuffer(tx);
if(buff->font == buff->rear )
{
buff->finished=1;
}else
{
/**防止由于时间差的问题导致中断重复发送缓冲区数据*****/
if(buff->font == BUFFSIZE ) buff->font=0;
USART_SendData(u,buff->TxBuff[buff->font]);
buff->TxBuff[buff->font] = 0xff;
buff->font++;
}
}
四 获取队列函数
当多个队列共存时,需要由该函数传递对应队列的指针,以便操作队列。
TxBuffer* GetTxBuffer(ConnIFName tx)
{
switch (tx)
{
case DGUSIF:
return &DgusTxBuff;
case WKIF:
return &WKTxBuff;
case CK1IF:
return &CKTxBuff;
default:
break;
}
return 0;
}