parent
38139e3923
commit
a7749c08ef
@ -1,114 +0,0 @@ |
||||
/**
|
||||
* Main task |
||||
*/ |
||||
|
||||
#include <stdio.h> |
||||
#include "FreeRTOS.h" |
||||
#include "task.h" |
||||
|
||||
#include "main.h" |
||||
#include "app.h" |
||||
|
||||
#include "ufb/framebuffer.h" |
||||
#include "iwdg.h" |
||||
#include "oled.h" |
||||
#include "ufb/fb_text.h" |
||||
#include "app_analog.h" |
||||
#include "app_knob.h" |
||||
#include "app_buzzer.h" |
||||
#include "app_heater.h" |
||||
|
||||
static struct App { |
||||
float oven_temp; |
||||
int16_t set_temp; |
||||
int16_t wheel_normed; |
||||
uint16_t wheel; |
||||
bool heating; |
||||
} s_app = {}; |
||||
|
||||
static void hw_init() |
||||
{ |
||||
app_analog_init(); |
||||
app_buzzer_init(); |
||||
app_heater_init(); |
||||
app_knob_init(); |
||||
|
||||
/* Prepare the framebuffer and OLED interface */ |
||||
oled_init(); |
||||
fb_clear(); |
||||
} |
||||
|
||||
void app_main_task(void *argument) |
||||
{ |
||||
hw_init(); |
||||
|
||||
/* Infinite loop */ |
||||
for (;;) { |
||||
HAL_GPIO_TogglePin(LED_GPIO_Port, LED_Pin); |
||||
|
||||
s_app.oven_temp = app_analog_get_temp(); |
||||
|
||||
for (int i = 0; i < 50; i++) { |
||||
uint16_t old_wheel = s_app.wheel; |
||||
s_app.wheel = app_knob_get_raw(); |
||||
|
||||
int16_t wheel_change = (int16_t)(s_app.wheel - old_wheel); |
||||
|
||||
if (wheel_change != 0) { |
||||
s_app.wheel_normed += wheel_change; |
||||
if (s_app.wheel_normed < 0) { |
||||
s_app.wheel_normed = 0; |
||||
} |
||||
if (s_app.wheel_normed > 500) { |
||||
s_app.wheel_normed = 500; |
||||
} |
||||
|
||||
int16_t old_temp = s_app.set_temp; |
||||
|
||||
s_app.set_temp = (s_app.wheel_normed / 2) * 5; |
||||
|
||||
if (old_temp != s_app.set_temp) { |
||||
app_buzzer_beep(); |
||||
} |
||||
} |
||||
|
||||
//s_app.push = 0 == HAL_GPIO_ReadPin(KNOB_PUSH_GPIO_Port, KNOB_PUSH_Pin);
|
||||
|
||||
if (wheel_change != 0 || i == 0) { |
||||
fb_clear(); |
||||
|
||||
char tmp[100]; |
||||
|
||||
sprintf(tmp, "Mereni: %d°C", (int) s_app.oven_temp); |
||||
fb_text(10, 10, tmp, 0, 1); |
||||
|
||||
sprintf(tmp, " Cil: %d°C", s_app.set_temp); |
||||
fb_text(10, 25, tmp, 0, 1); |
||||
|
||||
if (s_app.heating) { |
||||
fb_frame(0, 0, FBW, FBH, 2, 1); |
||||
} |
||||
|
||||
fb_blit(); |
||||
} |
||||
|
||||
vTaskDelay(10); |
||||
} |
||||
|
||||
// regulation
|
||||
|
||||
float set_f = (float) s_app.set_temp; |
||||
|
||||
if (!s_app.heating && s_app.oven_temp < set_f - 5.0f) { /* hysteresis */ |
||||
s_app.heating = true; |
||||
} |
||||
if (s_app.heating && s_app.oven_temp >= set_f) { |
||||
s_app.heating = false; |
||||
} |
||||
|
||||
app_heater_set(s_app.heating); |
||||
|
||||
// feed dogs
|
||||
HAL_IWDG_Refresh(&hiwdg); |
||||
} |
||||
} |
@ -1,19 +0,0 @@ |
||||
/**
|
||||
* TODO file description |
||||
*/ |
||||
|
||||
#ifndef BLUEPILLTROUBA_APP_ANALOG_H |
||||
#define BLUEPILLTROUBA_APP_ANALOG_H |
||||
|
||||
void app_analog_init(); |
||||
|
||||
/**
|
||||
* Get current oven temp. |
||||
* |
||||
* A slow float calculation is done here - call only when needed, at a roughly constant rate (e.g. 1s) to make smoothing work properly. |
||||
* |
||||
* @return the value in celsius |
||||
*/ |
||||
float app_analog_get_temp(); |
||||
|
||||
#endif //BLUEPILLTROUBA_APP_ANALOG_H
|
@ -0,0 +1,12 @@ |
||||
/**
|
||||
* TODO file description |
||||
*/ |
||||
|
||||
#include "app_gui.h" |
||||
#include "cmsis_os2.h" |
||||
|
||||
void app_task_gui(void *argument) { |
||||
while (1) { |
||||
osDelay(1000); |
||||
} |
||||
} |
@ -0,0 +1,10 @@ |
||||
/**
|
||||
* TODO file description |
||||
*/ |
||||
|
||||
#ifndef BLUEPILLTROUBA_APP_GUI_H |
||||
#define BLUEPILLTROUBA_APP_GUI_H |
||||
|
||||
void app_task_gui(void *argument); |
||||
|
||||
#endif //BLUEPILLTROUBA_APP_GUI_H
|
@ -1,23 +1,114 @@ |
||||
/**
|
||||
* TODO file description |
||||
*/ |
||||
|
||||
#include <stdio.h> |
||||
#include "main.h" |
||||
#include "FreeRTOS.h" |
||||
#include "task.h" |
||||
#include "app_temp.h" |
||||
#include "app_pid.h" |
||||
#include "app_heater.h" |
||||
#include "cmsis_os2.h" |
||||
#include "tim.h" |
||||
|
||||
void app_heater_init() |
||||
extern osMutexId_t heaterMutexHandle; |
||||
|
||||
static void heater_pwm_init() |
||||
{ |
||||
HAL_TIM_Base_Start(&htim3); |
||||
htim3.Instance->CCR1 = 0; // OFF
|
||||
HAL_TIM_PWM_Start(&htim3, TIM_CHANNEL_1); |
||||
} |
||||
|
||||
static void heater_pwm_set_perc(float perc) |
||||
{ |
||||
uint16_t perc_u = (uint16_t) perc; |
||||
if (perc_u > 100) { |
||||
perc_u = 100; |
||||
} |
||||
|
||||
// (TIM3->ARR / 100)
|
||||
|
||||
TIM3->CCR1 = 640 * perc_u; |
||||
} |
||||
|
||||
void app_heater_set(bool active) |
||||
static struct { |
||||
float oven_temp; |
||||
float soc_temp; |
||||
// these will be loaded from flash and stored back
|
||||
float tuning_p; |
||||
float tuning_i; |
||||
float tuning_d; |
||||
// PID state
|
||||
struct PID pid; |
||||
} state = { |
||||
.tuning_p = 10.0f, |
||||
.tuning_i = 0.052f, |
||||
.tuning_d = 100.0f, |
||||
.pid = { |
||||
.SampleTimeTicks = pdMS_TO_TICKS(1000), |
||||
.outMax = 100.0f, |
||||
.outMin = 0.0f, |
||||
.ctlMode = PID_MANUAL, |
||||
.controllerDirection = PID_DIRECT, |
||||
}, |
||||
}; |
||||
|
||||
static inline void heaterEnterCritical() { |
||||
osMutexAcquire(heaterMutexHandle, portMAX_DELAY); |
||||
} |
||||
|
||||
static inline void heaterExitCritical() { |
||||
osMutexRelease(heaterMutexHandle); |
||||
} |
||||
|
||||
void app_heater_set_tuning(float p, float i, float d) { |
||||
heaterEnterCritical(); |
||||
PID_SetTunings(&state.pid, p, i, d); |
||||
heaterExitCritical(); |
||||
} |
||||
|
||||
void app_heater_enable(bool enable) { |
||||
printf("Set heater enabled = %d\r\n", (int) enable); |
||||
heaterEnterCritical(); |
||||
PID_SetCtlMode(&state.pid, enable ? PID_AUTOMATIC : PID_MANUAL); |
||||
heaterExitCritical(); |
||||
} |
||||
|
||||
void app_heater_set_target(float target) { |
||||
printf("Set heater target = %d\r\n", (int) target); |
||||
heaterEnterCritical(); |
||||
PID_SetSetpoint(&state.pid, target); |
||||
heaterExitCritical(); |
||||
} |
||||
|
||||
void app_task_heater(void *argument) |
||||
{ |
||||
if (active) { |
||||
TIM3->CCR1 = TIM3->ARR / 2; // testing - 50%
|
||||
heater_pwm_init(); |
||||
|
||||
heaterEnterCritical(); |
||||
// TODO load from flash
|
||||
PID_SetTunings(&state.pid, state.tuning_p, state.tuning_i, state.tuning_d); |
||||
PID_Initialize(&state.pid); |
||||
heaterExitCritical(); |
||||
|
||||
uint32_t wake_time = xTaskGetTickCount(); |
||||
while (1) { |
||||
app_temp_sample(); |
||||
|
||||
state.oven_temp = app_temp_read_oven(); |
||||
state.soc_temp = app_temp_read_soc(); |
||||
|
||||
heaterEnterCritical(); |
||||
PID_Compute(&state.pid, state.oven_temp); |
||||
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 { |
||||
TIM3->CCR1 = 0; |
||||
// turn it off
|
||||
heater_pwm_set_perc(0); |
||||
} |
||||
heaterExitCritical(); |
||||
|
||||
// TODO notify UI thread of the new temperature and heating percent
|
||||
|
||||
vTaskDelayUntil(&wake_time, pdMS_TO_TICKS(500)); |
||||
} |
||||
} |
||||
|
@ -0,0 +1,122 @@ |
||||
/**
|
||||
* Main task |
||||
*/ |
||||
|
||||
#include <stdio.h> |
||||
#include "FreeRTOS.h" |
||||
#include "task.h" |
||||
|
||||
#include "main.h" |
||||
#include "app.h" |
||||
|
||||
#include "ufb/framebuffer.h" |
||||
#include "iwdg.h" |
||||
#include "oled.h" |
||||
#include "ufb/fb_text.h" |
||||
#include "app_temp.h" |
||||
#include "app_knob.h" |
||||
#include "app_buzzer.h" |
||||
#include "app_heater.h" |
||||
#include "cmsis_os2.h" |
||||
|
||||
static struct App { |
||||
float oven_temp; |
||||
int16_t set_temp; |
||||
int16_t wheel_normed; |
||||
uint16_t wheel; |
||||
bool run; |
||||
} s_app = {}; |
||||
|
||||
static void redraw_display() { |
||||
fb_clear(); |
||||
|
||||
char tmp[100]; |
||||
|
||||
sprintf(tmp, "Mereni: %d°C", (int) s_app.oven_temp); |
||||
fb_text(10, 5, tmp, 0, 1); |
||||
|
||||
sprintf(tmp, " Cil: %d°C", s_app.set_temp); |
||||
fb_text(10, 20, tmp, 0, 1); |
||||
|
||||
sprintf(tmp, " Stav: %s", s_app.run ? "ZAP" : "VYP"); |
||||
fb_text(10, 35, tmp, 0, 1); |
||||
|
||||
if (s_app.run) { |
||||
fb_frame(0, 0, FBW, FBH, 2, 1); |
||||
} |
||||
|
||||
fb_blit(); |
||||
} |
||||
|
||||
void app_task_main(void *argument) |
||||
{ |
||||
app_analog_init(); |
||||
app_buzzer_init(); |
||||
app_knob_init(); |
||||
|
||||
/* Prepare the framebuffer and OLED interface */ |
||||
oled_init(); |
||||
fb_clear(); |
||||
|
||||
/* Infinite loop */ |
||||
bool old_pushed = app_knob_pushed(); |
||||
|
||||
bool any_change = true; |
||||
uint32_t last_redraw = osKernelGetTickCount(); |
||||
|
||||
for (;;) { |
||||
// sampling is done in the heater loop
|
||||
|
||||
s_app.oven_temp = app_temp_read_oven(); |
||||
|
||||
uint16_t old_wheel = s_app.wheel; |
||||
s_app.wheel = app_knob_get_raw(); |
||||
|
||||
// TODO do this with interrupt and/or debouncing
|
||||
bool pushed = app_knob_pushed(); |
||||
if (pushed && !old_pushed) { |
||||
s_app.run ^= 1; |
||||
app_heater_enable(s_app.run); |
||||
app_buzzer_beep(); |
||||
any_change = true; |
||||
} |
||||
old_pushed = pushed; |
||||
|
||||
|
||||
int16_t wheel_change = (int16_t)(s_app.wheel - old_wheel); |
||||
if (wheel_change != 0) { |
||||
s_app.wheel_normed += wheel_change; |
||||
if (s_app.wheel_normed < 0) { |
||||
s_app.wheel_normed = 0; |
||||
} |
||||
if (s_app.wheel_normed > 500) { |
||||
s_app.wheel_normed = 500; |
||||
} |
||||
|
||||
int16_t old_temp = s_app.set_temp; |
||||
|
||||
s_app.set_temp = (s_app.wheel_normed / 2) * 5; |
||||
|
||||
if (old_temp != s_app.set_temp) { |
||||
app_buzzer_beep(); |
||||
app_heater_set_target((float) s_app.set_temp); |
||||
any_change = true; |
||||
} |
||||
} |
||||
|
||||
uint32_t now = osKernelGetTickCount(); |
||||
if (any_change || (now - last_redraw > pdMS_TO_TICKS(500))) { |
||||
last_redraw = now; |
||||
redraw_display(); |
||||
any_change = false; |
||||
|
||||
// Blink
|
||||
HAL_GPIO_TogglePin(LED_GPIO_Port, LED_Pin); |
||||
} |
||||
|
||||
vTaskDelay(pdMS_TO_TICKS(10)); |
||||
|
||||
// feed dogs
|
||||
HAL_IWDG_Refresh(&hiwdg); |
||||
} |
||||
} |
@ -0,0 +1,27 @@ |
||||
/**
|
||||
* TODO file description |
||||
*/ |
||||
|
||||
#ifndef BLUEPILLTROUBA_APP_TEMP_H |
||||
#define BLUEPILLTROUBA_APP_TEMP_H |
||||
|
||||
void app_analog_init(); |
||||
|
||||
/**
|
||||
* Update temperature measurement. |
||||
* |
||||
* A slow float calculation is done here - call only when needed, at a roughly constant rate (e.g. 1s) to make smoothing work properly. |
||||
* |
||||
* The oven temp is further averaged internally. |
||||
*/ |
||||
void app_temp_sample(); |
||||
|
||||
/// Read current oven temperature (celsius)
|
||||
/// The value is valid after calling app_temp_sample()
|
||||
float app_temp_read_oven(); |
||||
|
||||
/// Read current SOC temperature (celsius)
|
||||
/// The value is valid after calling app_temp_sample()
|
||||
float app_temp_read_soc(); |
||||
|
||||
#endif //BLUEPILLTROUBA_APP_TEMP_H
|
Loading…
Reference in new issue