1 前言
在我们使用CAN或者以太网调试时,经常需要缓存最近n次收到的数据,以便于我们对数据进行分析。
实现这一想法我们很容易就会想到队列,队列就是一种先进先出的数据结构,之前在《数据结构:基于数组的环形队列(循环队列)实现》介绍了基于数组的环形队列(循环队列)的实现,使用到了头尾2个指针,根据头尾指针的关系其实我们可以只使用尾指针就实现循环队列。
下面介绍一种只使用尾指针实现简单的数据缓存区(简单队列)的方法。
2 简单队列实现
2.1 简单队列的定义
#define MAX_DATA_NO 10 // 数据存储量
#define MAX_DATA_BUFF 10 // 数据缓存区大小
typedef struct
{
int fullFlg; /* 队列满标志 0-未满 1-满*/
int dataTail; /* 队列尾指针 */
int dataTotalCount; /* 总共数据量 */
int dataLen[MAX_DATA_NO]; /* 数据长度 */
int dataBuff[MAX_DATA_NO][MAX_DATA_BUFF]; /* 数据缓存区 */
} s_queue_t;
2.2 初始化简单队列
/**
* @brief 初始化简单队列
*
* @param sQueue 简单队列地址
*/
void init_squeue(s_queue_t *sQueue)
{
sQueue->fullFlg = 0;
sQueue->dataTail = 0;
sQueue->dataTotalCount = 0;
}
初始化简单队列的操作很简单,就是将尾指针、队列满标志、接收数据计数全部清零。
2.3 添加数据到队列
/**
* @brief 添加数据到简单队列
*
* @param sQueue 简单队列地址
* @param dataLen 数据长度
* @param dataBuff 数据缓存区
*/
void add_data_to_squeue(s_queue_t *sQueue, int dataLen, int *dataBuff)
{
int i;
sQueue->dataLen[sQueue->dataTail] = dataLen;
for (i = 0; i < dataLen; i++)
{
sQueue->dataBuff[sQueue->dataTail][i] = dataBuff[i];
}
sQueue->dataTail++;
if (sQueue->dataTail >= MAX_DATA_NO)
{
sQueue->dataTail = 0;
}
sQueue->dataTotalCount++;
if (sQueue->dataTotalCount >= MAX_DATA_NO)
{
sQueue->fullFlg = 1;
}
}
添加数据到队列就是将数据、数据长度写到尾指针指向的数据缓存区,然后将尾指针后移一位(超出缓存区容量时跳转到0)。
2.4 简单队列数据打印
/**
* @brief 打印简单队列数据
*
* @param dataHead 数据头
* @param dataNum 数据数量
* @param sQueue 简单队列地址
*/
void printf_squeue_data(int dataHead, int dataNum, s_queue_t *sQueue)
{
int p;
int i, j, k = 0;
printf("Num Len Data\r\n");
for (i = 0; i < dataNum; i++)
{
p = dataHead + i;
if (p >= MAX_DATA_NO)
{
p -= MAX_DATA_NO;
}
printf("%-3d %-2d ", ++k, sQueue->dataLen[p]);
for (j = 0; j < sQueue->dataLen[p]; j++)
{
printf("%d ", sQueue->dataBuff[p][j]);
}
printf("\r\n");
}
}
/**
* @brief 简单队列数据处理
*
* @param sQueue 队列地址
*/
void squeue_data_pro(s_queue_t *sQueue)
{
int i, j;
int dataHead, dataTail;
printf("Total data count : %d\r\n", sQueue->dataTotalCount);
if (sQueue->fullFlg != 1)
{
printf_squeue_data(0, sQueue->dataTotalCount, sQueue);
}
else
{
dataHead = sQueue->dataTail;
printf_squeue_data(dataHead, MAX_DATA_NO, sQueue);
}
}
简单队列数据打印分为2个部分:
(1)数据解析部分
根据简单队列句柄的队列满标志求得队列头指针值、数据数量。
(2)数据打印部分
根据传入的队列头和数据数量打印队列数据信息。
3 测试
3.1 添加7个数据(队列未满情况)
测试程序如下:
int main(void)
{
int i;
int data[10] = {0, 11, 12, 13, 14, 15, 16, 17, 18, 19};
s_queue_t sQueue;
init_squeue(&sQueue);
for (i = 0; i < 7; i++)
{
data[0]++;
add_data_to_squeue(&sQueue, 10, data);
}
squeue_data_pro(&sQueue);
return 0;
}
向简单队列添加7个数据,首个数据从1-7。打印结果如下:
测试正常。
3.2 添加700个数据(队列满情况)
测试程序如下:
int main(void)
{
int i;
int data[10] = {0, 11, 12, 13, 14, 15, 16, 17, 18, 19};
s_queue_t sQueue;
init_squeue(&sQueue);
for (i = 0; i < 700; i++)
{
data[0]++;
add_data_to_squeue(&sQueue, 10, data);
}
squeue_data_pro(&sQueue);
return 0;
}
向简单队列添加700个数据,首个数据从1-700。打印结果如下:
测试正常。