Visualización ECG en Tiempo Real en OLED con Arduino UNO
Componentes y suministros
| Arduino UNO | × | 1 |
| Dispositivo uECG | × | 1 |
| Módulo nRF24 (genérico) | × | 1 |
| Pantalla OLED 0.96" 64x128 (ElectroPeak) | × | 1 |
Sobre el proyecto
Hace tiempo publiqué un par de proyectos mostrando cómo obtener datos del dispositivo uECG, pero tenían código desordenado y solo usaban datos básicos. Finalmente escribí una librería Arduino que simplifica y hace todo mucho más fiable: https://github.com/ultimaterobotics/uECG_library (también necesitas instalar librería RF24 desde el Gestor de Librerías, y si quieres mostrar datos en OLED como en este proyecto, también la librería Adafruit SSD1306).
1. Esquemáticos
El esquema es el mismo que cualquier proyecto con módulo nRF24 y OLED: nRF24 conectado al bus SPI del Arduino (D13, D12, D11) y dos pines arbitrarios para CS y CE del módulo — elegí D10 y D9 por comodidad. Punto importante: el módulo nRF24 debe conectarse a la línea de 3.3V, ¡no a 5V! Ayuda mucho añadir un condensador de 1uF o 10uF entre 3.3V y GND, ya que estos módulos requieren voltaje estable que el Arduino no siempre proporciona en su línea de 3.3V.
El OLED se conecta vía I2C: SDA a A4, SCL a A5, alimentado de 5V. En mi caso, el módulo OLED tenía resistencias integradas para I2C. Si el tuyo no las tiene, necesitas añadir resistencias de 4.7k de SDA a 3.3V y SCL a 3.3V, aunque la mayoría de módulos recientes ya las traen.
2. Código
La librería uECG requiere unas líneas de código para operación correcta:
- En
setup(), llamauECG.begin(pin_cs, pin_ce)indicando qué pines usan CS y CE del nRF24. Enciende el módulo y lo configura internamente. - En
loop(), llamauECG.run()tan a menudo como sea posible: el uECG envía muchos datos (un paquete cada pocos ms) y si no llamas auECG.run()antes de que llegue el siguiente paquete, se perderán datos. Eso significa nunca usardelay()dentro del loop, y usarmillis()para tareas que requieran temporización.
El código de este proyecto está disponible como ejemplo dentro de la librería, y también adjunto abajo (si parece complejo, ten en cuenta que el 95% del código está dedicado a dibujo optimizado en pantalla; para solo imprimir valores en monitor serial necesitas unas pocas líneas):
#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 chip enable 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, prev_displ = 0;
uint8_t ecg_screen[128]; int ecg_screen_len = 128;
float ecg_avg = 0, ecg_max = 1, 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]);
for(int x = new_data; x < ecg_screen_len; x++)
ecg_screen[x-new_data] = ecg_screen[x];
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;
}
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;
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. Procesamiento de datos
Mucho procesamiento se hace en el dispositivo y puedes obtener varias estadísticas calculadas: BPM, GSR, último intervalo RR, parámetro HRV y 16 bins HRV (primer bin = latidos con variación <1%, segundo = 1-2%, etc), pasos caminados, lecturas del acelerómetro (tasa de refresco baja, solo para estimación de pose).
Pero también puedes obtener lecturas ECG crudas — el flujo de datos no es perfecto, de vez en cuando se pierden paquetes, pero aún obtienes algo usable.
Código
Librería uECG para Arduino: https://github.com/ultimaterobotics/uECG_library (incluye ejemplos OLED y serial simple)
Esquemáticos
Diagrama de conexiones nRF24 + OLED + Arduino UNO.
Proceso de manufactura
- Construya una API robusta de temperatura y sensores en Raspberry Pi usando el módulo GY‑91
- Primeros Pasos con TJBot: Construye, Configura y Controla por Voz tu Robot IA
- Construya el clásico juego Pong en Arduino UNO con pantalla OLED: Tutorial paso a paso
- Generador de Ondas JX – Oscilador DDS Compatible con Arduino con Pantalla OLED
- Autómatas Celulares en Tiempo Real con Arduino y Pantalla OLED 128x64
- Proyecto Arduino LCD DIY: Ensamblaje con resistencias, pulsador y display 16x2
- Tutorial Arduino para Principiantes 01: Inicia tu Primer Proyecto
- MAX86150 de Maxim: módulo integrado PPG y ECG para monitorización de salud móvil
- Fundamentos de módulos en Verilog: Estructura y sintaxis
- Dominar los parámetros en Verilog: Construir módulos reutilizables y escalables
- Sistema de Módulos Java 9: Mejoras, Link-Time e Imágenes de Runtime Personalizadas