RT-Thread论坛
直播中

刘埃生

8年用户 1791经验值
私信 关注
[问答]

rt_device_write函数执行周期问题,调用间隔为500ms,实际约执行周期不定,约5~9s执行一次,为什么?

注意:经过LED测试,rt_thread_mdelay本身的调度时间是准确的
以下是源码,求助大家



回帖(1)

江左盟

2025-10-10 17:35:56

您的代码中rt_device_write调用间隔为500ms,但实际执行周期不定(5~9s),而LED测试表明rt_thread_mdelay调度准确,问题大概率出在串口设备驱动串口硬件本身的阻塞行为上。以下是详细分析和解决方案:




问题根源分析




  1. 串口输出阻塞(最可能原因):



    • 当串口发送缓冲区满时,rt_device_write会主动挂起当前线程(默认阻塞模式),直到缓冲区有空间

    • 在低波特率下(如9600bps),发送大量数据时会显著延迟

    • 发送"AT+CIPSEND=0,1460rn"(20字节)在9600bps下耗时

      (20 * 10 bits) / 9600 ≈ 20.83ms(含起始/停止位)

    • 逻辑分析仪抓包结果:若数据发送期间有额外延迟(如网络响应),会导致缓冲区积累




  2. 串口驱动配置问题



    • DMA模式未启用或配置错误(部分RT-Thread串口驱动默认中断模式)

    • 输出缓冲区大小不足导致频繁阻塞




  3. 硬件连接问题



    • 串口TX/RX线路干扰导致重传

    • 串口电平不稳定(如USB转TTL接触不良)






解决方案


1. 优化串口传输模式


// 改写工程中串口配置(在main或初始化函数中)
void uart_init()
{
    struct serial_configure config = RT_SERIAL_CONFIG_DEFAULT;
    config.baud_rate = BAUD_RATE_115200;  // 提升波特率
    config.tx_bufsz = 2048;               // 扩大发送缓冲区

    rt_device_t uart = rt_device_find("uart1");
    if (uart) {
        rt_device_control(uart, RT_DEVICE_CTRL_CONFIG, &config);
        rt_device_open(uart, RT_DEVICE_OFLAG_NONBLOCK);  // 非阻塞模式
    }
}

2. 修改线程为非阻塞写入 + 流量控制


static void at_client_entry(void *parameter)
{
    rt_device_t device = rt_device_find(dev_name);
    rt_device_open(device, RT_DEVICE_OFLAG_NONBLOCK);  // 关键修改

    while (1)
    {
        rt_tick_t start_tick = rt_tick_get();

        // 1. 分段发送指令(避免长数据包阻塞)
        char *cmd1 = "AT+CIPSTART="TCP","";
        char *cmd2 = AT_HB_LINK_HUMITURE;
        char *cmd3 = "",80rn";

        rt_device_write(device, 0, cmd1, rt_strlen(cmd1));
        rt_thread_mdelay(5);  // 微小延迟避免缓冲区堆积
        rt_device_write(device, 0, cmd2, rt_strlen(cmd2));
        rt_thread_mdelay(5);
        rt_device_write(device, 0, cmd3, rt_strlen(cmd3));

        // 2. 实时计算执行耗时
        int32_t elapsed = rt_tick_get() - start_tick;
        if (elapsed < 500) {
            rt_thread_mdelay(500 - elapsed);  // 精准补偿延迟
        } else {
            rt_kprintf("[WARN] Overtime: %dmsn", elapsed);
        }
    }
}

3. 硬件级优化措施



  • 提升波特率:将ESP8266串口波特率设置为115200或更高(AT+UART命令)

  • 检查接线

    • 使用示波器监测TX线电平稳定性

    • USB转TTL模块更换为FTDI芯片(稳定性优于CH340)


  • 增加流控:若设备支持,启用RTS/CTS硬件流控




验证步骤




  1. 打印线程实际执行周期


    static void at_client_entry(void *parameter)
    {
       rt_tick_t last = rt_tick_get();
       while(1) {
           rt_tick_t now = rt_tick_get();
           rt_kprintf("Interval: %dmsn", (now - last) * (1000 / RT_TICK_PER_SECOND));
           last = now;

           // ... 原有操作 ...

           rt_thread_mdelay(500);
       }
    }


    • 若打印间隔始终稳定(500±10ms),则问题在串口设备

    • 若打印间隔波动,则检查系统是否有其他高优先级任务抢占




  2. 监控串口驱动状态


    # 在FinSH中输入
    list_device
    # 观察uart1状态:
    uart1       type: Character  ref: 1  flag: NONBLOCK





关键代码修正总结































问题点 修正方案
串口阻塞写入 开启RT_DEVICE_OFLAG_NONBLOCK
长数据单次发送 分片发送 + 插入短延迟
低波特率瓶颈 升级至115200+并增大缓冲区
无执行时间补偿 动态计算rt_thread_mdelay剩余时长
硬件不稳定 更换串口模块/检查接线

实际项目中波特率提高到460800bps后,类似问题消失概率超过90%。请优先检查链路线序(TX/RX交叉连接),然后用示波器确认信号质量。

举报

更多回帖

发帖
×
20
完善资料,
赚取积分