数码之家

 找回密码
 立即注册
搜索
查看: 1572|回复: 22

[STM] 疫情的时候买的血氧传感器MAX30102,打个板子利用起来

[复制链接]
发表于 2024-9-11 17:08:39 | 显示全部楼层 |阅读模式
疫情的时候买的血氧传感器MAX30102,一直吃灰没整起来, 某次整理元件发现,不想浪费了,就找了找库存元件,打了个板子
  • 屏幕是某手环拆的0.49寸oled,分辨率64*32
  • mcu是某电zi烟拆的stm32g030
  • 传感器是某宝买的拆机max30102(不是,实际是买的模块测试完自己拆的,疫情时买的传感器实测有问题,用不了)
  • PCB立创白嫖
  • 容阻来自库存

原理介绍
MAX30102 脉搏血氧计和心率传感器如何工作?MAX30102 或任何光学脉搏血氧计和心率传感器由一对高强度 LED(红色和红外,波长不同)和一个光电探测器组成。这些 LED 的波长分别为 660nm 和 880nm。
MAX30102 的工作原理是将两束光照射到手指或耳垂(或者基本上是皮肤不太厚的任何地方,因此两束光可以轻松穿透组织),并使用光电探测器测量反射光量。这种通过光检测脉搏的方法称为光电体积描记法。
MAX30102的工作可以分为两部分:心率测量和脉搏血氧饱和度(测量血液中的含氧量)。
心率测量动脉血中的氧合血红蛋白(HbO2)具有吸收红外光的特性。血液越红(血红蛋白越高),吸收的红外光就越多。当血液随着每次心跳泵入手指时,反射光的量会发生变化,从而在光电探测器的输出端产生变化的波形。当您继续照射光线并获取光电探测器读数时,您很快就会开始获得心率 (HR) 脉搏读数。
脉搏血氧仪脉搏血氧测定法的原理是,吸收的红光和红外光的量根据血液中的氧含量而变化。下图是含氧血红蛋白(HbO2)和脱氧血红蛋白(Hb)的吸收光谱。
从图中可以看出,脱氧血液吸收更多红光 (660nm),而含氧血液吸收更多红外光 (880nm)。通过测量光电探测器接收到的红外光和红光的比率,可以计算出血液中的氧含量 (SpO2)。


        简单来说就是血液中的血红蛋白回吸收光线,影响光线反射.光线照射手指,手指中血管随着心跳泵入血量不同导致反射回传感器的光量变化,产生跟随心率一块变化的波形,分析波形就能得到心率,手机摄像头可以通过软件测心率也是同样的原理.
        MAX30102集成红光+红外光LED+光线采样传感器,玻璃密封,同系列还有MAX30100和MAX30105,30100没有玻璃盖密封,更容易被污染,30105增加绿光LED,使用范围更广,也更贵,综合来说30102更具有性价比.
硬件原理
        硬件整体没啥复杂的,Typec输入,TP4054锂电充电,XC6206分别提供3.3V和1.8V工作电压,开关电路保证关机下的低功耗(约为0),ADC采集电池电压显示电量 ,传感器I2C接口通信采用轮询采数,通过库计算心率和血样.


        这里介绍下开关机电路,这个电路相对拨动开关更复杂,需要浪费一个IO,但是可以复用开关机和正常按键操作,而且不像拨动开关一样易坏,可以实现自动关机,关机后0功耗,核心就是Q1 PMOS,关机状态下Q2基极低电平,截止,无功耗,Q1 G极高电平,截止,整体电路无功耗.开机时按下SW1,Q1 G极拉低,导通,后续电路供电正常工作,单片机IO拉高Q2基极,Q2导通,持续拉低Q1 G极,保证SW1松手后Q1继续导通,此时SW1又可作为正常按键工作,通过D3检测SW1按下状态,实现单击/双击/长按等状态检测实现功能切换开关机.

        整机原理图


打板
原理图分开画,最后拼版打样,此处说个小技巧,拼版时可以打排孔,PCB厚度选1.2或者更薄更方便分割,排孔间隙铺铜或者走线抱持电气连接,更容易过检,这里只针对这种结构复杂体积小的电路,单独打板要好几单太麻烦,对于单纯为了拼版而拼版的强烈反对.
不建议拼版
不建议拼版
不建议拼版


分割,本来设计的时1.2的板厚,结果没券了,只剩一张彩券,只能打1.6了,随便划拉两刀掰开打磨一下,顶板开槽,可以分割后作为屏幕保护框
测试阶段,使用了排针和排母连接,方便拆卸,右侧传感器*2,还有一个绿色PCB,代表曾经失败过一版...
失败原因比较逗逼,下载正常,无限重启,不开启I2C就正常,开启I2C就无限重启,但是下载后又能直接启动,只要重新上电就无限重启
重新打板还是无限重启,最后发现是因为没有接电池,4054供电不足,接上电池就正常工作了

