MAX30100 sensor de latido de corazón y oxímetro de pulso con comunicaciones I2C para wearables de salud

publicado en: Portada | 37

Como explico en el artículo sobre el principio de funcionamiento del oxímetro para monitorización del pulso, una forma sencilla de estimar el pulso es infiriendo la cantidad de oxígeno en sangre por su color. Cuando la sangre pasa por los pulmones la hemoglobina (Hb) se oxigena convirtiéndose en oxihemoglobina (HbO2). En zonas del cuerpo bien irrigadas y con piel fina se puede detectar la absorción diferencial de luz de diferente color (longitud de onda), especialmente el rojo entorno a 650 nm, y el infrarrojo entorno a 950 nm. De manera mucho más cómoda y equiparable en eficacia, también se puede estimar el ritmo cardíaco (el pulso) midiendo la luz reflejada en cierta parte del cuerpo (un dedo, típicamente) en lugar de la luz que atraviesa esa zona.

Si bien no es especialmente difícil encontrar componentes electrónicos convencionales que se adapten bien tanto a la medida de la luz que atraviesa como a la que refleja, la popularización de los wearables con sistemas de monitorización de la salud ha animado a los fabricantes a integrar en un único componente LED, fotodiodos, circuitería de corrección y amplificación, conversión digital (ADC) de la señal obtenida y comunicaciones, lo que simplifica notablemente la medida del ritmo cardíaco desde un MCU. La serie MAX3010X de Maxim Integrated es un ejemplo bastante representativo de este tipo de productos, tanto para medir el pulso en un dedo (MAX30100) como para aplicarlo a muñequeras (MAX30101 y MAX30102).

MAX30100 sensor de latido de corazón (oxímetro de pulso) con comunicaciones I2C para wearables de salud

Si la longitud de onda de la luz emitida es suficientemente exacta, es decir, se ciñe a la correspondiente del rojo (650 nm) y del infrarrojo (950 nm) y el sensor que detecta la luz es suficientemente preciso, también es posible determinar la saturación (porcentual) arterial de oxígeno SpO2 (pulsioximetría).

La saturación de hemoglobina (SaO2) se suele expresar como un coeficiente que relaciona la proporción de Hb frente a la de HbO2 y se calcula dividiendo la cantidad estimada de HbO2 entre la suma de la misma y la de Hb. La SpO2 se obtiene multiplicando por 100 la SaO2 para expresarla como un porcentaje.

Este objetivo, determinar la presencia de oxígeno en sangre, es mucho más ambicioso que el explicado en el artículo sobre la monitorización del ritmo cardíaco usando un oxímetro mediante una librería Arduino para medir el pulso, que solamente busca detectar el latido del corazón. Aunque, como otros dispositivos similares, el MAX30100 está diseñado para ser implementado en wearables de salud y no en el ámbito clínico, añadir la posibilidad de estimar la SpO2 supone un paso adelante en prestaciones.

Funcionamiento del oxímetro de pulso MAX30100

El MAX30100 dispone de un LED rojo y otro infrarrojo (el MAX30101 cuenta además con un tercer LED verde) que quedan arriba en las siguientes imágenes de detalle y que iluminan alternativamente durante cierto tiempo (ancho de pulso) la zona expuesta (un dedo, por ejemplo). La luz reflejada se detecta con un fotodiodo, que queda en la parte de abajo de las siguientes imágenes de detalle. La corriente de estos LED se puede configurar a un valor entre cero y 50 mA.

MAX30100 oxímetro de pulso y sensor de latido de corazón con comunicaciones I2C para wearables de salud 1MAX30100 oxímetro de pulso y sensor de latido de corazón con comunicaciones I2C para wearables de salud 3MAX30100 oxímetro de pulso y sensor de latido de corazón con comunicaciones I2C para wearables de salud 4

A la intensidad de luz detectada por el fotodiodo ① se le corrige la desviación que produce la iluminación ambiental (ALC, cancelación de la luz ambiental), ② el ruido eléctrico de baja frecuencia (los 50 Hz o 60 Hz de la línea eléctrica dependiendo del lugar) y ③ la influencia de la temperatura, para lo que cuenta con un termómetro interno. La señal obtenida se convierte en valores digitales con un ADC por modulación Sigma-Delta y se almacena en un buffer al que se puede acceder desde un microcontrolador mediante el bus I2C con que cuenta el MAX30100.

La precisión del valor digital obtenido depende de tres parámetros que están interrelacionados: ① la resolución (configurable hasta 16 bits), ② el ancho del pulso que determina el tiempo de iluminación de los LED (entre 200 µs y 1600 µs) y ③ la velocidad de muestreo del fotodiodo (entre 50 y 1000 muestras por segundo). Para obtener una mayor resolución debe ser mayor la duración del pulso y se reduce el número de muestras que pueden tomarse. Los valores de más resolución (16  bits) corresponden con el pulso de 1600 µs y un máximo de 100 lecturas por segundo.

