Sensor Degupan Jantung Arduino: Pulse Sensor & MAX30102

Cartoon of a blue Arduino Uno wired to a purple MAX3010x module on a white mini breadboard, beside a round black pulse sensor with yellow, red and black leads resting on a fingertip

Kedua-dua sensor dalam panduan ini mengukur cahaya, bukan degupan jantung. Sebiji LED menyinar masuk ke dalam hujung jari anda, satu pengesan membaca cahaya yang kembali, dan setiap angka BPM dikira daripada masa antara naik-turun paras cahaya itu. Pulse sensor analog memplotkannya pada Uno dalam lima minit tanpa sebarang library — kuning ke A0, merah ke 5 V, hitam ke GND, kemudian analogRead() terus ke Serial Plotter. Modul MAX3010x ambil masa lebih lama: headernya kena disolder dahulu, dan satu bacaan register perlu dibuat sebelum anda pasang mana-mana library.

Adakah semua ini alat perubatan?

Tidak. Pulse sensor dan modul MAX3010x ialah komponen hobi dan projek pameran sains, bukan alat perubatan. Kedua-duanya tidak tepat dari segi perubatan, kedua-duanya tidak diperakui, dan tiada satu pun angka yang dikeluarkannya boleh digunakan untuk mendiagnos apa-apa, memantau sebarang keadaan kesihatan, atau membuat keputusan tentang kesihatan sesiapa. Kalau ada kebimbangan tentang kesihatan, jumpa doktor — bukan Arduino.

Anggap setiap angka yang keluar daripada binaan ini sebagai demonstrasi satu prinsip optik. Itu bukan penafian, itulah memang kerja yang dibuat oleh hardware ini, seperti yang diterangkan sepanjang panduan ini. Peratusan oksigen dalam darah lebih-lebih lagi: angka SpO₂ yang boleh dipertahankan memerlukan nisbah serapan merah-ke-inframerah yang dikalibrasi dan disahkan terhadap peralatan yang diperakui, jadi tunjukkan kadar degupan jantung dan bentuk gelombang mentah, dan nyatakan perkara itu dalam laporan anda. Keselamatan hardware pula pendek sahaja: DC voltan rendah daripada kabel USB, jangan dekati bekalan elektrik rumah, VIN pada 5 V atau 3.3 V sahaja, dan wayar MERAH pulse sensor pada rel 5 V atau 3.3 V dan tiada tempat lain.

Apa sebenarnya yang dibaca oleh “sensor kadar degupan jantung”?

Pulse sensor dan MAX3010x kedua-duanya menjalankan fotopletismografi, satu perkataan panjang untuk satu helah yang mudah. LED menolak cahaya masuk ke dalam hujung jari anda; kebanyakannya diserap dan diserakkan, dan sedikit sahaja yang kembali mengenai photodiode. Setiap degupan jantung mengembangkan arteri dalam tisu itu, jadi lebih banyak cahaya diserap dan sedikit kurang yang keluar semula.

Riak itu cuma sekitar satu peratus daripada paras cahaya tetap di bawahnya, jadi board pulse sensor bulat hitam itu sebenarnya bukan sensor semata-mata: chip di atasnya ialah amplifier yang membuang bahagian tetap tadi dan membesarkan apa yang tinggal. Dua perintang surface-mount menentukan sebesar mana hasilnya keluar — satu membekalkan LED, satu lagi membebankan pengesan. Riak yang telah dibesarkan perlu berayun ke bawah dan juga ke atas, jadi board itu meletakkan outputnya pada separuh voltan bekalan dan menumpangkan degupan di atas paras tersebut — sebab itulah A0 nampak voltan berhampiran pertengahan skala, analogRead() lebih kurang 512 pada board 5 V, dengan satu bonjolan setiap kali jantung berdegup, bukannya bacaan yang bermula dari sifar.

