MAX30100 Arduino : Capteur SpO2 et Rythme Cardiaque DIY
Comprendre la photopléthysmographie, l'absorption infrarouge de l'hémoglobine, le calcul du SpO2 par ratio R/IR et programmer un oxymètre de pouls Arduino avec MAX30100 — guide technique complet incluant projet PFE et comparaison avec le MAX30102.
Mars 2020. Pendant que le monde entier se ruait sur les masques chirurgicaux, dans les laboratoires d’instrumentation biomédicale de l’ISBS et de l’ENIT, des étudiants en PFE se sont concentrés sur un autre objet devenu soudainement vital : l’oxymètre de pouls. Cette pince à doigt anodine qui mesure la saturation en oxygène du sang est passée du statut d’accessoire médical méconnu à celui d’instrument grand public. Le composant clé de la majorité de ces appareils — y compris les smartwatches Apple Watch et Galaxy Watch — c’est un minuscule capteur SMD de 5,6 × 2,8 mm signé Maxim Integrated : le MAX30100.
Cinq ans plus tard, ce capteur reste l’un des composants pédagogiques les plus fascinants à manipuler. Il condense en quelques millimètres carrés un siècle de physique optique appliquée à la biologie, deux LEDs spectralement précises, un photodétecteur ultra-sensible, et toute une chaîne de traitement analogique-numérique intégrée. Pour 12 à 20 DT chez Didactico Sfax, vous tenez dans la main une technologie qui valait des dizaines de milliers de dollars dans les années 1970.
Le MAX30100 est un capteur pédagogique et de recherche, NON certifié dispositif médical (pas de marquage CE médical, pas d’agrément FDA). Les mesures qu’il produit ne doivent JAMAIS servir au diagnostic clinique, au suivi de patients hospitalisés ou à toute décision thérapeutique. Pour un usage médical, utilisez exclusivement un oxymètre homologué (norme ISO 80601-2-61). Ce guide vise l’apprentissage de la photopléthysmographie et le prototypage de projets éducatifs.
📋 Table
- La photopléthysmographie : voir le pouls avec de la lumière
- Pourquoi deux longueurs d’onde : 660 nm et 880 nm
- Le ratio R/IR et le calcul du SpO2
- Le MAX30100 en pratique : matériel et brochage
- Communication I2C et initialisation
- Code Arduino avec la librairie oxullo
- Traitement du signal : moyenne mobile et détection de pic
- Affichage sur écran OLED SSD1306
- MAX30100 vs MAX30102 : lequel choisir ?
- Projet PFE : oxymètre portable LiPo avec alerte SpO2
- FAQ
La photopléthysmographie : voir le pouls avec de la lumière
Posez votre doigt contre une LED rouge puissante dans le noir. Vous verrez la lumière traverser votre doigt et ressortir orangée — c’est votre sang qui filtre la lumière. C’est exactement le principe de la photopléthysmographie (abrégée PPG) découvert dans les années 1930. À chaque battement cardiaque, le ventricule gauche éjecte un volume de sang dans les artères. Cette pulsation arrive à vos extrémités (doigt, lobe d’oreille) et fait varier le volume sanguin capillaire au rythme du pouls.
Or, le sang absorbe la lumière. Plus il y a de sang dans le tissu, plus la lumière est atténuée. Si vous mesurez en continu la quantité de lumière transmise à travers le doigt, vous obtenez un signal qui oscille : minimum quand le sang afflue (plus d’absorption), maximum quand il reflue. La fréquence de cette oscillation, c’est votre rythme cardiaque. La forme de la courbe — appelée pleth wave — porte aussi de précieuses informations sur la rigidité artérielle et la perfusion périphérique.
Pourquoi deux longueurs d’onde : 660 nm et 880 nm
Si la PPG donnait uniquement le rythme cardiaque, le MAX30100 n’aurait qu’une seule LED. Mais il en a deux : une rouge à 660 nm et une infrarouge à 880 nm. Pourquoi ? Parce que l’hémoglobine — la molécule du sang qui transporte l’oxygène — n’absorbe pas la lumière de la même manière selon qu’elle est oxygénée ou non.
| Forme | Absorption à 660 nm (rouge) | Absorption à 940/880 nm (IR) |
|---|---|---|
| Hémoglobine oxygénée HbO2 | Faible | Modérée |
| Hémoglobine désoxygénée Hb | Forte | Faible |
C’est pour cela qu’une artère oxygénée apparaît rouge vif (elle laisse passer le rouge) et qu’une veine paraît bleutée (l’hémoglobine désoxygénée absorbe le rouge). Cette différence spectrale est la clé du calcul du SpO2.
Le ratio R/IR et le calcul du SpO2
Le signal PPG enregistré pour chaque longueur d’onde comporte deux composantes :
- Composante DC : la grosse moyenne, due à l’absorption par les tissus statiques (peau, os, sang veineux, eau).
- Composante AC : la petite oscillation autour de cette moyenne, due au volume pulsatile artériel.
On définit le ratio R :
R = (AC_rouge / DC_rouge) / (AC_IR / DC_IR)
Ce ratio est très astucieux : en divisant AC par DC pour chaque canal, on s’affranchit de l’intensité absolue (l’épaisseur du doigt, la pigmentation de la peau, la distance LED-photodiode). Il ne reste que la signature spectrale de l’hémoglobine, qui ne dépend que du SpO2.
La conversion R → SpO2 n’est pas linéaire et nécessite un étalonnage empirique (Beer-Lambert ne s’applique pas parfaitement aux milieux diffusants). Maxim fournit une approximation polynomiale typique :
SpO2 (%) ≈ 110 - 25 × R
Cette formule donne 100 % pour R ≈ 0,4 et 80 % pour R ≈ 1,2. Les fabricants d’oxymètres médicaux utilisent des tables de calibration multi-points dérivées de tests cliniques sur des volontaires en hypoxie contrôlée.
Le MAX30100 en pratique : matériel et brochage
Le module Didactico typique contient le MAX30100 monté sur une petite PCB rouge avec niveau-shifter intégré pour permettre la connexion à un Arduino UNO (5V) sans destruction (le MAX30100 fonctionne strictement en 1,8-3,3 V).
Brochage du module :
- VIN : 3,3 V ou 5 V selon module (vérifiez la sérigraphie)
- GND : masse commune
- SCL : I2C clock → A5 sur UNO, D22 sur Mega, GPIO22 sur ESP32
- SDA : I2C data → A4 sur UNO, D21 sur Mega, GPIO21 sur ESP32
- INT : interruption optionnelle (chute à LOW quand donnée prête)
- IRD / RD : broches IR et Red drive — non utilisées sur modules I2C
Le capteur lui-même contient :
- Une LED rouge 660 nm et une LED infrarouge 880 nm, dont l’intensité est programmable de 0 à 50 mA par pas de 0,2 mA.
- Une photodiode large bande avec amplificateur transimpédance intégré.
- Un convertisseur ADC 16 bits à 50-1000 échantillons par seconde.
- Un FIFO de 16 échantillons.
- Un capteur de température interne (±1 °C) pour compenser la dérive des LEDs.
Communication I2C et initialisation
Le MAX30100 communique en I2C standard à l’adresse fixe 0x57. Le bus accepte 100 kHz (standard) ou 400 kHz (fast mode), ce dernier étant recommandé pour ne pas perdre d’échantillons.
L’initialisation consiste à :
- Vérifier la présence du capteur (lecture du registre 0xFF qui doit valoir 0x11)
- Configurer le mode SpO2 (registre MODE_CONFIG = 0x03)
- Régler la fréquence d’échantillonnage (100 SPS typiquement)
- Régler la largeur d’impulsion LED (1600 µs = résolution 16 bits)
- Régler le courant des LEDs rouge et IR (typiquement 27,1 mA chacune)
Code Arduino avec la librairie oxullo
La librairie de référence est MAX30100lib par oxullo (installable depuis le gestionnaire de bibliothèques Arduino IDE). Elle encapsule toute l’arithmétique I2C et fournit un objet de haut niveau avec callbacks.
/*
* Lecture rythme cardiaque + SpO2 avec MAX30100
* Librairie : MAX30100lib (oxullo)
* Câblage : SDA→A4, SCL→A5 sur Arduino UNO
*/
#include <Wire.h>
#include "MAX30100_PulseOximeter.h"
#define INTERVAL_RAPPORT 1000 // ms
PulseOximeter poximetre;
uint32_t dernierRapport = 0;
// Callback : appelée par la librairie a chaque battement detecte
void surBattement() {
Serial.println(F("♥ Battement detecte"));
}
void setup() {
Serial.begin(115200);
Serial.print(F("Init MAX30100... "));
// begin() retourne false si capteur introuvable
if (!poximetre.begin()) {
Serial.println(F("ECHEC"));
while (1) delay(1000); // Bloque
}
Serial.println(F("OK"));
// Intensite des LEDs : compromis precision / consommation
poximetre.setIRLedCurrent(MAX30100_LED_CURR_27_1MA);
poximetre.setOnBeatDetectedCallback(surBattement);
}
void loop() {
// Lecture FIFO non-bloquante — DOIT etre appelee constamment
poximetre.update();
if (millis() - dernierRapport > INTERVAL_RAPPORT) {
float bpm = poximetre.getHeartRate();
uint8_t spo2 = poximetre.getSpO2();
Serial.print(F("BPM: "));
Serial.print(bpm, 1);
Serial.print(F(" SpO2: "));
Serial.print(spo2);
Serial.println(F("%"));
dernierRapport = millis();
}
}
Pièges classiques avec la librairie
1. Ne mettez jamais de delay() dans la loop(). La librairie a besoin que update() soit appelée plus de 100 fois par seconde pour vider le FIFO du capteur avant qu’il déborde. Tout délai supérieur à 10 ms dégrade le signal.
2. La détection de battement converge en 10 à 15 secondes après pose du doigt. Pendant ce temps, les valeurs sont nulles ou aberrantes. Affichez “mesure en cours…” au lieu de zéros qui inquiètent.
3. La pression du doigt sur le capteur compte énormément. Trop fort, vous écrasez les capillaires et le signal disparaît. Trop léger, la lumière parasite ambiante perturbe la mesure. Le point optimal est une pression équivalente à celle d’un stylo posé sur du papier.
Capteur MAX30100 Rythme Cardiaque + SpO2
Module I2C avec level-shifter intégré, compatible Arduino UNO/Mega/ESP32, idéal pour projets de fin d’études en instrumentation biomédicale. Disponible chez Didactico Sfax.
Traitement du signal : moyenne mobile et détection de pic
Si vous souhaitez aller au-delà de la librairie et accéder au signal brut, le MAX30100 expose les échantillons IR et RED dans son FIFO. Le signal brut ressemble à ceci (échantillonnage 100 Hz) :
Échantillon IR brut : 32500, 32480, 32450, 32420, 32395, 32420, 32480, ...
↑ baseline DC ≈ 32450, AC ≈ ±50
Le ratio AC/DC est faible (0,15 %) et le signal est noyé dans plusieurs sources de bruit : 50 Hz secteur (couplage électromagnétique), tremblements du doigt, lumière ambiante. Les traitements clés :
- Filtre passe-bande [0,5 – 5 Hz] : conserve les fréquences cardiaques plausibles (30-300 BPM) et élimine la composante DC et les harmoniques secteur. Implémentation simple : différence entre moyenne mobile courte (5 échantillons) et longue (50 échantillons).
- Détection de pic par seuillage adaptatif : un battement = passage du signal au-dessus de seuil_haut puis redescente sous seuil_bas. Période réfractaire de 300 ms minimum pour éviter de compter deux fois le même battement.
- Calcul du BPM : moyenne mobile sur les 8 derniers intervalles inter-pics.
BPM = 60000 / moyenne_intervalle_ms.
Affichage sur écran OLED SSD1306
Pour transformer la lecture série en oxymètre utilisable, l’écran OLED 0,96 pouces SSD1306 (128×64 pixels, I2C, adresse 0x3C) est le partenaire idéal. Il partage le même bus I2C que le MAX30100, donc deux fils SDA/SCL suffisent pour les deux. Librairie : Adafruit_SSD1306 + Adafruit_GFX.
#include <Adafruit_SSD1306.h>
#define LARGEUR 128
#define HAUTEUR 64
Adafruit_SSD1306 ecran(LARGEUR, HAUTEUR, &Wire, -1);
void afficherMesure(float bpm, uint8_t spo2) {
ecran.clearDisplay();
ecran.setTextSize(1);
ecran.setTextColor(SSD1306_WHITE);
ecran.setCursor(0, 0);
ecran.println(F("Oxymetre Didactico"));
ecran.drawLine(0, 10, 128, 10, SSD1306_WHITE);
ecran.setTextSize(2);
ecran.setCursor(0, 16);
ecran.print(F("BPM "));
ecran.println((int)bpm);
ecran.setCursor(0, 40);
ecran.print(F("SpO2 "));
ecran.print(spo2);
ecran.println(F("%"));
ecran.display();
}
MAX30100 vs MAX30102 : lequel choisir ?
Question posée à chaque commande chez Didactico : faut-il prendre le MAX30100 ou son successeur le MAX30102 ? Réponse courte : prenez le MAX30102 si vous en avez le choix.
| Critère | MAX30100 | MAX30102 |
|---|---|---|
| Année de sortie | 2014 | 2017 |
| Tension d’alimentation logique | 1,8 V uniquement (level-shifter requis) | 1,8 ou 3,3-5,5 V natif |
| LEDs | Rouge 660 nm + IR 880 nm | Rouge 660 nm + IR 880 nm + driver amélioré |
| Résolution ADC | 16 bits | 18 bits (4× plus précis) |
| Mode HR-only | Non | Oui (IR seule, économie énergie) |
| Compensation lumière ambiante | Basique | Avancée |
| Prix typique en Tunisie | 15-20 DT | 18-25 DT |
Le MAX30102 est plus stable, supporte directement les 5 V de l’Arduino UNO sans level-shifter externe, donne un signal moins bruité, et coûte à peine plus cher. La librairie sparkfun ou la même MAX30100lib (en mode compatible) fonctionne dessus avec un changement minime.
Projet PFE : oxymètre portable LiPo avec alerte SpO2
Voici un cahier des charges complet pour un projet de fin d’études d’environ trois mois en instrumentation biomédicale :
Cahier des charges
- Portable, autonome sur batterie LiPo 3,7 V 1000 mAh, recharge USB-C
- Mesure SpO2 et BPM en continu
- Écran OLED affichant valeurs + courbe pleth en temps réel
- Buzzer + LED rouge clignotants si SpO2 < 90 %
- Enregistrement sur SD-card horodaté pour traçabilité
- Bouton on/off, indication batterie faible
- Boîtier 3D imprimé ergonomique pour pince à doigt
Liste de matériel (BoM)
- Arduino Pro Mini 3,3 V ou ESP32 (préféré pour BLE futur)
- Module MAX30102 (plus stable que 30100)
- Écran OLED 0,96″ SSD1306 I2C
- Module TP4056 (charge LiPo USB-C avec protection)
- Régulateur step-up 3,3 V MT3608 (si UNO) ou intégré ESP32
- Batterie LiPo 1S 1000 mAh
- Buzzer piezo passif
- LED rouge 5 mm + résistance 220 Ω
- Bouton poussoir momentané
- Carte microSD + module SD-card SPI
- Câblage, boîtier PLA imprimé
Coût total : 90 à 130 DT chez Didactico Sfax. Comparable à un oxymètre d’entrée de gamme acheté en pharmacie, avec en bonus l’apprentissage de la chaîne complète : capteur → traitement signal → IHM → stockage.
Pseudo-architecture logicielle
setup():
init_I2C(MAX30102, OLED_SSD1306)
init_SPI(SD_card)
init_GPIO(bouton, LED, buzzer)
ouvrir_fichier_log()
loop():
poximetre.update() // CRITIQUE — appel haute frequence
if (millis() - tDernierAffichage > 100):
afficher_courbe_pleth(echantillon_brut)
if (millis() - tDernierRapport > 1000):
bpm = poximetre.getHeartRate()
spo2 = poximetre.getSpO2()
afficher_chiffres(bpm, spo2)
sd.println(millis(), bpm, spo2)
if (spo2 > 0 && spo2 < 90):
activer_alerte(buzzer, LED)
else:
desactiver_alerte()
if (millis() - tBatterieCheck > 30000):
afficher_niveau_batterie()
Calibration vs oxymètre médical
L’étape de validation est essentielle pour tout PFE sérieux. Procédure : enregistrer simultanément les mesures de votre prototype et celles d’un oxymètre médical homologué (CMS-50D par exemple) sur 20 sujets pendant 5 minutes au repos. Tracer le graphique de Bland-Altman. Si la moyenne des écarts est inférieure à ±2 % de SpO2 et l’écart-type inférieur à 3 %, votre prototype est dans les clous de la précision “grand public”. L’agrément médical (norme ISO 80601-2-61) nécessite des tests sur sujets en hypoxie contrôlée, hors de portée d’un PFE.
Pour aller plus loin
Pour un projet biomédical complet, le MAX30100 peut être combiné avec un module ECG AD8232 pour obtenir simultanément la fréquence cardiaque optique et électrique, et calculer le temps de transit du pouls (PTT) — une approximation de la pression artérielle non invasive.
FAQ
Pourquoi je n’arrive pas à détecter le capteur sur l’I2C ?
Vérifiez : (1) tension d’alimentation (3,3 V sur capteur nu, 5 V toléré sur module avec level-shifter), (2) résistances de pull-up sur SDA/SCL (4,7 kΩ — souvent intégrées au module), (3) Wire.begin() avant l’utilisation. Lancez un scanner I2C : si l’adresse 0x57 n’apparaît pas, c’est un problème matériel ou d’alimentation.
Le BPM affiché varie entre 60 et 200 sans raison, que faire ?
C’est presque toujours un problème de stabilité de pose. Le MAX30100 est très sensible au mouvement et à la pression. Solutions : (1) immobilisez le doigt, (2) ajustez la pression (modérée), (3) augmentez le courant LED si l’environnement est lumineux (44 mA au lieu de 27 mA), (4) attendez la convergence du filtre (10-15 secondes), (5) appliquez votre propre filtre passe-bande sur le signal brut.
Le SpO2 affiche 98 % en permanence, est-ce correct ?
Probablement correct ! Un adulte en bonne santé au repos a typiquement un SpO2 entre 96 % et 99 %. En dessous de 95 % au repos, c’est anormal. En dessous de 90 %, c’est une urgence médicale. Si vous voulez tester votre montage, retenez votre respiration : la SpO2 descend progressivement après 30-40 secondes (ne dépassez pas 1 minute, et n’essayez pas en cas de pathologie cardiaque).
Puis-je mesurer mon pouls au lobe d’oreille au lieu du doigt ?
Oui, c’est même préférable dans certains cas. Le lobe d’oreille est moins sensible aux mouvements de la main et moins gêné par le vernis à ongles. Le signal y est plus faible (tissu plus épais) donc augmentez le courant LED à 44-50 mA. Pratique pour un casque audio sportif intégrant un MAX30102.
Le vernis à ongles affecte-t-il vraiment la mesure ?
Oui, énormément, surtout les vernis rouges et noirs qui absorbent dans la bande 660 nm et faussent complètement le ratio R/IR. Le SpO2 peut être sous-estimé de 5 à 15 %. Les vernis transparents perturbent moins mais réduisent quand même le signal. Pour des mesures fiables : ongle nu, propre, sec.
Puis-je utiliser le MAX30100 sur ESP32 plutôt que Arduino ?
Absolument, et c’est même recommandé. L’ESP32 (GPIO21=SDA, GPIO22=SCL par défaut) a beaucoup plus de RAM pour stocker les buffers de signal, un Wi-Fi pour envoyer les données vers un dashboard cloud (Blynk, ThingsBoard, Firebase) et un CPU dual-core qui permet de traiter le signal sur un cœur et l’IHM sur l’autre. Le code Arduino fonctionne tel quel avec quelques ajustements de broches.
Quelle est la consommation électrique pour un appareil portable ?
MAX30100 en mode SpO2 actif : environ 8-12 mA (LEDs incluses). Arduino Pro Mini 3,3V au repos : 4 mA. OLED SSD1306 : 8-15 mA selon contenu. Total typique : 25-35 mA. Avec une LiPo 1000 mAh, autonomie d’environ 30-40 heures de mesure continue. Avec mise en veille de l’OLED et lecture périodique du capteur, on dépasse facilement 100 heures.
Conclusion
Le MAX30100 reste, neuf ans après sa sortie, l’une des plus belles introductions à l’instrumentation biomédicale qu’un étudiant puisse manipuler. Il condense des décennies de recherche en photopléthysmographie dans un boîtier accessible à 15 DT. Pour les étudiants de l’ISBS, de l’ENIT-Bio, de l’INSAT ou de l’ISET en filière biomédicale, c’est le composant de référence pour un projet de fin d’études abordable mais techniquement riche.
Chez Didactico, vous trouverez aussi bien le MAX30100 que son successeur MAX30102, les écrans OLED SSD1306, les modules de gestion de batterie LiPo TP4056, et l’ensemble du matériel pour bâtir une station santé complète. Livraison sous 24 à 48 heures partout en Tunisie depuis notre dépôt de Sfax. Le FabLab Sfax est aussi un excellent terrain de validation pour vos prototypes biomédicaux avant soutenance.
Bonne mesure — et n’oubliez jamais : ce que vous mesurez n’a de valeur scientifique que ce que vous savez sur les limites de la mesure.
🛒 Matériel nécessaire pour ce guide
Tout le matériel de ce tutoriel est disponible chez Didactico — livraison 24-48h partout en Tunisie, paiement à la livraison.
Capteur de fréquence cardiaque oxymètre MAX30100 Vert14,500 TND
Capteur de fréquence cardiaque oxymètre MAX30100 Violet16,000 TND📘 Guides liés : Kit ECG AD8232 : Moniteur Cardiaque DIY avec Arduino en Tunisie · Pulse Sensor Arduino : Construire une Station Santé DIY Complète
