tdse-tf_3-02

Controlador PID para derretidor de miel con control local via botones y remoto via WiFi
Index Commits Files Refs Submodules README
commit 55c191d2cbd2a50d62ab1395c157cd8c7ca179b9
parent 1aa759560465bbb9747fa33d377aebd9db64e768
Author: Martin Kloeckner <mjkloeckner@gmail.com>
Date:   Mon, 30 Mar 2026 00:12:34 -0300

Agregar submenu para modificar la temperatura deseada

Diffstat:
Mfirmware/app/inc/app.h | 9++++++---
Mfirmware/app/inc/display_i2c.h | 2++
Mfirmware/app/inc/task_menu_attribute.h | 6++++--
Mfirmware/app/inc/task_system_attribute.h | 3++-
Mfirmware/app/src/app.c | 28+++++++++++++++++++---------
Mfirmware/app/src/display_i2c.c | 18+++++++++---------
Mfirmware/app/src/task_menu.c | 122++++++++++++++++++++++++++++++++++++++++++++++++++++---------------------------
Mfirmware/app/src/task_system.c | 50++++++++++++++++++++++++++++++++++++++++----------
Mfirmware/app/src/task_temp_ctrl.c | 7+++----
Mfirmware/app/src/task_temp_sensor.c | 3---
10 files changed, 166 insertions(+), 82 deletions(-)
diff --git a/firmware/app/inc/app.h b/firmware/app/inc/app.h
@@ -12,14 +12,17 @@
 extern "C" {
 #endif
 
+#include <stdbool.h>
+
 extern uint32_t g_app_runtime_us;
 extern uint32_t g_app_WCET_us;
 extern volatile uint32_t g_app_tick_cnt;
 
 typedef struct {
-    uint16_t temp_set_point;        // Desired temp
-    uint16_t temp_sensor;           // Actual temp
-    uint8_t temp_controller_pwm_dc; // Duty cycle of output [0, 100]
+    uint16_t temp_set_point;   // Desired temp
+    int16_t temp_sensor;       // Actual temp
+    uint8_t temp_ctrl_pwm_dc;  // Duty cycle of output [0, 100]
+    bool temp_ctrl_enabled;
 } shared_data_type;
 
 extern void app_init(void);
diff --git a/firmware/app/inc/display_i2c.h b/firmware/app/inc/display_i2c.h
@@ -14,6 +14,8 @@
 extern "C" {
 #endif
 
+#define G_DISPLAY_CHAR_DEGREE_CODE 0xDF
+
 void display_i2c_init();
 void display_i2c_set_cursor_pos(uint8_t x, uint8_t y);
 void display_i2c_write_string(const char *str);
diff --git a/firmware/app/inc/task_menu_attribute.h b/firmware/app/inc/task_menu_attribute.h
@@ -29,7 +29,8 @@ extern "C" {
 /* Events to excite Task Menu */
 typedef enum {
     EV_MEN_ST_IDLE,
-    EV_MEN_ST_CLOCK,
+    EV_MEN_ST_CLOCK_SET,
+    EV_MEN_ST_TEMP_SET,
     EV_MEN_DISPLAY_UPDATE,
     EV_MEN_INACTIVE_TIMEOUT
 } task_menu_ev_t;
@@ -37,7 +38,8 @@ typedef enum {
 /* State of Task Menu */
 typedef enum {
     ST_MEN_IDLE,
-    ST_MEN_CLOCK
+    ST_MEN_CLOCK_SET,
+    ST_MEN_TEMP_SET
 } task_menu_st_t;
 
 typedef struct {
diff --git a/firmware/app/inc/task_system_attribute.h b/firmware/app/inc/task_system_attribute.h
@@ -40,7 +40,8 @@ typedef enum task_system_ev {
 
 typedef enum task_system_st {
     ST_SYS_IDLE,
-    ST_SYS_CLOCK,
+    ST_SYS_CLOCK_SET,
+    ST_SYS_TEMP_SET,
 } task_system_st_t;
 
 typedef struct {
diff --git a/firmware/app/src/app.c b/firmware/app/src/app.c
@@ -34,21 +34,21 @@ typedef struct {
 } task_cfg_t;
 
 typedef struct {
-    uint32_t WCET; // Task worst-case execution time (microseconds)
-    uint32_t WCET_interval; // WCET in last `WCET_sample_ticks` sample time in ms
+    uint32_t WCET;          // Task worst-case execution time in microseconds
+    uint32_t WCET_interval; // WCET in last `TASK_X_WCET_SAMPLE_TIME_MS` ms
 } task_dta_t;
 
 shared_data_type shared_data;
 uint32_t g_app_runtime_us;
 uint32_t g_app_WCET_us;        // Worst case execution time historically
-uint32_t g_app_WCET_sample_ms; // Worst case execution time in sample
+uint32_t g_app_WCET_sample_us; // Worst case execution time in sample time
 volatile uint32_t g_app_tick_cnt;
 
 const task_cfg_t task_cfg_list[] = {
     {task_system_init,      task_system_update,      &shared_data},
     {task_buttons_init,     task_buttons_update,     NULL},
     {task_leds_init,        task_leds_update,        NULL},
-    {task_menu_init,        task_menu_update,        NULL},
+    {task_menu_init,        task_menu_update,        &shared_data},
     {task_temp_ctrl_init,   task_temp_ctrl_update,   &shared_data},
     {task_temp_sensor_init, task_temp_sensor_update, &shared_data},
 };
@@ -69,11 +69,21 @@ void app_init(void)
         task_dta_list[index].WCET = TASK_X_WCET_INI;
     }
 
+    shared_data_type *p_shared_data = &shared_data;
+
+    p_shared_data->temp_set_point = 0;
+    p_shared_data->temp_sensor = -20;
+    p_shared_data->temp_ctrl_pwm_dc = 0;
+    p_shared_data->temp_ctrl_enabled = false;
+
     __asm("CPSID i");
     g_app_tick_cnt = G_APP_TICK_CNT_INI;
+    g_task_system_tick_cnt = G_APP_TICK_CNT_INI;
     g_task_buttons_tick_cnt = G_APP_TICK_CNT_INI;
+    g_task_leds_tick_cnt = G_APP_TICK_CNT_INI;
+    g_task_menu_tick_cnt = G_APP_TICK_CNT_INI;
+    g_task_temp_ctrl_tick_cnt = G_APP_TICK_CNT_INI;
     g_task_temp_sensor_tick_cnt = G_APP_TICK_CNT_INI;
-    g_task_system_tick_cnt = G_APP_TICK_CNT_INI;
     __asm("CPSIE i");
 
     LOGGER_INFO("Done initializing `app`");
@@ -102,14 +112,14 @@ void app_update(void)
         {
             cycle_counter_reset();
 
-            if (0 == g_app_WCET_sample_ms)
+            if (0 == g_app_WCET_sample_us)
             {
-                g_app_WCET_sample_ms = TASK_X_WCET_SAMPLE_TIME_MS;
+                g_app_WCET_sample_us = TASK_X_WCET_SAMPLE_TIME_MS;
                 task_dta_list[index].WCET_interval = 0;
             }
             else
             {
-                g_app_WCET_sample_ms--;
+                g_app_WCET_sample_us--;
             }
 
             (*task_cfg_list[index].task_update)(task_cfg_list[index].parameters);
@@ -119,7 +129,7 @@ void app_update(void)
 
             if (g_app_WCET_us < g_app_runtime_us) {
                 g_app_WCET_us = g_app_runtime_us;
-                LOGGER_INFO("app worst execution time (WCET): %lu us", g_app_WCET_us);
+                LOGGER_INFO("App worst execution time (WCET): %lu us", g_app_WCET_us);
             }
 
             if (task_dta_list[index].WCET < cycle_counter_time_us)
diff --git a/firmware/app/src/display_i2c.c b/firmware/app/src/display_i2c.c
@@ -15,7 +15,7 @@
 
 #define DISPLAY_I2C_ADDRESS        0x27
 #define DISPLAY_ASYNC_QUEUE_LEN    256
-#define DISPLAY_ASYNC_CLEAR_DEL_MS 1ul
+#define DISPLAY_ASYNC_CLEAR_DEL_MS 2ul
 #define DISPLAY_TICK_CNT_INI       0ul
 
 #define DISPLAY_CMD_CLEAR_DISPLAY   0b00000001
@@ -89,41 +89,41 @@ void display_i2c_init(void)
 
     display_i2c_send_cmd(DISPLAY_CMD_FUNCTION_SET |
                          DISPLAY_CMD_FUNCTION_SET_8BITS);
-    HAL_Delay(1);
+    HAL_Delay(2);
 
     display_i2c_send_cmd(DISPLAY_CMD_FUNCTION_SET |
                          DISPLAY_CMD_FUNCTION_SET_8BITS);
-    HAL_Delay(1);
+    HAL_Delay(2);
 
     display_i2c_send_cmd(DISPLAY_CMD_FUNCTION_SET |
                          DISPLAY_CMD_FUNCTION_SET_4BITS);
-    HAL_Delay(1);
+    HAL_Delay(2);
 
     display_i2c_send_cmd(DISPLAY_CMD_FUNCTION_SET |
                          DISPLAY_CMD_FUNCTION_SET_4BITS |
                          DISPLAY_CMD_FUNCTION_SET_2LINES |
                          DISPLAY_CMD_FUNCTION_SET_5x8DOTS);
-    HAL_Delay(1);
+    HAL_Delay(2);
 
     display_i2c_send_cmd(DISPLAY_CMD_DISPLAY_CONTROL |
                          DISPLAY_CMD_DISPLAY_CONTROL_DISPLAY_OFF |
                          DISPLAY_CMD_DISPLAY_CONTROL_CURSOR_OFF |
                          DISPLAY_CMD_DISPLAY_CONTROL_BLINK_OFF);
-    HAL_Delay(1);
+    HAL_Delay(2);
 
     display_i2c_send_cmd(DISPLAY_CMD_CLEAR_DISPLAY);
-    HAL_Delay(1);
+    HAL_Delay(2);
 
     display_i2c_send_cmd(DISPLAY_CMD_ENTRY_MODE_SET |
                          DISPLAY_CMD_ENTRY_MODE_SET_INCREMENT_CURSOR |
                          DISPLAY_CMD_ENTRY_MODE_SET_NO_SHIFT);
-    HAL_Delay(1);
+    HAL_Delay(2);
 
     display_i2c_send_cmd(DISPLAY_CMD_DISPLAY_CONTROL |
                          DISPLAY_CMD_DISPLAY_CONTROL_DISPLAY_ON |
                          DISPLAY_CMD_DISPLAY_CONTROL_CURSOR_OFF |
                          DISPLAY_CMD_DISPLAY_CONTROL_BLINK_OFF);
-    HAL_Delay(1);
+    HAL_Delay(2);
 
     b_display_i2c_dma_done = true;
     g_display_i2c_tick = DISPLAY_TICK_CNT_INI;
diff --git a/firmware/app/src/task_menu.c b/firmware/app/src/task_menu.c
@@ -19,14 +19,14 @@
 
 #define G_TASK_MEN_TICK_INI                0ul
 #define G_TASK_MEN_TICK_CNT_INI            0ul
-#define G_TASK_MEN_ST_CLOCK_UPDATE_RATE_MS 1000ul
+#define G_TASK_MEN_DISPLAY_UPDATE_RATE_MS  1000ul
 
 task_menu_dta_t task_menu_dta = {
     G_TASK_MEN_TICK_INI, ST_MEN_IDLE, EV_MEN_ST_IDLE, false
 };
 
 // Private functions declaration
-void task_menu_statechart(void);
+void task_menu_statechart(void *parameters);
 
 // Private variables
 bool g_display_update = false;
@@ -79,7 +79,7 @@ void task_menu_update(void *parameters)
     while (b_time_update_required)
     {
         display_i2c_async_tick();
-        task_menu_statechart();
+        task_menu_statechart(parameters);
 
         __asm("CPSID i");
         if (G_TASK_MEN_TICK_CNT_INI < g_task_menu_tick_cnt)
@@ -107,16 +107,31 @@ void menu_set_state(task_menu_st_t new_state)
 
     switch(new_state)
     {
-        case ST_MEN_CLOCK:
-            p_task_menu_dta->tick = G_TASK_MEN_ST_CLOCK_UPDATE_RATE_MS;
+        case ST_MEN_CLOCK_SET:
+            p_task_menu_dta->tick = G_TASK_MEN_DISPLAY_UPDATE_RATE_MS;
         break;
         default: break;
     }
 }
 
-void task_menu_statechart(void)
+int count_digits(int n) {
+    int count = 0;
+
+    if (n == 0) return 1;
+    if (n < 0) n = -n;
+
+    while (n > 0) {
+        n /= 10;
+        count++;
+    }
+
+    return count;
+}
+
+void task_menu_statechart(void *parameters)
 {
     task_menu_dta_t *p_task_menu_dta;
+    shared_data_type *p_shared_data = (shared_data_type *)parameters;
     char menu_row_str[16 + 4];
 
     p_task_menu_dta = &task_menu_dta;
@@ -127,54 +142,73 @@ void task_menu_statechart(void)
         p_task_menu_dta->event = task_menu_interface_get_event();
     }
 
-    if ((true == p_task_menu_dta->event_flag)
-        && (p_task_menu_dta->event == EV_MEN_INACTIVE_TIMEOUT)
-        && (p_task_menu_dta->state != ST_MEN_IDLE))
+    if (true == p_task_menu_dta->event_flag)
     {
         p_task_menu_dta->event_flag = false;
-        menu_set_state(ST_MEN_IDLE);
-    }
+        switch (p_task_menu_dta->event)
+        {
+            case EV_MEN_ST_IDLE:
+            case EV_MEN_INACTIVE_TIMEOUT:
+                menu_set_state(ST_MEN_IDLE);
+            break;
 
-    if ((true == p_task_menu_dta->event_flag)
-        && (p_task_menu_dta->event == EV_MEN_DISPLAY_UPDATE))
-    {
-        p_task_menu_dta->event_flag = false;
-        g_display_update = true;
+            case EV_MEN_DISPLAY_UPDATE:
+                g_display_update = true;
+            break;
+
+            case EV_MEN_ST_CLOCK_SET:
+                menu_set_state(ST_MEN_CLOCK_SET);
+            break;
+
+            case EV_MEN_ST_TEMP_SET:
+                menu_set_state(ST_MEN_TEMP_SET);
+            break;
+
+            default: break;
+        }
     }
 
     switch (p_task_menu_dta->state)
     {
         case ST_MEN_IDLE:
 
+            if (0 == p_task_menu_dta->tick)
+            {
+                g_display_update = true;
+                p_task_menu_dta->tick = G_TASK_MEN_DISPLAY_UPDATE_RATE_MS;
+            }
+            else 
+            {
+                p_task_menu_dta->tick--;
+            }
+
             if (g_display_update)
             {
                 g_display_update = false;
                 display_i2c_async_clear();
                 memset(menu_row_str, '\0', sizeof(menu_row_str));
-                snprintf(menu_row_str, 20, "Idle%10d%cC", g_ds18b20_temp, 0xDF);
+                snprintf(menu_row_str, 20, "Idle         %3s",
+                        p_shared_data->temp_ctrl_enabled ? "ON" : "");
                 display_i2c_async_write_string(menu_row_str);
-            }
 
-            if (true == p_task_menu_dta->event_flag)
-            {
-                p_task_menu_dta->event_flag = false;
-                switch (p_task_menu_dta->event)
-                {
-                    case EV_MEN_ST_CLOCK:
-                        menu_set_state(ST_MEN_CLOCK);
-                    break;
-                    default: break;
-                }
+                display_i2c_async_set_cursor_pos(4, 1);
+                memset(menu_row_str, '\0', sizeof(menu_row_str));
+                snprintf(menu_row_str, 20, "%*d(%d)%cC",
+                        (8 - count_digits(p_shared_data->temp_set_point)),
+                        p_shared_data->temp_sensor,
+                        p_shared_data->temp_set_point,
+                        G_DISPLAY_CHAR_DEGREE_CODE);
+                display_i2c_async_write_string(menu_row_str);
             }
 
         break;
 
-        case ST_MEN_CLOCK:
+        case ST_MEN_CLOCK_SET:
 
             if (0 == p_task_menu_dta->tick)
             {
                 g_display_update = true;
-                p_task_menu_dta->tick = G_TASK_MEN_ST_CLOCK_UPDATE_RATE_MS;
+                p_task_menu_dta->tick = G_TASK_MEN_DISPLAY_UPDATE_RATE_MS;
             }
             else 
             {
@@ -185,25 +219,31 @@ void task_menu_statechart(void)
             {
                 g_display_update = false;
                 display_i2c_async_clear();
-                memset(menu_row_str, '\0', sizeof(menu_row_str));
+                display_i2c_async_write_string("Clock>");
+                display_i2c_async_set_cursor_pos(8, 0);
 
                 HAL_RTC_GetTime(&hrtc, &s_time, RTC_FORMAT_BIN);
                 HAL_RTC_GetDate(&hrtc, &s_date, RTC_FORMAT_BIN);
-                sprintf(menu_row_str, "%02d:%02d:%02d",
+
+                memset(menu_row_str, '\0', sizeof(menu_row_str));
+                sprintf(menu_row_str, "%2d:%02d:%02d",
                         s_time.Hours, s_time.Minutes, s_time.Seconds);
                 display_i2c_async_write_string(menu_row_str);
             }
 
-            if (true == p_task_menu_dta->event_flag)
+        break;
+
+        case ST_MEN_TEMP_SET:
+
+            if (g_display_update)
             {
-                p_task_menu_dta->event_flag = false;
-                switch (p_task_menu_dta->event)
-                {
-                    case EV_MEN_ST_IDLE:
-                        menu_set_state(ST_MEN_IDLE);
-                    break;
-                    default: break;
-                }
+                g_display_update = false;
+                display_i2c_async_clear();
+                display_i2c_async_write_string("Temp>");
+                memset(menu_row_str, '\0', sizeof(menu_row_str));
+                sprintf(menu_row_str, "%9d%cC",
+                        p_shared_data->temp_set_point, G_DISPLAY_CHAR_DEGREE_CODE);
+                display_i2c_async_write_string(menu_row_str);
             }
 
         break;
diff --git a/firmware/app/src/task_system.c b/firmware/app/src/task_system.c
@@ -150,23 +150,23 @@ void task_system_statechart(void *parameters)
                 switch (p_task_system_dta->event)
                 {
                     case EV_SYS_BTN_C_ACTIVE:
-                        p_shared_data->temp_controller_pwm_dc =
-                            ((p_shared_data->temp_controller_pwm_dc + 5) % 100);
+                        p_shared_data->temp_ctrl_enabled = !p_shared_data->temp_ctrl_enabled;
+                        task_menu_interface_put_event(EV_MEN_DISPLAY_UPDATE);
                     break;
                     case EV_SYS_BTN_A_ACTIVE:
                     case EV_SYS_BTN_B_ACTIVE:
                     case EV_SYS_BTN_D_ACTIVE:
-                        p_task_system_dta->state = ST_SYS_CLOCK;
-                        task_menu_interface_put_event(EV_MEN_ST_CLOCK);
+                        p_task_system_dta->state = ST_SYS_CLOCK_SET;
+                        task_menu_interface_put_event(EV_MEN_ST_CLOCK_SET);
                         task_leds_interface_put_event(EV_LED_XX_BLINK, ID_LED_A);
                         task_leds_interface_put_event(EV_LED_XX_BLINK, ID_LED_B);
                     break;
                     default: break;
                 }
             }
-            break;
+        break;
 
-        case ST_SYS_CLOCK:
+        case ST_SYS_CLOCK_SET:
             if (true == p_task_system_dta->event_flag)
             {
                 p_task_system_dta->event_flag = false;
@@ -174,8 +174,8 @@ void task_system_statechart(void *parameters)
                 {
                     case EV_SYS_BTN_A_ACTIVE:
                     case EV_SYS_BTN_D_ACTIVE:
-                        p_task_system_dta->state = ST_SYS_IDLE;
-                        task_menu_interface_put_event(EV_MEN_ST_IDLE);
+                        p_task_system_dta->state = ST_SYS_TEMP_SET;
+                        task_menu_interface_put_event(EV_MEN_ST_TEMP_SET);
                         task_leds_interface_put_event(EV_LED_XX_OFF, ID_LED_A);
                         task_leds_interface_put_event(EV_LED_XX_OFF, ID_LED_B);
                     break;
@@ -190,13 +190,43 @@ void task_system_statechart(void *parameters)
                     default: break;
                 }
             }
-            break;
+        break;
+
+        case ST_SYS_TEMP_SET:
+            if (true == p_task_system_dta->event_flag)
+            {
+                p_task_system_dta->event_flag = false;
+                switch (p_task_system_dta->event)
+                {
+                    case EV_SYS_BTN_A_ACTIVE:
+                    case EV_SYS_BTN_D_ACTIVE:
+                        p_task_system_dta->state = ST_SYS_IDLE;
+                        task_menu_interface_put_event(EV_MEN_ST_IDLE);
+                    break;
+
+                    case EV_SYS_BTN_B_ACTIVE:
+                        p_shared_data->temp_set_point =
+                            ((p_shared_data->temp_set_point - 5) % 85);
+                        task_menu_interface_put_event(EV_MEN_DISPLAY_UPDATE);
+                    break;
+
+                    case EV_SYS_BTN_C_ACTIVE:
+                        p_shared_data->temp_set_point =
+                            ((p_shared_data->temp_set_point + 5) % 85);
+
+                        task_menu_interface_put_event(EV_MEN_DISPLAY_UPDATE);
+                    break;
+
+                    default: break;
+                }
+            }
+        break;
 
         default: 
             if (true == p_task_system_dta->event_flag)
             {
                 p_task_system_dta->event_flag = false;
             }
-            break;
+        break;
     }
 }
diff --git a/firmware/app/src/task_temp_ctrl.c b/firmware/app/src/task_temp_ctrl.c
@@ -28,8 +28,7 @@ void task_temp_ctrl_init(void *parameters)
     g_task_temp_ctrl_tick = G_TASK_CTRL_TICK_CNT_INI;
 
     shared_data_type *p_shared_data = (shared_data_type *)parameters;
-    p_shared_data->temp_controller_pwm_dc = 0;
-    TIM1->CCR1 = p_shared_data->temp_controller_pwm_dc;
+    TIM1->CCR1 = p_shared_data->temp_ctrl_pwm_dc;
     HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_1);
 
     LOGGER_INFO("Done initializing `task_temp_ctrl`");
@@ -62,9 +61,9 @@ void task_temp_ctrl_update(void *parameters)
         }
         __asm("CPSIE i");
 
-        if (p_shared_data->temp_controller_pwm_dc != TIM1->CCR1)
+        if (p_shared_data->temp_ctrl_pwm_dc != TIM1->CCR1)
         {
-            TIM1->CCR1 = p_shared_data->temp_controller_pwm_dc;
+            TIM1->CCR1 = p_shared_data->temp_ctrl_pwm_dc;
         }
     }
 }
diff --git a/firmware/app/src/task_temp_sensor.c b/firmware/app/src/task_temp_sensor.c
@@ -27,9 +27,6 @@ volatile uint32_t g_task_temp_sensor_tick_cnt;
 
 void task_temp_sensor_init(void *parameters)
 {
-    shared_data_type *p_shared_data = (shared_data_type *)parameters;
-    p_shared_data->temp_sensor = 0;
-
     LOGGER_INFO("Initializing `task_temp_sensor`...");
 
     g_task_temp_sensor_tick = G_TASK_TEMP_SEN_TICK_INI;