Tiada apa-apa dalam isyarat itu yang merupakan angka degupan seminit. BPM ialah tekaan yang dibuat oleh kod anda dengan mengukur jarak masa antara dua bonjolan dan membahagikan 60 000 ms dengannya — sebab itulah graf didahulukan sebelum angka di bawah nanti, dan sebab itulah bacaan jadi merepek sebaik sahaja jari anda beralih, kerana gerakan kecil buku jari pun menghasilkan bonjolan yang kod tak dapat bezakan daripada degupan jantung.

Kartun keratan rentas hujung jari dengan LED merah menyinar ke dalam tisu dan pengesan menangkap cahaya yang kembali, di sebelah bentuk gelombang nadi berwarna teal
Cahaya masuk, kurang cahaya keluar. Degupan jantung tak pernah diukur secara terus — ia cuma riak kecil yang menumpang di atas paras cahaya tetap yang jauh lebih besar.

Pilihan — dua benda yang membuang bahagian susah

ItemPriceQty
Soldering Service for Circuit Boards & Electronics - 5 Pins Soldering ServiceSoldering Service for Circuit Boards & Electronics - 5 Pins Soldering ServiceSOLSE05RM0.80
XL830L Digital Multimeter with backlight Portable Multimeter Electronics ProjectXL830L Digital Multimeter with backlight Portable Multimeter Electronics ProjectMULTIMERM25.95

Servis solder ini meliputi tepat lima pin, iaitu tepat seperti yang diperlukan oleh modul MAX3010x; ia perlu rundingan dahulu, jadi WhatsApp kami sebelum memasukkannya ke dalam troli. Langkau multimeter kalau anda sudah ada satu — ia disenaraikan kerana satu bacaan pada SDA sahaja sudah menjadi keseluruhan diagnosis dalam bahagian I2C di bawah.

Macam mana kedua-dua sensor boleh berkongsi satu Arduino Uno?

Pulse sensor ialah bahagian yang senang: tiga wayarnya masing-masing berakhir dengan plug satu-pin tersendiri yang berhujung pin male, dan header pada Uno pula socket female, jadi ia boleh dicucuk terus. MAX3010x pula bahagian yang menyusahkan — lima lubang berlapis yang masih kosong dan satu jalur header lima-pin yang longgar dalam beg, dan setelah header itu disolder, modul ini ada lima pin male dalam satu baris lurus sedangkan empat pin Uno yang diperlukannya duduk pada dua header berbeza. Jadi ia tak boleh dicucuk terus ke Uno; ia mesti diwayarkan. Dan wayar dari pin male modul ke socket female Uno mesti female di satu hujung dan male di hujung satu lagi.

Mini breadboard 170-titik menyelesaikan hal itu, sambil membuat satu lagi kerja. Lubangnya female, jadi pin modul boleh dicucuk masuk dan jumper male-to-male biasa membawa empat sambungan itu terus ke socket female Uno — setiap wayar dapat jenis hujung yang betul di kedua-dua belah. Ia tiada power rail — cuma baris lubang di kiri dan kanan satu alur tengah — dan itu tak jadi masalah di sini, kerana setiap baris ialah lima lubang yang disatukan oleh satu klip logam di bawahnya. Cucuk lima pin modul ke dalam lima baris bersebelahan dan setiap pin akan memiliki empat lubang lebih, jadi baris yang memegang VIN menjadi simpang 5 V anda: cucuk plug MERAH pulse sensor ke dalam salah satu lubang kosong pada baris itu, tarik satu jumper M-M dari lubang lain ke pin 5 V Uno, dan dua komponen berkongsi satu pin bekalan.

Komponen Wayar atau pin Pergi ke
Pulse sensor KUNING (S) A0 Uno — terus masuk ke dalam socket
Pulse sensor MERAH (+) Lubang kosong pada baris breadboard yang memegang VIN modul
Pulse sensor HITAM (−) GND Uno pada header POWER — terus cucuk
MAX3010x VIN Jumper dari baris itu ke 5V Uno
MAX3010x GND Jumper ke pin GND Uno di sebelah D13
MAX3010x SCL Jumper ke A5 Uno
MAX3010x SDA Jumper ke A4 Uno
MAX3010x INT Biarkan tidak bersambung

