calib GUI WIP

calib-gui
Ondřej Hruška 2 years ago
parent 08f1215c24
commit 6749bb5f52
  1. 1
      Core/Src/Gui/app_gui.c
  2. 29
      Core/Src/Gui/app_gui.h
  3. 186
      Core/Src/Gui/screen_calibration.c
  4. 2
      Core/Src/Gui/screen_manual.c
  5. 2
      Core/Src/Gui/screen_menu.c
  6. 30
      Core/Src/app_heater.c
  7. 7
      Core/Src/app_heater.h
  8. 3
      Core/Src/app_temp.h
  9. 1
      Makefile

@ -124,7 +124,6 @@ void switch_screen(screen_t pScreen, bool init) {
s_app.initial_pushed = s_app.pushed; s_app.initial_pushed = s_app.pushed;
s_app.screen = pScreen; s_app.screen = pScreen;
// clear the union field // clear the union field
memset(&s_app.page, 0, sizeof(s_app.page));
request_paint(); request_paint();
if (init) { if (init) {

@ -79,18 +79,23 @@ struct State {
/// Pointer to the currently active screen func /// Pointer to the currently active screen func
screen_t screen; screen_t screen;
/// data specific for each of the screens (not persistent across screen switching) /// Generic menu
union { struct menu_state {
/// Generic menu int pos;
struct menu_state { int len;
int pos; uint32_t change_time;
int len; uint32_t slide_end_time;
uint32_t change_time; uint16_t text_slide;
uint32_t slide_end_time; uint8_t tick_counter;
uint16_t text_slide; } menu;
uint8_t tick_counter;
} menu; struct calib_state {
} page; int phase;
float sample1;
float sample2;
int temp1;
int temp2;
} calib;
}; };
extern struct State s_app; extern struct State s_app;

@ -0,0 +1,186 @@
//
// Created by MightyPork on 2023/04/09.
//
#include <stddef.h>
#include "app_gui.h"
#include "app_heater.h"
#include "screen_menu.h"
#include "ufb/fb_text.h"
#include "app_temp.h"
#include "snprintf.h"
#include "FreeRTOS.h"
static const char* calib0_opts[] = {
"Pokračovat",
"Zrušit",
NULL
};
static void calib0_cb(int opt) {
switch (opt) {
case 0:
// Continue
s_app.calib.phase++;
request_paint();
app_heater_manual_override(100);
break;
case 1:
switch_screen(screen_home, true);
break;
}
}
static const char* calib1_opts[] = {
"Vzorek 1",
"Zrušit",
NULL
};
static void calib1_cb(int opt) {
switch (opt) {
case 0:
// Continue
s_app.calib.phase++;
request_paint();
s_app.calib.sample1 = app_temp_read_oven_raw();
app_heater_manual_override(0);
break;
case 1:
app_heater_manual_override(-1);
switch_screen(screen_home, true);
break;
}
}
static const char* calib3_opts[] = {
"Vzorek 2",
"Zrušit",
NULL
};
static void calib3_cb(int opt) {
switch (opt) {
case 0:
// Continue
s_app.calib.phase++;
request_paint();
s_app.calib.sample2 = app_temp_read_oven_raw();
app_heater_manual_override(0);
break;
case 1:
app_heater_manual_override(-1);
switch_screen(screen_home, true);
break;
}
}
void screen_manual_menu(GuiEvent event)
{
if (event == GUI_EVENT_SCREEN_INIT) {
s_app.calib.phase = 0;
s_app.calib.sample1 = s_app.calib.sample2 = 0.0f;
s_app.calib.temp1 = s_app.calib.temp2 = 0;
}
int phase = s_app.calib.phase;
int *pT;
switch (phase) {
case 0:
if (event == GUI_EVENT_PAINT) {
fb_text(FBW/2, 14, "Vychlaďte", TEXT_CENTER, 1);
fb_text(FBW/2, 24, "troubu", TEXT_CENTER, 1);
}
screen_menu(event, calib1_opts, calib1_cb);
break;
case 1: // Heater is active, waiting for mark
case 3:
if (event == GUI_EVENT_PAINT) {
fb_text(FBW/2, 14, "Zapiš teplotu", TEXT_CENTER, 1);
}
if (phase == 1) {
screen_menu(event, calib1_opts, calib1_cb);
} else {
screen_menu(event, calib3_opts, calib3_cb);
}
break;
case 2:
case 4:
if (phase == 2) {
pT = &s_app.calib.temp1;
} else {
pT = &s_app.calib.temp2;
}
if (event == GUI_EVENT_PAINT) {
fb_text(FBW/2, 14, phase == 2 ? "Teplota 1" : "Teplota 2", TEXT_CENTER, 1);
SPRINTF(stmp, "%d°C", *pT);
fb_text(FBW/2, 30, stmp, TEXT_CENTER | FONT_DOUBLE, 1);
fb_text(2, FBH - 8 * 3, "←→Nastav", 0, 1);
fb_text(2, FBH - 8 * 2, "> Potvrdit", 0, 1);
fb_text(2, FBH - 8 * 1, "» Zrušit", 0, 1);
return;
}
if (push_time() > pdMS_TO_TICKS(500)) {
input_sound_effect();
app_heater_manual_override_clear();
switch_screen(screen_home, true);
return;
}
if (event == GUI_EVENT_KNOB_PLUS) {
if (*pT < 500) {
*pT += 1;
input_sound_effect();
request_paint();
}
}
else if (event == GUI_EVENT_KNOB_MINUS) {
if (*pT > 0) {
input_sound_effect();
*pT -= 1;
request_paint();
}
} else if (event == GUI_EVENT_KNOB_RELEASE) {
s_app.calib.phase++;
request_paint();
if (s_app.calib.phase == 5) {
// TODO do the math
PRINTF("Sample 1 %f, T1 %d\r\n", s_app.calib.sample1, s_app.calib.temp1);
PRINTF("Sample 2 %f, T2 %d\r\n", s_app.calib.sample2, s_app.calib.temp2);
float corrected1 = c_to_val((float) s_app.calib.temp1);
float corrected2 = c_to_val((float) s_app.calib.temp2);
float a = ;
float b = ;
// TODO set and persist calibration
}
}
break;
case 5:
if (event == GUI_EVENT_PAINT) {
fb_text(FBW/2, 14, "Hotovo", TEXT_CENTER, 1);
fb_text(FBW/2, 36, "→Hlavní menu", TEXT_CENTER, 1);
}
if (event == GUI_EVENT_KNOB_RELEASE) {
switch_screen(screen_home, 1);
}
break;
}
}

@ -17,6 +17,8 @@ void screen_manual(GuiEvent event)
{ {
bool temp_changed = false; bool temp_changed = false;
if (event == GUI_EVENT_SCREEN_INIT) { if (event == GUI_EVENT_SCREEN_INIT) {
app_heater_manual_override_clear();
app_heater_enable(false);
return; return;
} }

@ -17,7 +17,7 @@ void screen_menu(GuiEvent event, const char **options, menu_callback_t cb) {
bool menu_changed = false; bool menu_changed = false;
const uint32_t tickNow = xTaskGetTickCount(); const uint32_t tickNow = xTaskGetTickCount();
struct menu_state *menu = &s_app.page.menu; struct menu_state *menu = &s_app.menu;
switch (event) { switch (event) {
case GUI_EVENT_SCREEN_INIT: case GUI_EVENT_SCREEN_INIT:

@ -39,12 +39,15 @@ static struct {
float tuning_p; float tuning_p;
float tuning_i; float tuning_i;
float tuning_d; float tuning_d;
/// Manual PWM override (percent, -1 = override disable)
int manual_override;
// PID state // PID state
struct PID pid; struct PID pid;
} state = { } state = {
.tuning_p = 10.0f, .tuning_p = 10.0f,
.tuning_i = 0.052f, .tuning_i = 0.052f,
.tuning_d = 100.0f, .tuning_d = 100.0f,
.manual_override = -1,
.pid = { .pid = {
.SampleTimeTicks = pdMS_TO_TICKS(1000), .SampleTimeTicks = pdMS_TO_TICKS(1000),
.outMax = 100.0f, .outMax = 100.0f,
@ -62,6 +65,17 @@ static inline void heaterExitCritical() {
osMutexRelease(heaterMutexHandle); osMutexRelease(heaterMutexHandle);
} }
void app_heater_manual_override(int percent) {
heaterEnterCritical();
PID_SetCtlMode(&state.pid, PID_MANUAL);
state.manual_override = percent;
heaterExitCritical();
}
void app_heater_manual_override_clear() {
app_heater_manual_override(-1);
}
void app_heater_set_tuning(float p, float i, float d) { void app_heater_set_tuning(float p, float i, float d) {
heaterEnterCritical(); heaterEnterCritical();
PID_SetTunings(&state.pid, p, i, d); PID_SetTunings(&state.pid, p, i, d);
@ -127,13 +141,19 @@ void app_task_heater(void *argument)
heaterEnterCritical(); heaterEnterCritical();
app_safety_pass_reg_loop_running(); app_safety_pass_reg_loop_running();
PID_Compute(&state.pid, state.oven_temp);
if (state.pid.ctlMode == PID_AUTOMATIC) { if (state.manual_override >= 0 && state.manual_override <= 100) {
PRINTF("temp %d, output %d\r\n", (int) state.oven_temp, (int) state.pid.Output); PRINTF("manual override %d%%\r\n", state.manual_override);
heater_pwm_set_perc(state.pid.Output); heater_pwm_set_perc(state.pid.Output);
} else { } else {
// turn it off PID_Compute(&state.pid, state.oven_temp);
heater_pwm_set_perc(0); if (state.pid.ctlMode == PID_AUTOMATIC) {
PRINTF("temp %d, output %d\r\n", (int) state.oven_temp, (int) state.pid.Output);
heater_pwm_set_perc(state.pid.Output);
} else {
// turn it off
heater_pwm_set_perc(0);
}
} }
heaterExitCritical(); heaterExitCritical();

@ -14,6 +14,13 @@ extern osThreadId_t heaterTskHandle;
void app_task_heater(void *argument); void app_task_heater(void *argument);
/// Clear manual override, disable heater for normal mode.
void app_heater_manual_override_clear();
/// Set manual override PWM 0-100%.
/// Also disables heater in the normal mode.
void app_heater_manual_override(int percent);
/// Set heater regulator tuning. /// Set heater regulator tuning.
/// Mutex is locked internally. /// Mutex is locked internally.
void app_heater_set_tuning(float p, float i, float d); void app_heater_set_tuning(float p, float i, float d);

@ -20,6 +20,9 @@ void app_temp_sample();
/// The value is valid after calling app_temp_sample() /// The value is valid after calling app_temp_sample()
float app_temp_read_oven(); float app_temp_read_oven();
/// Get the raw ADC value (divider voltage)
float app_temp_read_oven_raw();
/// Read current SOC temperature (celsius) /// Read current SOC temperature (celsius)
/// The value is valid after calling app_temp_sample() /// The value is valid after calling app_temp_sample()
float app_temp_read_soc(); float app_temp_read_soc();

@ -51,6 +51,7 @@ Core/Src/Gui/app_gui.c \
Core/Src/Gui/screen_menu.c \ Core/Src/Gui/screen_menu.c \
Core/Src/Gui/screen_home.c \ Core/Src/Gui/screen_home.c \
Core/Src/Gui/screen_manual.c \ Core/Src/Gui/screen_manual.c \
Core/Src/Gui/screen_calibration.c \
Core/Src/Gui/screen_manual_menu.c \ Core/Src/Gui/screen_manual_menu.c \
Core/Src/app_temp.c \ Core/Src/app_temp.c \
Core/Src/app_knob.c \ Core/Src/app_knob.c \

Loading…
Cancel
Save