2. 医疗设备数据采集接口与协议
医疗设备数据采集的第一道工程问题不是“怎么解析数据”,而是“数据从哪条物理链路进来、以什么协议封装、由谁负责拆包”。同一台监护仪可能同时提供 RS232 串口、USB 转串口、以太网和蓝牙四种出口,而它们承载的上层协议又可能是 HL7、DICOM 或 IEEE 11073。理解接口与协议的对应关系,是后续实时处理管线设计的前提。
一、四类物理接口的工程特征
RS232 是最传统的医疗设备接口,常见于监护仪、输液泵、血气分析仪。它采用点对点异步串行通信,工程上必须显式约定波特率、数据位、停止位、校验位和流控。例如某型号监护仪输出参数为 9600 bps、8 数据位、1 停止位、无校验、无流控,数据以 ASCII 文本行发送,每行以 \r\n 结束。RS232 的电气特性决定了传输距离通常不超过 15 米,且需要电平转换芯片(如 MAX232)才能与 MCU 的 TTL 电平对接。
USB 在医疗设备中多以两种形态出现:一是 USB CDC(通信设备类),设备枚举为虚拟串口,操作系统分配 COM 口,应用层仍按串口读写;二是 USB HID 或厂商自定义批量端点,需要 libusb 或厂商 SDK 直接操作端点。USB 的优势是即插即用和供电一体,但热插拔时的设备重枚举会导致句柄失效,采集程序必须监听设备到达/移除事件并重新打开。
以太网 是当前高端监护、影像和检验设备的主流接口。它提供高带宽和网络寻址能力,上层可承载 HL7 over MLLP、DICOM、IEEE 11073-20701 等。工程上需要关注 IP 分配方式(静态或 DHCP)、端口号、TCP 还是 UDP。例如 DICOM 存储服务通常监听 104 或 11112 端口,HL7 MLLP 常用 2575 端口。
蓝牙 在便携式血氧仪、血糖仪、动态心电贴中广泛使用。医疗场景多采用 BLE(低功耗蓝牙),通过 GATT 服务与特征值传输数据。IEEE 11073-20601 定义了 BLE 上的个人健康设备通信模型,设备以标准服务暴露测量值。蓝牙采集的难点在于配对、连接参数协商和断线重连,且不同厂商的 GATT 特征 UUID 可能不同,需要按设备型号维护映射表。
二、三大协议的核心差异
HL7 v2.x 是临床信息系统之间交换患者、医嘱、检验结果的主流标准。它采用竖线分隔的段结构,例如 MSH|^~\&|MONITOR|ICU|HIS|HOSP|202405121030||ORU^R01|MSG001|P|2.4,其中 MSH 段定义消息头,OBX 段承载观察结果。HL7 本身不规定传输层,医疗设备常通过 MLLP(最小下层协议)封装:以 0x0B 起始、0x1C 0x0D 结束,在 TCP 上传输。采集程序必须按这两个边界符拆帧,不能假设一次 recv 就是一条完整消息。
DICOM 面向医学影像,定义了影像对象、服务类和数据编码。设备通过 DIMSE 服务(如 C-STORE 发送影像、C-FIND 查询)交互。DICOM 文件由文件头和数据集组成,数据集使用显式 VR 小端或隐式 VR 小端编码。采集影像时,通常由设备主动向 PACS 或采集网关发起 C-STORE,网关作为 SCP 接收并落盘。DICOM 的标签(Tag)以组号和元素号表示,如 (0010,0010) 为患者姓名,(0008,0060) 为模态。
IEEE 11073 是个人健康设备通信标准族。11073-20601 定义抽象通信模型,11073-104xx 定义具体设备(如 10407 血压、10408 体温、10404 血氧)。设备以 MIB 对象形式暴露测量值,每个对象有属性(如 MDC_ATTR_NU_VAL_OBS 数值观察值)和单位代码。在 BLE 上,11073 通过 GATT 特征值传输,采集端需先发现服务、订阅 Notify,再按 ASN.1 或厂商编码解析字节流。
三、采集实战:从串口到结构化数据
以一台通过 RS232 输出 HL7 消息的监护仪为例,完整采集链路如下。物理层使用 USB 转 RS232 线缆,操作系统识别为 /dev/ttyUSB0(Linux)或 COM3(Windows)。串口参数设为 9600-8-N-1,无流控。应用层读取时不能按固定长度读,而应按行或按 MLLP 边界读取。
import serial
ser = serial.Serial('/dev/ttyUSB0', 9600, timeout=1.0)
buffer = b''
while True:
chunk = ser.read(256)
if not chunk:
continue
buffer += chunk
# MLLP 拆帧:0x0B ... 0x1C 0x0D
while b'\x0b' in buffer and b'\x1c\x0d' in buffer:
start = buffer.index(b'\x0b')
end = buffer.index(b'\x1c\x0d', start)
frame = buffer[start+1:end]
buffer = buffer[end+2:]
text = frame.decode('ascii', errors='replace')
# 按段解析
for seg in text.split('\r'):
fields = seg.split('|')
if fields[0] == 'OBX':
print('观察值:', fields[5], fields[6])
上述代码的关键点有三:一是 timeout=1.0 避免阻塞导致无法退出;二是缓冲区累积,因为一次 read 可能只收到半条消息;三是按 0x0B 和 0x1C 0x0D 定位帧边界,而不是按行分割,因为 HL7 段内可能包含 \r。解析出的 OBX 段中,fields[5] 是观察标识,fields[6] 是测量值,实际工程中还需结合 fields[2] 的值类型和 fields[3] 的标识符做映射。
四、以太网与蓝牙采集的差异处理
以太网采集 HL7 时,采集端通常作为 TCP 服务端监听 2575 端口,设备作为客户端连接。每个连接对应一台设备,需维护连接表。MLLP 拆帧逻辑与串口一致,但 TCP 是流式协议,必须处理粘包和半包。DICOM 采集则需引入 DCMTK 或 pydicom 等库,实现 C-STORE SCP,接收后按 SOP Instance UID 命名文件并写入数据库索引。
蓝牙 BLE 采集的流程不同:先扫描广播,按设备名称或服务 UUID 过滤;连接后调用 discoverServices,找到 11073 标准服务;对测量特征值使能 Notify,注册回调;在回调中按 11073 编码解析字节。BLE 的 MTU 通常为 23 字节,长数据需分包重组。断线后需重新扫描连接,不能复用旧句柄。
五、接口与协议选型对照
| 接口 | 典型协议 | 传输方向 | 采集端角色 | 关键参数 |
|---|---|---|---|---|
| RS232 | HL7 / 私有 ASCII | 设备 → 采集端 | 客户端(读串口) | 9600-8-N-1 |
| USB CDC | HL7 / 私有 | 设备 → 采集端 | 虚拟串口客户端 | COM 口号 / 序列号 |
| 以太网 | HL7 MLLP | 双向 | TCP 服务端 | 2575 端口 |
| 以太网 | DICOM | 设备 → 采集端 | C-STORE SCP | 104 / 11112 端口 |
| 蓝牙 BLE | IEEE 11073 | 设备 → 采集端 | GATT 客户端 | 服务 UUID / Notify |
实际项目中,一台设备可能同时开启多种接口。例如监护仪通过 RS232 输出实时波形,通过以太网向中央站发送 HL7 报警,通过 USB 导出历史趋势。采集系统应优先选择带宽足够、协议标准化程度高的通道,并为每条通道独立维护连接状态和重连策略。接口决定“怎么连”,协议决定“怎么解”,两者共同决定采集程序的线程模型、缓冲策略和异常恢复方式。