四、队列算法讲解
1、队列的作用
队列简单来说就是开辟一个数组(内存空间),然后有一个队列头指针pHead和一个队列尾指针pTail。
为什么一个数组存储要搞这么复杂?目的是为了设定一个数据存储和读取规则,数据在这个数组里面遵循先进先出的规则,不能插队。
这样最大的好处就是,数据不会丢失。
比如说我们做串口通讯的时候,通常是一帧数据过来,然后在串口中断里面接收数据,同时while(1)循环里解析和处理数据。
这种方式可能会出现一个问题,就是while(1)循环里面的串口哦数据还没解析完,又有一帧新的数据传过来,那老的数据就会被覆盖掉(这就是“插队”),这个时候队列就发挥作用了。
串口中断直接把接受字节数据都丢进队列里,while(1)不断从队列里取数据,只要队列够大,基本不存在丢包和插队的问题。
2、队列算法代码
1、队列数据结构。
/* 队列结构体定义,定义不同大小的队列 */
typedef struct
{
unsigned char *Head; // 头指针,指向队列头地址
unsigned char *Tail; // 尾指针,指向队列尾地址
unsigned char Buff[4+1]; // 队列数组的内存
}Queue4;
2、清空队列函数
/********************************************************************************************************
* @函数名 S_QueueEmpty
* @描述 清空一个队列
* @参数 Head-队列头地址, Tail-队列尾地址, HBuff-队列缓存
* @返回值 无
* @注意 无
********************************************************************************************************/
void S_QueueEmpty(unsigned char **Head, unsigned char **Tail, unsigned char *HBuff)
{
*Head = HBuff;
*Tail = HBuff;
}
3、入列函数
/********************************************************************************************************
* @函数名 S_QueueDataIn
* @描述 输入一个字节数据进队列
* @参数 Head-队列头地址, Tail-队列尾地址, HBuff-队列缓存
* @返回值 无
* @注意 无
********************************************************************************************************/
void S_QueueDataIn(unsigned char **Head, unsigned char **Tail, unsigned char *HBuff, unsigned short Len, unsigned char *HData, unsigned short DataLen)
{
unsigned short num;
unsigned char IptStatus;
if(CPUInterruptCtrlCBS != 0)
{
CPUInterruptCtrlCBS(CPU_ENTER_CRITICAL,&IptStatus);
}
for(num = 0; num < DataLen; num++, HData++)
{
**Tail = *HData;
(*Tail)++;
if(*Tail == HBuff+Len)
*Tail = HBuff;
if(*Tail == *Head)
{
if(++(*Head) == HBuff+Len)
*Head = HBuff;
}
}
if(CPUInterruptCtrlCBS != 0)
{
CPUInterruptCtrlCBS(CPU_EXIT_CRITICAL,&IptStatus);
}
}
4、出列函数
/********************************************************************************************************
* @函数名 S_QueueDataOut
* @描述 从队列里取出一个数据
* @参数 Head-队列头地址, Tail-队列尾地址, HBuff-队列缓存
* @返回值 取出的数据
* @注意 无
********************************************************************************************************/
unsigned char S_QueueDataOut(unsigned char **Head, unsigned char **Tail, unsigned char *HBuff, unsigned short Len, unsigned char *Data)
{
unsigned char back = 0;
unsigned char IptStatus;
if(CPUInterruptCtrlCBS != 0)
{
CPUInterruptCtrlCBS(CPU_ENTER_CRITICAL,&IptStatus);
}
*Data = 0;
if(*Tail != *Head)
{
*Data = **Head;
back = 1;
if(++(*Head) == HBuff+Len)
*Head = HBuff;
}
if(CPUInterruptCtrlCBS != 0)
{
CPUInterruptCtrlCBS(CPU_EXIT_CRITICAL,&IptStatus);
}
return back;
}
5、获取队列里数据个数函数
/********************************************************************************************************
* @函数名 S_QueueDataLen
* @描述 判断队列里数据的长度
* @参数 Head-队列头地址, Tail-队列尾地址, HBuff-队列缓存
* @返回值 队列里有数据个数
* @注意 无
********************************************************************************************************/
unsigned short S_QueueDataLen(unsigned char **Head, unsigned char **Tail, unsigned short Len)
{
if(*Tail > *Head)
return *Tail-*Head;
if(*Tail < *Head)
return *Tail+Len-*Head;
return 0;
}
6、用法展示
Queue8 TestSend; // 开辟一个八个字节的队列
void hal_LedInit(void)
{
unsigned char dat;
hal_ledConfig();
QueueEmpty(TestSend); // 清空队列
dat = 1;
QueueDataIn(TestSend,&dat,1);
dat = 2;
QueueDataIn(TestSend,&dat,1);
dat = 3;
QueueDataIn(TestSend,&dat,1);
}
void hal_LedProc(void)
{
unsigned char dat;
static unsigned short i = 0;
i++;
if(i > 100)
{
i=0;
hal_LedTurn();
}
QueueDataOut(TestSend,&dat);
QueueDataOut(TestSend,&dat);
QueueDataOut(TestSend,&dat);
}
7、在线仿真测试代码
在出列函数那里设置断点,查看dat的值的变化
?
?内核代码链接:
链接:https://pan.baidu.com/s/18UnOCch5dZd4ZJq3V8yGgA? 提取码:8zrs
|