然后又遇到取数异常,心率计算结果不准确,算不出血样,最后替换传感器正常,淘宝买的二手传感器坑壁
传感器焊接,为了降低整体厚度直接把传感器焊接到侧面了,学习苹果开创胶粘后盖,主打一个难为人

测试供电,骚紫色充电指示灯


成品展示
整体体积较小,和可乐瓶盖直径差不多,厚度微厚,主要是手里的铜柱就这么高,懒得打磨,不然可以再薄2mm
传感器使用705侧面密封,防止沾水腐蚀
测试效果,没啥UI,随便画了一下,心型本来是想按实际心率闪烁,最终落地显示手指效果,手指放上就显示,手指移开就不显示,HR是心率,O2是血氧
双击按钮切换显示内容,默认血氧数据,切换后显示心率波形,主要是开发阶段看数据状态的,长按关机


软件篇
整体使用arduino开发,偷懒直接用现成库,省的搞HAL来回折腾还得一直库
代码配合Baidu Comate开发,实际主要用了自动注释(公司要求保持AI辅助开发日用量...)
画电池
  1. /**
  2. * [url=home.php?mod=space&uid=650075]@brief[/url] 初始化电池显示
  3. *
  4. * 该函数用于初始化电池显示的界面。
  5. * 它清除指定的矩形区域,并绘制一个矩形框和一个矩形外框。
  6. */
  7. void initBat()
  8. {
  9.     clearBox(58, 8, 6, 24);
  10.     u8g2.drawBox(59, 8, 4, 2);
  11.     u8g2.drawFrame(58, 10, 6, 22);
  12. }
  13. /**
  14. * @brief 刷新电池状态
  15. *
  16. */
  17. void refreshBat(bool forceRefresh)
  18. {

  19.     static uint8_t old = 101;
  20.     if(forceRefresh){
  21.       old = 101;
  22.     }
  23.     // 电量检查
  24.     //(4.2/2)/(3.3/1024)=652
  25.     //  既adc=652时4.2v满电
  26.     uint32_t vBat, vMax, vMin, vSum;
  27.     vSum = vBat = vMax = vMin = analogRead(PB2);
  28.     for (int i = 0; i < 9; i++)
  29.     {
  30.         vBat = analogRead(PB2);
  31.         vSum += vBat;
  32.         if (vBat > vMax)
  33.             vMax = vBat;
  34.         if (vBat < vMin)
  35.             vMin = vBat;
  36.     }
  37.     vBat = ((vSum - vMax - vMin) >> 3) * 100 / 652;
  38.     if (vBat > 100)
  39.     {
  40.         vBat = 100;
  41.     }
  42.     // float f = 20.0 / 100 * vBat;
  43.     // vBat = (uint8_t)(ceil(f));
  44.     vBat = vBat / 5 + (vBat % 5 > 0 ? 1 : 0);
  45.     if (vBat != old)
  46.     {
  47.         old = vBat;

  48.         clearBox(59, 11, 4, 20 - vBat);
  49.         // 高度  20
  50.         u8g2.drawBox(59, 11 + 20 - vBat, 4, vBat);
  51.         u8g2.sendBuffer();
  52.     }
  53. }
复制代码

画心型
没有使用图片取模,直接线条画的
  1. /**
  2. * @brief 刷新心形图案
  3. *
  4. * 根据给定的显示标志,刷新心形图案的显示或清除。
  5. *
  6. * @param show 是否显示心形图案,true 为显示,false 为清除
  7. */
  8. void refreshHeart(bool show)
  9. {
  10.     static bool old = false;
  11.     if (show != old)
  12.     {
  13.         old = show;

  14.         if (show)
  15.         {
  16.             //    58 59 60 61 62 63
  17.             u8g2.drawPixel(59, 0);
  18.             u8g2.drawPixel(62, 0);
  19.             u8g2.drawLine(58, 1, 63, 1);
  20.             u8g2.drawLine(58, 2, 63, 2);
  21.             u8g2.drawLine(59, 3, 62, 3);
  22.             u8g2.drawLine(60, 4, 61, 4);
  23.             u8g2.sendBuffer();
  24.         }
  25.         else
  26.         {
  27.             clearBox(58, 0, 6, 5);
  28.         }
  29.     }
  30. }
复制代码

画波形
64像素的屏幕直接从缓冲区取64个值,高度压缩到屏幕高度
  1. void drawChart()
  2. {
  3.     u8g2.clearBuffer();
  4.     uint32_t max, min;
  5.     max = min = irBuffer[0];
  6.     for (int i = 1; i < 64; i++)
  7.     {
  8.         if (irBuffer[i] > max)
  9.             max = irBuffer[i];
  10.         if (irBuffer[i] < min)
  11.             min = irBuffer[i];
  12.     }
  13.     uint8_t step = (max - min) / 32;
  14.     for (int i = 0; i < 64; i++)
  15.     {
  16.         u8g2.drawPixel(i, (irBuffer[i] - min) / step);
  17.     }
  18.     u8g2.sendBuffer();
  19. }
