Affichage ECG temps réel sur OLED avec Arduino UNO
Composants et fournitures
| Arduino UNO | ×1 |
| Dispositif uECG | ×1 |
| Module nRF24 (générique) | ×1 |
| Module OLED 0,96" 64×128 (ElectroPeak) | ×1 |
À propos du projet
J'avais déjà publié quelques projets montrant comment récupérer les données du dispositif uECG, mais le code était complexe et n'utilisait que les données basiques. J'ai finalement écrit une bibliothèque Arduino qui simplifie grandement l'usage et le rend plus fiable : https://github.com/ultimaterobotics/uECG_library (il faut aussi installer la bibliothèque RF24 via le gestionnaire de bibliothèques, et pour l'affichage OLED comme ici, la bibliothèque Adafruit SSD1306).
1. Schéma de câblage
Le schéma est standard pour tout projet utilisant un module nRF24 et un OLED :
- nRF24 sur le bus SPI de l'Arduino (D13, D12, D11) + deux broches arbitraires pour CS et CE – j'ai choisi D10 (CS) et D9 (CE).
- Point crucial : le module nRF24 doit être alimenté en 3,3V, pas en 5V ! Un condensateur de 1 µF ou 10 µF entre 3,3V et GND aide beaucoup à stabiliser la tension (l'Arduino ne fournit pas toujours du 3,3V stable).
- OLED en I2C : SDA sur A4, SCL sur A5, alimenté en 5V. Mon module OLED avait des résistances de tirage I2C intégrées. Si le vôtre n'en a pas, ajoutez des résistances de 4,7 kΩ de SDA vers 3,3V et de SCL vers 3,3V.
Photo du montage assemblé ci-dessus. Schéma joint en bas.
2. Code
La bibliothèque uECG nécessite quelques lignes pour fonctionner correctement :
- Dans
setup():uECG.begin(pin_cs, pin_ce)– indique les broches CS et CE du nRF24, active le module et le configure. - Dans
loop(): appelezuECG.run()le plus souvent possible. Le uECG envoie beaucoup de données (un paquet toutes les quelques millisecondes) – siuECG.run()n'est pas appelé avant l'arrivée du paquet suivant, les données sont perdues. Donc jamais dedelay()dans la boucle, utilisezmillis()pour les temporisations (exemple dans la bibliothèque).
Le code de ce projet est disponible comme exemple dans la bibliothèque, et ci-dessous (95 % du code sert à l'affichage optimisé sur OLED ; pour un simple affichage série, quelques lignes suffisent) :
#include <uECG.h>
#include <Wire.h>
#include <Adafruit_SSD1306.h>
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET -1
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
int rf_cen = 9; // nRF24 CE pin
int rf_cs = 10; // nRF24 CS pin
void setup() {
Serial.begin(115200);
while(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
Serial.println(F("SSD1306 allocation failed"));
}
display.display();
delay(100);
uECG.begin(rf_cs, rf_cen);
delay(100);
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(WHITE);
display.cp437(true);
display.display();
delay(100);
Serial.println("after display");
}
uint32_t prev_data_count = 0;
uint32_t prev_displ = 0;
uint8_t ecg_screen[128];
int ecg_screen_len = 128;
float ecg_avg = 0;
float ecg_max = 1;
float ecg_min = -1;
int ecg_size = 40;
int displ_phase = 0;
void loop() {
uECG.run();
uint32_t data_count = uECG.getDataCount();
int new_data = data_count - prev_data_count;
prev_data_count = data_count;
if (new_data > 0) {
uint32_t ms = millis();
int16_t ecg_data[8];
uECG.getECG(ecg_data, new_data);
for (int x = 0; x < new_data; x++) Serial.println(ecg_data[x]);
// Décalage du buffer d'affichage
for (int x = new_data; x < ecg_screen_len; x++)
ecg_screen[x - new_data] = ecg_screen[x];
// Traitement des nouvelles données
for (int x = 0; x < new_data; x++) {
ecg_avg *= 0.99;
ecg_avg += 0.01 * ecg_data[x];
ecg_max = ecg_max * 0.995 + ecg_avg * 0.005;
ecg_min = ecg_min * 0.995 + ecg_avg * 0.005;
if (ecg_data[x] > ecg_max) ecg_max = ecg_data[x];
if (ecg_data[x] < ecg_min) ecg_min = ecg_data[x];
int ecg_y = 63 - ecg_size * (ecg_data[x] - ecg_min) / (ecg_max - ecg_min + 1);
ecg_screen[ecg_screen_len - 1 - new_data + x] = ecg_y;
}
// Affichage par phases (toutes les 30 ms)
if (ms - prev_displ > 30) {
prev_displ = ms;
if (displ_phase == 0) {
display.clearDisplay();
display.setCursor(0, 0);
display.print("BPM: "); display.println(uECG.getBPM());
display.print(" RR: "); display.println(uECG.getLastRR());
display.print("steps: "); display.print(uECG.getSteps());
int batt_mv = uECG.getBattery();
int batt_perc = (batt_mv - 3300) / 8;
if (batt_perc < 0) batt_perc = 0;
if (batt_perc > 100) batt_perc = 100;
// Indicateur batterie
display.drawLine(110, 0, 127, 0, WHITE);
display.drawLine(110, 10, 127, 10, WHITE);
display.drawLine(110, 0, 110, 10, WHITE);
display.drawLine(127, 0, 127, 10, WHITE);
int bat_len = batt_perc / 6;
for (int x = 1; x < 10; x++)
display.drawLine(110, x, 110 + bat_len, x, WHITE);
}
if (displ_phase == 1) {
for (int x = 1; x < ecg_screen_len/2; x++)
display.drawLine(x-1, ecg_screen[x-1], x, ecg_screen[x], WHITE);
}
if (displ_phase == 2) {
for (int x = ecg_screen_len/2; x < ecg_screen_len-1; x++)
display.drawLine(x-1, ecg_screen[x-1], x, ecg_screen[x], WHITE);
}
if (displ_phase == 3) display.display();
displ_phase++;
if (displ_phase > 3) displ_phase = 0;
}
}
}
3. Traitement des données
Beaucoup de traitement est fait sur le dispositif uECG lui-même. Vous pouvez récupérer diverses statistiques calculées :
- BPM (battements par minute)
- GSR (réponse cutanée galvanique)
- Dernier intervalle RR
- Paramètre HRV et 16 bacs HRV (1er bac : variation <1%, 2e : 1-2%, etc.)
- Nombre de pas
- Lectures accéléromètre (taux de rafraîchissement faible, bon pour estimation de posture)
Les données ECG brutes sont aussi accessibles – le flux n'est pas parfait (pertes de paquets occasionnelles), mais on obtient un signal exploitable (voir capture d'écran).
Si vous aviez ce dispositif au fond d'un tiroir, il fonctionne maintenant sans trop de tracas !
Code
Bibliothèque uECG Arduino (inclut exemples OLED et série simple) : https://github.com/ultimaterobotics/uECG_library
Schématiques
Schéma de câblage joint dans les fichiers du projet.
Processus de fabrication
- MAX86150 de Maxim : Module PPG et ECG Intégré pour Surveillance Santé Mobile
- Créer une API robuste de température et capteurs sur Raspberry Pi avec le module GY‑91
- Démarrage avec TJBot : Construire, Configurer et Contrôler par la Voix Votre Propre Robot IA
- Bases des modules Verilog : Structure et syntaxe
- Maîtriser les Paramètres Verilog : Construire des Modules Réutilisables et Évolutifs
- Système de modules Java 9 : Création, link-time et images d'exécution personnalisées
- Automates Cellulaires Temps Réel sur Arduino avec Écran OLED 128x64
- Projet Arduino LCD DIY : Assemblage avec résistances, bouton poussoir et afficheur 16x2
- Tutoriel Arduino Débutant 01 : Démarrez votre Premier Projet