1.适用于任何通信方式,主要是定时发送场景,已经线程之间的数据交互,可自定义数据类型,不局限于基本数据类型。
2.接口完善,实用性强,已分享给一部分人使用,反响非常好。
3.关注作者不迷路,更多使用的C实用库待你挖掘。
4.无需移植可直接使用。
/*********************************************************************************
*Copyright(C) -
*FileName: queue.c
*Author: 我不是阿沸
*Version: 6.1.0
*Date: 2023.08.20
*Description: 循环数据队列,用于带操作系统的串口发送与接收,或者线程间数据量很大的通信。
*Others: 使用接口前一定调用初始化接口,这里适配了rt_thread与FreeRTOS数据安全接口,如需要使用可以打开相关
宏定义,其他操作系统数据安全需自行实现
*History:
1.Date:2023/04/03
Author:我不是阿沸
Modification:增加数据安全保护,适配RT-Thread与FreeRTOS
2.Date:2023/05/16
Author:我不是阿沸
Modification:修改相关接口实现方式
3.Date:2023/07/18
Author:我不是阿沸
Modification:增加超时机制
4.Date:2023/08/20
Author:我不是阿沸
Modification:修改原有固定数据类型为自定义数据类型
5.其他修改
**********************************************************************************/
#include <stdio.h>
#include <string.h>
#define FREERTOSLOCK 0
#define RTTHREADLOCK 0
#define QUEUEDELAY(x) ;//SYSTEMDELAY(x)
#if FREERTOSLOCK
typedef struct{
void * queue;
int size;
int number;
StaticSemaphore_t xMutexBuffer;
SemaphoreHandle_t xSemaphore;
int rear; //队尾
int front; //对头
}LzQueue; //队列结构体
#elif RTTHREADLOCK
/**
* @brief 队列管理类
* @param 队列数据缓存首地址.
* @param 队列中元素的大小
* @param 队列中元素的个数
* @param 队列保护信号量
* @param 队列头
* @param 队列尾
*/
typedef struct{
void * queue;
int size;
int number;
struct rt_mutex rt_mutex_t;
int rear; //队尾
int front; //对头
}LzQueue; //队列结构体
#else
typedef struct{
void * queue;
int size;
int number;
int rear; //队尾
int front; //对头
}LzQueue; //队列结构体
#endif
#if FREERTOSLOCK
#define QUEUEDELAY(x) vTaskDelay(x)
#endif
void queueInitiate(LzQueue *Q, void * buffer, int number, int size);
int isFull(LzQueue * Q);
int isEmpty(LzQueue * Q);
int putQueue(LzQueue * Q, void * d);
int putQueueBt(LzQueue * Q, void * d, int outtime);
int getQueue(LzQueue *Q, void * d);
void clearQueue(LzQueue *Q);
int putQueueNoWait(LzQueue * Q, void * d);
/**
* @brief 初始化队列
* @param 队列管理者地址.
* @param 队列数据缓存地址
* @param 队列元素数量
* @param 队列元素大小
* @retval None
*/
void queueInitiate(LzQueue *Q, void * buffer, int number, int size){
#if FREERTOSLOCK
Q->xSemaphore = xSemaphoreCreateMutexStatic(&(Q->xMutexBuffer));
if(Q->xSemaphore == NULL) while(1);
if ( xSemaphoreGive( Q->xSemaphore ) != pdTRUE ) {
/* 如果要释放一个互斥量,必须先有第一次的获取*/
}
xSemaphoreTake(Q->xSemaphore, portMAX_DELAY);
#elif RTTHREADLOCK
if(RT_EOK != rt_mutex_init( &(Q->rt_mutex_t), "linze Q lock", RT_IPC_FLAG_FIFO)){
//while(1);
return;
}
#endif
Q->queue = buffer;
Q->number = number;
Q->size = size;
Q->front = 0; //初始化对头 ,指向队列头部的前一个位置
Q->rear = 0; //初始化队尾 ,指向队列尾部的具体数据
#if FREERTOSLOCK
xSemaphoreGive(Q->xSemaphore );
#elif RTTHREADLOCK
rt_mutex_release(&(Q->rt_mutex_t));
#endif
}
/**
* @brief 判断队列是否为满
* @param 队列管理者地址.
* @retval 队列满返回 1,否则返回 0
*/
int isFull(LzQueue * Q){
#if FREERTOSLOCK
xSemaphoreTake(Q->xSemaphore, portMAX_DELAY);
#elif RTTHREADLOCK
rt_mutex_take(&(Q->rt_mutex_t), RT_WAITING_FOREVER);
#endif
if(((Q->rear+1)%Q->number) == Q->front)
{
#if FREERTOSLOCK
xSemaphoreGive(Q->xSemaphore );
#elif RTTHREADLOCK
rt_mutex_release(&(Q->rt_mutex_t));
#endif
return 1; //队列满返回1
}
#if FREERTOSLOCK
xSemaphoreGive(Q->xSemaphore );
#elif RTTHREADLOCK
rt_mutex_release(&(Q->rt_mutex_t));
#endif
return 0; //队列没满返回0
}
/**
* @brief 判断队列是否空
* @param 队列管理者地址.
* @retval 队列空返回 1,否则返回 0
*/
int isEmpty(LzQueue *Q){
#if FREERTOSLOCK
BaseType_t xReturn = pdPASS;
xSemaphoreTake(Q->xSemaphore, portMAX_DELAY);
#elif RTTHREADLOCK
rt_mutex_take(&(Q->rt_mutex_t), RT_WAITING_FOREVER);
#endif
if(Q->rear == Q->front){
#if FREERTOSLOCK
xSemaphoreGive(Q->xSemaphore );
#elif RTTHREADLOCK
rt_mutex_release(&(Q->rt_mutex_t));
#endif
return 1; //队列空返回1
}
#if FREERTOSLOCK
xSemaphoreGive(Q->xSemaphore );
#elif RTTHREADLOCK
rt_mutex_release(&(Q->rt_mutex_t));
#endif
return 0; //队列空返回1
}
/**
* @brief 添加数据到队列
* @param 队列管理者地址, 需要添加的数据
* @retval 添加成功返回 1,失败返回 0
*/
int putQueue(LzQueue * Q, void * d) {
while( isFull(Q) ) { //判断队列是否满,满了就无法添加数据
QUEUEDELAY(1);
}
#if FREERTOSLOCK
xSemaphoreTake(Q->xSemaphore, portMAX_DELAY);
#elif RTTHREADLOCK
rt_mutex_take(&(Q->rt_mutex_t), RT_WAITING_FOREVER);
#endif
memcpy((unsigned char *)(Q->queue)+(Q->rear*Q->size), d, Q->size);
Q->rear = (Q->rear+1)% (Q->number);
#if FREERTOSLOCK
xSemaphoreGive(Q->xSemaphore );
#elif RTTHREADLOCK
rt_mutex_release(&(Q->rt_mutex_t));
#endif
return 1;
}
/**
* @brief 添加数据到队列,不带等待
* @param 队列管理者地址
* @param 需要添加的数据
* @retval 添加成功返回 1,失败返回 0
*/
int putQueueNoWait(LzQueue * Q, void * d) {
if( isFull(Q) ) { //判断队列是否满,满了就无法添加数据
return 0;
}
#if FREERTOSLOCK
xSemaphoreTake(Q->xSemaphore, portMAX_DELAY);
#elif RTTHREADLOCK
rt_mutex_take(&(Q->rt_mutex_t), RT_WAITING_FOREVER);
#endif
memcpy((unsigned char *)(Q->queue)+(Q->rear*Q->size), d, Q->size);
Q->rear = (Q->rear+1)% (Q->number);
#if FREERTOSLOCK
xSemaphoreGive(Q->xSemaphore );
#elif RTTHREADLOCK
rt_mutex_release(&(Q->rt_mutex_t));
#endif
return 1;
}
/**
* @brief 添加数据到队列,带等待超时机制
* @param 队列管理者地址,
* @param 需要添加的数据
* @param 等待时间
* @retval 成功返回 1,失败返回 0
*/
int putQueueBt(LzQueue * Q, void * d, int outtime) {
while(isFull(Q))
{
outtime--;
QUEUEDELAY(1);
if(outtime < 1) return 0;
}
#if FREERTOSLOCK
xSemaphoreTake(Q->xSemaphore, portMAX_DELAY);
#elif RTTHREADLOCK
rt_mutex_take(&(Q->rt_mutex_t), RT_WAITING_FOREVER);
#endif
memcpy((unsigned char *)(Q->queue)+(Q->rear*Q->size), d, Q->size);
Q->rear = (Q->rear+1)% (Q->number);
#if FREERTOSLOCK
xSemaphoreGive(Q->xSemaphore );
#elif RTTHREADLOCK
rt_mutex_release(&(Q->rt_mutex_t));
#endif
return 1;
}
/**
* @brief 从队列获取数据
* @param 队列管理者地址,
* @param 数据目标存放地址
* @retval 成功返回 1,失败返回 0
*/
int getQueue(LzQueue *Q, void * d){
if(isEmpty(Q)){
return 0;
}
#if FREERTOSLOCK
xSemaphoreTake(Q->xSemaphore, portMAX_DELAY);
#elif RTTHREADLOCK
rt_mutex_take(&(Q->rt_mutex_t), RT_WAITING_FOREVER);
#endif
memcpy(d, (unsigned char *)(Q->queue)+(Q->front*Q->size), Q->size);
Q->front = (Q->front+1)%(Q->number);
#if FREERTOSLOCK
xSemaphoreGive(Q->xSemaphore );
#elif RTTHREADLOCK
rt_mutex_release(&(Q->rt_mutex_t));
#endif
return 1;
}
/**
* @brief 清空队列所有数据
* @param 队列管理者地址
* @retval None
*/
void clearQueue(LzQueue *Q)
{
#if FREERTOSLOCK
xSemaphoreTake(Q->xSemaphore, portMAX_DELAY);
#elif RTTHREADLOCK
rt_mutex_take(&(Q->rt_mutex_t), RT_WAITING_FOREVER);
#endif
Q->front =0;
Q->rear = 0;
#if FREERTOSLOCK
xSemaphoreGive(Q->xSemaphore);
#elif RTTHREADLOCK
rt_mutex_release(&(Q->rt_mutex_t));
#endif
}
/****演示示例****/
typedef struct{
int age;
int high;
double xg;
char name[40];
}test;
typedef struct{
char buffer[20];
int len;
}test1;
LzQueue lz;
test t1[20];
//添加数据到队列,模拟串口发送数据,但不直接调用硬件接口,这样就可以提高效率
//应为串口发送需要一定的时间,有可能会阻碍当前线程的运行,可搭配任务栈使用
//在开一个线程专门获取这个队列的数据进行发送(多个串口一样的),提高了效率以及通信的可靠性
int fun1(void){
test t;
if(!isEmpty(&lz)){
getQueue(&lz, (void*)&t);
printf("name:%s, age:%d...\n", t.name, t.age);
}
}
int fun2(test * t){
if(!isFull(&lz)){
putQueueNoWait(&lz, (void*)t);
}
}
int main(void){
queueInitiate(&lz, (void *)&t1, 20, sizeof(test));
test t2 = {22, 180, 120, "I'm not Ah Fei"};
printf("name:%s, age:%d...\n", t2.name, t2.age);
while(1){
fun2(&t2);
fun1();
}
return 0;
}