接手档案库房监控平台改造的时候,我一开始以为就是把旧的Windows服务器换成国产系统的服务器,再把采集程序挪过去。真正做下来才发现,恒温恒湿设备这一块的协议对接才是整个项目里最磨人的一环——RS485总线上挂着的温湿度传感器、除湿机和空调,各自有自己的寄存器表;服务器换成信创环境的ARM架构和国产操作系统之后,原来那套驱动、串口库、编译方式全都得重新验证。这篇文章就把信创服务器对接恒温恒湿设备这条链路拆开讲清楚,从物理总线、协议帧格式,到信创Linux下的串口编程、多设备轮询,再到数据入库和告警联动,最后附上我实测过程中踩过的几个坑和完整的排查思路。搞档案信息化、做系统集成的朋友,或者正在做信创迁移的开发者,应该都能从这里找到能直接落地的参考。
1. 信创适配的隐藏工程量:档案库房监控远不是装个软件那么简单
1.1 档案库房的环境要求,决定了监控系统的存在价值
先得说清楚这件看起来"不起眼"的事。档案库房对温湿度是有硬性要求的,纸张在温度过高或湿度过大的环境里会发霉、变脆、粘连,字迹也可能褪色。按照档案行业的管理规定,库房温度一般控制在14~24摄氏度,相对湿度控制在45%~60%。超出这个范围,纸质档案的寿命会明显缩短。这个监控平台的核心职责就三件事:实时采集温湿度数据、超限告警、联动恒温恒湿设备自动调节。
需求听起来很简单,换成信创环境之后问题就来了。库房里的温湿度传感器是某厂商的RS485变送器,除湿机也是老牌国产设备,它们的调试工具全是Windows桌面程序,Linux下没有任何现成方案。服务器换成了鲲鹏或飞腾的ARM架构,操作系统换成了麒麟或统信,第一步连设备的"驱动"和"串口库"都要重新确认。很多做惯了Windows下Delphi或C#开发的人,初次面对这套组合时,往往卡在"设备就在那,数据就是读不出来"的尴尬境地。
1.2 信创环境的三个层次:CPU架构、操作系统、运行库
信创适配看着只是"换个服务器",其实波及的是三个独立的技术层次。
第一层是CPU架构。鲲鹏920、飞腾S2500是ARM架构,海光、兆芯则兼容x86指令集,龙芯有自主指令集。哪怕是ARM,不同主板的串口控制器、PCIe设备支持情况也有差异。很多闭源工业驱动只有x86版,ARM下根本没有对应版本。
第二层是操作系统。麒麟V10、统信UOS以Linux为基础,设备节点、权限模型、系统服务和Windows完全不一样。比如Windows下串口叫"COM3",Linux下叫/dev/ttyS0或/dev/ttyUSB0,首次接触时会很不习惯。
第三层是运行库和开发工具链。系统可能自带Python3,但pip源默认可能指向公网,在隔离内网里要配置内部源;C/C++编译工具链要重新安装;原来在Windows下编译好的Modbus动态库,在ARM下基本都要重新编译。
最容易被低估的是这一层带来的连锁反应。很多恒温恒湿设备的官方测试程序,是设备厂商早期用Delphi写的Windows程序,Linux下没有任何参考。搭建模拟器也要重新选择能在Linux上运行的软件。我后来直接绕开了这些,用Python的pyserial手写了一套Modbus RTU测试脚本,反而比官方工具更灵活,也更容易集成进正式平台。
2. 恒温恒湿设备的物理链路:RS485与Modbus RTU为什么是绕不开的选择
2.1 设备侧协议盘点:传感器、除湿机、空调各自怎么通信
档案库房里的恒温恒湿设备,按协议类型大致分三类。
第一类是温湿度传感器。通常是一个墙面安装的变送器,内部有温湿度探头,通过RS485总线输出,支持Modbus RTU协议。读寄存器就能拿到温度和湿度值,这是整个监控系统的"感知层"。
第二类是空调、除湿机、加湿机这类调控设备。它们本身不一定直接支持Modbus,但设备厂商一般会提供一个RS485控制板或者外接的Modbus继电器模块,通过写寄存器来控制设备的启停、设定温度、切换模式。
第三类是串口服务器。它本身不是环境设备,而是把RS485信号转换成以太网信号,方便服务器远程访问。在很多现场,库房和控制室距离远,串口服务器几乎是标配。
为什么这些设备清一色选Modbus RTU而不是BACnet、KNX或者其他更"智能"的总线协议?原因很现实:Modbus是公开协议,无授权费,实现简单,设备厂商只要用一个单片机就能支持。BACnet偏楼宇自控,KNX偏智能家居,协议栈复杂,小厂维护成本太高。Modbus RTU配合RS485,只需要一根双绞线,成本低、抗干扰强,在几十米到几百米的库房里足够用。
2.2 RS485总线的几个关键细节
RS485是差分信号,A、B两根线传输。总线上所有设备并联,主机发出请求,对应地址的从机应答。跟TCP/IP的"全双工、点对点"完全不是一个思路。
实际部署时有几个点特别容易被忽略。首先是终端电阻,总线两端要各加一个120欧姆的匹配电阻,否则信号反射会导致通信不稳定。其次是A、B线不要接反——这个错误我见过不少,新来的工程师拿着调试工具怎么都读不到数据,最后发现是传感器端A/B接反了。再次,所有设备的波特率、数据位、停止位、校验位必须一致,比如大家都用9600、8N1,有一个设备设成19200,整条总线都会异常。
2.3 Modbus RTU数据帧与寄存器模型
Modbus RTU一个标准请求帧长这样:
| 字段 | 长度 | 说明 |
|---|---|---|
| 地址码 | 1字节 | 从机地址,常用1~247,0x00为广播地址 |
| 功能码 | 1字节 | 0x03读保持寄存器,0x04读输入寄存器,0x06写单寄存器,0x10写多寄存器 |
| 数据区 | N字节 | 寄存器起始地址和数量,或写入的具体数据 |
| CRC校验 | 2字节 | CRC-16/Modbus算法,低字节在前 |
温湿度传感器里,保持寄存器的地址和含义由厂商自定义,但一般有固定约定。比如很多国产变送器的数据手册里会写:保持寄存器0x0001存放温度值,单位0.1℃;0x0002存放湿度值,单位0.1%RH。读的时候,一条0x03功能码的请求就能把两个寄存器一起读回来。
这里要特别提醒:寄存器地址、数据长度、单位缩放因子,每一家设备厂都可能不一样。拿到新设备,第一件事就是拿官方说明书核对寄存器表,千万别想当然。这是后面所有代码能跑通的前提。
3. 信创Linux下的串口通信实战:从设备节点到完整数据帧
3.1 确认串口设备节点与权限
在麒麟V10或统信UOS上,第一步是找到串口设备节点。主板原生串口一般是/dev/ttyS0,ARM平台也有可能是/dev/ttyAMA0,USB转串口一般是/dev/ttyUSB0。用dmesg命令能直接看到内核识别串口的信息:
dmesg | grep -i tty如果服务器是ARM架构,某些主板的串口控制器驱动可能没有自动加载,dmesg里看不到串口信息。这时候要检查内核模块,或者看BIOS里串口是否被禁用。原生串口在服务器上常常默认关闭,需要在BIOS里打开。
权限问题也很关键。普通用户默认没有权限访问/dev/ttyS0或/dev/ttyUSB0,临时用可以sudo,长期采集服务最好把运行用户加入dialout组:
sudo usermod -aG dialout $(whoami)然后重新登录终端,组权限才生效。
3.2 在信创操作系统上安装Python与pyserial
麒麟V10和统信UOS通常都自带Python3。pyserial是纯Python库,在ARM架构上不需要编译,安装非常省心:
pip3 install pyserial -i <内部镜像源>如果部署环境是完全隔离的内网,也可以直接拷贝pyserial源码目录到项目的site-packages里,纯Python库就是有这个好处。pyserial还自带了一个串口调试工具miniterm,命令是python3 -m serial.tools.miniterm,在信创环境下调试串口特别好用,相当于Windows下的串口助手。
3.3 完整的Modbus RTU读温湿度示例
下面这段代码是我在信创服务器上实际用过的读取逻辑,做了精简但保留核心处理。以读传感器保持寄存器0x0001开始、连续读2个寄存器为例:
import serial import time def crc16(data: bytes) -> int: crc = 0xFFFF for byte in data: crc ^= byte for _ in range(8): if crc & 1: crc = (crc >> 1) ^ 0xA001 else: crc >>= 1 return crc def build_read_request(slave_addr: int, start_reg: int, reg_count: int) -> bytes: frame = bytes([ slave_addr, 0x03, (start_reg >> 8) & 0xFF, start_reg & 0xFF, (reg_count >> 8) & 0xFF, reg_count & 0xFF ]) crc = crc16(frame) return frame + bytes([crc & 0xFF, (crc >> 8) & 0xFF]) def read_temperature_humidity(ser: serial.Serial, slave_addr: int, start_reg: int = 1): req = build_read_request(slave_addr, start_reg, 2) ser.write(req) time.sleep(0.05) # 等待设备应答,考虑RS485半双工切换时间 # 预期响应: 地址 + 功能码 + 字节数 + 4字节数据 + 2字节CRC = 9字节 resp = ser.read(9) if len(resp) < 9: return None crc_received = resp[-2] | (resp[-1] << 8) crc_calc = crc16(resp[:-2]) if crc_received != crc_calc: return None if resp[0] != slave_addr or resp[1] != 0x03: return None data = resp[3:7] temp_raw = int.from_bytes(data[0:2], byteorder='big', signed=True) humi_raw = int.from_bytes(data[2:4], byteorder='big') return temp_raw / 10.0, humi_raw / 10.0使用方式:
ser = serial.Serial('/dev/ttyUSB0', baudrate=9600, bytesize=8, parity='N', stopbits=1, timeout=0.3) temp, humi = read_temperature_humidity(ser, slave_addr=1) print(f"温度: {temp} ℃, 湿度: {humi} %RH")3.4 几个必须注意的参数细节
初学容易踩一个坑:串口的timeout参数。timeout=0.3表示每个读操作最多等0.3秒。写完后必须sleep一小段时间再读,这不是Python的毛病,而是RS485半双工的本质——设备从接收完请求到切换成发送状态,需要几十毫秒的时间,专业术语叫TURNAROUND TIME。如果你写完请求立刻串口读,大概率读到空。
还有数据字节序。绝大多数Modbus寄存器是大端传输,也就是高字节在前。但有些设备的数据在51单片机里存成小端,返回的数据是低字节在前。判断办法很简单:读回来的温度原始值如果是不合理的几千、几万,多半就是字节序反了,交换一下两个字节再算。
4. 多设备轮询与数据稳定性:掉线、错帧、半包问题怎么处理
4.1 串口收发流程的规划
瞬间明白,用承载的Textley
理想设置是:send超时0.1秒,TURNAROUND等待0.05秒,读取整体超时0.2秒。如果挂载设备较多,适当把读取超时放宽到0.3秒。正常的传感器响应时间在20~100毫秒之间,0.3秒超时已经足够,又不会让异常设备拖垮整条总线。
调试时用miniterm工具直接看原始字节流特别直观。如果发一条读请求后什么字节都没收到,先检查接线和地址;如果收到乱码,大概率是波特率、数据位配置不一致;如果收到一帧但长度不对,要么是设备响应异常,要么是读取超时导致数据被截断。
4.2 错帧与半包的接收处理
RS485在现场长距离布线时,即使有屏蔽层,也难免受到电机、变频器等设备的电磁干扰,造成数据位翻转、帧错误。我处理接收数据时从来不止判断"收到就行",而是做四层校验:
- 帧长校验:根据功能码和返回数据长度,判断是否收到完整帧;
- 从机地址校验:响应的地址码必须等于请求的目标地址;
- 功能码校验:响应功能码必须等于请求功能码;
- CRC校验:对整个数据区重新计算CRC,和收到的CRC逐字节比较。
如果CRC错误,这一帧直接丢弃,不用解析。连续丢帧才需要排查链路质量。
4.3 掉线重连与设备状态管理
设备长期运行在库房环境里,偶尔会出现无响应。我遇到最多的是两个原因:一是传感器的RS485端子松了,二是设备内部看门狗把Modbus从机功能卡死。处理办法是设置重试机制,连续3次无响应的设备标记为"离线",并停止向它发送查询;等到后续轮询中某一次恢复响应,又自动把状态改回"在线"。这个状态管理逻辑,比协议解析本身更影响平台的实际口碑——档案管理员每天看到满屏"离线告警"会很崩溃。
实际代码里,我会用一个简单字典维护每个设备的状态:
device_status = {} def poll_device(addr): result = read_temperature_humidity(ser, addr) if result is None: device_status.setdefault(addr, 0) device_status[addr] += 1 if device_status[addr] >= 3: return "offline" return "unstable" device_status[addr] = 0 return "online"4.4 稳定性验证的经验做法
平台上线前,我习惯在信创服务器上连读48小时,统计总请求数、无响次数、CRC错误数。正常情况下,好的RS485链路48小时错误率应该在万分之几以下。如果错误率明显偏高,优先检查总线两端终端电阻、屏蔽层接地、以及布线有没有跟强电走同一个线管。
另外一个实操小技巧:轮询脚本里故意关掉设备电源再恢复,看平台能否在10秒内自动识别并恢复采集。这个测试比跑48小时更能暴露状态管理逻辑的问题。
5. 从串口到网络:Modbus TCP网关与并行采集方案
5.1 为什么我在信创项目里更推荐串口服务器
ARM架构的信创服务器在串口支持上不完全稳定,有些板载串口的控制芯片在国产操作系统上的驱动有兼容问题。为了规避这一层不确定性,我在多数档案库房项目里直接用串口服务器。它一端接RS485总线,另一端走以太网,服务器通过网络访问设备数据。
这么做还有一个实际好处。库房里的RS485总线通常从各个传感器汇聚到某个位置,服务器却往往放在统一的机房里,距离可能有几十米甚至上百米。RS485虽然能长距离传,但走线经过强电井、桥架,干扰概率大增。串口服务器就地部署,传感器汇聚到它那里,再用网线或光纤传到机房,链路质量明显更稳。
5.2 串口服务器的工作模式
串口服务器常见的工作模式是"Modbus RTU转Modbus TCP"。设备侧它是RS485主机,网络侧它是TCP Server,默认监听502端口(和标准Modbus TCP一致)。它内部会自动完成协议转换:客户端用Modbus TCP协议连接它,它把请求拆包后转成RTU发给传感器,收到响应再返回给客户端。
配置项里最关键的是波特率。串口服务器要把波特率设置成和现场设备一致,比如9600。有些串口服务器支持"同步波特率"功能,可以自动识别总线上的波特率,但不是所有品牌都可靠,最好是手动固定。
5.3 Modbus TCP采集代码框架
用Python套接字直接实现Modbus TCP很轻量。TCP协议比RTU少了CRC校验,多了报文头:
import socket import struct def build_tcp_request(transaction_id, protocol_id=0, unit_id=1, start_reg=1, count=2): length = 6 # 单元标识1字节 + 功能码1字节 + 数据4字节 header = struct.pack('>HHHB', transaction_id, protocol_id, length, unit_id) body = struct.pack('>BHH', 0x03, start_reg, count) return header + body def read_tcp(sock, unit_id=1, start_reg=1): req = build_tcp_request(1, unit_id=unit_id, start_reg=start_reg) sock.sendall(req) resp = recv_all(sock, 9) return parse_registers(resp)注意TCP方式下,多个设备通过unit_id(即从机地址)区分,这条TCP连接上的所有请求共享一个连接。一次读一个设备的话,串口服务器的内部总线轮询由它自己做好,效率高不少。
5.4 多路并行采集的取舍
如果库房点位多、设备类型杂,可以在不同区域分别部署串口服务器,每台服务器对应一段RS485总线。采集服务用多线程或asyncio分别连接,并行采集互不干扰。这样即使某一路总线故障,其他点位的采集不受影响。
反过来,单串口服务器挂太多设备时要控制轮询周期。每个设备响应100毫秒,挂20个设备一轮就是2秒。这个数据更新频率对档案库房来说完全够用,但如果平台要求秒级刷新,就要考虑分路或者提高波特率了。我一般控制在每条RS485总线上挂不超过15个设备,保证单轮轮询在1.5秒内完成。
6. 监控平台的数据闭环:入库、告警规则与设备联动控制
6.1 数据存储设计:从SQLite到集中式数据库的演进
档案库房监控数据的写入频率很高。一个点位5秒一条记录,10个点位一天就有约17万条记录。如果按1分钟一条记录来存,一天2.8万条,一个月约86万条。这个量级对SQLite就有点吃力了,尤其做历史趋势查询时会明显变慢。
我一般分两级存储。边缘采集端(一台信创工控机或服务器)用SQLite做短期缓存,只保留最近7~30天数据;集中管理平台用达梦、人大金仓这类集中式数据库,接收各库房上报数据做长期归档和报表分析。这样既保证了边缘自治,又避免单点数据库被高频写入拖垮。
表结构可以设计得简单直接:
CREATE TABLE env_record ( id INTEGER PRIMARY KEY, device_addr INTEGER NOT NULL, temperature REAL NOT NULL, humidity REAL NOT NULL, record_time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ); CREATE INDEX idx_device_time ON env_record(device_addr, record_time);索引建在设备地址和时间上,查某个设备某段时间的趋势曲线时走索引,速度会快很多。
6.2 告警规则的工程化实现
告警逻辑看着简单——超限就报——但实际工程里要处理几个细节:
- 告警阈值要可配置,不能写死在代码里。档案库房有基本要求,但不同库房保存的档案材质不同,局部区域可以微调。温度上限、下限,湿度上限、下限,分别放在配置表里,管理员能在页面上改。
- 要设置"持续多长时间才告警",防止偶发噪声误报。比如温度连续5分钟超限才触发告警,15分钟内同一个告警不重复推送,这就叫告警抑制。否则校验一下这个逻辑:0点温度轻微超限,管理员睡一觉起来收到了上百条短信,体验极差。
- 告警恢复要记录清楚。什么时候开始告警、什么时候恢复、持续了多久,这些信息对事后分析库房设备运行问题很有价值。
我做过的一个简化版规则引擎核心逻辑可以抽象成这样:
def check_alarm(device, temperature, humidity): rules = get_rules(device) now = datetime.now() if temperature > rules.temp_high: if device.alarm_since is None: device.alarm_since = now if (now - device.alarm_since).seconds >= rules.delay_seconds: trigger_alarm(device, "temperature_high", temperature) else: if device.alarm_since is not None: clear_alarm(device, now) device.alarm_since = None6.3 从采集到控制的联动逻辑
监控平台不只是"看",还要"控"。湿度超过60%时自动启动除湿机,湿度低于40%时启动加湿,温度超过24度时联动空调制冷。这些操作本质上是向设备写寄存器。
写单寄存器用Modbus功能码0x06,写多寄存器用0x10。以除湿机控制板为例,手册上可能写着"保持寄存器0x0000为开关控制,写1启动,写0停止;0x0001为湿度设定值,单位0.1%RH"。代码逻辑并不复杂:
def write_register(ser, slave_addr, reg_addr, value): frame = bytes([slave_addr, 0x06, (reg_addr >> 8) & 0xFF, reg_addr & 0xFF, (value >> 8) & 0xFF, value & 0xFF]) crc = crc16(frame) frame += bytes([crc & 0xFF, (crc >> 8) & 0xFF]) ser.write(frame)但控制逻辑必须加保护。我强烈建议平台里设计"手动/自动"切换开关。维护人员在现场检修时切到手动,平台就不能自动启停设备,防止库里没人时除湿机突然启动造成安全问题。另外每次下发控制指令后要回读寄存器确认写入成功,别发了指令就当已控制到位——有些设备写寄存器成功,但执行机构卡住了,这种问题只能靠回读+状态反馈发现。
6.4 Web展示层与国产浏览器兼容
展示层我用轻量级HTTP服务提供JSON接口,前端页面按主题实时刷新。数据推送用SSE(Server-Sent Events)就够了,档案库房点位不多,没必要上WebSocket。SSE在HTTP协议之上,兼容性好,信创环境下常见的国产浏览器基本都能支持。
页面布局简单清晰:大屏展示当前温湿度,列表显示各设备在线状态,趋势图支持按小时、按天、按月查看。还有告警记录页面按时间倒序排列,处理状态标记未处理/已处理。这套东西不追求炫酷,稳定性优先——档案管理员用起来顺手,比花哨的图表实在得多。
7. 实测排错链路:信创服务器对接恒温恒湿设备最常见的四个坑
7.1 坑一:设备地址和波特率跟现场不一致
设备说明书上写默认地址是1,但现场传感器可能被前一家集成商改成了2、3或者更奇怪的地址。如果你按1去读,什么都读不到。我当时做测试时写过一个小函数,把1~247的地址全部轮询一遍,读温湿度寄存器,谁有响应就说明它在线,地址是多少、波特率多少,一次扫出来。
这个方法虽然基础,但真到了现场是最有效的。比对着说明书在那里猜快得多。现场工人跟我说"这设备从来没人改过",最后扫出来地址是7——之前接过的厂家调试人员自己改的。
7.2 坑二:RS485半双工的TURNAROUND时间
设备对请求的响应需要时间,这个时间因设备而异。有的设备80毫秒,有的要120毫秒。我之前调试一家除湿机,按照经验sleep 50毫秒后读取,结果时不时返回超时。后来把sleep拉长到120毫秒,问题彻底消失。
这类问题最容易被人误判成"线有问题"或者"设备不稳定"。排查方法就是逐步增大等待时间,看丢包率的变化。如果增大到200毫秒后还是丢包,才需要去查物理链路。
7.3 坑三:寄存器字节序和缩放系数搞错
某品牌传感器的温湿度寄存器,读回来温度原始值是421,我一除以10得到42.1℃,而现场温度明明只有21℃。后来才发现它的温度寄存器不是放大10倍,而是直接把真实温度做了偏移,需要减21才是真实值。有的传感器则把温度放大100倍,读4210才对应42.10℃——这些都是设备手册里写得清清楚楚、但容易被忽略的细节。
我的经验是:现场拿一个标准温湿度计做对照,读回来原始值之后,先不做任何转换,对比原始值和标准值的对应关系,把倍数、偏移量、字节序都推出来,再写解析函数。这样比只看手册可靠,因为手册可能对不上实际固件版本。
7.4 坑四:ARM主板的串口驱动兼容问题
有台信创服务器是ARM架构,板载串口在麒麟系统下dmesg能看到设备节点,但一打开就报错,或者打开正常但收发都超时。试了各种参数调整都没有,最后确认是内核驱动对该型号串口控制器的支持不完善。
解决方案就是绕开本地串口,加一台串口服务器走网络。这也印证了前面说的:在信创环境下,串口服务器不只是个可选配件,有时候是必要方案。服务器和采集端只用TCP通信,跟本地驱动完全解耦,受主机兼容性的影响就小多了。后来我把这种模式定为默认方案,只有点位特别少、设备就在服务器旁边时才直接用本地串口。
7.5 一次现场故障的完整复盘
最后分享一次印象深刻的排查过程。某个库房上线后运行了大概一周,管理员反馈湿度数据每隔几分钟就跳成0,过一会儿又自己恢复。从现象看像偶发通信中断。
我的排查链路按顺序走:
- 先看采集程序日志,发现跳0之前有一条CRC校验失败的记录,紧接着下一次轮询超时,然后第三次轮询又恢复正常。
- 单条CRC错误可能是偶发干扰,但隔几分钟就出现一次,说明干扰源持续存在。
- 去现场用万用表量RS485的A/B线静态电压,正常应稳定在2V以上,实际指针时不时抖动。
- 顺线检查,发现中间有一段线跟库房的空调供电线管走在一起,间距不足10厘米。空调压缩机启动瞬间,电磁干扰直接打在RS485线上。
- 处理方案:把RS485线跟强电线管拉开距离,给传感器侧的屏蔽层增加可靠接地,还在总线上补了一个原本缺失的120欧姆终端电阻。
- 重新跑48小时,CRC错误记录从原来每半小时一两次降到零。
这个案例让我深刻的点在于:协议、软件、服务器环境都正常的时候,物理链路往往是最后一块绊脚石。信创项目调试中,不要一有问题就怀疑国产化平台不稳,先回到物理层,用万用表和逻辑分析仪说话,比反复改代码参数靠谱得多。
这个项目做下来,我最深的体会是:恒温恒湿设备的协议对接本身并不难,难的是整个链路的系统思维。信创服务器、设备厂商、RS485线路、现场电磁环境,任何一环出问题,都会让简单的Modbus RTU变得不简单。调试的时候,先把链路模型在脑子里理清楚,再按现象一层层排除,远比对着日志乱猜有效。如果你正在做类似的档案监控或信创迁移项目,建议先做一次现场设备摸底,把每台设备的地址、波特率、寄存器空间、响应时间都记录下来,再开始写平台代码——这份清单,比任何高深的架构设计都值钱。