基于STM32 的心电和脉搏波监测
2023-11-30陈飙邹远文
陈飙,邹远文
(四川大学,四川成都 610065)
随着人们对于自身生理健康的日渐重视,在日常生活中能够方便、实时地进行生理信号的监测变得愈加重要。
人体的心电(ECG)和脉搏波含有丰富的生理信息,具有医疗和健康指导意义。利用心电波形可以进行异常心跳的检测与分类[1],而利用脉搏波特别是光电容积描记脉搏波(PPG)可以进行多种心血管疾病的诊断[2],甚至可以结合ECG 和PPG 进行血压的预测[3]。因此,本文基于STM32 设计了一种生理信号监测方案,可以实时同步监测清晰稳定的ECG 和PPG 波形。
1 总体设计与流程
方案总体上由信号的采集、处理和显示3 个部分构成。其中采集部分由STM32 的模拟/数字转换(ADC)部分对心电模块和脉搏波传感器采集的模拟信号进行采样从而转化成数字信号,而处理部分则是由STM32对采样的数字信号进行滤波并实时提取信号波形的特征计算一些生理参数,显示部分是STM32 将处理后的信号和特征参数通过LCD 屏和LabVIEW 上位机进行实时显示。
方案选用的器件包括用于采集模拟生理信号的AD8232 心电模块、脉搏波传感器,用作主控芯片的STM32F103C8T6,用于显示的LCD 屏和运行LabVIEW上位机的个人电脑(PC)。
2 信号采集
STM32F103C8T6 的信号采集部分工作流程如图1所示,包括STM32 对ECG 和PPG 模拟信号的ADC采样及采样后数字信号的DMA(Direct Memory Access,直接存储器访问)传输。
图1 STM32 的模拟信号采集流程
2.1 ADC 采样
由于需要同步采集ECG 和PPG,所以使用STM32的双ADC 同步规则模式,即ADC1(主ADC)的外部触发同时给ADC2(从ADC)提供触发,这样ADC1和ADC2 的2 个通道就能同时进行ADC 采样。主ADC的外部触发源配置为通用定时器TIM3 的TRGO 触发输出信号,同时将定时器的TRGO 信号配置为定时器的更新事件,这里是定时器的计数器在向上计数模式下从0 计数到自动重装载值产生溢出时的更新事件。因此ADC 的采样频率实际上由计数器的时钟频率和自动重装载值决定,可由以下公式计算:
式中:fADC为ADC 的采样频率的数值,也是计数器计数溢出的更新频率的数值;RARR为自动重装载寄存器的数值;fCNT为计数器的时钟频率的数值;fPSC为定时器的时钟频率,由APB1 总线的时钟频率结合APB1的预分频系数获得,此处为72 MHz。
这里将PSC 预分频值设置为71,ARR 自动重装载值设置为1 000,从而得到1 kHz 的ADC 采样频率。
2.2 DMA 传输
在完成一次ADC 采样后,ADC1 和ADC2 同时转换的2 个12 位ADC 值分别存储在32 位的ADC1 数据寄存器的低16 位和高16 位中,为了避免连续转换时数据被覆盖丢失,需要及时读取。另外,为了避免CPU(中央处理器)频繁响应中断,选择DMA 来进行外设ADC 到内部存储器的高速数据传输。STM32 的DMA1 通道1 在内部直接与ADC1 相连,除了基本的数据传输方向(从外设读)、外设数据宽度(32 位)等配置,还需要注意在内存中预先分配一个数组作为缓冲区,缓冲区的大小也是DMA 通道的CNDTR 传输数量寄存器的值,进一步将DMA 通道配置为循环模式,存储器地址执行增量操作,这样DMA 就能自动搬运数据填满数组缓冲区,并且下一次自动从数组基地址重头开始向内存搬运数据。
为了避免缓冲区数据被覆盖,需要及时读取数据并进行处理,但同时不应影响DMA 的高速连续传输,因此需要采用类似乒乓缓存的双缓冲区[4],并且使能DMA 的HT 传输过半中断和TC 传输完成中断。每当DMA 传输50%的数据后,CPU 通过HT 中断将缓冲区数组的前50%数据读出处理(此时DMA 仍在继续向后50%填充数据),并且关闭HT 中断;当DMA 传输完成时,再通过TC 中断将缓冲区的后50%读出处理,再开启HT 中断。如此交错反复,实现ADC 的连续采样和周期性及时处理。中断处理的时间间隔取决于缓冲区的大小,这里缓冲区数组长度设置为200,这样DMA 每传输100 个数据也就是每隔100 ms 触发一次中断,进行数据读取与信号处理。
3 信号处理
3.1 平滑滤波
原始的ECG 和PPG 信号最主要的噪声是随机噪声,需要采用平均滤波来平滑曲线。这里采用滑动窗口数组来进行平均滤波,即每次接收1 个新的信号点,就将数组的首项数据去除,数组整体数据左移1 位,将新数据放入到数组的尾项,然后对这个窗口数组里的所有数据求平均值。这样在不损失采样点数量或采样频率的情况下很好地消除尖锐噪声,提取了一定区间内的波形变化趋势。
另外,滑动窗口越大,平均滤波后的曲线越平滑,但波形的特征越容易丢失,因此需要平衡好噪声与波形特征的取舍,选择合适的数组大小。EGG 和PPG 的原始含噪声波形和滤波后波形如图2 所示。
图2 ECG 和PPG 波形的滑动平均滤波
3.2 特征检测
ECG 和PPG 的波形特征蕴含着丰富的生理信息,这里考虑心率和血压这2 种常见的生理参数。首先,ECG 的R 波间隔或者PPG 的波峰间隔都可以作为一个心跳周期,从而得到每分钟的心跳次数即心率。其次,目前一种有潜力的无袖式血压测量方法是通过脉搏波在人体动脉中的传播速度来关联预测血压,这种速度可以体现为脉搏波从动脉近端到远端的传输时间,一般通过ECG 的R 波与PPG 的某些特征点的时间差来计算,这里常用的特征点包括PPG 的峰值、足部、最大斜率/导数处等。
特征检测算法需要对每个新的滤波后信号点进行实时判断,从而及时地跟踪并记录波形变化。首先设定波形的峰值、谷值、周期及阈值初值,并且在连续判断信号点的过程中不断更新。具体来说,在更新过程中,阈值被不断调整为波形峰值和谷值的平均值,因此每当出现大于阈值的信号点,就意味着波形此时正处于上升阶段即将到达波峰,也标志着新的心跳节拍的开始;当出现小于阈值的点时,则说明处于波峰的下降阶段,标志着当前一拍的结束。需要注意避免ECG 的T 波和PPG 的重搏波干扰,即判断时不仅仅依赖于信号点的数值大小,还要注意信号点的时间距离上一拍的时间间隔是否大于1/2~3/5 个心跳周期。因此,ECG 的R 波和PPG 的波峰都可以通过一拍结束后更新的最大值来确定。PPG 的足部也就是波峰的山脚,则应在旧的一拍结束后新的一拍开始前这个时间段对信号点时间进行更新。当信号点首次出现超过5%~10%阈值(具体数值根据总体信号幅度确定)的上升幅度后,就停止更新,表示刚好从底部平缓的变化转为向波峰快速爬升,表明已经找到了足部。而在检测到峰值之前,出现最大上升幅度的点则被认为是最大斜率处。对本方案中某次实时采集的波形和特征数据保存后进行离线处理,绘制的图像如图3 所示。可以看到波形非常稳定而且细节十分清晰,并且各个特征都被清晰地用虚线标注了出来,不仅说明提取算法有效,也体现了波形质量良好。
图3 ECG 和PPG 的波形及特征
3.3 数据通信
STM32 需要与外部设备建立通信,再将滤波后的信号点和生理特征等数据传输给外接设备进行显示。首先考虑小巧便携的显示方案,这里选用了分辨率为240×240 的1.3 英寸TFT-LCD 显示模块,其内核是一块单片机控制和驱动芯片ST7789V3,支持8 位/9 位的并行输入控制。
STM32 选择串行外设接口SPI 进行与LCD 的通信,有助于节省I/O(输入输出接口)资源,同时可以通过软件模拟SPI的方式来自由地使用任意I/O进行通信。因为只需显示,所以只用向屏幕写入数据,4 线制SPI 写时序如图4 所示。
图4 LCD 的SPI 写时序图
每次写入时需要将CS 片选引脚拉低,然后将数据引脚SDA 设置为要发送的字节的每位的高低电平,然后将时钟引脚SCL 时钟先设为低电平再设为高电平,这样SDA 就会在SCL 时钟的上升沿被采样从而将该位电平发送出去,依次发送8 位就刚好完成1 个字节的发送。另外,在发送字节时还需要设置D/CX 引脚的高低电平,因为芯片会在SCL 的第8 个上升沿对D/CX引脚电平进行采样,从而确定写入的是数据还是命令。
由于LCD 的屏幕尺寸较小,所以也考虑了引入大尺寸的屏幕来同时进行ECG 和PPG 波形的监测,而且也便于观察波形细节。这里采用LabVIEW 设计了一款PC 端上位机软件,可以实时接收STM32 从串口发送来的数据包并进行解析与显示。这里选用STM32 的通用同步异步收发器USART1 作为串口,其波特率可以通过波特比率寄存器BRR 进行配置,而通过配置控制寄存器CR1 的PCE 检验控制使能位和M 字长位以及CR2 的停止位,可将USART1 设置为无校验、8 位数据位、1 位停止位,然后使能USART1。另外,需要使能发送和接收。发送一帧数据(一个字节)时,需要向数据寄存器DR 写入数据,在硬件上实际是数据被送到发送数据寄存器TDR 或者直接送到移位寄存器,当1 帧数据发送完成后状态寄存器SR 的TC 传输完成标志位被置1,通过读一次SR 寄存器和写一次DR 寄存器来清除TC 位并同时写入下一帧。当一个字符被接收时,SR 寄存器的读数据寄存器非空RXNE 位被硬件置1,通过使能RXNE 中断来及时读取数据。
4 生理参数显示
在LCD 或上位机进行显示的时候涉及CPU 对LCD 的频繁写操作或者向串口连续收发数据的操作,为了避免还未读取处理的数据被后续DMA 中断送来的新数据覆盖,同样也需要设置缓冲区。这里通过缓冲数组和读、写双指针的交替移动来实现先进先出环形缓冲区FIFO 的设计[5-6],如图5 所示。读、写指针一开始都是缓冲数组的基地址,DMA 每次中断处理时就进行写指针的自增,并根据指针地址进行缓冲数组新数据的填充,如果指针超过数组大小就回到数组开头的基地址,如此循环反复,构成了一个环形缓冲区。读指针也是如此,当LCD 和上位机每次取数据时,读指针根据读取数据的数量进行移动。因此,缓冲区中读指针和写指针之间的数据就是待读取的新数据,而2 个指针重合则表明暂时没有有效的数据可读取,等待DMA 中断填充新的有效数据。
图5 缓冲数组模拟环形缓冲区读写示意图
4.1 LCD
ECG 或PPG 波形数据在LCD 显示的时候需要进行刷新作画,这里选择波形从右往左的滚动刷新方式。由于软件模拟SPI 的速率不是太高,为了保证刷新的流畅性,在DMA 中断里除了滑动平均滤波外,还进行了简单的平均滤波,即将100 个新的信号点每隔10 个点求平均值,这样在滤除噪声且基本保留波形变化趋势的情况下,LCD 每次需要刷新的点数就降低到了10 个。每次刷新前类似于滑动窗口的思想,存放屏幕波形数据的旧数组(大小等于屏幕分辨率240)会集体左移10 个位置,新的10 个数据被放到数组最后面产生新的波形数组。刷新时会从左到右逐点擦除旧的波形点连线,同时每擦除一条连线就在同样位置画新数组2 个信号点的连线,这种方式有利于显示帧的平滑过渡,即使在刷新帧数较低时人眼也不会感觉到波形平移的明显卡顿。LCD 波形监测界面如图6 所示。
图6 LCD 波形监测界面
4.2 LabVIEW 上位机
LabVIEW 上位机的前面板如图7 所示,程序流程如图8 所示。程序主体是个状态机,本质上是包含在while 循环结构内的条件结构,通过枚举类型条件和移位寄存器进行各个状态的跳转。程序运行时,首先在“init”分支里对一些变量进行初始化,然后进入最主要的“wait”分支,通过事件结构进行各类事件的检测,比如检测到串口操作按钮开启时就打开相应的串口,并且将数据位、停止位、奇偶校验进行与STM32 的串口同样的配置,通过下拉列表选择相对应的波特率。另外还有保存图像、退出程序等事件。当“wait”分支没有检测到事件时就会跳转“send”分支,如果“开始采集”按钮开启即上位机处于采集状态且布尔型变量“处理完成标志位”为真表明当前数据已处理显示完毕,此时会向STM32 发送一个特定命令字节,表示准备好接收下一批数据,STM32 的串口中断检测到命令后就会读取环形缓冲区中的有效数据并发送给上位机;如果不满足条件,程序就会跳回“wait”分支继续进行事件检测。
图7 LabVIEW 上位机波形监测界面
图8 LabVIEW 上位机程序流程图
在成功向STM32 串口发送了读取命令后程序就会跳转到“getdata”分支,对串口接收的字节数进行判断,如果数量达到规定的数据包字节数就表示接收完毕,进入下个分支“deal”进行数据处理显示,否则回到“wait”分支继续进行等待。在“deal”分支中,首先是根据协议对接收的数据包进行字节的拆分与合并,从而提取波形采样值、心率及其生理参数;其次将这些信息保存为CSV 文件,同时利用波形图表进行ECG 和PPG 的波形滚动显示,另外在前面板里还显示了心率(BPM)和心跳周期(IBI)。
5 结论
人们对日常健康的监测需求愈加强烈,而类似STM32 这样低成本、低功耗的MCU(微控制单元)芯片非常适合用在可穿戴设备或其它医疗电子设备,能够使人们随时随地监测自己的生理状态。本文提出了一种基于STM32 的ECG 和PPG 监测方案,能够方便实时地监测ECG 或PPG 波形,另外除了LCD 式的便携监测方案外,还演示了使用PC 等大屏设备进行多个波形及波形细节与生理特征的监视,为类似医院的心电图机、血氧仪等设备提供了一种简便的替代思路。最后,本文对方案的整体流程及具体算法都进行了详细讨论,为此类装置从理论向实践的转化提供了一个较好的示例。