Kedua-dua sensor boleh duduk pada Uno serentak kerana masing-masing menggunakan pin yang berbeza — satu input analog berbanding bas dua-wayar pada A4 dan A5 — sebab itulah ini satu binaan, bukan dua. Wayarkan kedua-duanya sekali sahaja, kemudian tukar-tukar sketch; setiap sketch di bawah memandu satu sensor. (Pin bertanda SDA dan SCL di hujung kiri sekali header digital itu ialah dua pin yang sama, disatukan di dalam board — guna mana-mana pasangan.) VIN menerima 5 V walaupun die di dalamnya berjalan pada 1.8 V, kerana modul ini membawa rangkaian regulatornya sendiri: VIN membekalkan satu regulator 3.3 V, dan output regulator itu pula membekalkan satu regulator 1.8 V untuk chip. Sebab itulah pin tersebut dinamakan VIN dan bukan VCC, dan sebab itulah mana-mana rel Uno sendiri boleh digunakan — 3.3 V atau 5 V, dan tiada apa-apa yang lebih tinggi daripada itu. Segala-galanya selepas VIN ialah regulator kecil atas board yang bersaiz untuk voltan logik, jadi bekalan 9 V atau 12 V tempatnya pada barrel jack Uno, bukan pada pin ini.

Kartun close-up board sensor MAX3010x ungu yang kecil dengan lima lubang solder perak yang masih kosong, di sebelah jalur header lima-pin hitam yang longgar dan sebatang besi solder
Apa yang sebenarnya ada dalam beg: breakout MAX3010x ungu dengan lima lubang berlapis yang masih kosong, dan satu jalur header lima-pin longgar yang seseorang kena solder.

Menyolder lima pin ialah kerja lima belas minit — panduan solder header pin kami menyusuri baris itu satu per satu, dan helahnya ialah tegakkan header dalam breadboard dahulu supaya board duduk rata semasa anda mencantum pin pertama. Satu bahaya yang betul-betul nyata: hujung besi solder berhampiran 350 °C melecurkan kulit sebelum anda sempat terasa, jadi guna permukaan tahan haba, letak besi solder dalam pemegangnya, dan buka tingkap untuk asap flux. Atau servis solder 5-pin menguruskan lima pin ini untuk anda. Gerakannya berbaloi ditonton:

MAX3010x yang mana sebenarnya ada pada board anda?

Keluarga MAX3010x berkongsi satu susun atur breakout yang sama, dan di sinilah kebanyakan projek tersekat. Nama GY merujuk kepada satu bentuk board — segi empat ungu yang sama, lima pad yang sama, cetakan yang sama — jadi laminat itu memberitahu anda board mana yang anda pegang, bukan die mana yang terikat di dalam pakej optik hitam tersebut. Anda tak boleh pastikannya dengan melihat sahaja, sebab itulah Maxim meletakkan satu register identiti di dalam silikonnya.

Register 0xFF ialah identiti itu, dan ia baca-sahaja. Peta register datasheet MAX30105 daripada Maxim menyenaraikan 0xFF sebagai PART_ID dengan nilai 0x15, dan library SparkFun — ditulis untuk MAX30102 dan MAX30105 sekali gus — melayan kedua-duanya sebagai komponen yang sama; MAX30100 yang lebih lama menjawab 0x11, iaitu nilai yang di-hard-code oleh library MAX30100 oxullo sebagai ID yang dijangkanya. Seluruh keluarga ini menjawab pada alamat 7-bit 0x57: datasheet menyebut alamat tulis 0xAE dan alamat baca 0xAF, dan bit paling rendah ialah penanda baca/tulis, jadi 0xAE yang dianjak ke kanan sebanyak satu memberikan 0x57 yang dijangka oleh library Wire Arduino.

