简介:本资源是一套完整的心电采集系统整机开发方案,面向电子工程师、嵌入式开发者及医疗设备研发人员,解决从生物信号采集、硬件电路实现到嵌入式软件控制的全链路技术落地问题。压缩包共111个文件,涵盖Altium Designer格式的PCB工程(.pcbdoc)与原理图(.schdoc)、基于C语言的单片机固件源码(.c/.h为主,含MKL25Z4系列底层驱动如system_MKL25Z4.c、usb.c等)、上位机通信支持文件及编译输出产物(.hex/.axf/.bin),整体大小仅2.98MB,结构紧凑、模块清晰,便于快速部署与二次开发。已有637人学习下载,适用于课程设计、毕业设计、便携式心电仪原型开发及嵌入式医疗电子项目实践。读者可直接导入AD进行PCB修改,复现高精度模拟前端调理电路,运行C源码实现ADC采样、数字滤波与UART/USB数据上传,并结合整机方案理解电源管理、抗干扰布局与临床信号采集规范。
1. 项目概述:从零到一打造心电采集设备
最近在整理过去的项目资料,翻出了一个压箱底的宝贝——一个完整的单导联心电采集设备方案。这个项目麻雀虽小,五脏俱全,从硬件PCB工程、原理图,到C语言源程序,再到整机结构考量,形成了一个完整的闭环。对于想入门生物电信号采集,特别是心电图的硬件工程师或嵌入式开发者来说,这个项目就像一份清晰的“地图”,能让你避开很多初期摸索的弯路。心电信号极其微弱,通常在毫伏级别,且混杂着大量的工频干扰、肌电噪声,如何从嘈杂的背景中稳定、准确地提取出那颗“心脏跳动的电信号”,是整个过程的核心挑战。这个方案就是围绕这个挑战展开的,它不仅仅是一堆文件,更是一套解决问题的思路和工程实现的方法论。
2. 核心硬件电路设计与选型解析
硬件电路是整个系统的基础,决定了信号质量的“天花板”。心电采集硬件通常包括前端模拟调理电路、主控及模数转换单元、电源管理以及通信接口等部分。
2.1 前端模拟调理电路:信号的第一道关卡
前端电路是重中之重,直接接触人体电极,负责完成信号的拾取、初步放大和滤波。其设计直接决定了最终信号的信噪比。
仪表放大器是关键:心电信号是差分信号,即需要测量两个体表电极之间的电位差。因此,必须使用仪表放大器作为第一级放大。仪表放大器具有极高的共模抑制比,能有效抑制人体携带的50Hz工频干扰等共模噪声。常用的芯片有AD620、INA128、AD8221等。在这个方案中,我选择了AD8221,因为它具有出色的直流精度和噪声性能,且增益通过单一电阻设置,非常方便。
高通滤波去除基线漂移:人体与电极接触会产生直流偏移电位,且呼吸、运动会导致信号基线缓慢漂移。必须在放大后立即加入一个高通滤波器,通常截止频率设置在0.05Hz到0.5Hz之间。这里我采用了一个一阶RC高通滤波器,截止频率约0.5Hz,能有效滤除直流和极低频漂移,而又不会损失心电信号中有用的低频成分(如ST段)。
低通滤波抑制高频噪声:心电信号的主要能量集中在0.05Hz到100Hz之间,尤其是QRS波群(心跳的主要特征)在17Hz左右能量最强。为了抑制高频肌电噪声、环境射频干扰等,需要设置一个低通滤波器。我设计了一个二阶有源低通滤波器(采用Sallen-Key拓扑),截止频率设定在150Hz。这个频率既能保留心电信号的主要特征,又能滤除大部分无用的高频噪声。
右腿驱动电路:这是一个提升系统共模抑制能力的“神器”。它通过一个反向放大器,将仪表放大器检测到的共模噪声反馈回人体的右腿驱动电极,从而主动抵消人体感应的共模电压,能将系统的整体共模抑制比再提升20dB以上,是应对强工频干扰环境(如靠近电脑、电源适配器)的必备电路。
注意:前端模拟电路的布局布线必须极其考究。所有模拟信号走线应尽可能短,并用地平面包围。仪表放大器的增益设置电阻必须紧贴芯片引脚,且需使用高精度、低温漂的电阻。电源去耦电容(通常为0.1uF和10uF并联)必须靠近每个运放的电源引脚放置。
2.2 主控与ADC选型:数字化的桥梁
经过调理后的模拟心电信号需要被转换为数字信号,供后续处理。这里有两种主流方案:一是使用集成ADC的微控制器,二是使用独立的高精度ADC芯片。
方案选择:集成ADC的MCU。对于单导联、采样率要求不高(通常250Hz-500Hz足够)的心电采集,选择一款内置16位及以上精度ADC的微控制器是性价比最高的方案。我选择了STM32F103C8T6,也就是常说的“蓝色药丸”。它内置12位ADC,通过过采样和软件平均,可以有效提升分辨率,满足入门级心电采集的需求。其充足的SRAM和Flash也便于运行滤波算法和存储数据。
参考电压与输入范围匹配:STM32的ADC参考电压通常为3.3V。我们的前端调理电路输出信号幅值应设计在0V至3.3V的动态范围内。通常,经过放大滤波后的心电信号幅值在±1.5V左右,因此需要通过一个电平抬升电路(例如,用一个运放构成加法器,加入一个1.65V的偏置电压),将信号整体抬升至0-3.3V范围内,以匹配ADC的单极性输入要求。
采样率设置:根据奈奎斯特采样定理,采样率至少应为信号最高频率的2倍。心电信号我们关心到150Hz,因此采样率至少300Hz。实际中,为了波形更光滑,通常采用250Hz或500Hz。设置过高的采样率会增加数据量和处理负担,且对ADC性能要求更高。本项目设置为500Hz,这是一个在精度和资源消耗间很好的平衡点。
2.3 电源管理电路设计:纯净的能量供给
模拟电路对电源噪声非常敏感,特别是前端小信号放大电路。一个纹波大的电源会直接将噪声引入信号链。
线性稳压器是首选:开关电源虽然效率高,但固有的开关噪声会污染敏感的模拟地。因此,为模拟部分供电必须使用低压差线性稳压器。我使用AMS1117-3.3为整个系统的模拟和数字部分提供3.3V主电源。但更优的做法是,使用两个独立的LDO分别为模拟部分和数字部分供电,并在磁珠或0欧电阻进行单点连接,以实现更好的隔离。
退耦与旁路电容的布置:这是老生常谈但至关重要的一点。每个IC的电源引脚附近,都必须放置一个0.1uF的陶瓷电容(用于滤除高频噪声)和一个10uF的钽电容或电解电容(用于提供瞬时电流,稳定低频)。PCB布局时,这些电容必须尽可能靠近IC引脚,回流路径要短。
电池供电与低功耗考量:如果设计为便携式设备,需要考虑电池供电。可以使用单节锂离子电池(3.7V),通过LDO降压至3.3V。同时,主控MCU应充分利用休眠模式,在ADC采样间隙进入低功耗状态,以延长续航。
3. PCB设计实战:从原理图到可靠电路板
有了清晰的原理图,PCB设计就是将理论转化为实物的关键一步。好的PCB设计能保证硬件性能,差的布局布线则可能让之前所有的电路设计功亏一篑。
3.1 元件布局的哲学:分区与流向
布局不是简单的摆放,而是遵循信号流和电源流的艺术。
严格分区:将PCB板清晰地划分为几个区域:模拟前端区(包含仪表放大器、滤波运放)、数字主控区(MCU、数字接口)、电源区、接口区。各区之间用清晰的“壕沟”(无铜区域)或通过板子物理形状进行隔离。
信号流向线性化:模拟信号的路径应尽可能呈一条直线,从输入连接器(电极接口)-> 前端调理电路 -> ADC输入引脚。避免信号线来回折返、跨越分区,减少耦合干扰的机会。
敏感元件优先放置:优先放置仪表放大器、滤波运放、基准电压源等最敏感的模拟器件。将它们集中在模拟区域的核心,并为其预留充足的退耦电容空间。
连接器的位置:电极输入连接器应放在板边,并立即进入模拟区域。电源输入/输出连接器、通信接口(如USB、蓝牙模块接口)应靠近板边相应位置,并置于数字区域或接口区域。
3.2 布线规则与技巧:细节决定成败
布线是布局思想的执行,这里充满了“军规”。
模拟信号线:走线尽量短而粗。使用合适的线宽(如10mil以上)以减小寄生电阻和电感。避免90度直角走线,采用45度或圆弧拐角,以减少高频信号反射和电磁辐射。最关键的是,模拟信号线一定要被“地平面”护卫——即在其相邻层(最好是正下方)有完整的地平面,这为信号提供了最短的返回路径和屏蔽。
电源线:电源走线要足够宽,特别是总电源输入线。可以采用“星型”或“树状”拓扑向各个子区域供电,避免因共用一段细长走线而导致子电路间通过电源线耦合噪声。
地平面设计:地平面是电路的“基石”。对于混合信号电路,通常采用“统一地平面”而非分地。即在PCB内部层(如Layer2)布置一个完整、连续的地平面层。模拟和数字部分的地都在这个平面上,但通过物理布局上的分区来实现隔离。这种做法的好处是避免了分割地平面带来的复杂回流路径问题。所有器件的地引脚都通过短而粗的过孔直接连接到这个内部地平面。
过孔的使用:过孔会引入寄生电感,因此模拟信号路径上应尽量避免使用过孔。如果必须使用,可以并联多个过孔来减小电感。电源和地的过孔则可以多用,以确保低阻抗连接。
实操心得:在绘制PCB时,我习惯先用粗线(如20mil)把所有的电源线和地线网络连接好,形成一个主干框架。然后再用细一些的线(如10-12mil)去连接信号线。最后,进行敷铜操作,将空白区域用接地铜皮填充,并确保铜皮与地网络良好连接。敷铜时要注意避免出现孤立的铜岛。
3.3 设计检查与生产文件输出
设计完成后,自查和工具检查必不可少。
DRC检查:利用EDA工具的设计规则检查功能,检查线宽、线距、过孔尺寸等是否符合预设的工艺要求(例如,根据PCB生产厂商的工艺能力,设定最小线宽/线距为6mil/6mil)。
电气规则检查:检查是否有未连接的网线、悬空的引脚。确保电源和地的网络连接正确无误。
生成生产文件:最终需要给PCB工厂的文件是Gerber文件集。通常包括:
- 各层的铜箔文件(.GTL 顶层, .GBL 底层, .G1, .G2... 内层)
- 阻焊层文件(.GTS 顶层阻焊, .GBS 底层阻焊)
- 丝印层文件(.GTO 顶层丝印, .GBO 底层丝印)
- 钻孔文件(.DRL 钻孔数据和 .TXT 钻孔表)
- 板框文件(.GML 或 .GM1)
使用嘉立创EDA等工具可以一键生成这些文件并打包。务必在发板前,用免费的Gerber查看器(如GC-Prevue)或在线查看工具再次检查Gerber文件,确认层叠顺序、孔径、板框无误。
4. 嵌入式软件(C语言)实现详解
硬件是躯体,软件是灵魂。心电采集的软件需要完成ADC采样、数字滤波、特征提取和数据传输等任务。
4.1 系统初始化与ADC配置
系统上电后,首先要初始化各个外设。
// 以STM32 HAL库为例 void System_Init(void) { HAL_Init(); // 初始化HAL库 SystemClock_Config(); // 配置系统时钟,确保ADC时钟稳定 MX_GPIO_Init(); // 初始化GPIO,包括LED、按键等 MX_ADC1_Init(); // 初始化ADC MX_USART1_UART_Init(); // 初始化串口,用于调试或数据传输 MX_TIM2_Init(); // 初始化定时器,用于触发ADC定时采样 } void MX_ADC1_Init(void) { ADC_ChannelConfTypeDef sConfig = {0}; hadc1.Instance = ADC1; hadc1.Init.ScanConvMode = ADC_SCAN_DISABLE; // 单通道,禁用扫描 hadc1.Init.ContinuousConvMode = DISABLE; // 禁用连续转换,由定时器触发 hadc1.Init.DiscontinuousConvMode = DISABLE; hadc1.Init.ExternalTrigConv = ADC_EXTERNALTRIGCONV_T2_TRGO; // 定时器2触发 hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT; hadc1.Init.NbrOfConversion = 1; if (HAL_ADC_Init(&hadc1) != HAL_OK) { Error_Handler(); } // 配置采样通道 sConfig.Channel = ADC_CHANNEL_1; // 对应MCU的PA1引脚 sConfig.Rank = ADC_REGULAR_RANK_1; sConfig.SamplingTime = ADC_SAMPLETIME_239CYCLES_5; // 采样时间,影响输入阻抗 if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK) { Error_Handler(); } }关键点在于将ADC配置为由定时器触发,而非连续转换或软件触发。这样可以获得极其稳定、等间隔的采样点,对后续的信号处理至关重要。定时器TIM2被设置为产生500Hz的中断来触发ADC。
4.2 数字滤波算法实现
尽管有模拟滤波,数字滤波可以进一步净化信号,且灵活可调。心电处理中常用的是带通滤波,以进一步抑制工频干扰和基线漂移。
IIR数字带通滤波器:由于其计算效率高,在嵌入式系统中广泛应用。这里设计一个二阶IIR带通滤波器,通带为5Hz-40Hz,能有效保留QRS波群的主要能量,同时抑制50Hz工频和更低频率的基线漂移。
首先,可以使用MATLAB或Python的scipy.signal库中的butter函数生成滤波器系数。
# Python 示例:生成滤波器系数 import scipy.signal as signal fs = 500 # 采样率 lowcut = 5.0 highcut = 40.0 nyq = 0.5 * fs low = lowcut / nyq high = highcut / nyq b, a = signal.butter(2, [low, high], btype='band') print('b coefficients:', b) # 分子系数 print('a coefficients:', a) # 分母系数将得到的系数b0, b1, b2, a1, a2应用到C语言的差分方程实现中:
// 定义滤波器结构体和系数 typedef struct { float b0, b1, b2, a1, a2; float x1, x2, y1, y2; // 历史输入/输出值 } IIR_BPF_Filter; IIR_BPF_Filter ecg_filter; void IIR_Filter_Init(IIR_BPF_Filter* f, float b0, float b1, float b2, float a1, float a2) { f->b0 = b0; f->b1 = b1; f->b2 = b2; f->a1 = a1; f->a2 = a2; f->x1 = f->x2 = f->y1 = f->y2 = 0.0f; // 初始化历史数据为0 } float IIR_Filter_Process(IIR_BPF_Filter* f, float input) { float output; output = f->b0 * input + f->b1 * f->x1 + f->b2 * f->x2 - f->a1 * f->y1 - f->a2 * f->y2; // 更新历史数据 f->x2 = f->x1; f->x1 = input; f->y2 = f->y1; f->y1 = output; return output; }在ADC中断服务程序中,读取ADC值,转换为电压值,然后调用IIR_Filter_Process进行滤波。
工频陷波器:如果环境中50Hz工频干扰特别强,可以额外加入一个陷波器。一个简单的二阶IIR陷波器可以有效滤除特定频率。其中心频率设置为50Hz,品质因数Q值设置适中(如Q=30),以避免对附近频率成分造成过度衰减。
4.3 心电特征检测算法
滤波后的信号,我们需要检测出每个心跳(QRS波群),最经典、最可靠的算法之一是Pan-Tompkins算法。它计算量小,非常适合在MCU上实时运行。其主要步骤包括:
- 微分:突出QRS波群的快速上升和下降沿。
y[n] = (1/8) * (2*x[n] + x[n-1] - x[n-3] - 2*x[n-4]) - 平方:使所有点变为正数,并进一步放大高频成分(QRS波)。
y[n] = (x[n])^2 - 滑动窗口积分:平滑信号,得到一个包络,其中QRS波对应一个明显的波峰。
y[n] = (1/N) * (x[n-(N-1)] + x[n-(N-2)] + ... + x[n]),N通常对应150ms的窗口长度。 - 自适应阈值检测:对积分后的信号,动态设置一个阈值。当信号超过阈值时,认为检测到一个QRS波。阈值需要根据最近检测到的心跳间隔和信号幅度进行动态更新,以适应心率变化和信号幅度波动。
在MCU上实现时,需要维护几个数据缓冲区来存储历史采样点。检测到QRS波后,可以计算瞬时心率(60 / RR间隔(秒))。
4.4 数据存储与通信
处理后的数据需要输出。简单的方式是通过串口以一定格式(如CSV)打印到PC端,用串口绘图工具或Python/Matlab脚本实时显示波形。
// 在ADC中断或主循环中 float raw_voltage = ADC_Value * 3.3f / 4096.0f; // 12位ADC,参考电压3.3V float filtered_ecg = IIR_Filter_Process(&ecg_filter, raw_voltage); // 检测QRS... printf("%.3f, %.3f\\n", HAL_GetTick()/1000.0, filtered_ecg); // 输出时间和电压值对于更复杂的应用,可以将数据存储在SD卡中,或通过蓝牙模块(如HC-05, ESP32)无线传输到手机App。
5. 整机集成与测试验证
当PCB打样回来,元器件焊接完毕,程序也烧录好后,就进入了最激动人心也最考验人的联调测试阶段。
5.1 上电前检查与静态测试
目视检查:首先用放大镜仔细检查PCB有无短路、断路、虚焊、连锡、元件错件或反向等问题。特别是芯片引脚密集处和模拟前端区域。
电源对地短路测试:使用万用表蜂鸣档,测量板子上所有电源网络(3.3V, 5V等)与地之间的电阻。在未上电时,应有一个较大的阻值(至少几百欧姆以上),如果直接导通或阻值极小,说明存在严重短路,绝对不能上电。
静态电压测试:确认无短路后,先不插主控MCU,给板子上电。用万用表测量LDO的输出电压是否为稳定的3.3V。然后测量模拟运放的电源引脚电压、参考电压源输出等关键点电压是否正常。
5.2 信号通路动态测试
插上MCU,编写一个简单的测试程序,让ADC循环采样并将原始值通过串口输出。此时先不连接人体电极。
输入端短路测试:将心电电极输入端(RA, LA)短接在一起,并连接到电路板的地(RL)。理论上,仪表放大器输入差分电压为0,输出应该是一个稳定的直流电平(即你设计的抬升电压,如1.65V)。通过串口绘图观察ADC输出的值,应该是一条稳定的直线,噪声很小。这可以验证前端放大电路的基本工作是否正常,共模抑制能力如何。
注入测试信号:使用函数信号发生器,产生一个频率在1Hz-10Hz,幅值在1mV-2mV左右的正弦波或方波,模拟心电信号。将其差分地注入到RA和LA输入端(注意信号发生器的地要与板子地共地)。观察ADC输出的波形。你应该能看到一个被放大、滤波后的清晰波形。通过计算输入输出幅值比,可以验证放大器的增益是否与设计一致。改变输入信号频率,可以粗略验证滤波器的通带特性。
5.3 真人实测与干扰应对
这是最关键的环节。使用一次性心电电极片,按照标准I导联位置(RA:右腕, LA:左腕, RL:右踝)粘贴好,并连接到设备。
观察波形:上电后,通过串口绘图工具观察波形。你应该能看到清晰的P波、QRS波群和T波。可能遇到的问题及对策:
- 基线严重漂移:可能是电极与皮肤接触不良,或人体运动导致。确保电极粘贴牢固,测试者保持静止。软件中的高通滤波器参数可以适当提高截止频率(如到1Hz)。
- 强烈的50Hz工频干扰:波形上叠加了密集的锯齿状噪声。首先检查右腿驱动电路是否正常工作,反馈是否接入。其次,检查设备是否远离强干扰源(如手机、充电器、电脑主机)。尝试让测试者使用电池供电的笔记本电脑观察,以排除市电地线环路引入的干扰。可以尝试在软件中启用或调整50Hz陷波器。
- 肌电干扰:不规则的毛刺噪声,源于肌肉颤动。让测试者放松,尤其是手臂。软件的低通滤波器可以适当降低截止频率(如到100Hz)。
- 波形幅度太小或饱和:检查放大器增益设置。幅度太小则增加增益电阻;饱和则减小增益或检查电平抬升电路是否正常。
心率计算验证:让测试者同时手动测量脉搏(如触摸桡动脉计数),与设备计算出的心率进行对比,验证QRS检测算法的准确性。可以在算法中增加一些简单的逻辑,比如限制心率在合理范围(如40-180次/分),并滤除由于干扰造成的假阳性检测。
5.4 整机封装与功耗优化
测试稳定后,可以考虑为PCB设计一个3D打印或亚克力切割的外壳,保护电路并方便握持。如果使用电池供电,需要在软件中全面优化功耗:
- 将MCU主频在满足需求的情况下尽量调低。
- 让MCU在ADC采样间隔进入Stop或Sleep模式。
- 关闭不用的外设时钟。
- 采用间歇工作模式:例如,只在上电后采集30秒数据,然后进入深度休眠,等待按键唤醒。
这个从原理图、PCB到代码的完整心电采集方案,其价值不仅在于实现了一个功能,更在于提供了一个处理生物微弱信号的完整范本。其中关于噪声抑制、电源完整性、混合信号布局、实时信号处理算法的经验,可以迁移到很多其他传感器应用中去。调试过程中,一台示波器(观察模拟节点波形)和一个串口绘图工具(观察数字滤波后结果)是你的最佳搭档,耐心和细致的观察比任何复杂的理论都更能解决问题。
本文还有配套的精品资源,点击获取