You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Modbus调用反复返回相同帧问题排查求助

Modbus RTU读取重复值排查(C语言程序)

环境与执行流程

  • 硬件:Kunbus RevPi Connect(树莓派),RS485网络接入6个传感器(含4个Dat3018热电偶数字化传感器)
  • 程序核心流程:
    1. 发送厂商指定的同步命令,触发Dat3018将实时采样值写入内部寄存器
    2. 执行其他业务操作
    3. 通过Modbus RTU读取寄存器存储值到树莓派

异常现象

  • 首次循环运行正常,能获取随传感器变化的实时数值
  • 从第二次循环开始,所有读取请求返回的帧与首次结果完全一致,即便传感器数值已发生变化
  • 重启程序后,首次循环又能正常获取新的数值
  • 用Python脚本执行完全相同的操作,可稳定获取变化的数值,排除硬件、传感器协议命令本身的问题

关键命令与代码片段

同步命令帧(厂商确认有效,重复调用可刷新寄存器值)

[FF][06][00][00][00][0A][1C][13]

读取同步值的函数与从站命令帧

int read_tempature_synced_values(modbus_t *RTU_context, int slave_addr, uint16_t output[]){
    modbus_set_slave(RTU_context, slave_addr);
    // 减去1以抵消库自带的+1偏移
    return modbus_read_registers(RTU_context, _temp_sync_tempatures_start_addr-1, 8, output); 
}

从站#20的读取命令帧:

[14][03][00][16][00][08][A7][0D]

读取逻辑主代码片段

// 读取温度测量值
for (int i = 0; op_args->settings_instance->tempatureSlaveAddr[i] != -1; ++i){
    uint16_t *raw_measures = malloc(8 * sizeof(uint16_t));
    read_tempature_synced_values(op_args->modbus_instance, op_args->settings_instance->tempatureSlaveAddr[i], raw_measures);
    usleep(op_args->settings_instance->delay_ms);
    for (int u = 0; u <= 7; ++u){
        if(valid_sensors[i][u] == FALSE){ // 确认该位置有有效传感器
            measurements[measurements_taken].TYPE = TEMPATURE_MEASUREMENT_TYPE;
            measurements[measurements_taken].bankNumber = i;
            measurements[measurements_taken].sensorNumber = u;
            measurements[measurements_taken].measurementTime = sync_time;
            measurements[measurements_taken].tempatueReading = ((float)raw_measures[u])/10;
            measurements_taken += 1;
        }
    }
    free(raw_measures);
    modbus_flush(op_args->modbus_instance);
}

额外异常表现

程序运行时会随机出现以下打印信息,且错误发生在串口或SQLite数据库连接操作之前:

ERROR Connection timed out: select
ERROR Connection timed out: select

排查方向与建议

  1. 清空libmodbus内部缓冲区:libmodbus可能存在未清空的接收缓存,导致第二次循环读取到旧数据。尝试在每次循环开始(或同步命令发送后)调用modbus_clear_rtu_buffer(RTU_context)强制清空缓冲区。
  2. 确认同步命令执行状态:检查同步命令的发送返回值,确保每次循环的同步命令都成功发送并被传感器接收。若使用自定义帧发送,需校验发送字节数或传感器响应。
  3. 修正延迟时间单位:当前usleep的参数单位是微秒,若配置的delay_ms是毫秒值,实际延迟会不足(比如配置100仅等待100微秒),导致Dat3018未完成寄存器写入就开始读取。需确认参数单位匹配,或改为usleep(op_args->settings_instance->delay_ms * 1000)。
  4. 添加错误处理逻辑:当前代码未处理read_tempature_synced_values的返回值,若某次读取失败,raw_measures可能残留旧内存数据。需添加返回值判断:
    int ret = read_tempature_synced_values(op_args->modbus_instance, slave_addr, raw_measures);
    if (ret == -1) {
        fprintf(stderr, "Slave %d read failed: %s\n", slave_addr, modbus_strerror(errno));
        // 执行重试或跳过逻辑
    }
    
  5. 校验从站地址切换状态:多次切换从站地址后,modbus_set_slave可能未正确更新上下文状态,可在每次设置从站地址后调用modbus_flush,或检查modbus_set_slave的返回值是否为0(成功)。
  6. 对齐串口参数:对比Python脚本使用的串口参数(波特率、奇偶校验、停止位、流控)与C程序是否完全一致,RS485场景通常无需硬件流控,需确认配置匹配。

内容的提问来源于stack exchange,提问作者4DoorToyota

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.19 10:25:22