Ini penting kerana kedua-dua library menolak die yang salah, kemudian menyalahkan wiring anda pula. begin() SparkFun memulangkan false kalau ID bukan 0x15; yang oxullo pula buat perkara sama, terhadap 0x11. Contoh-contoh mereka sendiri memang menguji boolean itu, tetapi mesej yang anda dapat cumalah MAX30105 was not found. Please check wiring/power. daripada SparkFun atau FAILED kosong daripada oxullo — kedua-duanya menghantar anda balik kepada jumper yang memang tak pernah jadi punca. Jalankan yang ini dahulu:

// Yang mana satu MAX3010x sebenarnya ada pada breakout anda?
// Wiring: VIN -> 5V Uno, GND -> GND, SCL -> A5, SDA -> A4.
#include <Wire.h>

const uint8_t MAX3010X_ADDR   = 0x57;   // seluruh keluarga ini menjawab di sini
const uint8_t REG_REVISION_ID = 0xFE;
const uint8_t REG_PART_ID     = 0xFF;

bool readReg(uint8_t reg, uint8_t &value) {
  Wire.beginTransmission(MAX3010X_ADDR);
  Wire.write(reg);
  if (Wire.endTransmission(false) != 0) return false;   // repeated start, tiada stop
  if (Wire.requestFrom(MAX3010X_ADDR, (uint8_t)1) != 1) return false;
  value = Wire.read();
  return true;
}

void setup() {
  Serial.begin(115200);
  while (!Serial) { }
  Wire.begin();

  Serial.println(F("Mengimbas bas I2C..."));
  uint8_t found = 0;
  for (uint8_t addr = 1; addr < 127; addr++) {
    Wire.beginTransmission(addr);
    if (Wire.endTransmission() == 0) {
      Serial.print(F("  peranti menjawab pada 0x"));
      Serial.println(addr, HEX);
      found++;
    }
  }
  if (found == 0) {
    Serial.println(F("Tiada apa-apa menjawab. Betulkan bas dahulu sebelum pasang mana-mana library."));
    return;
  }

  uint8_t part = 0, rev = 0;
  if (!readReg(REG_PART_ID, part) || !readReg(REG_REVISION_ID, rev)) {
    Serial.println(F("0x57 menjawab imbasan tetapi bacaan ID gagal."));
    return;
  }

  Serial.print(F("Part ID 0x"));
  Serial.print(part, HEX);
  Serial.print(F(", revision 0x"));
  Serial.println(rev, HEX);

  if (part == 0x11) {
    Serial.println(F("-> MAX30100. Pasang MAX30100lib oleh OXullo Intersecans."));
  } else if (part == 0x15) {
    Serial.println(F("-> MAX30102 atau MAX30105. Pasang SparkFun MAX3010x."));
  } else {
    Serial.println(F("-> Bukan part ID MAX3010x."));
  }
}

void loop() { }

Kemudian pasang satu sahaja: MAX30100lib oleh OXullo Intersecans untuk 0x11, atau SparkFun MAX3010x Pulse and Proximity Sensor Library untuk 0x15. Taip nama penuhnya — carian “MAX30” memulangkan satu skrin penuh entri, kebanyakannya fork yang nama class-nya takkan padan dengan contoh kod yang anda jumpa. Panduan MPU6050 kami juga bermula dengan imbasan bas yang sama.

Kenapa imbasan I2C tak jumpa apa-apa walaupun setiap wayar betul?

I2C ialah bas open-drain, dan satu fakta itu sahaja menjelaskan satu kegagalan yang boleh menelan waktu petang anda. Datasheet ATmega328P sendiri menyebut: “A high level is output when all TWI devices tri-state their outputs, allowing the pull-up resistors to pull the line high.” Tiada apa-apa yang memacu talian itu ke paras tinggi; peranti cuma menariknya ke bawah atau melepaskannya. Jadi paras tinggi itu bukan 5 V Uno — ia rel mana sahaja yang menjadi tempat perintang pull-up itu diikat.

