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。打印结果如下:
测试正常。