#include <stdio.h>
#include <math.h>
#include <stdbool.h>
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/gpio.h"
#include "driver/adc.h"
#include "driver/i2c.h"
#include "esp_rom_sys.h"
#include "esp_log.h"
/* =========================================================
* CONFIGURACIÓN DE HARDWARE Y SEÑALES CLÍNICAS
* ========================================================= */
// Indicadores visuales de eventos fisiológicos cardíacos
#define LED_INDICADOR_SISTOLE GPIO_NUM_18 // Activo durante la fase de sístole ventricular
#define LED_INDICADOR_MODO_PROTECCION GPIO_NUM_19 // Indica activación de modo de protección clínica
// Canales ADC asociados a variables fisiológicas simuladas
#define ADC_LLENADO_DIASTOLICO ADC1_CHANNEL_6 // GPIO34 – Simulación de retorno venoso / llenado ventricular
#define ADC_CONTROL_FRECUENCIA_CARDIACA ADC1_CHANNEL_7 // GPIO35 – Control manual de frecuencia cardíaca
// Rango operativo del ADC del ESP32
#define ADC_VALOR_MINIMO 0
#define ADC_VALOR_MAXIMO 4095
// Umbrales de zonas de operación del potenciómetro
#define ADC_ZONA_BAJA_MAX 1500
#define ADC_ZONA_MEDIA_MAX 3000
// Configuración del bus I2C para sistema de monitoreo (LCD)
#define PIN_I2C_SDA GPIO_NUM_21
#define PIN_I2C_SCL GPIO_NUM_22
#define PUERTO_I2C I2C_NUM_0
// Umbrales ADC para detección de cambios en la frecuencia cardíaca
#define FC_ADC_UMBRAL_ENTRADA_LENTA 1300
#define FC_ADC_UMBRAL_SALIDA_LENTA 1500
#define FC_ADC_UMBRAL_ENTRADA_RAPIDA 2800
#define FC_ADC_UMBRAL_SALIDA_RAPIDA 2600
/* =========================================================
* PARÁMETROS FISIOLÓGICOS CARDÍACOS
* ========================================================= */
#define VOLUMEN_TELEDIASTOLICO_OBJETIVO_ML 70.0f // Volumen ventricular objetivo al final de la diástole
#define FACTOR_LLENADO_DIASTOLICO_BASAL 0.08f // Factor basal de llenado ventricular
#define VOLUMEN_VENTRICULAR_MINIMO_ML 40.0f // Volumen ventricular mínimo fisiológicamente aceptable
/* =========================================================
* PARÁMETROS HEMODINÁMICOS (MODELO SIMPLIFICADO)
* ========================================================= */
#define COMPLIANCIA_ARTERIAL_SIMULADA 1.5f
#define FACTOR_ESCURRIMIENTO_ARTERIAL 0.015f
#define PRESION_ARTERIAL_MINIMA_MM_HG 60.0f
#define PRESION_ARTERIAL_MAXIMA_MM_HG 120.0f
/* =========================================================
* PARÁMETROS TEMPORALES DEL CICLO CARDÍACO
* ========================================================= */
#define PERIODO_CONTROL_CICLO_CARDIACO_MS 10
/* =========================================================
* UMBRALES CLÍNICOS DE VOLUMEN VENTRICULAR
* ========================================================= */
#define VOLUMEN_CRITICO_ML 40.0f
#define VOLUMEN_NORMAL_MINIMO_ML 60.0f
#define VOLUMEN_NORMAL_MAXIMO_ML 100.0f
/* =========================================================
* LÍMITES DE FRECUENCIA CARDÍACA
* ========================================================= */
#define FRECUENCIA_CARDIACA_MINIMA_BPM 60
#define FRECUENCIA_CARDIACA_MAXIMA_BPM 110
#define FRECUENCIA_PROTECCION_BAJA_BPM 60
#define FRECUENCIA_PROTECCION_ALTA_BPM 80
// Confirmación clínica por persistencia temporal
#define CICLOS_CONFIRMACION_CLINICA 5
/* =========================================================
* DEFINICIÓN DE ESTADOS FISIOLÓGICOS Y CLÍNICOS
* ========================================================= */
// Fases del ciclo cardíaco
typedef enum {
FASE_CICLO_DIASTOLE = 0,
FASE_CICLO_SISTOLE
} fase_ciclo_cardiaco_t;
// Estados clínicos globales del sistema
typedef enum {
ESTADO_CLINICO_NORMAL = 0,
ESTADO_CLINICO_LLENADO_LENTO,
ESTADO_CLINICO_FRECUENCIA_ELEVADA,
ESTADO_CLINICO_ASISTOLIA
} estado_clinico_sistema_t;
// Modos de control de frecuencia cardíaca
typedef enum {
MODO_CONTROL_FC_NORMAL = 0,
MODO_CONTROL_FC_LLENADO_LENTO,
MODO_CONTROL_FC_ACELERADO
} modo_control_frecuencia_cardiaca_t;
/* =========================================================
* VARIABLES GLOBALES DEL MODELO CARDIOVASCULAR
* ========================================================= */
/* ---------------------
* Dinámica cardíaca
* --------------------- */
static fase_ciclo_cardiaco_t fase_ciclo_actual = FASE_CICLO_DIASTOLE;
static float volumen_ventricular_actual_ml = 0.0f; // Volumen ventricular instantáneo
static float volumen_sistolico_actual_ml = 0.0f; // Volumen sistólico eyectado por latido
/* ---------------------
* Dinámica hemodinámica (modelo arterial simplificado)
* --------------------- */
static float volumen_arterial_simulado_ml = 0.0f;
static float presion_arterial_actual_mmHg = PRESION_ARTERIAL_MINIMA_MM_HG;
/* ---------------------
* Estado clínico global
* (solo modificable por la tarea de supervisión clínica)
* --------------------- */
static estado_clinico_sistema_t estado_clinico_actual = ESTADO_CLINICO_NORMAL;
static bool modo_proteccion_clinica_activo = false;
/* ---------------------
* Control de frecuencia cardíaca
* --------------------- */
static int frecuencia_cardiaca_actual_bpm = 70;
static modo_control_frecuencia_cardiaca_t modo_control_fc_actual = MODO_CONTROL_FC_NORMAL;
/* ---------------------
* Variables auxiliares de monitoreo
* --------------------- */
static int presion_arterial_visualizada_mmHg = 0;
/* ---------------------
* Confirmación clínica por persistencia temporal
* --------------------- */
static float volumen_sistolico_minimo_ml = 999.0f;
static float volumen_sistolico_maximo_ml = 0.0f;
static int contador_confirmacion_clinica = 0;
static estado_clinico_sistema_t estado_clinico_pendiente = ESTADO_CLINICO_NORMAL;
static estado_clinico_sistema_t estado_clinico_confirmado = ESTADO_CLINICO_NORMAL;
/* ---------------------
* Entrada solicitada por operador (potenciómetro)
* --------------------- */
volatile int frecuencia_cardiaca_solicitada_bpm = 70;
/* =========================================================
* ESTADOS FISIOLÓGICOS DERIVADOS
* ========================================================= */
// Estado del volumen circulante ventricular
typedef enum {
ESTADO_VOLUMEN_VENTRICULAR_BAJO,
ESTADO_VOLUMEN_VENTRICULAR_LLENADO_LENTO,
ESTADO_VOLUMEN_VENTRICULAR_NORMAL
} estado_volumen_ventricular_t;
// Estado de la eyección sistólica
typedef enum {
ESTADO_EYECCION_SISTOLICA_LENTA,
ESTADO_EYECCION_SISTOLICA_NORMAL,
ESTADO_EYECCION_SISTOLICA_RAPIDA
} estado_eyeccion_sistolica_t;
/* ---------------------
* Modo global del sistema
* --------------------- */
typedef enum {
MODO_SISTEMA_NORMAL,
MODO_SISTEMA_PROTECCION_CLINICA
} modo_sistema_t;
modo_sistema_t modo_sistema_actual = MODO_SISTEMA_NORMAL;
int frecuencia_cardiaca_forzada_bpm = 70;
char registro_clinico_texto[64];
/* ---------------------
* Inicialización de estados fisiológicos
* --------------------- */
estado_volumen_ventricular_t estado_volumen_ventricular = ESTADO_VOLUMEN_VENTRICULAR_NORMAL;
estado_eyeccion_sistolica_t estado_eyeccion_sistolica = ESTADO_EYECCION_SISTOLICA_NORMAL;
static int frecuencia_cardiaca_interna_bpm __attribute__((unused)) = 70;
/* =========================================================
* FUNCIONES AUXILIARES
* ========================================================= */
// Zonas de operación del potenciómetro
typedef enum {
ZONA_POTENCIOMETRO_BAJA = 0,
ZONA_POTENCIOMETRO_MEDIA,
ZONA_POTENCIOMETRO_ALTA
} zona_potenciometro_t;
zona_potenciometro_t obtener_zona_potenciometro(int valor_adc)
{
if (valor_adc <= ADC_ZONA_BAJA_MAX)
return ZONA_POTENCIOMETRO_BAJA;
if (valor_adc <= ADC_ZONA_MEDIA_MAX)
return ZONA_POTENCIOMETRO_MEDIA;
return ZONA_POTENCIOMETRO_ALTA;
}
/* ---------------------
* Filtro digital de señales ADC
* --------------------- */
#define FACTOR_FILTRO_ADC 0.1f
static float adc_llenado_filtrado = 0.0f;
static float adc_frecuencia_filtrado = 0.0f;
/* ---------------------
* Utilidades matemáticas
* --------------------- */
static int mapear_entero(int x, int in_min, int in_max, int out_min, int out_max)
{
if (x < in_min) x = in_min;
if (x > in_max) x = in_max;
return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}
/* =========================================================
* PROCESO DEL CICLO CARDÍACO
* Modelo fisiológico ventricular – SIN lógica clínica
* ========================================================= */
void tarea_ciclo_cardiaco(void *arg)
{
TickType_t marca_tiempo_anterior = xTaskGetTickCount();
int duracion_sistole_ms = 0;
int tiempo_transcurrido_ms = 0;
while (1)
{
/* =================================================
* ADQUISICIÓN DE SEÑALES ANALÓGICAS + FILTRADO
* ================================================= */
// Señal de llenado ventricular (retorno venoso / precarga)
int adc_llenado_bruto = adc1_get_raw(ADC_LLENADO_DIASTOLICO);
adc_llenado_filtrado += FACTOR_FILTRO_ADC *
(adc_llenado_bruto - adc_llenado_filtrado);
ESP_LOGI("ADC", "Llenado ventricular ADC = %d", adc_llenado_bruto);
// Señal de control de frecuencia cardíaca
int adc_frecuencia_bruto = adc1_get_raw(ADC_CONTROL_FRECUENCIA_CARDIACA);
adc_frecuencia_filtrado += FACTOR_FILTRO_ADC *
(adc_frecuencia_bruto - adc_frecuencia_filtrado);
int adc_fc_filtrada = (int)adc_frecuencia_filtrado;
/* =================================================
* CLASIFICACIÓN DEL ESTADO DE VOLUMEN (PRECARGA)
* ================================================= */
int adc_llenado_sin_filtro = adc1_get_raw(ADC_LLENADO_DIASTOLICO);
if (adc_llenado_sin_filtro < 1400)
estado_volumen_ventricular = ESTADO_VOLUMEN_VENTRICULAR_BAJO;
else if (adc_llenado_sin_filtro < 3000)
estado_volumen_ventricular = ESTADO_VOLUMEN_VENTRICULAR_LLENADO_LENTO;
else
estado_volumen_ventricular = ESTADO_VOLUMEN_VENTRICULAR_NORMAL;
/* =================================================
* CLASIFICACIÓN DEL ESTADO DE EYECCIÓN SISTÓLICA
* ================================================= */
if (adc_frecuencia_filtrado < 1400)
estado_eyeccion_sistolica = ESTADO_EYECCION_SISTOLICA_LENTA;
else if (adc_frecuencia_filtrado < 2800)
estado_eyeccion_sistolica = ESTADO_EYECCION_SISTOLICA_NORMAL;
else
estado_eyeccion_sistolica = ESTADO_EYECCION_SISTOLICA_RAPIDA;
/* =================================================
* HISTÉRESIS DEL CONTROL DE FRECUENCIA CARDÍACA
* ================================================= */
switch (modo_control_fc_actual)
{
case MODO_CONTROL_FC_NORMAL:
if (adc_fc_filtrada < FC_ADC_UMBRAL_ENTRADA_LENTA)
modo_control_fc_actual = MODO_CONTROL_FC_LLENADO_LENTO;
else if (adc_fc_filtrada > FC_ADC_UMBRAL_ENTRADA_RAPIDA)
modo_control_fc_actual = MODO_CONTROL_FC_ACELERADO;
break;
case MODO_CONTROL_FC_LLENADO_LENTO:
if (adc_fc_filtrada > FC_ADC_UMBRAL_SALIDA_LENTA)
modo_control_fc_actual = MODO_CONTROL_FC_NORMAL;
break;
case MODO_CONTROL_FC_ACELERADO:
if (adc_fc_filtrada < FC_ADC_UMBRAL_SALIDA_RAPIDA)
modo_control_fc_actual = MODO_CONTROL_FC_NORMAL;
break;
}
/* =================================================
* FRECUENCIA CARDÍACA EFECTIVA DEL SISTEMA
* ================================================= */
int bpm_efectivo = (modo_sistema_actual == MODO_SISTEMA_PROTECCION_CLINICA)
? frecuencia_cardiaca_forzada_bpm
: frecuencia_cardiaca_actual_bpm;
int duracion_ciclo_ms = 60000 / bpm_efectivo;
duracion_sistole_ms = duracion_ciclo_ms / 3;
/* =================================================
* CÁLCULO DE TASA DE LLENADO DIASTÓLICO
* ================================================= */
float tasa_llenado_diastolico =
FACTOR_LLENADO_DIASTOLICO_BASAL *
mapear_entero((int)adc_llenado_filtrado,
ADC_VALOR_MINIMO,
ADC_VALOR_MAXIMO,
50,
150) / 100.0f;
/* =================================================
* MÁQUINA DE ESTADOS DEL CICLO CARDÍACO
* ================================================= */
if (fase_ciclo_actual == FASE_CICLO_DIASTOLE)
{
// Fase de llenado ventricular
volumen_ventricular_actual_ml +=
tasa_llenado_diastolico * VOLUMEN_TELEDIASTOLICO_OBJETIVO_ML;
if (volumen_ventricular_actual_ml >=
VOLUMEN_TELEDIASTOLICO_OBJETIVO_ML)
{
fase_ciclo_actual = FASE_CICLO_SISTOLE;
tiempo_transcurrido_ms = 0;
// Indicador visual de inicio de sístole
gpio_set_level(LED_INDICADOR_SISTOLE, 1);
}
}
else
{
// Fase de eyección sistólica
tiempo_transcurrido_ms += PERIODO_CONTROL_CICLO_CARDIACO_MS;
if (tiempo_transcurrido_ms >= duracion_sistole_ms)
{
// Fin de sístole → cálculo de volumen sistólico
volumen_sistolico_actual_ml = volumen_ventricular_actual_ml;
volumen_arterial_simulado_ml += volumen_sistolico_actual_ml;
// Registro para evaluación clínica posterior
volumen_sistolico_minimo_ml =
fminf(volumen_sistolico_minimo_ml,
volumen_sistolico_actual_ml);
volumen_sistolico_maximo_ml =
fmaxf(volumen_sistolico_maximo_ml,
volumen_sistolico_actual_ml);
contador_confirmacion_clinica++;
volumen_ventricular_actual_ml = 0.0f;
fase_ciclo_actual = FASE_CICLO_DIASTOLE;
// Apagado del indicador de sístole
gpio_set_level(LED_INDICADOR_SISTOLE, 0);
}
}
vTaskDelayUntil(&marca_tiempo_anterior,
pdMS_TO_TICKS(PERIODO_CONTROL_CICLO_CARDIACO_MS));
}
}
/* =========================================================
* PROCESO SUPERVISOR CLÍNICO
* ÚNICA autoridad de decisión clínica del sistema
* ========================================================= */
void tarea_supervision_clinica(void *arg)
{
TickType_t marca_tiempo_anterior = xTaskGetTickCount();
TickType_t estado_desde = xTaskGetTickCount();
/* Estados detectados vs confirmados */
bool modo_proteccion_detectado = false;
bool modo_proteccion_confirmado = false;
int frecuencia_detectada_bpm = 0;
int frecuencia_confirmada_bpm = 0;
char mensaje_detectado[64] = "";
char mensaje_confirmado[64] = "sistema estable";
while (1)
{
/* =================================================
* DETECCIÓN CLÍNICA (SIN ACTUAR)
* ================================================= */
modo_proteccion_detectado = false;
frecuencia_detectada_bpm = frecuencia_cardiaca_actual_bpm;
strcpy(mensaje_detectado, "sistema estable");
/* ---- Evaluación del estado de volumen ---- */
if (estado_volumen_ventricular == ESTADO_VOLUMEN_VENTRICULAR_BAJO)
{
modo_proteccion_detectado = true;
frecuencia_detectada_bpm = FRECUENCIA_PROTECCION_BAJA_BPM;
strcpy(mensaje_detectado,
"volumen bajo + eyeccion segura MIN");
}
else if (estado_volumen_ventricular ==
ESTADO_VOLUMEN_VENTRICULAR_LLENADO_LENTO)
{
modo_proteccion_detectado = true;
frecuencia_detectada_bpm = FRECUENCIA_PROTECCION_ALTA_BPM;
strcpy(mensaje_detectado,
"llenado lento + eyeccion segura MAX");
}
else if (estado_volumen_ventricular ==
ESTADO_VOLUMEN_VENTRICULAR_NORMAL)
{
if (estado_eyeccion_sistolica ==
ESTADO_EYECCION_SISTOLICA_LENTA ||
estado_eyeccion_sistolica ==
ESTADO_EYECCION_SISTOLICA_RAPIDA)
{
modo_proteccion_detectado = true;
frecuencia_detectada_bpm = FRECUENCIA_PROTECCION_ALTA_BPM;
strcpy(mensaje_detectado,
"volumen estable + eyeccion segura MAX");
}
}
/* =================================================
* HISTÉRESIS TEMPORAL DE CONFIRMACIÓN CLÍNICA
* ================================================= */
if (modo_proteccion_detectado != modo_proteccion_confirmado ||
frecuencia_detectada_bpm != frecuencia_confirmada_bpm ||
strcmp(mensaje_detectado, mensaje_confirmado) != 0)
{
if ((xTaskGetTickCount() - estado_desde) >
pdMS_TO_TICKS(1500))
{
modo_proteccion_confirmado = modo_proteccion_detectado;
frecuencia_confirmada_bpm = frecuencia_detectada_bpm;
strcpy(mensaje_confirmado, mensaje_detectado);
estado_desde = xTaskGetTickCount();
ESP_LOGI("SUPERVISOR_CLINICO",
"ESTADO CONFIRMADO: %s",
mensaje_confirmado);
}
}
else
{
estado_desde = xTaskGetTickCount();
}
/* =================================================
* APLICACIÓN DEL ESTADO CLÍNICO CONFIRMADO
* ================================================= */
modo_proteccion_clinica_activo = modo_proteccion_confirmado;
if (modo_proteccion_clinica_activo)
frecuencia_cardiaca_forzada_bpm = frecuencia_confirmada_bpm;
modo_sistema_actual =
modo_proteccion_clinica_activo
? MODO_SISTEMA_PROTECCION_CLINICA
: MODO_SISTEMA_NORMAL;
strcpy(registro_clinico_texto, mensaje_confirmado);
gpio_set_level(LED_INDICADOR_MODO_PROTECCION,
modo_proteccion_clinica_activo);
vTaskDelayUntil(&marca_tiempo_anterior,
pdMS_TO_TICKS(200));
}
}
/* =========================================================
* PROCESO HEMODINÁMICO VASCULAR
* Modelo pasivo de volumen y presión arterial
* ========================================================= */
void tarea_modelo_vascular(void *arg)
{
TickType_t marca_tiempo_anterior = xTaskGetTickCount();
while (1)
{
/* =================================================
* ESCURRIMIENTO ARTERIAL
* Representa resistencia vascular periférica
* ================================================= */
volumen_arterial_simulado_ml -=
volumen_arterial_simulado_ml * FACTOR_ESCURRIMIENTO_ARTERIAL;
if (volumen_arterial_simulado_ml < 0.0f)
volumen_arterial_simulado_ml = 0.0f;
/* =================================================
* CÁLCULO DE PRESIÓN ARTERIAL MEDIA SIMULADA
* Modelo lineal presión–volumen (compliance)
* ================================================= */
presion_arterial_actual_mmHg =
volumen_arterial_simulado_ml / COMPLIANCIA_ARTERIAL_SIMULADA;
if (presion_arterial_actual_mmHg > PRESION_ARTERIAL_MAXIMA_MM_HG)
presion_arterial_actual_mmHg = PRESION_ARTERIAL_MAXIMA_MM_HG;
if (presion_arterial_actual_mmHg < PRESION_ARTERIAL_MINIMA_MM_HG)
presion_arterial_actual_mmHg = PRESION_ARTERIAL_MINIMA_MM_HG;
/* Variable auxiliar para visualización clínica */
presion_arterial_visualizada_mmHg =
(int)presion_arterial_actual_mmHg;
vTaskDelayUntil(&marca_tiempo_anterior,
pdMS_TO_TICKS(50));
}
}
/* =========================================================
* PROTOTIPOS DEL CONTROLADOR LCD
* ========================================================= */
static void lcd_init(void);
static void lcd_cmd(uint8_t c);
static void lcd_char(char c);
static void lcd_set_cursor(uint8_t col, uint8_t row);
static void lcd_print(const char *s);
/* =========================================================
* PROCESO DE VISUALIZACIÓN CLÍNICA
* Monitoreo en tiempo real de variables fisiológicas
* ========================================================= */
void tarea_visualizacion_clinica(void *arg)
{
char linea_lcd[21];
/* Inicialización del dispositivo LCD */
lcd_init();
while (1)
{
/* Limpieza de pantalla */
lcd_cmd(0x01);
vTaskDelay(pdMS_TO_TICKS(5));
/* =================================================
* LÍNEA 1: VOLUMEN SISTÓLICO + FRECUENCIA CARDÍACA
* ================================================= */
lcd_set_cursor(0, 0);
snprintf(linea_lcd, sizeof(linea_lcd),
"VS:%3.0fml FC:%3d",
volumen_sistolico_actual_ml,
frecuencia_cardiaca_forzada_bpm);
lcd_print(linea_lcd);
/* =================================================
* LÍNEA 2: ESTADO OPERATIVO DEL SISTEMA
* ================================================= */
lcd_set_cursor(0, 1);
if (modo_proteccion_clinica_activo)
lcd_print("MODO: SEGURO");
else
lcd_print("MODO: ESTABLE");
/* =================================================
* LÍNEA 3: MENSAJE CLÍNICO (PARTE SUPERIOR)
* ================================================= */
lcd_set_cursor(0, 2);
strncpy(linea_lcd, registro_clinico_texto, 20);
linea_lcd[20] = '\0';
lcd_print(linea_lcd);
/* =================================================
* LÍNEA 4: MENSAJE CLÍNICO (CONTINUACIÓN SI EXISTE)
* ================================================= */
if (strlen(registro_clinico_texto) > 20)
{
lcd_set_cursor(0, 3);
strncpy(linea_lcd,
registro_clinico_texto + 20,
20);
linea_lcd[20] = '\0';
lcd_print(linea_lcd);
}
vTaskDelay(pdMS_TO_TICKS(300));
}
}
/* =========================================================
* CONTROLADOR LCD I2C
* HD44780 + PCF8574
* ========================================================= */
#define LCD_ADDR 0x27
#define LCD_BACKLIGHT 0x08
#define LCD_ENABLE 0x04
static void lcd_write(uint8_t data)
{
i2c_cmd_handle_t cmd = i2c_cmd_link_create();
i2c_master_start(cmd);
i2c_master_write_byte(cmd,
(LCD_ADDR << 1) | I2C_MASTER_WRITE,
true);
i2c_master_write_byte(cmd,
data | LCD_BACKLIGHT,
true);
i2c_master_stop(cmd);
i2c_master_cmd_begin(PUERTO_I2C,
cmd,
pdMS_TO_TICKS(100));
i2c_cmd_link_delete(cmd);
}
static void lcd_pulse(uint8_t data)
{
lcd_write(data | LCD_ENABLE);
esp_rom_delay_us(1);
lcd_write(data & ~LCD_ENABLE);
esp_rom_delay_us(50);
}
static void lcd_send(uint8_t value, uint8_t mode)
{
uint8_t high = (value & 0xF0) | mode;
uint8_t low = ((value << 4) & 0xF0) | mode;
lcd_pulse(high);
lcd_pulse(low);
}
static void lcd_cmd(uint8_t cmd) { lcd_send(cmd, 0x00); }
static void lcd_char(char c) { lcd_send(c, 0x01); }
static void lcd_set_cursor(uint8_t col, uint8_t row)
{
static uint8_t offsets[] = {0x00, 0x40, 0x14, 0x54};
if (row > 3) row = 3;
lcd_cmd(0x80 | (col + offsets[row]));
}
static void lcd_print(const char *s)
{
while (*s)
lcd_char(*s++);
}
static void lcd_init(void)
{
vTaskDelay(pdMS_TO_TICKS(50));
lcd_cmd(0x33);
lcd_cmd(0x32);
lcd_cmd(0x28);
lcd_cmd(0x0C);
lcd_cmd(0x06);
lcd_cmd(0x01);
vTaskDelay(pdMS_TO_TICKS(5));
}
/* =========================================================
* FUNCIÓN PRINCIPAL
* Inicialización del sistema y creación de procesos
* ========================================================= */
void app_main(void)
{
gpio_set_direction(LED_INDICADOR_SISTOLE, GPIO_MODE_OUTPUT);
gpio_set_direction(LED_INDICADOR_MODO_PROTECCION, GPIO_MODE_OUTPUT);
adc1_config_width(ADC_WIDTH_BIT_12);
adc1_config_channel_atten(ADC_LLENADO_DIASTOLICO, ADC_ATTEN_DB_12);
adc1_config_channel_atten(ADC_CONTROL_FRECUENCIA_CARDIACA, ADC_ATTEN_DB_12);
i2c_config_t i2c = {
.mode = I2C_MODE_MASTER,
.sda_io_num = PIN_I2C_SDA,
.scl_io_num = PIN_I2C_SCL,
.sda_pullup_en = GPIO_PULLUP_ENABLE,
.scl_pullup_en = GPIO_PULLUP_ENABLE,
.master.clk_speed = 100000
};
i2c_param_config(PUERTO_I2C, &i2c);
i2c_driver_install(PUERTO_I2C,
I2C_MODE_MASTER,
0,
0,
0);
xTaskCreate(tarea_ciclo_cardiaco,
"ciclo_cardiaco",
4096,
NULL,
5,
NULL);
xTaskCreate(tarea_supervision_clinica,
"supervisor_clinico",
4096,
NULL,
4,
NULL);
xTaskCreate(tarea_modelo_vascular,
"modelo_vascular",
4096,
NULL,
3,
NULL);
xTaskCreate(tarea_visualizacion_clinica,
"display_clinico",
4096,
NULL,
2,
NULL);
}