心率传感器是一种用于测量人体心跳率的传感器。它可以通过监测心脏的电活动或血流来提供实时的心率数据,并将心率数据转换为电信号或数字信号。心率是指心脏每分钟跳动的次数,通常以“bpm”(每分钟跳动次数)为单位。
图1:max30102光电式心率血氧传感器、XD-58C Pulse Sensor脉冲传感器
心率传感器的工作原理可以分为两种常见的方法:光电传感和电生理传感。
光电传感:这是最常见的心率传感器工作原理。它使用了光敏元件(例如光电二极管或光敏电阻)来测量皮肤上的血流变化,从而推导出心率数据。有些设备也可以估计血液中的氧气水平。
光学心率传感器是是智能穿戴设备中最为普及的用于心率检测的传感器之一。它采用电光溶剂脉搏波描记法(PPG)来测量心率及其他生物计量指标。
PPG测量原理:通过电容灯光射向皮肤,透过皮肤组织反射回的光被光敏传感器接受并转换成电信号,再经过电信号转换成数字信号,再根据血液的吸光率算出心率。简化测量过程就是:发射光——转换成电信号——转换成数字信号。
图2:光学心率传感器的基本结构与运行
光学心率传感器使用四个主要技术元件来测量心率:
光学心率传感器可生成测量心率的PPG波形并将该心率数据作为基础生物计量值,但是利用PPG波形可以测量的对象远不止于此。图3是经过简化的PPG信号,该信号代表了多个生物计量的测量结果。
下面我们进一步详细解读某些光学心率传感器可以测得的结果:
图 4:光谱
选择绿光作为测量光源是考虑到以下几个特点:
图 5: 光电式心率传感电路
电生理传感:这种传感器利用人体的生物电活动来测量心率。即心脏在每次心跳时都会产生一个小电流,具有电检测功能的心率监测器通过检测和跟踪该电流,实现心率的测量。 常用的电生理传感器是心电图(ECG)传感器,通过测量心脏产生的电信号来确定心率。
工作过程如下:
无论是光电传感还是电生理传感,心率传感器通常会将采集到的数据发送给处理器或设备进行分析和显示。这样,用户就可以实时了解自己的心率情况。
需要注意的是,不同型号的心率传感器可能采用不同的工作原理和技术细节,但基本原理是类似的:通过测量血流变化或心脏电信号来推导心率数据。
深入:使用脉冲传感器和Arduino检测,测量和绘制心率 (lastminuteengineers.com)
MAX30102脉搏血氧仪和心率传感器与Arduino接口 (lastminuteengineers.com)
AD8232 ECG模块引脚排列,与Arduino接口,应用 (microcontrollerslab.com)
下面是个人案例,使用Mircopython编写程序驱动RP2040读取Max30102的数据。
驱动文件包含三个.py文件。
前面两个文件可在后面链接中下载:https://github.com/n-elia/MAX30102-MicroPython-driver/tree/main/max30102
检测心率.py程序如下
from machine import SoftI2C, Pin, Timer from utime import ticks_diff, ticks_us from max30102 import MAX30102, MAX30105_PULSE_AMP_MEDIUM BEATS = 0 # 存储心率 FINGER_FLAG = False # 默认表示未检测到手指 def display_info(t): # 如果没有检测到手指,那么就不显示 if FINGER_FLAG is False: return print('心率: ', BEATS) def main(): global BEATS, FINGER_FLAG # 如果需要对全局变量修改,则需要global声明 # 创建I2C对象(检测MAX30102) i2c = SoftI2C(sda=Pin(16), scl=Pin(17), freq=400000) # Fast: 400kHz, slow: 100kHz # 创建传感器对象 sensor = MAX30102(i2c=i2c) # 检测是否有传感器 if sensor.i2c_address not in i2c.scan(): print("没有找到传感器") return elif not (sensor.check_part_id()): # 检查传感器是否兼容 print("检测到的I2C设备不是MAX30102或者MAX30105") return else: print("传感器已识别到") print("使用默认配置设置传感器") sensor.setup_sensor() # 对传感器进行设定 sensor.set_sample_rate(400) sensor.set_fifo_average(8) sensor.set_active_leds_amplitude(MAX30105_PULSE_AMP_MEDIUM) t_start = ticks_us() # Starting time of the acquisition MAX_HISTORY = 32 history = [] beats_history = [] beat = False while True: sensor.check() if sensor.available(): # FIFO 先进先出,从队列中取数据。都是整形int red_reading = sensor.pop_red_from_storage() ir_reading = sensor.pop_ir_from_storage() if red_reading < 1000: print('No finger') FINGER_FLAG = False # 表示没有放手指 continue else: FINGER_FLAG = True # 表示手指已放 # 计算心率 history.append(red_reading) # 为了防止列表过大,这里取列表的后32个元素 history = history[-MAX_HISTORY:] # 提取必要数据 minima, maxima = min(history), max(history) threshold_on = (minima + maxima * 3) // 4 # 3/4 threshold_off = (minima + maxima) // 2 # 1/2 if not beat and red_reading > threshold_on: beat = True t_us = ticks_diff(ticks_us(), t_start) t_s = t_us/1000000 f = 1/t_s bpm = f * 60 if bpm < 500: t_start = ticks_us() beats_history.append(bpm) beats_history = beats_history[-MAX_HISTORY:] # 只保留最大30个元素数据 BEATS = round(sum(beats_history)/len(beats_history), 2) # 四舍五入 if beat and red_reading < threshold_off: beat = False if __name__ == '__main__': tim = Timer(period=1000, mode=Timer.PERIODIC, callback=display_info) main()