做心电采集的硬件工程师,十有八九都被模拟前端折磨过:心电信号只有毫伏级,电极一贴上,工频干扰、基线漂移、运动伪迹全来了。ADS1293这片芯片,相当于把仪表放大器、可编程增益、24位高精度ADC、右腿驱动、导联脱落检测全部打包进一颗小封装里,省掉了一大堆分立器件和调试时间。这篇东西不讲太多虚的,就从电极怎么贴、硬件怎么画、SPI怎么配、波形怎么调,一路写到常见的坑和排查方法,适合正在做便携心电、可穿戴健康设备,或者准备拿ADS1293做原型验证的工程师参考。
1. 项目定位与芯片选型思路
1.1 为什么非要选专业生物电模拟前端
先把心电采集的难点说透。ECG信号从皮肤表面引出,幅度大概在0.5mV到4mV之间,带宽主要集中在0.05Hz到100Hz,QRS主波的能量又集中在10Hz左右。这意味着信号不仅小,而且处在一个工频噪声、肌肉电噪声、运动伪迹横行的频段里。普通MCU自带ADC根本没法直接用,必须先把信号放大、滤波、抬到合适的电压范围。
传统分立方案是先用仪表放大器做第一级差分放大,再加二阶低通滤波,后面接运放做第二级增益,最后进MCU的12位或16位ADC。这套方案性能很难做好:仪表放大器选型要考虑共模抑制比、输入偏置电流、噪声密度;PCB布局稍微差一点,50Hz工频干扰就能把信号淹没;还要额外设计右腿驱动电路来压共模电压。调起来很费时间,性能上限还摆在那边。
ADS1293这类专用模拟前端把这条链路压缩到一颗芯片。内部集成了三路低噪声放大器、三个24位Delta-Sigma ADC、右腿驱动放大器、Wilson/Goldberger网络所需的部分逻辑、还有交流/直流导联脱落检测,甚至能扩展出呼吸阻抗测量。MCU通过SPI接口读写寄存器,剩下的高精度模拟部分不用自己操心了。
1.2 ADS1293的核心规格与适用场景
ADS1293在设计上有个很讨巧的地方,它虽然是三通道,但通道不是固定绑死的。每路输入都可以被路由到任意一个ADC通道,通道路由表在寄存器里可配。这意味着它既可以做标准的三导联,也可以通过多片级联扩展成12导联,芯片之间用菊花链连接,主控侧只占一个SPI口。这个特性对做多导联设备来说非常实用。
功耗方面,这颗芯片整体功耗低,支持多种低功耗模式,非常适合电池供电的便携设备。数据速率可调,从几十SPS到几千SPS都能配,配合不同应用场景:做心率监测可以把速率调低来省电,做诊断级波形就要把速率拉高、同时把内部滤波器带宽放宽。内部还集成振荡器,节省一颗外部晶振,布局更省空间。
选型时还要注意区分ADS1293和ADS1292:ADS1292是双通道,主要面向单导联/两导联可穿戴;ADS1293是三通道,路由更灵活,还多了呼吸测量相关的配置。如果只做单导联心率,ADS1292就够;如果要做三导联、或者想为后续多导联升级留余量,ADS1293更合适。我实际用下来,ADS1293的寄存器配置项更多,初期初始化代码写起来复杂一些,但换来的是通道布局和控制上的自由度,这个取舍是值得的。
2. 硬件设计:从电极贴片到输入链路的细节
2.1 电极贴片怎么选、怎么贴
模拟前端做得再好,电极接触这一关过不了,后面全是白搭。市面上用得最多的是Ag/AgCl(银/氯化银)一次性湿电极,里面自带导电凝胶,极化电压低、噪声小、信号稳定,医院心电监护基本都这种。缺点是导电胶会慢慢干涸,贴久了皮肤容易发红,不适合做长时间连续监测的产品。
可穿戴产品比较流行的是干电极或者织物电极,不需要导电凝胶,佩戴舒适性好,可以长时间使用。但干电极的接触阻抗高,运动时电极和皮肤之间会有微小的相对滑动,产生明显的运动伪迹。实测下来,干电极做静息状态心率监测问题不大,一旦人开始走动、跑步,波形就会变得很难看。这种情况下需要在软件里加运动噪声抑制,或者把电极做小、做贴合,尽量减少滑动。
贴放位置直接影响信号质量。标准三导联是RA(右上肢/右锁骨下)、LA(左上肢/左锁骨下)、LL(左下腹),三个电极构成一个近似等边三角形,心脏大致在中心。如果是单导联胸贴,通常把正负极放在胸骨两侧,参考/右腿驱动电极放在边上。贴之前最好用酒精棉擦一下皮肤,去除油脂和角质,能把皮肤-电极界面阻抗从几百K欧姆降到几十K欧姆,波形质量提升很明显。
特别提醒,右腿驱动(RLD)电极一定要接,而且要离信号电极远一点。RLD电极的作用不是采信号,而是把共模电压通过反相放大器“压”下去。如果它和信号电极靠太近,会被差模信号污染,共模抑制效果大打折扣。
2.2 输入保护与前端滤波怎么设计
ADS1293虽然有内部ESD保护,但外部输入通路还是要加一级保护和滤波。电极线在临床场景里可能碰到静电放电,甚至除颤高压(做监护设备必须考虑),所以输入端最好串电阻限流,再并联TVS管或二极管钳位。串阻一般取100kΩ到1MΩ,阻值太小起不到保护作用,太大又会让输入偏置电流产生明显电压降,得不偿失。
在串阻后面放一阶RC低通滤波,对射频干扰和带外噪声做初步抑制。R取几百欧到1kΩ,C取1nF到10nF,截止频率大致落在几十kHz到几百kHz。注意这个外部滤波不需要把带宽压得很低,因为ADS1293内部还有可配置的数字/模拟滤波,外部RC主要负责抗射频干扰和防混叠。电容必须用C0G/NPO这种温度稳定、低介质吸收的材质,别为了省成本用X5R/X7R,压电效应和电容随电压变化会引入额外噪声。
输入走线一定要对称、等长。ECG本质是差分测量,两根输入线上耦合的噪声如果不对称,就会从共模噪声变成差模噪声,后端再好的共模抑制比也救不回来。我的习惯是让RA/LA/LL走线以差分对的形式并行走,尽量少打过孔,周围用地线包住。屏蔽线外层在芯片端单点接地,不要两端都接,否则会形成地环路,反而引入工频干扰。
2.3 电源、地与PCB布局的实战经验
ADS1293的模拟电源和数字电源建议分开走,各用一颗1uF+0.1uF去耦电容,0.1uF尽量贴近芯片的电源引脚放。模拟电源和数字电源之间用磁珠或0Ω电阻单点连接,避免数字开关噪声耦合进模拟电源。地平面要完整,不要在芯片底部把地挖空。模拟地和数字地在芯片下方汇合,形成单点接地,这是抑制数字噪声干扰的最佳实践。
板子的地平面会比走线本身更重要。我做过一版两层板,顶层铺地、底层走信号,实测基线噪声明显偏大;改成四层板,把第二层作为完整地平面后,噪声峰值直接从几十uV降到个位数uV。如果预算允许,强烈建议直接上四层板,这么做的收益远比多焊几颗精密运放大。
MCU部分的数字走线尽量远离模拟输入线,特别是SPI的SCLK和数据线,它们的翻转频率很高,很容易通过空间耦合串进模拟前端。如果板子空间紧凑,可以在模拟区域加一片铺地隔离带。心电线束方面,用屏蔽线优于普通导线,双绞线也有一定抗共模能力;我测过,线束甩动产生的运动伪迹,用带屏蔽层的三芯线比普通线能改善一半以上。
3. 软件驱动:初始化流程与寄存器配置
3.1 SPI通信准备与电平匹配
ADS1293使用SPI接口通信,主从模式配置在芯片侧,MCU作为主机。通信前先确认逻辑电平:ADS1293数字I/O是1.8V逻辑,如果MCU是3.3V或5V供电,需要加电平转换,或者选支持1.8V逻辑的MCU。直接硬接会损坏芯片接口,也可能导致读回来的寄存器值全是乱的。比较省事的方法是找带1.8V电平能力的SPI引脚,或者用TXB0106这种双向电平转换芯片。
SPI模式要按数据手册配置时钟极性和相位,不同厂家对模式编号的叫法容易混淆,建议直接用逻辑分析仪抓CLK、CS、SDI、SDO的时序确认。通信的基本操作是读寄存器和写寄存器,每条命令先发寄存器地址,再跟数据字节。多字节读写时注意地址自动递增的规则,这会让初始化代码简洁不少。
3.2 初始化流程:从复位到启动转换
初始化顺序建议按照“复位→读取设备ID校验→全局配置→输入路由→通道使能→增益→采样率/滤波器→RLD配置→导联脱落配置→启动转换”这个顺序来做。先复位芯片,至少等待复位完成后延时几个毫秒,再读设备ID寄存器确认SPI通路没问题。设备ID校验通过后再做后续配置,这些步骤如果倒过来,很容易出现配置不生效、找不到原因的诡异问题。
通道配置这块,要先把每个ADC通道对应的输入引脚选好。比如三导联模式下,让ADC1采集RA-LA、ADC2采集RA-LL、ADC3采集LA-LL,并不需要三个ADC直接对应三个电极,而是配置成两个输入端的差值。AD1293内部有输入多路复用器,通过寄存器把INA、INB、INC路由到指定的PGA和ADC。这一点和分立放大器方案很不一样,刚开始写代码时容易搞混。
采样率和增益要根据应用来定。心率监测模式下,采样率设到125SPS或250SPS就够,内部低通滤波开到40Hz或100Hz;如果要做诊断级分析,采样率拉高到500SPS以上,带宽放宽,但数据量和功耗也会同步上去。增益方面,PGA增益和输入范围要匹配好。心电信号只有几毫伏,但电极极化电压可能到几百毫伏,ADC的满量程输入范围是基于输入范围的,并不是把所有增益都调到最大就一定好,需要留出直流偏置余量。我之前在一版板子上把PGA增益调满,结果静息状态波形很好,人一动就削顶,就是因为直流偏置把信号顶到饱和区了。
3.3 RLD配置与导联脱落检测
右腿驱动是ECG前端稳定工作的关键。配置RLD时,需要把参与共模检测的电极选好,一般是所有信号电极的平均值,然后在输出端通过电阻接到人体。RLD输出引脚和人体之间的串阻不能省,它决定了驱动强度和稳定性,太大会削弱共模抑制效果,太小又有安全风险,具体阻值按手册推荐值取即可。RLD还内置了积分器和限幅滤波,需要配置相关带宽和增益参数,保证环路稳定。
导联脱落检测方面,ADS1293支持交流和直流两种检测模式。直流检测比较简单,在电极上施加直流电流,当电极脱落时电压异常,检测电路置标志位;交流检测则利用低幅值的交流激励电流,它的好处是能和心电采集同时进行,不影响正常波形。配置时要注意设置脱落的阈值和迟滞,避免在阈值边界反复跳变,否则软件会不断报“导联脱落-恢复-脱落”,整个状态机被搞得乱七八糟。我一般会把阈值设到阻抗高阻范围的中上档,再加上50ms到100ms的持续确认时间,能过滤掉大部分瞬间接触不良的误报。
初始化完成后,把芯片配置为连续转换模式,SPI读取数据时先看DRDY信号(或配置为中断线),在数据就绪后再读,不要用固定延时去猜。DRDY信号没有就绪时读到的数据可能是上一帧的残余,波形会看起来卡顿或者漏拍。
4. 数据采集与信号处理
4.1 数据帧读取与格式转换
ADS1293的数据输出格式是三通道顺序排列的24位ADC字。每个通道的数据在DRDY有效后就绪,MCU通过SPI连续读取三个24位数据,然后拼接成signed int32。拼接时要注意字节序——通常先读高位、再读中位、最后读低位,但不同配置下输出顺序可能不一样。我习惯把三个字节拼成32位后,先判断符号位扩展是否正确,再看波形是否连续。
原始ADC码需要转换成物理量纲,方便调试和波形对比。转换公式很简单:电压(mV) = ADC码 / (2^23 - 1) × 满量程输入范围(mV)。如果满量程范围是±Vref/gain,那么一档的分辨率能达到微伏级。24位ADC的分辨率远超实际需求,但这片芯片这么做的好处是省掉了模拟端的增益级,同时利用过采样和内部数字滤波来提升有效分辨率,这也是它能在小封装里实现高信噪比的核心原因。
数据处理的第一步是画原始码流曲线。先别急着加任何数字滤波,直接看读取出来的数据是不是正常波形。如果原始波形有形态、有节律,说明前端、SPI和格式转换都对了;如果波形乱跳、饱和、或者一直不变,那就别往下做滤波了,先回头查硬件和初始化。这个习惯能省掉大量无谓的调试时间。
4.2 数字滤波:工频陷波与基线漂移处理
原始心电信号进入MCU后,通常先做50Hz工频陷波,再做带通滤波。工频陷波可以用二阶IIR Notch滤波器,中心频率50Hz,带宽不要设太宽,1Hz到2Hz就够,太宽会把QRS波群的高频成分也削掉。IIR滤波器设计有现成工具可以用,算出系数后,在MCU上用一个二阶直接II型结构实现即可。国内用50Hz,出口产品要考虑60Hz,或者在程序里做个可配置项。
这里给一个通用的双二阶IIR实现结构,C语言代码可以直接抄:
typedef struct { float b0, b1, b2; float a1, a2; float x1, x2, y1, y2; } biquad_t; float biquad_run(biquad_t *f, float x) { float y = f->b0 * x + f->b1 * f->x1 + f->b2 * f->x2 - f->a1 * f->y1 - f->a2 * f->y2; f->x2 = f->x1; f->x1 = x; f->y2 = f->y1; f->y1 = y; return y; }带通滤波的截止频率按应用来切。做心率监测,0.5Hz到40Hz就够了,0.5Hz高通能把呼吸引起的基线漂移压住,40Hz低通能滤掉大部分肌电噪声。做诊断级心电图,标准要求是0.05Hz到100Hz,但这意味着基线漂移会更明显,对电极和皮肤接触的要求也更高。如果MCU没有FPU,要把浮点IIR改成定点,或者直接调用CMSIS-DSP里的arm_biquad_cascade_df1_f32,实测效率高不少。
除了IIR,中值滤波对消除基线漂移也很有用。中值滤波器的窗口长度需要覆盖一个心动周期以上,通常设300ms到500ms。用中值滤波的结果作为基线估计,原始信号减去基线就能得到零点的波形。这个方法对运动伪迹的抑制比单纯高通滤波好,但处理延时较大,实时性要求高的场景要慎重,需要平衡延迟和基线抑制效果。
4.3 波形显示与上位机联调
数据处理链路通了以后,最关键的一步是可视化。我一般先用串口把三通道的24位原始数据打包发到PC,用Python的pyqtgraph实时绘制成滚动波形。这个反馈比任何调试日志都直观:波形形态对不对、噪声大不大、电极动不动,一眼就能看出来。串口协议尽量用简单的帧格式,比如帧头+通道数+数据CRC,加上时间戳,方便事后回放分析。
帧格式示例可以采用这样:
// 数据帧:0xAA 0x55 | ch_num | data0[3] | data1[3] | data2[3] | crc8发送时要注意字节序一致,PC端解析后直接按4.1节的方式转成电压值。串口波特率用921600或者更高,三通道@250SPS的数据量很小,完全没有压力。如果用蓝牙低功耗传输,建议把数据打包得更紧凑,并且考虑掉帧重传机制,否则无线传输的抖动会在波形上形成毛刺。
波形能实时显示了,再做心率的实时计算就有基础了。最简单的做法是检测R波峰值:先做带通滤波,再用自适应阈值做幅度检测,在波形上找到R峰位置,相邻R峰时间间隔换算成BPM。这个方法虽然粗糙,但作为实时心率算法完全够用,后面要做的更复杂分析再替换成QRS检测算法。
5. 常见问题与排查实操
5.1 典型异常现象与排查思路
做ADS1293项目时,我遇到最多的问题集中在几个典型现象上。整理成一张速查表,实际调试时可以对着逐项排查。
| 现象 | 可能原因 | 排查方向 |
|---|---|---|
| 波形是一条直线 | 导联脱落、通道未使能、输入路由错误 | 看导联脱落状态寄存器,确认SPI读写成功 |
| 波形长时间饱和/削顶 | 直流偏置过大、增益过高、RLD未工作 | 看原始数据是否贴近满量程,降低增益或检查RLD |
| 50Hz工频干扰明显 | 屏蔽接地不良、RLD配置错误、地环路 | 用电池供电排除地环路,检查右腿驱动引脚 |
| 基线大幅漂移 | 电极接触不稳、线材甩动、高通截止频率过低 | 重贴电极,缩短线材,加大数字高通频率 |
| QRS波太矮或看不到 | 增益不足、电极位置不佳、皮肤阻抗过高 | 换电极位置,清洁皮肤,提高PGA增益 |
| SPI读数据全是0或FF | 电平不匹配、SPI模式不对、CS时序不对 | 逻辑分析仪抓时序,确认SCLK/CS/SDI/SDO |
| 多通道数据错位 | 通道转换顺序配置错、读取顺序和输出顺序不一致 | 核对寄存器配置和读数据顺序 |
5.2 几个值得注意的避坑细节
第一个坑是RLD电极没接好。RLD输出的驱动能力有限,如果电极和皮肤接触阻抗太大,共模抑制效果会急剧下降,波形上会出现非常“干净”的50Hz正弦波干扰。这时候换电极、加导电膏通常能解决。别上来就调陷波器,那是治标不治本。
第二个坑是交流导联脱落检测和心电采集互相干扰。交流激励电流虽然很小,但如果频率设置和心电频段靠得太近,会在波形上叠加上周期性的小毛刺。解决办法是把交流激励频率设高一些,或者在数据处理时避开这个频段,又或者直接评估:做长时监测时,多数情况下用直流检测就够了,不一定非要开交流模式。
第三个坑是SPI时序上的毛刺导致随机寄存器写错。曾经遇到过初始化偶尔失败,后来发现是MCU在SPI写入时CS信号没有先拉低足够时间,个别时候还没准备好就启动了时钟。把所有寄存器的配置值都打出来人工比对,才找到是REG_CONFIG这个寄存器在OS上被SPI的时钟干扰写错了。解决办法是CS低电平和SCLK开始之间加至少几百纳秒的延时,并且对关键配置寄存器在写完后读回来校验一次。
第四个坑是数据处理链路上的字节序。24位ADC数据拼装时,如果搞错了高/中/低的顺序,波形并不会完全乱掉,而是出现类似“打碎重组”的锯齿状波形,幅度甚至会变得很大。这个很迷惑,因为看起来有点形态,但又不正常。遇到这种波形,第一件事就去检查数据拼装的字节序和符号扩展。
6. 一点个人体会
ADS1293是我用过的几款生物电前端里,性能/集成度/开发成本的平衡做得最均衡的之一。硬件上最需要注意的是把前端输入、电源、地平面这些基础的功夫做足,软件上则是把初始化的顺序和寄存器校验作为第一优先级。我踩过几次坑之后形成的习惯是:拿到新板子先把设备ID读出来,然后在寄存器里逐项核对,最后再连电极看波形。这套流程看起来保守,但在真正出问题时能帮你快速定位到“硬件问题还是配置问题”,往往是节省最多时间的一步。
最后再分享一个小技巧:调试阶段不要急着把所有滤波都叠上,先把原始波形和fiilter后波形放在同一张图上对比,一旦滤波参数设计不合理,原始波形还在、滤波波形出现畸变,你能立刻察觉;而你只盯着处理后的波形看的话,很多作用会在不知不觉中被滤波算法掩盖掉。先把源头弄干净,再用算法锦上添花,这条路我实测下来最稳。