Pada breakout ini, perintang pull-up 4.7 kΩ untuk SDA, SCL dan INT duduk pada salah satu rel dalaman modul itu sendiri, dan yang mana satu bergantung pada revisi board. Satu batch yang banyak dilaporkan, didokumenkan oleh Reed Paper, mengikatnya pada 1.8 V: “They are connected to the supply + 1.8V!!! If such a module is connected to a 5V logic of Arduino board – it will not be visible on the I2C bus because the logic levels are too low.”

Kiraannya menunjukkan hal itu memang berlaku. Wire.begin() menghidupkan pull-up dalaman ATmega pada A4 dan A5 — dua baris di dalam core yang disertakan, digitalWrite(SDA, 1); digitalWrite(SCL, 1); — dan datasheet ATmega328P menilainya pada 20–50 kΩ. Salah satu daripadanya dari 5 V melawan 4.7 kΩ modul yang menuju ke 1.8 V meninggalkan talian tersebut pada satu titik pembahagi voltan: dengan 50 kΩ yang paling lemah, beza 3.2 V merentasi 54.7 kΩ menolak 58 µA, yang mengangkat nod itu 0.28 V di atas 1.8 V, jadi ia berehat berhampiran 2.1 V; dengan 20 kΩ yang paling kuat pula, lebih kurang 2.4 V.

Hujung penerima yang menentukan segalanya. Datasheet yang sama meletakkan ambang input-tinggi ATmega328P pada 0.6 × VCC untuk I/O biasa dan 0.7 × VCC yang lebih ketat dalam jadual bas dua-wayarnya — 3.0 V dan 3.5 V pada Uno 5 V. Talian pada 2.1 V tak sampai kepada mana-mana satu pun, jadi Uno membaca logik rendah yang berkekalan, tiada apa-apa yang mengaku terima, dan imbasan seluruh ruang alamat melaporkan kosong: tiada ralat, tiada timeout, wiring sempurna. Malah revisi 3.3 V pun duduk di bawah angka 3.5 V itu, sebab itulah modul yang sama menjadi untuk seorang dan tidak menjadi untuk seorang lagi.

Kartun multimeter bersarung oren dengan probe merah dan hitam mengukur voltan idle pada wayar jumper di modul MAX3010x ungu yang duduk pada mini breadboard putih
Tiga puluh saat dengan meter lebih baik daripada sejam mencabut dan mencucuk semula jumper: uji SDA berbanding ground semasa board berkuasa, dan baca paras idle-nya.

Itu menukar satu petang yang hilang kepada satu ukuran sahaja. Biarkan sketch pengimbas tadi kekal di dalam board dan berjalan, supaya pull-up Uno sendiri hidup, kemudian multimeter pada mod volt DC, probe hitam pada GND dan probe merah pada jumper SDA — panduan multimeter kami menerangkan bahagian dailnya. Tiga bacaan, tiga jawapan berbeza. Hampir 5 V bermakna tiada apa-apa pada modul itu yang menarik talian tersebut ke bawah — pada breakout yang memang membawa pull-up 4.7 kΩ sendiri, itu menunjuk kepada sambungan, bukan kepada paras logik: VIN tak berkuasa, sambungan solder kering, atau jumper yang tersasar satu baris. Sekitar 3.3 hingga 3.5 V pula ialah revisi yang baik, ditarik naik ke rel 3.3 V modul itu sendiri — melepasi angka 0.6 × VCC tetapi tersangkut sedikit di bawah 3.5 V yang dikehendaki oleh jadual dua-wayar, sebab itulah board sebegini kebanyakan masa menjadi dan sesekali merajuk; di situ host dengan logik 3.3 V seperti ESP32 menamatkan pertikaian (lihat perbandingan board kami), dan kalau imbasan masih tak jumpa apa-apa pada paras itu, pandang kepada kuasa dan solder, bukan kepada logik. Sekitar 2 V pula ialah revisi dengan rel 1.8 V, dan di situ satu-satunya jalan yang jujur ialah pengubahsuaian terdokumen yang memindahkan pull-up itu ke 3.3 V — kerja halus di bawah kanta pembesar, bukan kerja solder kali pertama — kerana datasheet ESP32 meletakkan ambang tingginya sendiri pada 0.75 × 3.3 V, lebih kurang 2.5 V, yang juga tak dilepasi oleh 2 V.

