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

Modbus ASCII传感器通信异常:数据间隔不准、采集中断求助

Modbus ASCII传感器数据采集问题修正方案

问题1:数据采集间隔不精确

原因

当前代码在完成一轮数据读写、计算、保存后调用time.sleep(1),但串口通信、数据处理、文件IO等操作本身会消耗额外时间,导致实际间隔大于1秒,累积下来误差会越来越大。

解决方案

采用固定时间点调度:记录每次循环的目标执行时间,计算当前时间与目标时间的差值,只sleep需要的时间,抵消代码执行耗时。


问题2:程序运行数次后停止输出与保存

原因

ser.readline()会一直阻塞,直到接收到换行符。如果传感器未返回数据、返回数据格式异常(无换行)或串口通信中断,程序会永久卡在这一步,表现为停止输出。

解决方案

  1. 给串口设置超时时间,避免无限阻塞;
  2. 增加响应合法性校验,处理空响应或格式错误的情况;
  3. 优化文件操作:循环外打开文件,避免频繁打开/关闭文件的开销与潜在异常。

修正后的代码

import serial
import time
import os

# 创建存储目录
folder_name = time.strftime("%H%M%S%d%m%y")
os.makedirs(folder_name, exist_ok=True)

# 初始化串口,添加超时时间(1秒)
ser = serial.Serial(
    port='COM3',
    baudrate=19200,
    parity=serial.PARITY_EVEN,
    stopbits=serial.STOPBITS_ONE,
    bytesize=serial.EIGHTBITS,
    timeout=1  # 关键:设置串口读取超时
)

# 写入文件表头
file_path = os.path.join(folder_name, "data.txt")
with open(file_path, "w") as file:
    file.write("date_time\telapsed_seconds\tO2_ppm\tO2_percent\n")

start_time = time.time()
next_run_time = start_time  # 初始化下一次运行时间

try:
    # 循环内保持文件打开状态,减少IO操作
    with open(file_path, "a") as file:
        while True:
            # 发送Modbus指令
            ser.write(b':010400000004F7\r\n')
            
            # 读取响应,超时后返回空字符串
            response = ser.readline().decode(errors='ignore').strip()
            
            if not response:
                print("未接收到传感器响应,跳过本次采集")
                # 记录空响应数据
                timestamp = time.strftime("%Y-%m-%d %H:%M:%S")
                elapsed_seconds = time.time() - start_time
                file.write(f"{timestamp}\t{elapsed_seconds:.2f}\tN/A\tN/A\n")
                file.flush()  # 立即写入磁盘,避免数据丢失
            else:
                print(f"响应数据:{response}")
                # 简单校验响应格式长度,可根据实际协议完善
                if len(response) >= 15:
                    try:
                        o2_ppm = float(response[7:15]) / 100.0
                        o2_percent = o2_ppm / 10000
                        print(f"O2_ppm: {o2_ppm:.2f}, O2_percent: {o2_percent:.6f}")
                        
                        # 记录有效数据
                        timestamp = time.strftime("%Y-%m-%d %H:%M:%S")
                        elapsed_seconds = time.time() - start_time
                        file.write(f"{timestamp}\t{elapsed_seconds:.2f}\t{o2_ppm:.2f}\t{o2_percent:.6f}\n")
                        file.flush()
                    except ValueError:
                        print("响应数据格式错误,无法解析为数值")
                        timestamp = time.strftime("%Y-%m-%d %H:%M:%S")
                        elapsed_seconds = time.time() - start_time
                        file.write(f"{timestamp}\t{elapsed_seconds:.2f}\tERROR\tERROR\n")
                        file.flush()
                else:
                    print("响应数据长度不足,格式异常")
                    timestamp = time.strftime("%Y-%m-%d %H:%M:%S")
                    elapsed_seconds = time.time() - start_time
                    file.write(f"{timestamp}\t{elapsed_seconds:.2f}\tERROR\tERROR\n")
                    file.flush()
            
            # 调度下一次执行,保证间隔精确1秒
            next_run_time += 1
            sleep_duration = next_run_time - time.time()
            if sleep_duration > 0:
                time.sleep(sleep_duration)

except KeyboardInterrupt:
    print("用户终止程序")

finally:
    ser.close()
    print("串口已关闭")

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.13 07:27:15