El oxímetro de pulso MAX30100 guarda la configuración en un conjunto de registros de 8  bits y utiliza una memoria FIFO de 64 bytes para almacenar hasta 16 lecturas completas formadas por 16 bits para el canal rojo y otros 16 bits para el canal infrarrojo. Como es posible disminuir la resolución para aumentar la velocidad de conversión analógica a digital o leer el valor del pulso en lugar de la intensidad de luz, los bits que sobran al usarlo de este modo se ignoran (se rellenan con ceros) almacenando siempre el mismo número de lecturas en la memoria FIFO.

Se pueden configurar dos modos de funcionamiento en el MAX30100, el modo «latido», que consiste en utilizar solamente la luz infrarroja, y el modo «SpO2», que considera tanto la luz roja como la infrarroja, por lo que almacena el doble de datos en la memoria FIFO.

Circuito de aplicación del MAX30100

La inclusión del MAX30100 en un circuito es muy sencilla. Del lado del MCU solamente es necesario conectar el bus I2C y una entrada para las interrupciones utilizando, para las tres líneas, resistencias de 4K7. El lado de la alimentación necesita dos tensiones diferentes, la que alimenta los LED, de 3V3 (y hasta 50 mA) aunque es tolerante a 5 V y la que alimenta el resto de componentes del MAX30100 de 1V8. Por su uso, normalmente portátil, es frecuente que la alimentación principal sea de 3V3 y solamente será necesario un pequeño regulador de tensión; si la tensión base fuera diferentes (5 V, por ejemplo) el circuito debería de disponer de dos reguladores, uno para cada nivel de tensión.

MAX30100 diagrama de conexión del oxímetro de pulso y sensor de latido

En el esquema de ejemplo anterior se han utilizado reguladores 6206 (hasta 250 mA), como los LM6206 o los XC6206, pensando en el bajo consumo del MAX30100. Si se necesitara una corriente mayor para otros componentes del circuito, con mínimas modificaciones (condensadores electrolíticos de 10 µF a la entrada y 22 µF a la salida), se puede sustituir, por ejemplo, por algún 1117 (algo más de 1 A) como los LM1117 o los AMS1117, que también son muy económicos y sencillos de encontrar.

Para el esquema, solamente se ha utilizado una conexión para ambos LED pero el MAX30100 permite conectarlos por separado, incluyendo una conexión para cada ánodo. Los ánodos están internamente conectados a GND a través del driver de los LED. Típicamente, los ánodos de ambos LED se dejan sin conectar, por lo que no están indicados en el diagrama del ejemplo.

Gestión por software del oxímetro de pulso MAX30100

Atendiendo a método de uso propuesto en la hoja de datos del MAX30100, una vez configurado el modo de funcionamiento, la lectura del pulso o de la intensidad de luz detectada por los LED debe realizarse: ① consultando primero el número de lecturas disponibles y ② repetirse tantas veces como valores haya disponibles en la FIFO. El puntero que indica la lectura que corresponde consultar se actualiza automáticamente, si la lectura no se hubiera podido realizar de forma correcta sería necesario ③ actualizar «manualmente» el puntero para releer el valor que quede pendiente.

El uso más habitual consiste en realizar una lectura periódica del sensor de pulso pero también se puede optar por usar la interrupción que se activa cuando la FIFO está casi llena y recoger los valores cuando se produzca el aviso. Una vez generada la interrupción el proceso de lectura sería el mismo. Si se opta por la lectura periódica, no es necesario gestionar el tiempo desde el MCU, ya que el MAX30100 generará una interrupción cuando termine el ciclo de integración, que tiene una duración fija y configurable.

Además del modo de lectura de HbO2oxihemoglobina, que entrega dos bytes para los valores de intensidad de luz roja en infrarroja detectada, el MAX30100 dispone de un «modo latido» (o pulso) que solamente almacena el valor (dos bytes) de la lectura de la luz infrarroja, dejando a cero los dos restantes que igualmente será necesario recibir para que se actualice el puntero de lectura.

La lectura de la temperatura no se realiza de forma sistemática como la de la luz reflejada. El protocolo habitual para leer la temperatura consiste en activar la interrupción correspondiente y el modo de lectura de temperatura. Cuando se ha completado el proceso (el MAX30100 tarda unos 30 ms en completar la lectura de la temperatura) se activa la interrupción y se desactiva el modo de lectura de la temperatura, por lo que será necesario activarlo para volver a medirla.

La temperatura se almacena en dos registros de 8 bits como una parte entera en complemento a dos (con signo) y otra fraccionaria en incrementos de dieciseisavos de grado Celsius.

Registros del MAX30100

Para explicar la finalidad de los registros del MAX30100 y el significado de los valores que representan, se puede utilizar como referencia el encabezado con el que se definen para usarlos en la programación con el conocido entorno de desarrollo de Arduino.

