队列是一种先进先出(FIFO)的线性数据结构,只允许在队尾插入元素,在队头删除元素。对于队列的操作包括:入队,出队,查看队头元素,判断队列是否为空的操作。
基本特性:先进先出的原则,最先进入队列的元素,最先被移除队列。
主要操作:
入队(enqueue):在队列的尾端添加元素。
出队(dequeue):在队列的首端移除元素。
队列的实现方式如下所示:
1:数组实现:
使用固定大小的数组
需要处理循环队列的情况以避免空间浪费
2:链表实现:
使用单向链表,头指针指向队首,尾指针指向队尾
不需要预先分配固定大小
二:代码实现部分:
2.1 队列结构体定义
typedef struct TQelemType //队列每帧数据结构体 { uint8_t uLength; //数据长度 uint8_t buffer[32]; //数据数组 }QelemType; typedef struct Tsquene //队列结构体 { QelemType *base; int front; int rear; }squene;
2.2 队列初始化
/************************************************************************** - 功能描述:队列初始化 - 参数说明:*s 队列句柄 *buf 队列结构体数据地址 - 返回说明:-1 失败 0 成功 **************************************************************************/ int8_t Initquene(squene *s, QelemType *buf) { s->base=buf; if(!s->base) return -1; s->front=0; s->rear=0; return 0; }
2.2 入队列函数如下:
/************************************************************************** - 功能描述:入队列 - 参数说明:*s 队列句柄 *e 要入队列数据的地址 - 返回说明:无 **************************************************************************/ void enquene(squene *s,QelemType *e) { if(((s->rear)+1)%MAXSIZE==s->front) { return ; } memcpy(&(s->base[s->rear]), e, sizeof(QelemType)); s->rear=((s->rear)+1)%MAXSIZE; }
2.3 出队列函数如下所示:
/************************************************************************** - 功能描述:出队列 - 参数说明:*s 队列句柄 *e 出队列数据要写入的地址 - 返回说明:-1 失败 0 成功 **************************************************************************/ int8_t dequene(squene *s,QelemType *e) { if(s->rear==s->front) { return -1; } memcpy(e, &(s->base[s->front]), sizeof(QelemType)); memset(&(s->base[s->front]), 0, sizeof(QelemType)); s->front=((s->front)+1) % MAXSIZE; return 0; }
2.4初始化所使用的队列:
/************************************************************************** - 功能描述:初始化所有应用的队列 - 参数说明:void - 返回说明:void **************************************************************************/ void Queue_Init(void) { Initquene(&QUsart1Tx, QUsart1TxData); }
2.5 这里定义两个发送函数,主要是为了验证队列的输出函数:
void SendMPT01Order(uint8_t order) { QelemType Data = {0}; Data.uLength = 6 ; //需要发送的数据长度 Data.buffer[0] = 0xFE; Data.buffer[1] = 0x04; Data.buffer[2] = 0xA1; Data.buffer[3] = order; Data.buffer[4] = 0x00; // Data.buffer[5] = CalcSum2(5,&Data.buffer[0]); //SUM // SendDataToUART4(6); //发送数据 enquene(&QUsart1Tx,&Data); } void SendMPT01Ctrl(uint8_t TempCtrl,uint8_t AutoCtrl) { QelemType Data = {0}; Data.uLength = 6 ; //需要发送的数据长度 Data.buffer[0] = 0xFE; Data.buffer[1] = 0x04; Data.buffer[2] = 0xA2; Data.buffer[3] = 0x03; Data.buffer[4] = 0x00; enquene(&QUsart1Tx,&Data); }
2.6 重新定义一下串口的发送函数:
void Usart1Txbuffer(void) { QelemType Data = {0},*PreData = NULL; //创建临时一帧队列数据 PreData = &Data; if(dequene(&QUsart1Tx,PreData) != 0) //出队列 return; memcpy(SendBuffer1,PreData->buffer,Data.uLength ); HAL_UART_Transmit(&huart1,SendBuffer1,Data.uLength,100); }
主要实现:当队列种的数据不为空时,将队列的数据拷贝到串口的发送函数里面。
2.7 验证函数:
if(Time6point %100 == 0) { Usart1Txbuffer(); } if(Time6point %200 == 0) { SendMPT01Order(01); } if(Time6point %500 == 0) { } if(Time6point %1000 == 0) { SendMPT01Ctrl (01,02); Time6point = 0 ; // HAL_UART_Transmit(&huart1,OUTPUT_str,sizeof(OUTPUT_str),100); HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_5); }
三:实物图片如下所示:
可见函数验证功能正常,使用队列的方式发送数据,可以保证数据正常发送,不会被其他发送函数打断。