复制代码

启用传感器
传感器设置较多,没有仔细研究,主要就是LED亮度,采样频率,LED模式(红/红外/绿--max30105支持绿光)等
  1.     byte ledBrightness = 150;  //Options: 0=Off to 255=50mA
  2.     byte sampleAverage = 4;   //Options: 1, 2, 4, 8, 16, 32
  3.     byte ledMode = 2;         //Options: 1 = Red only, 2 = Red + IR, 3 = Red + IR + Green
  4.     byte sampleRate = 200;    //Options: 50, 100, 200, 400, 800, 1000, 1600, 3200
  5.     int pulseWidth = 411;     //Options: 69, 118, 215, 411
  6.     int adcRange = 16384;      //Options: 2048, 4096, 8192, 16384

  7.     particleSensor.setup(ledBrightness, sampleAverage, ledMode, sampleRate, pulseWidth, adcRange); // Configure sensor with these settings
复制代码


从传感器采集到红光和红外光的强度数值(传感器自动过滤环境光等干扰因素,但是无法完全屏蔽,所以使用时应尽量保持稳定,实际手握持强度无法保持高度稳定,会影响测量效果,这也是成品都用夹子外形的原因)
  1.   isPress = true;
  2.     // take 25 sets of samples before calculating the heart rate.
  3.     // for (uint16_t i = BUFFER_SIZE - FreqS * 2; i < BUFFER_SIZE; i++)
  4.     for (uint16_t i = 0; i < BUFFER_SIZE; i++)
  5.     {
  6.         while (particleSensor.available() == false) // do we have new data?
  7.             particleSensor.check();                 // Check the sensor for new data
  8.         redBuffer[i] = particleSensor.getFIFORed();
  9.         irBuffer[i] = particleSensor.getFIFOIR();
  10.         particleSensor.nextSample(); // We're finished with this sample so move to next sample
  11.         button.tick();
  12.         if (irBuffer[BUFFER_SIZE - 1] < 25000)
  13.             isPress = false;
  14.     }
  15.     time = millis() - time;
  16. #ifdef ENABLE_OLED
  17.     refreshHeart(isPress);
  18. #endif
  19.     for (uint16_t i = 0; i < BUFFER_SIZE; i++)
  20.     // for (uint16_t i = BUFFER_SIZE - FreqS * 2; i < BUFFER_SIZE; i++)
  21.     {
  22.         // send samples and calculation result to terminal program through UART
  23.         log_debug("red:%d,ir:%d", redBuffer[i], irBuffer[i]);
  24.     }
  25.     if (isPress)
  26.         maxim_heart_rate_and_oxygen_saturation(irBuffer, BUFFER_SIZE, redBuffer, &spo2, &validSPO2, &heartRate, &validHeartRate);
复制代码


实际上在研究的时候看到gitee上有个开源的Python上位机,也测试了一下,直接串口输出采样数据
  1. void loop()
  2. {
  3.   button.tick();
  4.   while (particleSensor.available() == false)  //do we have new data?
  5.     particleSensor.check();                    //Check the sensor for new data
  6.   particleSensor.nextSample();                 //We're finished with this sample so move to next sample
  7.   log_debug("[DATA] R:%d,IR:%d,time:%d",particleSensor.getRed(),particleSensor.getIR(),millis());
  8. }
复制代码

上位机实时分析


相关文件
立创eda开源还得审核,也得编辑一波,懒得整了,直接把PCB文件上传gitee了,有需要的导入eda或者直接用geber上传打样就行


本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x

打赏

参与人数 4家元 +180 收起 理由
8139 + 30 謝謝分享
jf201006 + 30 原創內容
微笑的先生 + 30 专业高玩!
不长叶子的树 + 90

查看全部打赏

 楼主| 发表于 2024-9-11 17:11:40 | 显示全部楼层
论坛不支持markdown编辑有点小忧伤,为了防止页面刷新和网络等原因导致编辑失败内容丢失,现在都习惯了本地markdown编辑,然后上传,论坛只能粘贴后在全部样式重新调整
回复 支持 反对

使用道具 举报

发表于 2024-9-11 20:42:41 | 显示全部楼层
成品也不是很贵,自制的最大问题的壳子,成品一般都做成夹手指式,使用比较方便,尤其是做一段时间监测。
回复 支持 反对

使用道具 举报

发表于 2024-9-12 08:29:07 | 显示全部楼层
才买了一个led数码管的血氧仪,4.5元,过了一个星期,竟然降到3.9元包邮,这东西怎么挣钱的
回复 支持 反对

