一、环形收发队列构建
1、构造环形收发数组及其长度
#define buff_size 10
Unsigned char buff[buff_size];
2、定义环形收发读/写位置
u16 R_Buff;
u16 W_Buff;
3、结构体封装
typedef struct Qbuff
{
u16 write; //写位置
u16 read; //读位置
u8 buff[buff_size]; //环形缓冲收发数组
}CircularBuff;
二、案例
假设环形收发数组长度为8。W/R分贝为实际的读写位置,Size为实际存储的数据的长度。
1、写入4个数据,则Write=4; Read=0; Size=4;
2、读取3个数据,则Write=4; Read=3; Size=4-3=1;
4、写入7个数据,则Write=(4+7)=11; Read=3; Size=1+7=8;
数组会先写后四个数据,写满后,再从头开些写到第3位置,(4+7)%8=3
此时,写数据长度Write-读数据长度Read=11-3=8,环形收发数组满了。
5、读取8个数据,则Write=11; Read=3+8=11; Size=11-11=0
此时,写数据长度Write=读数据长度Read=11,环形收发数组为空。
三、代码
“.h文件”
#define buff_size 500 //环形缓冲队列的容量
typedef struct Qbuff
{
u16 write; //写位置
u16 read; //读位置
u8 buff[buff_size]; //环形缓冲收发数组
}CircularBuff;
“.c文件”
1、首先来实现队列
void init_buff(void) //初始化队列
{
Cbuff.write=0;
Cbuff.read=0;
memset(Cbuff.buff,0,buff_size);
}
u8 write_buff(u8 wdata) //入队
{
if(((Cbuff.write-Cbuff.read)==buff_size)) //如果写位置减去读位置等于队列长度,就说明这个环形队列已经满
{
return 0;
}
Cbuff.buff[Cbuff.write%buff_size]=wdata; //将数据放入环形队列
Cbuff.write=Cbuff.write+1; //环形队列位置+1,如果超过了队列长度则回到队列头
return 1;
}
u8 read_buff(u8 *rdata) //出队
{
if(Cbuff.read==Cbuff.write) //如果写位置和读的位置相等,就说明这个环形队列为空,则从头开始重新存
{
init_buff();
return 0;
}
*rdata=Cbuff.buff[Cbuff.read%buff_size];
Cbuff.read=Cbuff.read+1;
return 1;
}
2、主循环做数据出队与数据包拆分
void move_data(void)
{
int i=0;
u16 size1,size2,size3; //记录三包数据的切分位置
u16 len1,len2,len3; //记录三包数据的长度
u8 CrcBuff1[100],CrcBuff2[100],CrcBuff3[100]; //CRC切分好的数据包
if(ok_flag) //连续10ms没有接收到数据,ok_flag置1
{
ok_flag=Cbuff.write; //将接收到的数据长度赋值给ok_flag
for(i=0;i<ok_flag;i++) //循环读取所有数据
{
if(read_buff(&data)) //缓冲非空,若有3个数据包
{
BuffHandle[i]=data;
}
}
for(i=0;i<ok_flag;i++) //数据包切分,最大三包数据
{
if((BuffHandle[i-2]==0xF0)&&(BuffHandle[i-1]==0x10)) //判断数据头0xF0 0x10
{
size1=i-2; //记录切分位置
len1=BuffHandle[i]; //记录数据包长度
memcpy(CrcBuff1,BuffHandle+size1,len1); //获取切分好的数据包
}
if((BuffHandle[i-2]==0xF0)&&(BuffHandle[i-1]==0x0F)) //判断数据头0xF0 0x0F
{
size2=i-2; //记录切分位置
len2=BuffHandle[i]; //记录数据包长度
memcpy(CrcBuff2,BuffHandle+size2,len2); //获取切分好的数据包
}
if((BuffHandle[i-2]==0xF0)&&(BuffHandle[i-1]==0x0F)) //判断数据头0xF0 0x0F
{
size3=i-2; //记录切分位置
len3=BuffHandle[i]; //记录数据包长度
memcpy(CrcBuff3,BuffHandle+size3,len3); //获取切分好的数据包
}
}
}
}
3、串口接收中断入队
void USART1_IRQHandler(void)
{
if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) //接收中断
{
USART_ClearITPendingBit(USART1,USART_IT_RXNE); //清除标志位
write_buff(USART_ReceiveData(USART1));//读取接收到的数据
}
}