Apa yang anda tidak patut buat ialah penyelesaian popular menggantung satu lagi pull-up ke 5 V. Pin chip itu memang tahan — datasheet menilai “All Other Pins to GND”, iaitu tempat duduknya SDA dan SCL, pada −0.3 V hingga +6.0 V — tetapi perintang 4.7 kΩ modul itu sendiri masih duduk pada rel dalaman tadi, jadi 4.7 kΩ kedua ke 5 V cuma mengangkat talian itu ke lebih kurang 3.4 V sambil menolak kira-kira 340 µA ke belakang masuk ke dalam output regulator yang boleh membekal tetapi tidak boleh menyerap arus. Maksimum mutlak VDD ialah +2.2 V.

Macam mana nak dapat bentuk gelombang, kemudian angka?

Pulse sensor memberi hasil pada upload yang pertama, sebab itulah ia sesuai untuk projek yang ada tarikh akhir. Satu perkara sebelum anda menyentuhnya: jari diletakkan pada muka optiknya, bukan sebelah yang anda nampak dalam gambar produk kami — sebelah itu membawa komponen dan tiga titik solder, jadi tampal sekeping pita penebat di atasnya dahulu. Hujung jari yang lembap merentasi sambungan solder yang terdedah itulah punca amplifier kecil ini mati. Kemudian upload yang ini, buka Tools → Serial Plotter pada 115200 dan letakkan hujung jari pada board bulat itu dengan tekanan lembut yang tetap — cukup kemas supaya tak tergelincir, cukup ringan supaya darah tak terperah keluar:

// Pulse sensor: bentuk gelombang PPG mentah, untuk Serial Plotter Arduino IDE.
// Wiring pada modul ini: KUNING -> A0, MERAH -> 5V, HITAM -> GND. Tiada library.
// Ini demonstrasi isyarat optik, bukan pengukuran perubatan.

const uint8_t PPG_PIN = A0;
const unsigned long SAMPLE_US = 10000UL;   // 10 ms antara sampel = 100 Hz

void setup() {
  Serial.begin(115200);
}

void loop() {
  static unsigned long lastSample = 0;
  if (micros() - lastSample < SAMPLE_US) return;   // kekalkan kadar pensampelan supaya tetap
  lastSample += SAMPLE_US;

  Serial.println(analogRead(PPG_PIN));   // 0..1023; berehat berhampiran 512 pada Uno 5 V
}

Angka 100 Hz itu dipilih, bukan diteka. Jantung yang berehat berdegup berhampiran 1 Hz, tetapi lonjakan tajam dan takuk kecil selepas setiap degupan membawa perincian sehingga kira-kira 10 Hz, jadi 100 sampel sesaat meletakkan lebih kurang sepuluh titik merentasi setiap kitaran komponen terpantas itu — dan ia murah, kerana baud 115200 memindahkan kira-kira 11 520 bait sesaat berbanding lebih kurang 600 bait yang diperlukan oleh seratus baris pendek tadi.