Como el proceso de lectura de datos y envío de información para la configuración sigue siempre el mismo protocolo, se pueden usar desde funciones para simplificar su uso y no distraer en la explicación del proceso de explotación del MAX30100.

Lectura de la temperatura interna del MAX30100

Como se ha dicho, la temperatura se utiliza para corregir su influencia en la medida obtenida al iluminar con el LED infrarrojo. Lo habitual es leer la temperatura a intervalos fijos y promediar algunas lecturas para obtener el valor que se utiliza como referencia. Una frecuencia razonable puede ser tomar una medida cada segundo y promediar las de 10 segundos. Abajo puede verse el código que ilustra este proceso y descargar el ejemplo de lectura de la temperatura del oxímetro de pulso MAX30100 desde Arduino.

El iniciar el programa se configura el MAX30100 para que atienda a la interrupción correspondiente a la temperatura pero no se activa dicha interrupción ni en el MAX30100 ni en Arduino hasta que no transcurre el intervalo configurado (1000 ms). Es importante recordar que la interrupción se desactivará automáticamente al concluir la integración de la temperatura, por eso, el programa debe volver a activarla a cada intervalo para que se produzca una nueva lectura.

También es importante, con respecto al comportamiento general de las interrupciones del MAX30100, resaltar que la interrupción permanece activa (y el pin estará a nivel bajo) hasta que se desactiven expresamente o se lea el registro que informa de la causa de la interrupción, que en código se ha definido como MAX30100_INTERRUPCION_ESTADO y que corresponde a la dirección 0x00.

Estimación del pulso con el MAX30100 leyendo la luz infrarroja reflejada

La nomenclatura usada al hablar de dispositivos como el MAX30100, la propia hoja de datos es un buen ejemplo, pueden inducir a error y hacer pensar que la información que entrega es el valor de la frecuencia cardíaca o del ritmo cardíaco pero la medida que ofrece MAX30100 es la intensidad de luz infrarroja y/o roja reflejada.

Utilizando el valor de esas intensidades a lo largo del tiempo es posible estimar tanto el pulso (la frecuencia cardíaca) como en nivel de oxigenación de la sangre (la relación entre la cantidad de hemoglobina y la cantidad de oxihemoglobina)

Ya se ha dicho que el MAX30100 almacena varias lecturas en una FIFO lo que permite leer varios valores ya preparados en lugar de ir cargando cada uno que se integra. Si el MCU no está muy ocupado con otras tareas también es posible leer cada valor cuando el MAX30100 informe, generando una interrupción, de que el proceso de la ADC ha terminado.

El siguiente ejemplo, además de ilustrar este estilo de explotación del oxímetro de pulso MAX30100, permite obtener los datos para su análisis y la determinación del método de estimación del pulso. Es relevante tener presente que el rango de valores dependerá del color (transparencia) de la piel y el grosor de los tejidos de cada individuo así como de la posición sobre el sensor de latido, por lo que será importante realizar las primeras pruebas en un entorno conocido: el mismo sujeto y un sistema (soporte) que fije la posición del dedo en el oxímetro de pulso.

En el bloque de configuración del ejemplo de arriba se le indica al oxímetro de pulso MAX30100 que ① genere una interrupción cuando el pulso esté listo (hay que recordar que «pulso» hace referencia a la lectura de la luz infrarroja) estableciendo el valor del registro en 0x01 que en el código se denomina MAX30100_INTERRUPCION_ACTIVA, ② lea y calcule solamente la ADC de la luz infrarroja reflejada (registro MAX30100_CONFIGURACION_MODO en 0x06 con el valor «pulso»), ③ utilice alta resolución, 100 muestras por segundo y un pulso de 1600 µs (forzado por la resolución) para lo que se establece el valor OR de los anteriores campos en el registro de la dirección 0x09 que en el código se ha denominado MAX30100_CONFIGURACION_LED y ④ utilice una intensidad de 0&nsb;mA para el LED rojo (lo apague) y una intensidad de 50 mA (la máxima) para el infrarrojo.

Al contrario de cómo se hacía en el caso de la lectura de la temperatura del MAX30100, en este ejemplo la interrupción se asigna en la configuración, pero solamente es para iniciar el proceso, ya que cada vez que se detecta una interrupción se libera (dentro de la función llamada) se desactiva (al leer el registro) y se vuelve a asignar cuando se termina de leer la intensidad de luz infrarroja. En este caso, aunque se repite la asignación de la función como respuesta a la configuración, no se vuelve a activar la interrupción del lectura ya que, a diferencia de la temperatura, el MAX30100 no la cambia.

En el caso de optar por leer la FIFO cuando haya varias muestras disponibles sería necesario primero calcular las que hay disponibles y luego realizar las lecturas de los valores dentro un bucle.

