1.0 为什么要使用环形队列
在代码中使用环形队列进行程序的编写,由于在实际开发过程中,会出现接收数据频率太快快于主流程读取数据的频率,这个时候后面来的数据会覆盖前面一包数据,这个时候可以使用环形队列的方式解决这个问题。
2.0 环形队列的基本概念
队列是一种先进先出,后进后出的数据结构,队列有对头和队尾之分,对头负责出数据,队尾负责 数据的插入。
队列初始化与队列满的操作
使用环形队列的方式实现数据的重复使用
如何判断队列是空的还是满的,当对头指向队尾的时候,也就是对头和队尾同时指向一个数据区间重合的时候表示队列处于空的状态,当队列尾部 + 1,和头部重合的时候也表示队列处于满的状态
3.0 环形队列的实现
环形队列或循环队列是一种特殊的队列数据结构,它使用固定大小的数组实现,通过使用模运算来实现队尾到队首的循环链接。当队列达到数组的末端时,它可以回到数组的开始处继续存储数据,这样可以有效地避免数组空间的浪费。环形队列的两个关键指针是front
(队首)和rear
(队尾),它们分别指向队列的前端和后端。
代码实现:queue.c
#include <stdint.h>
#include "queue.h"
/**
****************************************************************
* @brief 初始化(创建)队列,每个队列须先执行该函数才能使用
* @param queue, 队列变量指针
* @param buffer, 队列缓存区地址
* @param size, 队列缓存区长度
* @return
****************************************************************
*/
void QueueInit(QueueType_t *queue, uint8_t *buffer, uint32_t size)
{
queue->buffer = buffer;
queue->size = size;
queue->head = 0;
queue->tail = 0;
}
/**
****************************************************************
* @brief 压入数据到队列中
* @param queue, 队列变量指针
* @param data, 待压入队列的数据
* @return 压入队列是否成功
****************************************************************
*/
QueueStatus_t QueuePush(QueueType_t *queue, uint8_t data)
{
uint32_t index = (queue->tail + 1) % queue->size;
if (index == queue->head)
{
return QUEUE_OVERLOAD;
}
queue->buffer[queue->tail] = data;
queue->tail = index;
return QUEUE_OK;
}
/**
****************************************************************
* @brief 从队列中弹出数据
* @param queue, 队列变量指针
* @param pdata, 待弹出队列的数据缓存地址
* @return 弹出队列是否成功
****************************************************************
*/
QueueStatus_t QueuePop(QueueType_t *queue, uint8_t *pdata)
{
if(queue->head == queue->tail)
{
return QUEUE_EMPTY;
}
*pdata = queue->buffer[queue->head];
queue->head = (queue->head + 1) % queue->size;
return QUEUE_OK;
}
/**
****************************************************************
* @brief 压入一组数据到队列中
* @param queue, 队列变量指针
* @param pArray, 待压入队列的数组地址
* @param len, 待压入队列的元素个数
* @return 实际压入到队列的元素个数
****************************************************************
*/
uint32_t QueuePushArray(QueueType_t *queue, uint8_t *pArray, uint32_t len)
{
uint32_t i;
for (i = 0; i < len; i++)
{
if(QueuePush(queue, pArray[i]) == QUEUE_OVERLOAD)
{
break;
}
}
return i;
}
/**
****************************************************************
* @brief 从队列中弹出一组数据
* @param queue, 队列变量指针
* @param pArray, 待弹出队列的数据缓存地址
* @param len, 待弹出队列的数据的最大长度
* @return 实际弹出数据的数量
****************************************************************
*/
uint32_t QueuePopArray(QueueType_t *queue, uint8_t *pArray, uint32_t len)
{
uint32_t i;
for(i = 0; i < len; i++)
{
if (QueuePop(queue, &pArray[i]) == QUEUE_EMPTY)
{
break;
}
}
return i;
}
/**
****************************************************************
* @brief 获取队列中数据的个数
* @param queue, 队列变量指针
* @return 队列中数据的个数
****************************************************************
*/
uint32_t QueueCount(QueueType_t *queue)
{
if (queue->head <= queue->tail)
{
return queue->tail - queue->head;
}
return queue->size + queue->tail - queue->head;
}
代码实现queue.h
#ifndef __QUEUE_H_
#define __QUEUE_H_
#include <stdint.h>
#include <stdint.h>
typedef struct
{
uint32_t head; //数组下标,指向队头
uint32_t tail; //数组下标,指向队尾
uint32_t size; //队列缓存长度(初始化时赋值)
uint8_t *buffer; //队列缓存数组(初始化时赋值)
} QueueType_t;
typedef enum
{
QUEUE_OK = 0, //队列正常
QUEUE_ERROR, //队列错误
QUEUE_OVERLOAD, //队列已满
QUEUE_EMPTY //队列已空
} QueueStatus_t;
/**
****************************************************************
* @brief 初始化(创建)队列,每个队列须先执行该函数才能使用
* @param queue, 队列变量指针
* @param buffer, 队列缓存区地址
* @param size, 队列缓存区长度
* @return
****************************************************************
*/
void QueueInit(QueueType_t *queue, uint8_t *buffer, uint32_t size);
/**
****************************************************************
* @brief 压入数据到队列中
* @param queue, 队列变量指针
* @param data, 待压入队列的数据
* @return 压入队列是否成功
****************************************************************
*/
QueueStatus_t QueuePush(QueueType_t *queue, uint8_t data);
/**
****************************************************************
* @brief 从队列中弹出数据
* @param queue, 队列变量指针
* @param pdata, 待弹出队列的数据缓存地址
* @return 弹出队列是否成功
****************************************************************
*/
QueueStatus_t QueuePop(QueueType_t *queue, uint8_t *pdata);
/**
****************************************************************
* @brief 压入一组数据到队列中
* @param queue, 队列变量指针
* @param pArray, 待压入队列的数组地址
* @param len, 待压入队列的元素个数
* @return 实际压入到队列的元素个数
****************************************************************
*/
uint32_t QueuePushArray(QueueType_t *queue, uint8_t *pArray, uint32_t len);
/**
****************************************************************
* @brief 从队列中弹出一组数据
* @param queue, 队列变量指针
* @param pArray, 待弹出队列的数据缓存地址
* @param len, 待弹出队列的数据的最大长度
* @return 实际弹出数据的数量
****************************************************************
*/
uint32_t QueuePopArray(QueueType_t *queue, uint8_t *pArray, uint32_t len);
/**
****************************************************************
* @brief 获取队列中数据的个数
* @param queue, 队列变量指针
* @return 队列中数据的个数
****************************************************************
*/
uint32_t QueueCount(QueueType_t *queue);
#endif
以上是环形队列实现的基础代码,参考郭天祥ARM32教程编写,仅用于学习参考