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;
		}
	}
}

小结

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

相关推荐
m0_748254092 分钟前
STM32--超声波模块(HC—SR04)(标准库+HAL库)
stm32·单片机·嵌入式硬件
南城花随雪。11 分钟前
单片机:实现FFT快速傅里叶变换算法(附带源码)
单片机·嵌入式硬件·算法
逝灮24 分钟前
【蓝桥杯——物联网设计与开发】基础模块8 - RTC
stm32·单片机·嵌入式硬件·mcu·物联网·蓝桥杯·rtc
LXL_241 小时前
模拟——郑益慧_笔记1_绪论
嵌入式硬件
weixin_452600697 小时前
串行时钟保持芯片D1380/D1381,低功耗工作方式自带秒、分、时、日、日期、月、年的串行时钟保持芯片,每个月多少天以及闰年能自动调节
科技·单片机·嵌入式硬件·时钟·白色家电电源·微机串行时钟
森旺电子10 小时前
51单片机仿真摇号抽奖机源程序 12864液晶显示
单片机·嵌入式硬件·51单片机
不过四级不改名67712 小时前
蓝桥杯嵌入式备赛教程(1、led,2、lcd,3、key)
stm32·嵌入式硬件·蓝桥杯
小A15912 小时前
STM32完全学习——SPI接口的FLASH(DMA模式)
stm32·嵌入式硬件·学习
Rorsion12 小时前
各种电机原理介绍
单片机·嵌入式硬件
善 .15 小时前
单片机的内存是指RAM还是ROM
单片机·嵌入式硬件