使用道具 举报

发表于 2024-9-12 09:28:53 | 显示全部楼层
谢谢分享,详细拆机技术贴
回复 支持 反对

使用道具 举报

发表于 2024-9-12 10:44:54 | 显示全部楼层
这个血氧传感器读出来的数据还需要校准啊?
回复 支持 反对

使用道具 举报

 楼主| 发表于 2024-9-12 13:19:33 | 显示全部楼层
sjtx1971 发表于 2024-9-12 08:29
才买了一个led数码管的血氧仪,4.5元,过了一个星期,竟然降到3.9元包邮,这东西怎么挣钱的 ...

估计是疫情时生产的现在清库存,这价格没啥好挣得了,也不是走量的大众货,就是一个让他挣两块也顶不住
回复 支持 反对

使用道具 举报

 楼主| 发表于 2024-9-12 13:21:49 | 显示全部楼层
mmxx2015 发表于 2024-9-11 20:42
成品也不是很贵,自制的最大问题的壳子,成品一般都做成夹手指式,使用比较方便,尤其是做一段时间监测。 ...

主要是夹子式的压力恒定,手持的压力不稳定,波动会比较大
回复 支持 反对

使用道具 举报

发表于 2024-9-12 17:02:22 | 显示全部楼层
大概看了一下,这个工作原理跟现在的手环监测血氧是同一个原理(好像叫反射式),而医用上用的都是用对射式的(发光管照射指甲盖,对应指纹部位接装接收管)

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复 支持 反对

使用道具 举报

发表于 2024-9-12 17:21:48 | 显示全部楼层
sjtx1971 发表于 2024-9-12 08:29
才买了一个led数码管的血氧仪,4.5元,过了一个星期,竟然降到3.9元包邮,这东西怎么挣钱的 ...

这么便宜?MAX30102都不止这个钱,所以一定不是MAX30102的
回复 支持 反对

使用道具 举报

发表于 2024-9-12 17:22:55 | 显示全部楼层
总是觉得MAX30102太难弄,之前有个这样的模块,不会玩转让了。
回复 支持 反对

使用道具 举报

发表于 2024-9-12 22:06:18 | 显示全部楼层
lmn2005 发表于 2024-9-12 17:21
这么便宜?MAX30102都不止这个钱,所以一定不是MAX30102的

没拆开,不知道什么型号的芯片,多多上买的,血氧精确度不知道,心跳还是挺准的,和我的血压计一样
回复 支持 反对

使用道具 举报

发表于 2024-9-12 23:24:46 | 显示全部楼层
就这么个简单microcontroller+传感器组合
疫情期间,最低100多,体温计也贵得离谱
回复 支持 反对

使用道具 举报

 楼主| 发表于 2024-9-13 08:55:52 | 显示全部楼层
lbys518 发表于 2024-9-12 17:02
大概看了一下,这个工作原理跟现在的手环监测血氧是同一个原理(好像叫反射式),而医用上用的都是用对射式 ...

对,我记得对射的精度更高点,但是分体的更麻烦,像手环类的只能用反射
回复 支持 反对

使用道具 举报

发表于 2024-9-13 10:51:08 | 显示全部楼层
sjtx1971 发表于 2024-9-12 22:06
没拆开,不知道什么型号的芯片,多多上买的,血氧精确度不知道,心跳还是挺准的,和我的血压计一样 ...

心跳应该比较容易准确些,因为脉冲很明显
回复 支持 反对

使用道具 举报

发表于 2024-9-15 10:50:44 | 显示全部楼层
lmn2005 发表于 2024-9-13 10:51
心跳应该比较容易准确些,因为脉冲很明显

应该是,血氧数值都是97.98,很少能达到99的,也没有对比,不知道是不是准确
回复 支持 反对

使用道具 举报

发表于 2024-9-18 11:24:43 | 显示全部楼层
如果不用CHRG那个IO,是不是用个STC8G1K08A就能完成了?
回复 支持 反对

使用道具 举报

 楼主| 发表于 2024-9-18 11:34:04 | 显示全部楼层
kindzhon 发表于 2024-9-18 11:24
如果不用CHRG那个IO,是不是用个STC8G1K08A就能完成了?

可以,那个是充电状态检测,实际没用
回复 支持 反对

使用道具 举报

发表于 2024-9-18 14:11:32 | 显示全部楼层
就是板材取的有点不美,其他的都好
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

APP|手机版|小黑屋|关于我们|联系我们|法律条款|技术知识分享平台

闽公网安备35020502000485号

闽ICP备2021002735号-2

GMT+8, 2024-10-11 02:17 , Processed in 0.265201 second(s), 13 queries , Redis On.

Powered by Discuz!

© 2006-2023 smzj.net

快速回复 返回顶部 返回列表