Para construir el valor de la intensidad se asigna a un entero sin signo (16 bits) y se rota 8 bits el primer valor que se carga en la lectura del bus I2C del MAX30100 (ya que son los 8 bits más significativos) luego se le suman (OR) los 8 bits (los menos significativos) de la segunda lectura.

Desde el siguiente enlace es posible descargar el ejemplo para Arduino de lectura desde el MAX30100 de la intensidad de luz infrarroja reflejada para estimar la frecuencia cardíaca (pulso) del código de arriba. Con este ejemplo, dependiendo del contexto de medida del que se hablaba antes, puede obtenerse una lectura similar a la de la captura de pantalla de abajo.

MAX30100 lectura intensidad infrarrojo estimación frecuencia cardíaca (pulso) plotter serie Arduino

Analizando la gráfica resultante del código de ejemplo es posible, además de acotar el rango de valores útiles, buscar un método de cálculo del pulso basado en la medida del oxímetro de pulso MAX30100 de la luz infrarroja reflejada. A simple vista, lo más sencillo parece medir el tiempo entre el inicio de las crestas o los valles del gráfico, por desgracia, hay algunos inconvenientes que impiden simplemente detectar cuándo se cambia la dirección de la curva.

En primer lugar, la banda de valores máximos y mínimos es relativamente estrecha comparada con el rango de posibles valores. En segundo lugar, esta franja puede ir variando a lo largo del tiempo (lo que, en parte, puede que se minimice cuando la lectura se estabilice) dependiendo, por ejemplo, de lo cerca que se sitúe en el sensor el objeto medido (un dedo, normalmente). Por último, los valores no siguen una distribución uniforme (del valle a la cima) sino que existe, en el mejor caso, la inflexión que en un ECG correspondería con el complejo QRS y en el peor, más o menos ruido en la lectura, dependiendo también de la resolución y la frecuencia de muestreo.

MAX30100 intensidad infrarrojo estimación frecuencia cardíaca plotter serie Arduino ruido

La gráfica de la captura de pantalla de arriba muestra la salida del trazador serie de Arduino con una frecuencia de muestreo más alta. La distribución de valores puede llegar a ser tan ruidosa que oculte los quiebros de la curva (en este caso en concreto, por la influencia de luz ambiental). Por otro lado, es interesante apreciar que siguen claramente destacados los máximos y los mínimos que permitirían calcular la frecuencia cardíaca (pulso).

Dos de las formas más económicas en recursos del MCU que pueden utilizarse consisten en ① promediar los valores obtenidos hasta que solamente resulten relevantes los máximos y los mínimos y tomar unos u otros y determinar el tiempo transcurrido entre ellos y ② estimar cuándo los valores dejan de subir o de bajar, admitiendo una tolerancia (máximo de duración de valores en una dirección cuando se atiende a la contraria) y midiendo el tiempo entre ambos eventos. Si el rango de datos está muy bien acotado el primer método parece más sencillo pero se intuye que el segundo será más flexible si el rango de datos es variable (normalmente cuando el contexto físico es más susceptible de cambiar) por lo que es la opción que se toma como referencia.

Al código de ejemplo de lectura desde el MAX30100 de la intensidad de luz infrarroja reflejada hay que añadir tres nuevas variables para ① almacenar la intensidad medida en la lectura anterior (para saber si aumenta o disminuye), ② el momento en el que se detectó la última inflexión (he elegido ascendente, pero podría hacerse al contrario) y ③ el momento en el que se encontró la última referencia válida de pulso.

Para estimar la frecuencia cardíaca se comparan las intensidades, si se ha cambiado la dirección (crece y antes decrecía o al contrario) y el tiempo transcurrido supera la tolerancia admisible, se ha encontrado un pico de la curva de los que determinan el pulso.

La tolerancia, definida en el programa como #define TOLERANCIA_DESCENSO 120, es el valor de cambio de dirección que se admite sin considerar que se ha alcanzado la cresta o el valle de la curva, depende del contexto, especialmente de la resolución y la frecuencia de muestreo, pero también del sujeto al que se le mide el pulso y del dispositivo físico sobre el que se ubica el sensor de latidos. Los primeros parámetros se establecen en el programa, así que se pueden coordinar con la tolerancia pero los primeros cambian en tiempo de ejecución, así que puede ser interesante considerar la alternativa de modificarlos mientras se usa el dispositivo (por ejemplo, tomando el valor de un potenciómetro).

Para hacer pruebas de los valores que se obtienen con esta estimación, se puede descargar el código de ejemplo para Arduino de cálculo del pulso con la lectura de luz infrarroja del MAX30100. En la captura de pantalla de abajo se puede ver un ejemplo de resultado una vez estabilizada la medida.

MAX30100 estimación frecuencia cardíaca lectura luz infrarroja

Estimación de la SpO2 con el MAX30100 leyendo la luz roja e infrarroja

