使用串口中断发送数据时好时坏,有时能收到有时为错误数据,但数据长度正确

问题代码分析

uint8_t analogOutChlSet(uint8_t dev,analog_out_ch_e channel,uint16_t val)
{
    uint8_t ret=0;
    uint8_t send_buf[32]={0};
    uint16_t send_len=0;
    
    mb_req_s req={0};
    MSGQUEUE_OBJ_t msg;
    
    req.Id=dev;
    req.Func=0x06;
    req.RW_Reg=channel;
    req.RW_Value[0]=val;
    
    // 生成命令
    ret=mbMasGen(send_buf,&send_len,&req);
    if(ret){
        LOG_ERROR(0,"mbMasGen Param Error:%d",ret);
        return 1;
    }
    
    // 发送命令
    rs485Send(LINK_RS485_UP,send_buf,send_len);
    
    // 等待响应
    if(osMessageQueueGet(gParam.os_msg_com_ext,&msg,NULL,1000)!=osOK){
        LOG_ERROR(0,"mbMasGen no reply");
        return 2;
    }
    
    // 重新打开接收
    uartComExtRecv();
    
    // 判定响应是否正确
    ret=mbMasAth(msg.msg_buf,msg.msg_length,&req);
    if(ret){
        LOG_ERROR(0,"mbMasAth response error:%d",ret);
        return 3;
    }
    
    return 0;
}

该代码生成Modbus请求并验证modbus响应是否正确,问题在于我使用的串口中断发送函数为非阻塞,DMA发送同理,发送函数执行完成后等待消息队列会阻塞线程进而导致上下文切换。

现在来看第四行的变量声明,该变量为局部变量,当上下文切换后该变量对于串口中断外设后不可访问,发送出来的数据实际上是不确定任务的栈内数据。

至于为何问题时断时续是因为受到数据长度影响,数据短(比如几字节)情况下可能还未上下文切换串口外设已经发送完成了,此时数据接收到的肯定没问题

解决方案

使用static修饰变量或者将变量设置为全局变量。

带操作系统下应该使用非阻塞式函数,涉及到发送数据时要注意消息buffer变量的作用域。

文章作者:四文鱼Max

本文链接:https://blog.awolon.fun/archives/stm32-uart-send-abnormal.html

许可协议:CC BY-SA 4.0

标签: none

添加新评论