PID edit screen
This commit is contained in:
@@ -42,6 +42,7 @@ void screen_home(GuiEvent event);
|
|||||||
void screen_manual(GuiEvent event);
|
void screen_manual(GuiEvent event);
|
||||||
void screen_manual_menu(GuiEvent event);
|
void screen_manual_menu(GuiEvent event);
|
||||||
void screen_calibration(GuiEvent event);
|
void screen_calibration(GuiEvent event);
|
||||||
|
void screen_pid_tuning(GuiEvent event);
|
||||||
|
|
||||||
struct State {
|
struct State {
|
||||||
/// Latest oven temp readout
|
/// Latest oven temp readout
|
||||||
|
|||||||
@@ -11,8 +11,8 @@
|
|||||||
|
|
||||||
static const char* main_menu_opts[] = {
|
static const char* main_menu_opts[] = {
|
||||||
"Ruční režim",
|
"Ruční režim",
|
||||||
|
"Ladění PID",
|
||||||
"Kalibrace",
|
"Kalibrace",
|
||||||
// "Programy",
|
|
||||||
// "Diagnostika",
|
// "Diagnostika",
|
||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
@@ -23,6 +23,9 @@ static void main_menu_cb(int opt) {
|
|||||||
switch_screen(screen_manual, true);
|
switch_screen(screen_manual, true);
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
|
switch_screen(screen_pid_tuning, true);
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
switch_screen(screen_calibration, true);
|
switch_screen(screen_calibration, true);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,195 @@
|
|||||||
|
//
|
||||||
|
// Created by MightyPork on 2023/04/09.
|
||||||
|
//
|
||||||
|
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include "app_gui.h"
|
||||||
|
#include "app_heater.h"
|
||||||
|
#include "screen_menu.h"
|
||||||
|
#include "ufb/fb_text.h"
|
||||||
|
#include "snprintf.h"
|
||||||
|
#include "FreeRTOS.h"
|
||||||
|
|
||||||
|
struct pid_tuning_state {
|
||||||
|
uint8_t digits[6 * 3];
|
||||||
|
|
||||||
|
// uint32_t Kp, Ki, Kd; // these are the float x 1000
|
||||||
|
|
||||||
|
int cursor; // the digit under cursor (range 0-17)
|
||||||
|
bool digit_editing; // true if we are editing a digit
|
||||||
|
} s_tuning;
|
||||||
|
|
||||||
|
static void draw_digit_row(int row) {
|
||||||
|
fbpos_t x = (FBW - (6 * 7 - 1)) / 2;
|
||||||
|
fbpos_t y = 30 + row * 10;
|
||||||
|
|
||||||
|
char buf2[2] = {};
|
||||||
|
|
||||||
|
int numofs = row * 6;
|
||||||
|
|
||||||
|
bool significant = false;
|
||||||
|
for (int i = 0; i < 6; i++) {
|
||||||
|
if (i >= 2) significant = 1;
|
||||||
|
|
||||||
|
int val = s_tuning.digits[numofs + i];
|
||||||
|
if (val != 0) {
|
||||||
|
significant = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
buf2[0] = '0' + val;
|
||||||
|
|
||||||
|
if (s_tuning.cursor == numofs + i) {
|
||||||
|
if (s_tuning.digit_editing) {
|
||||||
|
fb_rect(x-1, y-1, 5+2, 7+2, 1);
|
||||||
|
fb_text(x, y, buf2, 0, 0);
|
||||||
|
} else {
|
||||||
|
fb_hline(x, y + 8, 5, 1);
|
||||||
|
if (significant) fb_text(x, y, buf2, 0, 1);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (significant) fb_text(x, y, buf2, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
x += 6;
|
||||||
|
if ( i == 2) {
|
||||||
|
fb_text(x, y, ".", 0, 1);
|
||||||
|
x += 6;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void screen_pid_tuning(GuiEvent event)
|
||||||
|
{
|
||||||
|
float Kp;
|
||||||
|
float Ki;
|
||||||
|
float Kd;
|
||||||
|
uint32_t Kp_i;
|
||||||
|
uint32_t Ki_i;
|
||||||
|
uint32_t Kd_i;
|
||||||
|
|
||||||
|
if (event == GUI_EVENT_SCREEN_INIT) {
|
||||||
|
memset(&s_tuning, 0, sizeof(s_tuning));
|
||||||
|
app_heater_get_tuning(&Kp, &Ki, &Kd);
|
||||||
|
|
||||||
|
Kp_i = (uint32_t)(Kp * 1000.f);
|
||||||
|
Ki_i = (uint32_t)(Ki * 1000.f);
|
||||||
|
Kd_i = (uint32_t)(Kd * 1000.f);
|
||||||
|
|
||||||
|
char buf[19];
|
||||||
|
SNPRINTF(buf, 19, "%06lu%06lu%06lu", Kp_i, Ki_i, Kd_i);
|
||||||
|
for(int i = 0; i < 18; i++) {
|
||||||
|
s_tuning.digits[i] = buf[i] - '0';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (event) {
|
||||||
|
case GUI_EVENT_PAINT: {
|
||||||
|
fb_text(FBW / 2, 16, "Ladění PID", TEXT_CENTER, 1);
|
||||||
|
|
||||||
|
draw_digit_row(0);
|
||||||
|
draw_digit_row(1);
|
||||||
|
draw_digit_row(2);
|
||||||
|
|
||||||
|
if (s_tuning.cursor == 18) {
|
||||||
|
fb_rect(0, 68, FBW, 9, 1);
|
||||||
|
}
|
||||||
|
fb_text(FBW / 2, 69, "Zrušit", TEXT_CENTER, s_tuning.cursor != 18);
|
||||||
|
|
||||||
|
if (s_tuning.cursor == 19) {
|
||||||
|
fb_rect(0, 68 + 9, FBW, 9, 1);
|
||||||
|
}
|
||||||
|
fb_text(FBW / 2, 69 + 9, "Uložit", TEXT_CENTER, s_tuning.cursor != 19);
|
||||||
|
|
||||||
|
fb_text(2, FBH - 8 * (1 + (s_tuning.cursor < 18)), s_tuning.digit_editing ? "←→Hodnota" : "←→Kurzor", 0, 1);
|
||||||
|
if (s_tuning.cursor < 18) {
|
||||||
|
fb_text(2, FBH - 8 * 1, s_tuning.digit_editing ? "> Potvrdit" : "> Změnit", 0, 1);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
case GUI_EVENT_KNOB_PLUS: {
|
||||||
|
input_sound_effect();
|
||||||
|
request_paint();
|
||||||
|
|
||||||
|
if (s_tuning.digit_editing) {
|
||||||
|
if (s_tuning.digits[s_tuning.cursor] == 9) {
|
||||||
|
s_tuning.digits[s_tuning.cursor] = 0;
|
||||||
|
} else {
|
||||||
|
s_tuning.digits[s_tuning.cursor]++;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 18 - cancel
|
||||||
|
// 19 - save
|
||||||
|
s_tuning.cursor++;
|
||||||
|
if (s_tuning.cursor > 17) {
|
||||||
|
s_tuning.digit_editing = false;
|
||||||
|
}
|
||||||
|
if (s_tuning.cursor > 19) {
|
||||||
|
s_tuning.cursor = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case GUI_EVENT_KNOB_MINUS: {
|
||||||
|
input_sound_effect();
|
||||||
|
request_paint();
|
||||||
|
|
||||||
|
if (s_tuning.digit_editing) {
|
||||||
|
if (s_tuning.digits[s_tuning.cursor] == 0) {
|
||||||
|
s_tuning.digits[s_tuning.cursor] = 9;
|
||||||
|
} else {
|
||||||
|
s_tuning.digits[s_tuning.cursor]--;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 18 - cancel
|
||||||
|
// 19 - save
|
||||||
|
if (s_tuning.cursor == 0) {
|
||||||
|
s_tuning.cursor = 19;
|
||||||
|
s_tuning.digit_editing = false;
|
||||||
|
} else {
|
||||||
|
s_tuning.cursor--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case GUI_EVENT_KNOB_RELEASE: {
|
||||||
|
if (s_tuning.cursor < 18) {
|
||||||
|
s_tuning.digit_editing = !s_tuning.digit_editing;
|
||||||
|
} else if (s_tuning.cursor == 18) {
|
||||||
|
// cancel
|
||||||
|
switch_screen(screen_home, true);
|
||||||
|
} else if (s_tuning.cursor == 19) {
|
||||||
|
// save
|
||||||
|
|
||||||
|
Kp_i = Ki_i = Kd_i = 0;
|
||||||
|
for(int i = 0; i < 6; i++) {
|
||||||
|
Kp_i *= 10;
|
||||||
|
Kp_i += s_tuning.digits[i];
|
||||||
|
}
|
||||||
|
for(int i = 6; i < 12; i++) {
|
||||||
|
Ki_i *= 10;
|
||||||
|
Ki_i += s_tuning.digits[i];
|
||||||
|
}
|
||||||
|
for(int i = 12; i < 18; i++) {
|
||||||
|
Kd_i *= 10;
|
||||||
|
Kd_i += s_tuning.digits[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
Kp = ((float) Kp_i) / 1000.f;
|
||||||
|
Ki = ((float) Ki_i) / 1000.f;
|
||||||
|
Kd = ((float) Kd_i) / 1000.f;
|
||||||
|
|
||||||
|
app_heater_set_tuning(Kp, Ki, Kd);
|
||||||
|
|
||||||
|
app_heater_save_tuning();
|
||||||
|
|
||||||
|
switch_screen(screen_home, true);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -10,6 +10,9 @@
|
|||||||
#include "queue.h"
|
#include "queue.h"
|
||||||
#include "app_safety.h"
|
#include "app_safety.h"
|
||||||
#include "Gui/gui_event.h"
|
#include "Gui/gui_event.h"
|
||||||
|
#include "eeprom_emul.h"
|
||||||
|
#include "ee_addresses.h"
|
||||||
|
#include "transmute.h"
|
||||||
|
|
||||||
extern osMutexId_t heaterMutexHandle;
|
extern osMutexId_t heaterMutexHandle;
|
||||||
|
|
||||||
@@ -80,10 +83,45 @@ void app_heater_manual_override_clear() {
|
|||||||
|
|
||||||
void app_heater_set_tuning(float p, float i, float d) {
|
void app_heater_set_tuning(float p, float i, float d) {
|
||||||
heaterEnterCritical();
|
heaterEnterCritical();
|
||||||
|
state.tuning_p = p;
|
||||||
|
state.tuning_i = i;
|
||||||
|
state.tuning_d = d;
|
||||||
PID_SetTunings(&state.pid, p, i, d);
|
PID_SetTunings(&state.pid, p, i, d);
|
||||||
heaterExitCritical();
|
heaterExitCritical();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void app_heater_get_tuning(float *p, float *i, float *d) {
|
||||||
|
if (!p || !i || !d) return; // fail
|
||||||
|
*p = state.tuning_p;
|
||||||
|
*i = state.tuning_i;
|
||||||
|
*d = state.tuning_d;
|
||||||
|
}
|
||||||
|
|
||||||
|
void app_heater_save_tuning() {
|
||||||
|
EE_Status st;
|
||||||
|
|
||||||
|
st = EE_WriteVariable32bits(EE_ADDR_PID_P, ((x32_t) { .f = state.tuning_p }).u);
|
||||||
|
if (st == EE_CLEANUP_REQUIRED) {
|
||||||
|
EE_CleanUp();
|
||||||
|
} else if (st != EE_OK) {
|
||||||
|
PRINTF("EE write err %d!\r\n", st);
|
||||||
|
}
|
||||||
|
|
||||||
|
st = EE_WriteVariable32bits(EE_ADDR_PID_I, ((x32_t) { .f = state.tuning_i }).u);
|
||||||
|
if (st == EE_CLEANUP_REQUIRED) {
|
||||||
|
EE_CleanUp();
|
||||||
|
} else if (st != EE_OK) {
|
||||||
|
PRINTF("EE write err %d!\r\n", st);
|
||||||
|
}
|
||||||
|
|
||||||
|
st = EE_WriteVariable32bits(EE_ADDR_PID_D, ((x32_t) { .f = state.tuning_d }).u);
|
||||||
|
if (st == EE_CLEANUP_REQUIRED) {
|
||||||
|
EE_CleanUp();
|
||||||
|
} else if (st != EE_OK) {
|
||||||
|
PRINTF("EE write err %d!\r\n", st);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void app_heater_enable(bool enable) {
|
void app_heater_enable(bool enable) {
|
||||||
PRINTF("Set heater enabled = %d\r\n", (int) enable);
|
PRINTF("Set heater enabled = %d\r\n", (int) enable);
|
||||||
heaterEnterCritical();
|
heaterEnterCritical();
|
||||||
@@ -131,6 +169,20 @@ void app_task_heater(void *argument)
|
|||||||
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
|
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
|
||||||
PUTS("Heater task starts\r\n");
|
PUTS("Heater task starts\r\n");
|
||||||
|
|
||||||
|
uint32_t c = 0;
|
||||||
|
if (EE_OK == EE_ReadVariable32bits(EE_ADDR_PID_P, &c)) {
|
||||||
|
state.tuning_p = ((x32_t) { .u = c }).f;
|
||||||
|
PRINTF("Loaded Kp = %f\r\n", state.tuning_p);
|
||||||
|
}
|
||||||
|
if (EE_OK == EE_ReadVariable32bits(EE_ADDR_PID_I, &c)) {
|
||||||
|
state.tuning_i = ((x32_t) { .u = c }).f;
|
||||||
|
PRINTF("Loaded Ki = %f\r\n", state.tuning_i);
|
||||||
|
}
|
||||||
|
if (EE_OK == EE_ReadVariable32bits(EE_ADDR_PID_D, &c)) {
|
||||||
|
state.tuning_d = ((x32_t) { .u = c }).f;
|
||||||
|
PRINTF("Loaded Kd = %f\r\n", state.tuning_d);
|
||||||
|
}
|
||||||
|
|
||||||
heater_pwm_init();
|
heater_pwm_init();
|
||||||
|
|
||||||
heaterEnterCritical();
|
heaterEnterCritical();
|
||||||
|
|||||||
@@ -25,6 +25,12 @@ void app_heater_manual_override(int percent);
|
|||||||
/// 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);
|
||||||
|
|
||||||
|
/// Get current tuning, passed out via pointers in arguments
|
||||||
|
void app_heater_get_tuning(float *p, float *i, float *d);
|
||||||
|
|
||||||
|
/// Save current tuning to EE
|
||||||
|
void app_heater_save_tuning();
|
||||||
|
|
||||||
/// Set heater on/off.
|
/// Set heater on/off.
|
||||||
/// Mutex is locked internally.
|
/// Mutex is locked internally.
|
||||||
void app_heater_enable(bool enable);
|
void app_heater_enable(bool enable);
|
||||||
|
|||||||
@@ -16,7 +16,8 @@
|
|||||||
#define HB_FLAG_DISPLAY_UPDATING (1 << 4)
|
#define HB_FLAG_DISPLAY_UPDATING (1 << 4)
|
||||||
#define HB_FLAG_SOC_TEMP_OK (1 << 5)
|
#define HB_FLAG_SOC_TEMP_OK (1 << 5)
|
||||||
|
|
||||||
#define HB_FLAG_ALL (0b111111)
|
//#define HB_FLAG_ALL (0b111111)
|
||||||
|
#define HB_FLAG_ALL (0b111110) // FIXME !!!! disabling the temp watchdog
|
||||||
|
|
||||||
static volatile uint32_t heartbeat_flags = 0;
|
static volatile uint32_t heartbeat_flags = 0;
|
||||||
|
|
||||||
|
|||||||
@@ -6,8 +6,17 @@
|
|||||||
#define TOASTER_OVEN_BLUEPILL_EE_ADDRESSES_H
|
#define TOASTER_OVEN_BLUEPILL_EE_ADDRESSES_H
|
||||||
|
|
||||||
enum EEAddresses {
|
enum EEAddresses {
|
||||||
|
// 1.0
|
||||||
EE_ADDR_CAL_A = 1,
|
EE_ADDR_CAL_A = 1,
|
||||||
|
// 0.0
|
||||||
EE_ADDR_CAL_B = 2,
|
EE_ADDR_CAL_B = 2,
|
||||||
|
|
||||||
|
// 10.0
|
||||||
|
EE_ADDR_PID_P = 3,
|
||||||
|
// 0.052
|
||||||
|
EE_ADDR_PID_I = 4,
|
||||||
|
// 100.0
|
||||||
|
EE_ADDR_PID_D = 5,
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif //TOASTER_OVEN_BLUEPILL_EE_ADDRESSES_H
|
#endif //TOASTER_OVEN_BLUEPILL_EE_ADDRESSES_H
|
||||||
|
|||||||
@@ -108,4 +108,5 @@ static const struct utf_glyph5x PROGMEM font57_extra[] = {
|
|||||||
{.utf={.symbol="ď"}, {{0x38, 0x44, 0x45, 0x48, 0x7f}}},
|
{.utf={.symbol="ď"}, {{0x38, 0x44, 0x45, 0x48, 0x7f}}},
|
||||||
{.utf={.symbol="á"}, {{0x20, 0x54, 0x54, 0x55, 0x79}}},
|
{.utf={.symbol="á"}, {{0x20, 0x54, 0x54, 0x55, 0x79}}},
|
||||||
{.utf={.symbol="»"}, {{0x22, 0x14, 0x2a, 0x14, 0x08}}},
|
{.utf={.symbol="»"}, {{0x22, 0x14, 0x2a, 0x14, 0x08}}},
|
||||||
|
{.utf={.symbol="ě"}, {{0x38, 0x55, 0x56, 0x55, 0x18}}},
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -951,6 +951,14 @@ const char *font_extras[] = {
|
|||||||
" x x ",
|
" x x ",
|
||||||
"x x ",
|
"x x ",
|
||||||
" ",
|
" ",
|
||||||
|
// 101 "e"
|
||||||
|
" x x ",
|
||||||
|
" x ",
|
||||||
|
" ### ",
|
||||||
|
"# #",
|
||||||
|
"#####",
|
||||||
|
"# ",
|
||||||
|
" ### ",
|
||||||
};
|
};
|
||||||
|
|
||||||
const char *font_extras_utf[] = {
|
const char *font_extras_utf[] = {
|
||||||
@@ -977,6 +985,7 @@ const char *font_extras_utf[] = {
|
|||||||
"ď",
|
"ď",
|
||||||
"á",
|
"á",
|
||||||
"»",
|
"»",
|
||||||
|
"ě",
|
||||||
};
|
};
|
||||||
|
|
||||||
#include "fontedit_render.inc.c"
|
#include "fontedit_render.inc.c"
|
||||||
|
|||||||
@@ -53,6 +53,7 @@ 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_calibration.c \
|
||||||
Core/Src/Gui/screen_manual_menu.c \
|
Core/Src/Gui/screen_manual_menu.c \
|
||||||
|
Core/Src/Gui/screen_pid_tuning.c \
|
||||||
Core/Src/app_temp.c \
|
Core/Src/app_temp.c \
|
||||||
Core/Src/app_knob.c \
|
Core/Src/app_knob.c \
|
||||||
Core/Src/app_buzzer.c \
|
Core/Src/app_buzzer.c \
|
||||||
|
|||||||
Reference in New Issue
Block a user