Como se decía más arriba, la saturación de oxígeno en sangre se suele expresar como un porcentaje que relaciona la presencia de oxihemoglobina con la de hemoglobina. La SpO2 se puede calcular con la fórmula: SpO2=100×HbO2÷(HbO2+Hb)

Las medidas que el MAX30100 entrega corresponden a la luz roja e infrarroja reflejada en la zona expuesta al sensor y emitida por los correspondientes LED. Como la hemoglobina absorbe más radiación en la longitud de onda del rojo (~650 nm) y la oxihemoglobina del infrarrojo (~950 nm), se puede inferir la presencia de Hb y HbO2 por la luz de cada tipo medida.

Supuesto que la longitud de onda de la luz emitida por cada LED sea la correcta, un inconveniente al calcular la SpO2 podría consistir en la intensidad diferencial emitida por cada uno de los LED. Para compensarla, además de un desplazamiento y un coeficiente estimados por ensayo, sería posible suministrar diferente corriente a cada uno de los LED. Para ilustrar esta posibilidad y para poder visualizar la distribución de ambas medidas, en el siguiente código de ejemplo se utilizan 30600 µA para el rojo y 50000 µA para el infrarrojo de forma que en la gráfica que se obtiene con el trazador serie de Arduino puede superponer los valores medidos para ambos LED.

MAX30100 hemoglobina y oxihemoglobina estimadas con la medida de la luz roja e infrarroja

Con pruebas de este tipo se pueden conocer mejor los márgenes en los que funciona un de sensor, el MAX30100, en este caso. Por ejemplo, he observado que hasta no llegar a los 7600 µA no se detecta de manera estable la luz reflejada y que la luz que emite el LED rojo a más de 40200 µA satura el fotodiodo.

Suponiendo que la calibración de la relación entre la luz roja e infrarroja sea correcta (hay que recordar que se detecta la luz reflejada, no la absorbida), al sustituir en el anterior código de lectura de ambas intensidades la salida (los códigos Serial.print de las líneas 41 a 43) del valor por:

se obtiene una lectura como la de la captura de pantalla de abajo, en la que puede verse que el porcentaje está siempre muy cerca del 100 %, como cabría esperar. De hecho, al tratarse de un dispositivo usado como wearable de salud (es decir, un equipo no apto para su uso clínico), el límite inferior de lectura debería estar siempre por encima del 95 % de saturación.

MAX30100 gráfica cálculo saturación porcentual arterial de oxígeno SpO2 luz roja e infrarroja reflejada

Víctor Ventura

Desarrollando aplicaciones para la web conocí el potencial de internet de las cosas, encontré la excusa perfecta para satisfacer la inquietud de aprender electrónica que había tenido desde siempre. Ahora puedo darme el gusto de programar las cosas que yo mismo diseño y fabrico.

Más entradas - Página web

Sígueme:
TwitterLinkedIn

Seguir Víctor Ventura:

Programador multimedia y web + IoT. Mejor con software libre.

Desarrollando aplicaciones para la web conocí el potencial de internet de las cosas, encontré la excusa perfecta para satisfacer la inquietud de aprender electrónica que había tenido desde siempre. Ahora puedo darme el gusto de programar las cosas que yo mismo diseño y fabrico.

