怕快樂缺氧?用 Arduino 開發板與 MAX30100 打造自己的 DIY 簡易脈搏血氧儀

Photo by Syed Ali on Unsplash

這是一篇很短的文,其實也不算創新,但最近剛好能派上用場。

簡而言之,在台灣於 2021 年 5 月爆發大規模社區感染後,有許多在家等待就醫的人因「快樂缺氧」(happy hypoxia)猝逝,也就是因肺部受感染後血氧濃度降低、但患者本身沒有明顯感覺,導致情況惡化就來不及了。也因為如此,人們開始搶購血氧機,甚至有醫生傳授若搶不到血氧機時該怎麼檢查是否隱性缺氧。

剛好我手上有個別人給的 MAX30100 脈搏血氧感測模組,趕快做了一個 DIY 血氧機,裝在一個名片盒裡面給我爸媽用。

由於 MAX30100 感測器(右下紅點)前面沒有東西,所以顯示的數據會怪怪的。

MAX30100 是加州 Maxim Integrated 公司製造的感測器晶片,藉由測量可見紅光和紅外線光在手指血管的吸收程度來測量脈搏(心律)及血氧濃度。你很容易在網路上找到以它為基礎製作的模組:

就算它的精確度可能不及正式的血氧儀,我們也不需要知道 1% 或 2% 的差別。若測出來數字掉到 90% 以下,自己卻覺得無異狀的話,這就能當成很有用的警訊。

材料

以下我假設你已經懂怎麼使用 Arduino 開發板製作創客裝置。這個簡易血氧儀只需要以下設備:

  • 一個 Arduino AVR 家族開發版:Uno、Nano、Micro、Leonardo 等皆可。
  • 一個 LCD 16x2 I2C 顯示模組(背後有 I2C 轉接板的 HD44780 螢幕,請參考這篇說明)
  • 一個 MAX30100 脈搏與血氧感測模組
  • 麵包板和杜邦線(除非你打算用線直接焊在板子腳位上)
  • (選擇性)一個 LED 和 220Ω 電阻

根據產品規格書,MAX30100、MAX30102 和 MAX30105 的通訊方式相同,因此理論上也可以用在這裡,但我手邊沒有材料來驗證。

較老的 Arduino 系列開發板在台灣仍然容易找到,而且另外兩個原件剛好都需要 5V 電源(MAX30100 理論上用 3.3V 也能跑,但測試發現在 5V 電源下運作才正常 — — 雖然正確來說 Arduino 接 USB 的實際輸出是 4.7V 左右),直接用 Arduino 就直接、便宜又方便。

我個人用的是以前在電子材料行買的 Arduino Pro micro,其實就是縮小型的 Leonardo。但使用不同 Arduino 板子時要注意 I2C 腳位會有不同:

  • Uno/Nano/Pro mini:SCL → A5,SDA → A4
  • Leonardo/Micro/Pro micro:SCL → 3,SDA → 2
  • Mega2560:SCL → 21,SDA → 20

LCD 和 MAX30100 電源(Vin/Vcc)都接 5V,GND 接 GND。此外本文的程式會用內建 LED(腳位 13)的閃動代表脈搏指示器,但我用的 Pro micro 剛好沒有,所以是外接了一個藍色 LED,這樣從盒子裡看也比較顯眼。

下圖以 Arduino Nano 為基礎示範接線(不含外接 LED):

程式

這裡使用的函式庫分別是:

在 Arduino IDE 的函式庫畫面搜尋它們和下載之,或者用上面的連結下載 .zip 和匯入。

這支程式其實就是以這兩個函式庫的範例程式為基礎組合而成。程式會根據你選擇的板子使用預設的 I2C 腳位,這部分就不必再設定,但注意有些 LCD 可能會有 I2C 位址 0x3f 而不是 0x27。而若你有外接 LED 的話,也記得更改常數 BEAT_LED 的腳位。

#include <Wire.h>
#include "MAX30100_PulseOximeter.h"
#include <LiquidCrystal_I2C.h>
#define REPORTING_PERIOD_MS 1000 // 數據顯示間隔 (毫秒)
#define BEAT_LED 13 // 脈搏指示 LED 的腳位
PulseOximeter pox;
uint32_t tsLastReport = 0;
LiquidCrystal_I2C lcd(0x27, 16, 2); // LCD I2C 位址和長寬void setup() {
pinMode(BEAT_LED, OUTPUT);
digitalWrite(BEAT_LED, LOW);
// 初始化 LCD
lcd.init();
lcd.backlight();
lcd.clear();
lcd.print("Arduino Oximeter");
delay(1000);
// 初始化 MAX30100, 若失敗就用無窮迴圈卡住
if (!pox.begin()) {
lcd.setCursor(0, 1);
lcd.print("Failed to init!");
while (true) {}
}
// 設定測到脈搏時要回呼的函式 (必須放在 setup 最後一行)
pox.setOnBeatDetectedCallback(onBeatDetected);
}
void loop() {
pox.update(); // 更新 MAX30100 讀數
// 每隔指定的時間讀一次讀數, 並顯示在 LCD 上
if (millis() - tsLastReport > REPORTING_PERIOD_MS) {
float bpm = pox.getHeartRate();
uint8_t spo2 = pox.getSpO2();
lcd.clear();
lcd.home();
lcd.print(" Bpm : " + String(bpm)); // 顯示脈搏 bpm
lcd.setCursor(0, 1);
lcd.print(" SpO2: " + String(spo2) + "%"); // 顯示血氧濃度
tsLastReport = millis();
}
}
void onBeatDetected() { // 點亮 LED 50 毫秒代表一次脈搏
pinMode(BEAT_LED, OUTPUT);
digitalWrite(BEAT_LED, HIGH);
delay(50);
digitalWrite(BEAT_LED, LOW);
}

我的版本裝在名片盒中,蓋住所有裸露的電子接點,只在 MAX30100 的讀取頭上挖個洞,並盡量固定杜邦線免得鬆脫。既然電源來自 USB 線,就能沿用手機充電器。

通電後,把食指按在紅燈上,等一段時間就能看到測出結果。理論上我也應該找個東西罩住手指上方,像市面上的血氧儀那樣,不過只要手沒有被強光照到就似乎沒明顯影響。

Photo by Dhaya Eddine Bentaleb on Unsplash

--

--

--

Technical writer, former translator and IT editor. My writing power is 100% generated by coffee.

Love podcasts or audiobooks? Learn on the go with our new app.

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Alan Wang

Alan Wang

Technical writer, former translator and IT editor. My writing power is 100% generated by coffee.

More from Medium

UWP Windows 通用Windows平台開發

SIMULINK

What problems does Corda Blockchain want to solve?and its key features

Top 5 Windows Events for Incident Response