打印
[应用相关]

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

[复制链接]
734|6
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
概要
本文写自正在做的项目,需要使用串口2处理EasyModBus传输的报文,原本采用中断处理的方式,在屏幕,按键,感应器同时传输下,产生了丢包现象,偶发性的死机问题,所以改用消息队列进行缓存,逐条处理。

整体流程
创建队列
串口中断接收报文,简易判别
添加入队列
解包任务,从队列中取出报文
解包做相应处理
具体实现
创建队列
结构体

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


使用特权

评论回复
沙发
纠结的那些年|  楼主 | 2024-3-31 22:42 | 只看该作者
初始化----主函数调用
struct CommQueue sendQueue,recvQueue;

void QUEUE_init(struct CommQueue *queue)
{
        queue->head = 0;
        queue->tail = 0;
        queue->isEmpty = 1;
}

QUEUE_init(&recvQueue);
QUEUE_init(&sendQueue);

使用特权

评论回复
板凳
纠结的那些年|  楼主 | 2024-3-31 22:42 | 只看该作者
添加到队列

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

使用特权

评论回复
地板
纠结的那些年|  楼主 | 2024-3-31 22:42 | 只看该作者
从队列中取出
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;
}

使用特权

评论回复
5
纠结的那些年|  楼主 | 2024-3-31 22:42 | 只看该作者
中断接收报文-进行判断
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);
                }
        }
}

使用特权

评论回复
6
纠结的那些年|  楼主 | 2024-3-31 22:42 | 只看该作者
队列中取出数据解包 --请根据自己的实际进行修改

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

使用特权

评论回复
7
纠结的那些年|  楼主 | 2024-3-31 22:42 | 只看该作者
小结
使用队列后,解决丢包现象。可靠性得到进一步保证。

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

46

主题

688

帖子

0

粉丝