Menukar surihan itu menjadi BPM memerlukan satu idea lagi. Pencetus yang tetap tak menjadi kerana paras rehatnya hanyut mengikut tekanan dan kulit, jadi sketch di bawah menjejak bacaan tertinggi dan terendah dalam dua saat terakhir dan mencetus pada paras 60 % naik dalam julat ayunan yang sedang dihasilkan oleh jari anda. Tempoh sekatan 300 ms menghadkannya pada 200 BPM supaya satu tepi yang bising tak dikira dua kali; jurang melebihi 2000 ms pula dianggap sebagai permulaan semula. Ingatan itu ada harganya, dan lebih baik anda jangkakan daripada terpaksa debug: sejurus selepas setiap set semula dua saat, julat ayunan perlu dibina semula sebelum sesuatu degupan boleh melepasi ambang, jadi sekali-sekala satu degupan tak dikira dan baris berikutnya mencetak kira-kira separuh daripada kadar sebenar anda. Baca rentetan angka yang sepadan antara satu sama lain, jangan sesekali percaya satu baris.

// Pulse sensor: menukar bentuk gelombang itu menjadi angka BPM.
// KUNING -> A0, MERAH -> 5V, HITAM -> GND. Tiada library. Serial Monitor pada 115200.
// Demonstrasi prinsip optik. Bukan pengukuran perubatan.

const uint8_t      PPG_PIN        = A0;
const unsigned long SAMPLE_US     = 10000UL;  // 100 sampel sesaat
const unsigned long WINDOW_MS     = 2000UL;   // berapa lama nilai ekstrem diingati
const unsigned long REFRACTORY_MS = 300UL;    // abaikan apa-apa melebihi 200 BPM
const unsigned long SLOWEST_MS    = 2000UL;   // bawah 30 BPM: anggap sebagai permulaan semula
const int           MIN_SWING     = 20;       // unit ADC; bawah ini, tiada jari

int  hi = 0, lo = 1023;
unsigned long windowStart = 0;
unsigned long lastBeat = 0;
bool above = false;

void setup() {
  Serial.begin(115200);
}

void loop() {
  static unsigned long lastSample = 0;
  if (micros() - lastSample < SAMPLE_US) return;
  lastSample += SAMPLE_US;

  int reading = analogRead(PPG_PIN);
  unsigned long now = millis();

  if (reading > hi) hi = reading;
  if (reading < lo) lo = reading;

  // Paras pencetus bukan pemalar. Ia duduk pada 60 % naik dalam julat ayunan
  // yang sedang dihasilkan oleh jari ini, jadi ia tahan paras DC yang hanyut.
  int span = hi - lo;
  int threshold = lo + (span * 3) / 5;

  if (span >= MIN_SWING && reading > threshold && !above &&
      now - lastBeat > REFRACTORY_MS) {
    above = true;
    unsigned long interval = now - lastBeat;
    bool firstEver = (lastBeat == 0);   // tiada apa-apa untuk mengukur degupan pertama
    lastBeat = now;
    if (!firstEver && interval < SLOWEST_MS) {
      Serial.print(F("degupan: "));
      Serial.print(interval);
      Serial.print(F(" ms sejak yang sebelumnya -> "));
      Serial.print(60000UL / interval);
      Serial.println(F(" BPM (demo sahaja)"));
    }
  }
  if (reading < threshold) above = false;   // sedia untuk lintasan menaik seterusnya

  // Lupakan nilai ekstrem lama, kalau tidak satu gerakan tersasar menetapkan aras sepanjang sesi.
  if (now - windowStart > WINDOW_MS) {
    windowStart = now;
    hi = reading;
    lo = reading;
  }
}

Tekanan jari ialah satu bahagian yang tiada siapa dapat betulkan hanya daripada penerangan bertulis, jadi ia berbaloi ditonton:

Kesilapan biasa yang kami nampak daripada pelanggan sebenar

Memasang library sebelum menyemak part ID. Sketch itu compile, upload, kemudian mengumumkan bahawa sensor tak dijumpai — sila semak wiring dan kuasa. Jadi satu jam berikutnya habis pada wiring yang sememangnya sudah betul. begin() membaca register 0xFF, tak berkenan dengan jawapannya, dan tiada cara untuk memberitahu anda hal itu. Baca ID dahulu.

