Obtención de ECG en tiempo real en la pantalla OLED
Componentes y suministros
| × | 1 | ||||
| × | 1 | ||||
| × | 1 | ||||
| × | 1 |
Acerca de este proyecto
Hace algún tiempo publiqué un par de proyectos que demostraban cómo obtener datos del dispositivo uECG, pero tenían bastante código desordenado y todavía usaban solo datos básicos de él. Entonces, finalmente escribí una biblioteca Arduino que hace que esto sea más simple y mucho más confiable, aquí está:https://github.com/ultimaterobotics/uECG_library (tenga en cuenta que también necesita instalar la biblioteca RF24 desde Library Manager, y si desea mostrar datos en OLED como en este proyecto, también la biblioteca SSD1306 de Adafruit).
1. Esquemas
Schematics es el mismo que para cualquier otro proyecto que use el módulo nRF24 y OLED:nRF24 está conectado al bus SPI de Arduino (D13, D12, D11) y dos pines arbitrarios para las líneas del módulo CS y CE; elegí D10 y D9 por conveniencia. El único punto importante :el módulo nRF24 debe estar conectado a 3.3V línea, no a 5V! También ayuda mucho agregar un capacitor de 1uF o 10uF entre 3.3V y GND; esos módulos nRF24 requieren un voltaje estable que Arduino no siempre puede proporcionar en su línea de 3.3V, los capacitores ayudan con eso.
OLED se conecta a través de I2C - SDA a A4, SCL a A5 y se alimenta desde una línea de 5V. En mi caso, el módulo OLED tenía resistencias integradas para el protocolo I2C. En caso de que su módulo no los tenga, debe agregar resistencias de 4.7k de SDA a 3.3V y de SCL a 3.3V, aunque la mayoría de los módulos que he visto recientemente ya las tienen.
Puede ver los esquemas adjuntos a continuación, y aquí hay una foto del proyecto ensamblado:
2. Código
La biblioteca uECG requiere bastantes líneas de código para su correcto funcionamiento, a saber:
en setup (), debe llamar a uECG.begin (pin_cs, pin_ce); debe decirle qué números de pin se utilizan para las líneas nRF24 CS y CE, encenderá el módulo y lo pondrá en el modo correcto internamente.
En loop (), debe llamar a uECG.run () con la mayor frecuencia posible:el dispositivo uECG envía una gran cantidad de datos, un paquete cada pocos milisegundos, y si no llama a uECG.run () antes de la próxima llega el paquete, sus datos se perderán. Eso significa nunca llamar a la función delay () dentro del bucle, y usar millis () para tareas que requieren tiempo (he agregado un ejemplo de eso en los ejemplos de la biblioteca).
Este código de proyecto está disponible como ejemplo dentro de la biblioteca, y también se adjunta a continuación (si parece demasiado complejo, tenga en cuenta que aquí el 95% del código está dedicado al dibujo de visualización optimizado, para valores de impresión simples en el monitor en serie que usted solo necesito unas pocas líneas):
#include
#include
#include
#define SCREEN_WIDTH 128 // OLED ancho de pantalla, en píxeles
#define SCREEN_HEIGHT 64 // Altura de la pantalla OLED, en píxeles
// Declaración para una pantalla SSD1306 conectada a I2C (pines SDA, SCL)
# define OLED_RESET -1 // Restablecer el número de pin (o -1 si se comparte el pin de restablecimiento de Arduino)
Pantalla Adafruit_SSD1306 (SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
int rf_cen =9; // pin de habilitación del chip nRF24
int rf_cs =10; // pin nRF24 CS
void setup () {
Serial.begin (115200); // Salida en serie:muy útil para depurar
while (! display.begin (SSD1306_SWITCHCAPVCC, 0x3C)) {// Dirección 0x3D para 128x64
Serial.println (F ("Falló la asignación SSD1306"));
}
display.display ();
delay (100);
uECG.begin (rf_cs, rf_cen);
delay (100);
// Limpiar el búfer
display.clearDisplay ();
display.setTextSize (1); // Escala de píxeles normal 1:1
display.setTextColor (WHITE); // Dibuja texto blanco
display.cp437 (true); // Use la fuente completa de 256 caracteres 'Página de códigos 437'
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;
bucle void ()
{
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, nuevos_datos);
for (int x =0; x Serial.println (ecg_data [x]);
for (int x =nuevos_datos; x ecg_screen [x-new_data] =ecg_screen [x];
for (int x =0; 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] 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 ( "pasos:");
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, BLANCO);
display.drawLine (110, 10, 127, 10, BLANCO);
display.drawLine ( 110, 0, 110, 10, BLANCO);
display.drawLine (127, 0, 127, 10, BLANCO);
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)
{
para ( int x =1; 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 display.drawLine (x-1, ecg_screen [x- 1], x, ecg_screen [x], WHITE);
}
if (displ_phase ==3)
display.display ();
displ_phase ++;
if (fase_displ> 3) fase_displ =0;
}
}
}
3. Procesamiento de datos
Se realiza una gran cantidad de procesamiento a bordo y puede obtener varias estadísticas calculadas por el dispositivo:BPM, GSR, último intervalo RR, parámetro HRV y 16 intervalos de HRV (el primer intervalo representa la cantidad de latidos con variación <1%, segundo intervalo - variación entre 1 y 2%, etc.), número de pasos recorridos, lecturas del acelerómetro (aunque la frecuencia de actualización es baja, por lo que solo es buena para la estimación de pose).
Pero también puede obtener lecturas de ECG sin procesar:el flujo de datos no es perfecto, de vez en cuando se pierden algunos paquetes, pero aún puede obtener algo utilizable:
Bueno, eso es todo:si tuvieras este dispositivo acumulando polvo en una esquina, ahora realmente funciona sin demasiados problemas :)
Código
biblioteca arduino uECG
Tiene OLED y ejemplos de serie simples dentro de https://github.com/ultimaterobotics/uECG_libraryEsquemas
Proceso de manufactura
- Maxim:módulo integrado de biosensor PPG y ECG para dispositivos móviles
- API de sensor ambiental con un RPi
- Introducción a TJBot
- Módulo Verilog
- Parámetros de Verilog
- Java 9 - Sistema de módulos
- Juego Arduino Pong - Pantalla OLED
- Generador de ondas JX
- Autómatas celulares basados en Arduino y OLED
- ¡Esquiva las Defs!
- Tutorial de Arduino 01:Primeros pasos