37 Respuestas

  1. Pablo Urbano

    Hola. Estoy intentando hacer un wearable casero que toma el pulso además de otras cosas.
    Entre otros, he probado el programa que sale en este artículo pero no consigo que me funcione o puede ser que tenga roto el MAX30100, porque me salen unos valores incorrectos.
    Con el programa de la gráfica y mucho probar he conseguido que me salga algo parecido a la foto que sale en este artículo pero la gráfico va bajando cada vez.
    Gracias de antemano por tu ayuda y un saludo.

    • Víctor Ventura

      Hola, Pablo.

      Si entiendo bien lo de la «gráfica que va bajando» el primero de los problemas que tienes es que no colocas bien el sensor en el lugar en el que mides el pulso. Es muy importante que quede fijo. Para las pruebas puedes hacer algo rudimentario y provisional como pegarlo con cinta aislante (en mi caso mejoró mucho); es muy incómodo si lo haces sobre tu propio dedo, pero resuelves otro (posible) problema: que la luz exterior interfiera la lectura. A largo plazo debes contar con que el diseño del soporte físico es algo significativo en el proyecto.

      Lo del pulso incorrecto (no nos das muchos datos) se me ocurre que puede ser en parte por lo mismo y mejorará mucho cuando fijes el sensor pero también es relativamente habitual tener lecturas irregulares. Puedes corregirlo, por un lado, descartando las que estén claramente fuera de rango (por ejemplo usando constrain) y por otro promediando unos cuantos valores (quiero decir buscando un valor intermedio, no necesariamente la media). El problema con el pulso es que debe ser leído en tiempo real para se útil, de forma que no se puede esperar a recibir muchos valores y buscar, por ejemplo, la mediana de los valores sin los picos, así que debes conformarte con almacenar unos pocos datos (algo como media docena) y trabajar con ellos.

      Gracias por participar en polaridad.es y suerte con tu proyecto.

  2. juan pablo

    buenas, intente con estos codigos y no me parece ninguna lectura. me salen simbolos, no se si me puedas ayudar

    • Víctor Ventura

      Hola, Juan Pablo. Con los datos que das no se me ocurre cómo ayudarte 🙁 ¿Dónde salen esos símbolos? ¿Puede ser que estés confundiendo el monitor serie (texto) con el trazador (plotter) serie (gráfico)?

  3. Pablo

    Buenas, igual no tiene configurada la misma tasa de transferencia en el código y en el monitor

  4. Naim

    Hola,

    En el ejemplo de sale el ritmo cardiaco: la frquenci cardiaca estimada es de 63 pulsasiones por minuto.

    el pin de interrupcion: #define PIN_INTERRUPCION 7 // Usando una placa Arduino Leonardo

    Si utilizo arduino UNO que tengo que poner?

    Gracias.

    • Víctor Ventura

      Hola, Naim.

      En las placas Arduino Uno solamente puedes utilizar el pin 2 y el 3 para asignar interrupciones con attachInterrupt. Por ejemplo, tendrías que hacer algo como attachInterrupt(digitalPinToInterrupt(2),leer_algo,LOW); o más correcto y fácil de leer (y más cercano a los ejemplos) #define PIN_INTERRUPCION 2 y luego attachInterrupt(digitalPinToInterrupt(PIN_INTERRUPCION),leer_algo,LOW);

      Gracias a ti por participar en polaridad.es

  5. Naïm

    Gracias,

    Se tarda un tiempo en estabilizar la senyal, se puede mejorar este tiempo¿?

    • Víctor Ventura

      Hola, Naïm.

      Sí y no 😀

      El sensor empieza a trabajar bastante rápido (al menos para lo lento que yo soy) pero lo de dejar el dedo quieto y que los datos que va monitorizando sirvan para algo tarda más (incluso yo mismo llegaba a pensar que no funcionara al principio de usarlo).

      Los mejores resultados los he conseguido encerrando el sensor en algo que impida (lo mejor posible) que entre la luz y ayude lo más posible a que el dedo quede en una posición concreta. Si tienes impresión 3D a tu alcance no es difícil diseñar un pequeño «dedal» para las pruebas.

      Si estás diseñando algo para producción, por mi experiencia, la parte de programación puedes resolverla fácil usando algo chapucero (una funda de cartón ya sirve) pero la parte del diseño del producto debes hacerla con mucho cuidado para que no fracase porque los usuarios sufran el comportamiento que te decía al principio o, algo peor, durante el proceso, un pequeño movimiento o lo que sea, devuelva datos erróneos. Tendrás que trabajarte eso muy bien y añadir cosas como avisos de que la medición tiene problemas para que no decepcione al usuario.

      Espero haberte ayudado un poco con esto.

      Gracias a ti por participar en polaridad.es

  6. Naïm

    Hola,

    1. Tienes algun tutorial sobre el MAX30102

    2. Es compatible los codigos con el MAX30102?

    • Víctor Ventura

      Hola, Naïm.

      No tengo ningún tutorial sobre el MAX30102 🙁

      Creo que es compatible con el MAX30100 pero no lo he probado (ni estudiado la hoja de datos) y no te lo puedo garantizar.

      Tengo pendiente pedir alguno de prueba y modificar este artículo si encuentro algo relevante pero ahora mismo no ando ni regular de tiempo 🙁

      Si lo investigas, por favor, cuéntanos por aquí lo que descubras.

      ¡Gracias por participar en polaridad.es!

      • Naïm

        Por supuesto si consigo algun resultado interesante con el max30102 lo compartire

  7. Andrés Calle

    Hola buenas tardes, estoy trabajando con este sensor MAX30100, y con un microcontrolador K53 de la familia Freescale, tengo problemas leyendo el registro FIFO_DATA del sensor. El código que implemento es muy similar al tuyo, acá lo comparto y espero comprendas un poco:

    if(Leer==1){ //bandera propia con la que contro si es SpO2 y FC o unicamente FC
    Flag=Read_Regis_MAX30100(0x00); // verifico el registro de estado de interrupción
    if(Flag=!0){ // condicional al que ingresa si la interrupción es activada y la toma de la muestra esta lista
    Flag=0;
    for(i=0;i<4;i++){// con este for, leo 4 veces el registro FIFO-DATA, 2 para infrarojo y 2 para rojo
    Lectura[i]=Read_Regis_MAX30100(0x05);
    }
    IR=(Lectura[0]<<8 | Lectura[1]); //uno los vectores para infrarrojo
    R=(Lectura[2]<<8 | Lectura[3]); // uno los vectores para rojo
    }
    }

    adicionalmente te cuento, que con este código he notado que al realizar las iteraciones paso por paso mediante el debug del software, la adquisición de los datos es correcta, sin embargo cuando corro el programa de lleno, la adquisición es incorrecta, eso me indica a pensar que debe ser un problema con el reloj del MCU y la lectura. no se si tuviste algo similar y puedas ayudarme.

    Saludos

  8. Ian F.

    Hola,
    primero que nada gracias por la aportación sobre este sensor, me ha sido de gran utilidad.
    Te comento que no he podido cambiar la velocidad de muestreo, quiero utilizar 1000mps con un ancho de pulso de 200us (como está indicado en el datasheet), sin embargo al tratar de cambiar esta configuración en tu código la señal se mantiene a la misma frecuencia de muestreo de 100mps. ¿Cómo fue que tu si pudiste cambiar la frecuencia de muestreo en uno de tus ejemplos?
    Saludos.

    • Víctor Ventura

      Hola, Ian.

      No sé exactamente cómo lo haces ni cómo verificas que no te funciona 🙁

      A lo peor hay algún error en el código de ejemplo que has utilizado (ayudaría saber cuál es, para arreglarlo). Lo que sí puedo confirmarte, porque en su momento lo utilicé, es que la frecuencia de muestreo se cambia sin mayor problema.

      Supongo que lo has tenido en cuenta porque es una obviedad pero, como he confundido con eso a algún lector de polaridad.es, es bueno recordar que la salida serie (o lo que sea que se use para mostrar los datos) debe variar de velocidad en función de la velocidad a la que funcione el sensor.

      Saludos y gracias por participar en polaridad.es 🙂

      • Ian F.

        Gracias por la pronta respuesta. 🙂
        El código que utilice fue “el ejemplo para Arduino de lectura desde el MAX30100 de la intensidad de luz infrarroja reflejada para estimar la frecuencia cardíaca (pulso)”, que tiene como nombre de archivo “MAX30100_leer_intensidad_infrarroja”.

        Originalmente se establece la velocidad de muestreo con la línea 17 del código:
        enviar_i2c(MAX30100_DIRECCION,MAX30100_CONFIGURACION_SPO2,MAX30100_ALTA_RESOLUCION|MAX30100_PULSO_100_MPS|MAX30100_TIEMPO_LED_1600);

        y la reemplace por esta:
        enviar_i2c(MAX30100_DIRECCION,MAX30100_CONFIGURACION_SPO2, MAX30100_PULSO_1000_MPS|MAX30100_TIEMPO_LED_200);

        Además, y como mencionas cambie la velocidad de transmisión serie por 115200 baudios. La forma que verifique la velocidad de muestreo es usando otro puerto como salida digital, haciendo que dicho puerto pasara a HIGH cuando se empieza a leer la intensidad dada por el sensor y después el puerto pasara a LOW cuando se terminan de escribir los datos de la intensidad, de esta forma pude observar mediante un osciloscopio que la intensidad se mostraba a una frecuencia de 100Hz es decir que se obtenían 100 muestras por segundo. Este método da una aproximación, en realidad no sé en qué me haya equivocado.
        Espero que puedas ayudarme.

        • Víctor Ventura

          Hola, Ian.

          ¡Me alegro de ver que mis lectores tienen tanto nivel! 🙂

          Por lo que dices, parece que lo estás haciendo bien. Lo único que se me ocurre es un conflicto de configuración. El registro 0x07 (SPO2) almacena el ancho del pulso (bits cero y uno) y el tiempo de muestreo (bits dos a cuatro) y puede ser que uno contradiga al otro.

          Otra vez gracias por participar en polaridad.es, creo que tu aportación es muy interesante para otros lectores.

          Saludos.

          • Ian F.

            Hola, Víctor.
            Creo que encontré el problema, dentro de tu código para el registro 0x07 (SPO2) los valores para la frecuencia de muestreo son:

            Revisando esto me di cuenta que no se configuran los bits dos a cuatro adecuados para el registro, por lo que los valores tendrían que ser:

            Ya probé estos valores y parece ser que funcionan correctamente, espero que alguien mas pueda confirmarlo también.
            Otra cosa que me gustaría que me explicaras es cómo funciona la función “recibir_i2c”, no entiendo muy bien por qué generas un cronometro y pones un TIMEOUT.
            Saludos.

          • Víctor Ventura

            Hola, Ian.

            Tienes razón, en el código de ejemplo los bits están desplazados dos posiciones (quizá por haber copiado, pegado y olvidado cambiar los datos del ancho del pulso, no recuerdo) ¡Gracias por avisar! 🙂

            Lo he cambiado en el artículo para no confundir a los lectores.

            Con respecto al timeout de la lectura I2C, como he comentado en algunos artículos, es improbable que haga falta en Arduino pero lo incluyo para recordar que no siempre las comunicaciones van a funcionar bien (y más con dispositivos externos al PCB). La idea es que, si algo va mal, el dispositivo no se quede esperando los datos indefinidamente.

            Gracias por participar en polaridad.es

  9. pablo morales

    Hola, con este modulo se puede obtener la presion arterial, existen varios smartband en el mercado que ya ofrecen este tipo de servicios pero no veo que exista un modulo especifco para eso.

  10. Juanma

    Buenas,
    he leído que el sensor típicamente se coloca en el dedo.
    ¿Sería posible colocarlo en otra zona del cuerpo, como antebrazo, muñeca o cuello?

    También comentas que: «el rango de valores dependerá del color (transparencia) de la piel y el grosor de los tejidos de cada individuo así como de la posición sobre el sensor de latido, por lo que será importante realizar las primeras pruebas en un entorno conocido: el mismo sujeto y un sistema (soporte) que fije la posición del dedo en el oxímetro de pulso.»
    ¿Quiere eso decir que cada vez que vayamos a medir en un sujeto distinto hay que realizar unas primeras pruebas para acondicionar el sensor, o con hacerlo para el primer sujeto es suficiente? ¿Varían mucho las lecturas de un sujeto a otro (tanto como para poder malinterpretarlas)?

    Gracias

    • Víctor Ventura

      Hola, Juanma.

      Me pillas fatal de tiempo y me gustaría poder hacer alguna prueba antes de contestarte; el artículo tiene ya casi un año y mis últimos experimentos con el MAX30100 poco menos. Por favor, toma lo que te respondo con la precaución que corresponde a hacerlo de memoria.

      En primer lugar, como mide la luz reflejada, sí, debería ser posible colocarlo en otra parte del cuerpo que tenga la piel lo bastante fina y bien irrigada como para poder detectar el pulso.

      El principal problema que he encontrado usando este dispositivo es la gran variación de medidas en función de la colocación (y me temo que esto tendrá que ver con lo anterior) Por eso, lo más fiable es acompañarlo de un fijación estable y hacerlo en un dedo es sencillo y resuelves dos problemas de una vez.

      Te hará más llevadero el proceso de escritura del programa (que necesita muchas pruebas) tener un entorno controlado (la misma persona, el mismo lugar de medida) Sospecho que, al ser algo tan evidente para ti y a lo peor por no haberlo aclarado yo muy bien, te ha sonado a que siempre tendrás que medir el pulso de la misma persona. No es así, puedes medir el pulso de muchas personas una vez que hayas determinado cómo hacerlo de forma estable valiéndote para ello de un entorno estable.

      Espero ayudarte con esto. Gracias por visitar el blog y un saludo.

  11. jeremi

    buenas tardes, cual es el esquema de conexión de max30100 a arduino ?

  12. Fabiola

    Alguien sabe si ese sensor puede ser utilizado en la muñeca de la mano para tomar mediciones? O alguno que me recomienden para el uso en la muñeca que sea pequeño me urge.

    • Víctor Ventura

      Hola, Fabiola.

      Para la muñeca no te va a servir el MAX30100, necesitas el MAX30102 pero también es muy barato y fácil de conseguir.

      Suerte con tu proyecto.

  13. Andres Torres

    Hola, gracias por documentar sobre este sensor. Tengo una pregunta, hago las conexiones Vin=3.3V Gnd=Gnd, Scl=Scl, Sda=Sda, INT=2 (sobre aduino Uno) con respectivas resistencias pull up 4.7kOhms, no veo el dichoso led rojo encendido ¿Es normal? Intento ver la entrada INT pero siempre está en alto, nunca baja a cero. ¿Alguna idea?

    • Cristian Pérez

      Buen día.
      Andrés estoy igual.
      Será que está dañado el sensor.
      Pero no veo como se alimente el led y encienda

      No visualizo el puerto v+led?

  14. saray

    hola no pude realizar el de la frecuencia cardiaca tengo un arduino nano y ya le puse las librerias del nano pero #include «enviar_recibir_i2c.h» esta no supe como era me podrian ayudar

  15. giovanni

    hola buenas tardes disculpa lo que pasa es que hice una programacion similar para el arduino nano pero ahora quiero utilizar un mega y no corre la programacion no se si sea por el senso..
    me podrias ayudar…??
    gracias y muy buen trabajo

  16. Luis Valseca Soto

    Hola, en el apartado «Circuito de aplicación del MAX30100», donde dice:
    «Los ánodos están internamente conectados a GND a través del driver de los LED. Típicamente, los ánodos de ambos LED se dejan sin conectar»,
    deberia decir:
    «Los catodos están internamente conectados a GND a través del driver de los LED. Típicamente, los catodos de ambos LED se dejan sin conectar»
    Un cordial saludo
    Luis Valseca

  17. Gustavo

    Hola yo ya tengo el max30100 y estoy interesado en realizar el prototipo , sin embargo he notado que dependiendo la distancia que haya entre los led y el dedo hay una variacion de la respues , cual seria la distancia optima entre el sensor y el objetivo?

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *