STM32 消息队列处理串口发送的报文

文章目录

概要

本文写自正在做的项目,需要使用串口2处理EasyModBus传输的报文,原本采用中断处理的方式,在屏幕,按键,感应器同时传输下,产生了丢包现象,偶发性的死机问题,所以改用消息队列进行缓存,逐条处理。

整体流程

  • 创建队列
  • 串口中断接收报文,简易判别
  • 添加入队列
  • 解包任务,从队列中取出报文
  • 解包做相应处理

具体实现

  • 创建队列
    结构体
c 复制代码
#define QUEUE_LENGTH 	20

struct CommData
{
	uint8_t data[50];
	uint8_t length;
};

struct CommQueue
{
	uint8_t head;
	uint8_t tail;
	uint8_t isEmpty;
	struct CommData data[QUEUE_LENGTH];
};

初始化----主函数调用

c 复制代码
struct CommQueue sendQueue,recvQueue;

void QUEUE_init(struct CommQueue *queue)
{
	queue->head = 0;
	queue->tail = 0;
	queue->isEmpty = 1;
}
c 复制代码
QUEUE_init(&recvQueue);
QUEUE_init(&sendQueue);
  • 添加到队列
c 复制代码
uint8_t QUEUE_add(struct CommQueue *queue,struct CommData data)
{
	uint8_t rtl = 1;

	__disable_irq();

	if(queue->isEmpty)
	{
		memcpy(&queue->data[queue->tail],&data,sizeof(data));
		queue->tail ++;
		queue->tail %= QUEUE_LENGTH;
		queue->isEmpty = 0;
	}
	else
	{
		if(queue->tail == queue->head)
		{
			__enable_irq();
			return 0;
		}

		memcpy(&queue->data[queue->tail],&data,sizeof(data));
		queue->tail ++;
		queue->tail %= QUEUE_LENGTH;
	}

	__enable_irq();

	return rtl;
}
  • 从队列中取出
c 复制代码
uint8_t QUEUE_get(struct CommQueue *queue,struct CommData *data)
{
	uint8_t rtl=1;

	__disable_irq();

	if(queue->isEmpty)
	{
		__enable_irq();
		return 0;
	}
	else
	{
		memcpy(data,&queue->data[queue->head],sizeof(struct CommData));
		queue->head ++;
		queue->head %= QUEUE_LENGTH;

		if(queue->head == queue->tail)
		{
			queue->isEmpty = 1;
		}
	}

	__enable_irq();

	return rtl;
}
  • 中断接收报文-进行判断
c 复制代码
void USART2_IRQHandler(void)
{
	struct CommData recvData_U2;
	unsigned char data;
	static uint8_t count = 0;
	static unsigned char check_data ; //记录第一位数据

	data = USART2->DR;
	recvData_U2.data[count] = data;
	count++;
	if(count==1)
	{//报文头
		if(recvData_U2.data[0] != 0x0A && recvData_U2.data[0] != 0x0E)
		{
			count = 0;
			return ;
		}
	}
   //简易校验-确保接收个数
	if(count == 2) 
		check_data = recvData_U2.data[1];
	if(count == check_data) //接受数据位数和记录的一致表示此组数据接收完成
	{
	    //报文尾判断
		if(recvData_U2.data[count-1]!=0x0D)
		{
			count = 0;
			return ;
		}
		else
		{
			recvData_U2.length = count;
			count = 0;
		}
		if((recvData_U2.data[0]==0x0A && recvData_U2.data[2]== 0))
		{//需要及时处理的--直接调用相应函数,不用入队
			StopModeMB();
		}
		else
		{//入队
			QUEUE_add(&recvQueue,recvData_U2);
		}
	}
}
  • 队列中取出数据解包 --请根据自己的实际进行修改
c 复制代码
struct CommData recvData_U2H;
void Usart2_ParameterHandler()
{
	uint8_t i;
	unsigned char check_code=0 ;
	while(QUEUE_get(&recvQueue, &recvData_U2H))
	{
		for(i=0;i<recvData_U2H.length-2;i++)
		{
			check_code += recvData_U2H.data[i];
		}
		switch (recvData_U2H.data[0])
		{
		case 0x0A:
			if( recvData_U2H.data[1] == 0x0A && recvData_U2H.data[recvData_U2H.length-2] == check_code)
			{
				if(recvData_U2H.data[4] == 0x00 && recvData_U2H.data[5] == 0x00 )
				{
					Send_ParameterInit();
				}
				else
					Updata_Parameter();
			}
			break;
		case 0x0E:
			if( recvData_U2H.data[1] == 0x06 && recvData_U2H.data[recvData_U2H.length-2] == check_code)
			{//动作执行
				sysPara.SL = recvData_U2H.data[2];
			}
			break;
		default :
			//  解包失败 --执行响应动作
			HAL_GPIO_WritePin(GPIOC, GPIO_PIN_14,GPIO_PIN_RESET);
			HAL_GPIO_WritePin(GPIOC, GPIO_PIN_15,GPIO_PIN_RESET);
			break;
		}
	}
}

小结

使用队列后,解决丢包现象。可靠性得到进一步保证。

相关推荐
西瓜籽@16 分钟前
STM32——毕设基于单片机的多功能节能窗控制系统
stm32·单片机·课程设计
远翔调光芯片^138287988722 小时前
远翔升压恒流芯片FP7209X与FP7209M什么区别?做以下应用市场摄影补光灯、便携灯、智能家居(调光)市场、太阳能、车灯、洗墙灯、舞台灯必看!
科技·单片机·智能家居·能源
极客小张3 小时前
基于STM32的智能充电桩:集成RTOS、MQTT与SQLite的先进管理系统设计思路
stm32·单片机·嵌入式硬件·mqtt·sqlite·毕业设计·智能充电桩
m0_739312876 小时前
【STM32】项目实战——OV7725/OV2604摄像头颜色识别检测(开源)
stm32·单片机·嵌入式硬件
嵌入式小章6 小时前
基于STM32的实时时钟(RTC)教学
stm32·嵌入式硬件·实时音视频
TeYiToKu7 小时前
笔记整理—linux驱动开发部分(9)framebuffer驱动框架
linux·c语言·arm开发·驱动开发·笔记·嵌入式硬件·arm
基极向上的三极管8 小时前
【AD】3-4 在原理图中放置元件
嵌入式硬件
徐嵌8 小时前
STM32项目---水质水位检测
stm32·单片机·嵌入式硬件
徐嵌8 小时前
STM32项目---畜牧定位器
c语言·stm32·单片机·物联网·iot
lantiandianzi8 小时前
基于单片机的老人生活安全监测系统
单片机·嵌入式硬件·生活