Menyemak semula wiring selama sejam sedangkan wiring memang bukan puncanya. Imbasan yang senyap terasa persis seperti jumper longgar, jadi orang mencabut dan mencucuk semula segalanya berulang kali. Satu bacaan meter menyelesaikannya, dan ia juga menangkap punca senyap yang satu lagi: pad yang nampak macam sudah disolder tetapi menyembunyikan sambungan solder sejuk.

Mengejar BPM yang stabil sedangkan jari sedang bergerak. Surihan itu ialah paras cahaya, jadi jari yang beralih ialah isyarat yang benar-benar wujud dan memang tak dapat dibezakan daripada satu degupan. Letakkan tangan anda di atas meja dan baca angka hanya selepas plotter kelihatan sekata.

Membina projek berpaksikan peratusan SpO₂. Bacaan yang nampak munasabah itulah perangkapnya. Bina demonstrasi itu berpaksikan kadar degupan jantung dan bentuk gelombang, anggap mana-mana angka oksigen sebagai eksperimen yang belum disahkan dan nyatakan hal itu — itu memang penyertaan pameran sains yang lebih kukuh pun. Halaman idea projek RBT kami ada lebih banyak binaan yang mendapat markah baik daripada hakim.

Soalan lazim

Bolehkah modul MAX30102 mengukur oksigen dalam darah saya dengan tepat?

Tidak. Ia breakout hobi, bukan alat perubatan, dan tiada apa-apa yang dicetaknya boleh digunakan untuk menilai kesihatan sesiapa. Angka SpO₂ yang boleh dipertahankan memerlukan nisbah serapan merah-ke-inframerah yang dikalibrasi dan disahkan terhadap peralatan yang diperakui. Tunjukkan kadar degupan jantung dan bentuk gelombang mentah sebaliknya.

Kenapa pengimbas I2C saya tak jumpa apa-apa sedangkan wiring betul?

I2C tak pernah memacu talian itu ke paras tinggi — perintang pull-up yang buat kerja itu, jadi paras tinggi ialah rel tempat perintang tersebut diikat. Pada revisi breakout ini yang menggunakan rel rendah, bas idle berhampiran 2 V, sedangkan Arduino Uno 5 V memerlukan sekurang-kurangnya 3.0 V untuk mengira sesuatu sebagai tinggi, jadi ia membaca logik rendah yang berkekalan dan melaporkan kosong. Ukur SDA berbanding GND untuk mengesahkannya.

Library Arduino mana yang saya patut pasang untuk sensor ini?

Baca register 0xFF dahulu. 0x11 bermakna MAX30100 — pasang MAX30100lib oleh OXullo Intersecans. 0x15 bermakna MAX30102 atau MAX30105 — pasang SparkFun MAX3010x Pulse and Proximity Sensor Library. Kedua-duanya menolak die yang salah dan melaporkannya sebagai masalah wiring.

Adakah modul MAX3010x datang dengan headernya sudah disolder?

Tidak — ia dihantar dengan lima lubang berlapis yang masih kosong dan satu jalur header lima-pin yang longgar. Solder lima sambungan itu sendiri, atau tambah servis solder 5-pin kami, yang perlu rundingan dahulu: WhatsApp kami sebelum memasukkannya ke dalam troli.

Bolehkah saya jalankan kedua-dua sensor pada satu Arduino Uno serentak?

Boleh. Pulse sensor menggunakan satu input analog dan MAX3010x menggunakan A4 dan A5, jadi kedua-duanya tak pernah berlanggar. Kongsi 5 V dan GND melalui mini breadboard dan kedua-duanya berjalan dengan satu kabel USB.

Kemas kini terakhir Ogos 2026. Tersangkut? Chat dengan kami di WhatsApp.

Leave a Reply

Your email address will not be published. Required fields are marked *