mostly working PID now
This commit is contained in:
+7
-3
@@ -27,8 +27,12 @@ Dma.ADC1.0.Priority=DMA_PRIORITY_MEDIUM
|
||||
Dma.ADC1.0.RequestParameters=Instance,Direction,PeriphInc,MemInc,PeriphDataAlignment,MemDataAlignment,Mode,Priority
|
||||
Dma.Request0=ADC1
|
||||
Dma.RequestsNb=1
|
||||
FREERTOS.IPParameters=Tasks01,configUSE_MALLOC_FAILED_HOOK,configCHECK_FOR_STACK_OVERFLOW,configUSE_NEWLIB_REENTRANT
|
||||
FREERTOS.Tasks01=defaultTask,24,128,StartDefaultTask,Default,NULL,Dynamic,NULL,NULL
|
||||
FREERTOS.FootprintOK=true
|
||||
FREERTOS.IPParameters=Tasks01,configUSE_MALLOC_FAILED_HOOK,configCHECK_FOR_STACK_OVERFLOW,configUSE_NEWLIB_REENTRANT,FootprintOK,Mutexes01,Queues01,Timers01
|
||||
FREERTOS.Mutexes01=heaterMutex,Static,heaterMutexControlBlock
|
||||
FREERTOS.Queues01=guiEventQue,16,8,1,Static,guiEventQueBuffer,guiEventQueControlBlock
|
||||
FREERTOS.Tasks01=mainTsk,24,128,app_task_main,As weak,NULL,Static,defaultTaskBuffer,defaultTaskControlBlock;heaterTsk,24,128,app_task_heater,As external,NULL,Static,heaterTskBuffer,heaterTskControlBlock;guiTsk,40,128,app_task_gui,As external,NULL,Static,guiTskBuffer,guiTskControlBlock
|
||||
FREERTOS.Timers01=beepTimer,app_beep_end,osTimerOnce,As external,NULL,Static,beepTimerControlBlock
|
||||
FREERTOS.configCHECK_FOR_STACK_OVERFLOW=2
|
||||
FREERTOS.configUSE_MALLOC_FAILED_HOOK=1
|
||||
FREERTOS.configUSE_NEWLIB_REENTRANT=1
|
||||
@@ -236,7 +240,7 @@ TIM3.Channel-PWM\ Generation1\ CH1=TIM_CHANNEL_1
|
||||
TIM3.IPParameters=Channel-PWM Generation1 CH1,Prescaler,Pulse-PWM Generation1 CH1,Period
|
||||
TIM3.Period=64000
|
||||
TIM3.Prescaler=2000
|
||||
TIM3.Pulse-PWM\ Generation1\ CH1=32000
|
||||
TIM3.Pulse-PWM\ Generation1\ CH1=0
|
||||
TIM4.IC2Filter=15
|
||||
TIM4.IPParameters=IC2Filter,Prescaler
|
||||
TIM4.Prescaler=0
|
||||
|
||||
-114
@@ -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
|
||||
+20
-5
@@ -6,20 +6,35 @@
|
||||
#include "app_buzzer.h"
|
||||
#include "tim.h"
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
#include "cmsis_os2.h"
|
||||
#include "timers.h"
|
||||
|
||||
extern osTimerId_t beepTimerHandle;
|
||||
|
||||
//void app_beep_end(void *argument);
|
||||
|
||||
//static TimerHandle_t s_timer;
|
||||
|
||||
void app_buzzer_init()
|
||||
{
|
||||
/* Enable buzzer PWM */
|
||||
TIM2->CCR1 = 0;
|
||||
HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_1);
|
||||
|
||||
// s_timer = xTimerCreate("beep", 50, 0, NULL, app_beep_end);
|
||||
}
|
||||
|
||||
void app_buzzer_beep() {
|
||||
|
||||
// TODO make this non-blocking
|
||||
TIM2->ARR = 25714;
|
||||
TIM2->CCR1 = TIM2->ARR/2;
|
||||
vTaskDelay(50);
|
||||
|
||||
osTimerStop(beepTimerHandle);
|
||||
|
||||
osTimerStart(beepTimerHandle, pdMS_TO_TICKS(10));
|
||||
|
||||
// xTimerStart(s_timer, pdMS_TO_TICKS(1000));
|
||||
}
|
||||
|
||||
void app_beep_end(TimerHandle_t timerHandle) {
|
||||
TIM2->CCR1 = 0;
|
||||
vTaskDelay(50);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
+102
-11
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
void app_heater_set(bool active)
|
||||
static void heater_pwm_set_perc(float perc)
|
||||
{
|
||||
if (active) {
|
||||
TIM3->CCR1 = TIM3->ARR / 2; // testing - 50%
|
||||
} else {
|
||||
TIM3->CCR1 = 0;
|
||||
uint16_t perc_u = (uint16_t) perc;
|
||||
if (perc_u > 100) {
|
||||
perc_u = 100;
|
||||
}
|
||||
|
||||
// (TIM3->ARR / 100)
|
||||
|
||||
TIM3->CCR1 = 640 * perc_u;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
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 {
|
||||
// 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));
|
||||
}
|
||||
}
|
||||
|
||||
+13
-3
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* TODO file description
|
||||
* Heater PWM control & regulation + temp sensing loop
|
||||
*/
|
||||
|
||||
#ifndef BLUEPILLTROUBA_APP_HEATER_H
|
||||
@@ -7,8 +7,18 @@
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
void app_heater_init();
|
||||
void app_task_heater(void *argument);
|
||||
|
||||
void app_heater_set(bool active);
|
||||
/// Set heater regulator tuning.
|
||||
/// Mutex is locked internally.
|
||||
void app_heater_set_tuning(float p, float i, float d);
|
||||
|
||||
/// Set heater on/off.
|
||||
/// Mutex is locked internally.
|
||||
void app_heater_enable(bool enable);
|
||||
|
||||
/// Set heater setpoint
|
||||
/// Mutex is locked internally.
|
||||
void app_heater_set_target(float target);
|
||||
|
||||
#endif //BLUEPILLTROUBA_APP_HEATER_H
|
||||
|
||||
@@ -21,3 +21,8 @@ void app_knob_init()
|
||||
uint16_t app_knob_get_raw() {
|
||||
return htim4.Instance->CNT;
|
||||
}
|
||||
|
||||
|
||||
bool app_knob_pushed() {
|
||||
return 0 == HAL_GPIO_ReadPin(KNOB_PUSH_GPIO_Port, KNOB_PUSH_Pin);
|
||||
}
|
||||
|
||||
@@ -8,5 +8,6 @@
|
||||
void app_knob_init();
|
||||
|
||||
uint16_t app_knob_get_raw();
|
||||
bool app_knob_pushed();
|
||||
|
||||
#endif //BLUEPILLTROUBA_APP_KNOB_H
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
+35
-26
@@ -3,6 +3,7 @@
|
||||
#include <stdint.h>
|
||||
#include <FreeRTOS.h>
|
||||
#include <task.h>
|
||||
#include <stdio.h>
|
||||
|
||||
static void clampOutput(struct PID *self)
|
||||
{
|
||||
@@ -16,21 +17,29 @@ static void clampIterm(struct PID *self)
|
||||
else if (self->ITerm < self->outMin) { self->ITerm = self->outMin; }
|
||||
}
|
||||
|
||||
void PID_Compute(struct PID *self, float Input)
|
||||
void PID_Compute(struct PID *self, float input)
|
||||
{
|
||||
if (!self->ctlMode) { return; }
|
||||
self->Input = Input;
|
||||
if (self->ctlMode != PID_AUTOMATIC) { return; }
|
||||
self->Input = input;
|
||||
|
||||
uint32_t now = xTaskGetTickCount();
|
||||
int32_t timeChange = (now - self->lastTime) * (uint32_t) 1000 / (uint32_t) configTICK_RATE_HZ;
|
||||
if (timeChange >= self->SampleTime) {
|
||||
int32_t timeChange = (now - self->lastTime);
|
||||
if (timeChange >= self->SampleTimeTicks) {
|
||||
printf("compute\r\n");
|
||||
/*Compute all the working error variables*/
|
||||
float error = self->Setpoint - Input;
|
||||
float error = self->Setpoint - input;
|
||||
self->ITerm += (self->ki * error);
|
||||
|
||||
clampIterm(self);
|
||||
|
||||
float dInput = (Input - self->lastInput);
|
||||
float dInput = (input - self->lastInput);
|
||||
|
||||
|
||||
printf("calc x100 %d + %d - %d\r\n",
|
||||
(int) (100 * (self->kp * error)),
|
||||
(int) (100 * (self->ITerm)),
|
||||
(int) (100 * (self->kd * dInput))
|
||||
);
|
||||
|
||||
/*Compute PID Output*/
|
||||
self->Output = self->kp * error + self->ITerm - self->kd * dInput;
|
||||
@@ -38,21 +47,21 @@ void PID_Compute(struct PID *self, float Input)
|
||||
clampOutput(self);
|
||||
|
||||
/*Remember some variables for next time*/
|
||||
self->lastInput = Input;
|
||||
self->lastInput = input;
|
||||
self->lastTime = now;
|
||||
}
|
||||
}
|
||||
|
||||
void PID_SetSetpoint(struct PID *self, float Setpoint)
|
||||
void PID_SetSetpoint(struct PID *self, float setpoint)
|
||||
{
|
||||
self->Setpoint = Setpoint;
|
||||
self->Setpoint = setpoint;
|
||||
}
|
||||
|
||||
void PID_SetTunings(struct PID *self, float Kp, float Ki, float Kd)
|
||||
{
|
||||
if (Kp < 0 || Ki < 0 || Kd < 0) { return; }
|
||||
|
||||
float SampleTimeInSec = ((float) self->SampleTime) / 1000;
|
||||
float SampleTimeInSec = ((float) self->SampleTimeTicks) / configTICK_RATE_HZ;
|
||||
self->kp = Kp;
|
||||
self->ki = Ki * SampleTimeInSec;
|
||||
self->kd = Kd / SampleTimeInSec;
|
||||
@@ -64,34 +73,34 @@ void PID_SetTunings(struct PID *self, float Kp, float Ki, float Kd)
|
||||
}
|
||||
}
|
||||
|
||||
void PID_SetSampleTime(struct PID *self, uint32_t NewSampleTime)
|
||||
void PID_SetSampleTime(struct PID *self, uint32_t new_sample_time)
|
||||
{
|
||||
if (NewSampleTime > 0) {
|
||||
float ratio = (float) NewSampleTime
|
||||
/ (float) self->SampleTime;
|
||||
if (new_sample_time > 0) {
|
||||
float ratio = (float) new_sample_time
|
||||
/ (float) self->SampleTimeTicks;
|
||||
self->ki *= ratio;
|
||||
self->kd /= ratio;
|
||||
self->SampleTime = (uint32_t) NewSampleTime;
|
||||
self->SampleTimeTicks = (uint32_t) new_sample_time;
|
||||
}
|
||||
}
|
||||
|
||||
void PID_SetOutputLimits(struct PID *self, float Min, float Max)
|
||||
void PID_SetOutputLimits(struct PID *self, float min, float max)
|
||||
{
|
||||
if (Min > Max) { return; }
|
||||
self->outMin = Min;
|
||||
self->outMax = Max;
|
||||
if (min > max) { return; }
|
||||
self->outMin = min;
|
||||
self->outMax = max;
|
||||
|
||||
clampOutput(self);
|
||||
clampIterm(self);
|
||||
}
|
||||
|
||||
void PID_SetCtlMode(struct PID *self, enum PIDCtlMode Mode)
|
||||
void PID_SetCtlMode(struct PID *self, enum PIDCtlMode mode)
|
||||
{
|
||||
bool newAuto = (Mode == PID_AUTOMATIC);
|
||||
if (newAuto == !self->ctlMode) { /*we just went from manual to auto*/
|
||||
if (mode == PID_AUTOMATIC && self->ctlMode == PID_MANUAL) {
|
||||
/*we just went from manual to auto*/
|
||||
PID_Initialize(self);
|
||||
}
|
||||
self->ctlMode = newAuto;
|
||||
self->ctlMode = mode;
|
||||
}
|
||||
|
||||
void PID_Initialize(struct PID *self)
|
||||
@@ -102,7 +111,7 @@ void PID_Initialize(struct PID *self)
|
||||
clampIterm(self);
|
||||
}
|
||||
|
||||
void PID_SetControllerDirection(struct PID *self, enum PIDDirection Direction)
|
||||
void PID_SetControllerDirection(struct PID *self, enum PIDDirection direction)
|
||||
{
|
||||
self->controllerDirection = Direction;
|
||||
self->controllerDirection = direction;
|
||||
}
|
||||
|
||||
+8
-8
@@ -25,28 +25,28 @@ struct PID {
|
||||
float Input, Output, Setpoint;
|
||||
float ITerm, lastInput;
|
||||
float kp, ki, kd;
|
||||
uint32_t SampleTime; // millis
|
||||
uint32_t SampleTimeTicks;
|
||||
float outMin, outMax;
|
||||
enum PIDCtlMode ctlMode; // false
|
||||
enum PIDDirection controllerDirection;
|
||||
};
|
||||
|
||||
#define PID_DEFAULT() { .SampleTime = 1000, .ctlMode=PID_MANUAL, .controllerDirection=PID_DIRECT }
|
||||
#define PID_DEFAULT() { .SampleTimeMs = 1000, .ctlMode=PID_MANUAL, .controllerDirection=PID_DIRECT }
|
||||
|
||||
void PID_Compute(struct PID *self, float Input);
|
||||
void PID_Compute(struct PID *self, float input);
|
||||
|
||||
void PID_SetTunings(struct PID *self, float Kp, float Ki, float Kd);
|
||||
|
||||
void PID_SetSampleTime(struct PID *self, uint32_t NewSampleTime);
|
||||
void PID_SetSampleTime(struct PID *self, uint32_t new_sample_time);
|
||||
|
||||
void PID_SetOutputLimits(struct PID *self, float Min, float Max);
|
||||
void PID_SetOutputLimits(struct PID *self, float min, float max);
|
||||
|
||||
void PID_SetCtlMode(struct PID *self, enum PIDCtlMode Mode);
|
||||
void PID_SetCtlMode(struct PID *self, enum PIDCtlMode mode);
|
||||
|
||||
void PID_Initialize(struct PID *self);
|
||||
|
||||
void PID_SetSetpoint(struct PID *self, float Setpoint);
|
||||
void PID_SetSetpoint(struct PID *self, float setpoint);
|
||||
|
||||
void PID_SetControllerDirection(struct PID *self, enum PIDDirection Direction);
|
||||
void PID_SetControllerDirection(struct PID *self, enum PIDDirection direction);
|
||||
|
||||
#endif //ARDUINOPID_H
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include "app_analog.h"
|
||||
#include "app_temp.h"
|
||||
#include "adc.h"
|
||||
|
||||
/* DMA dest */
|
||||
@@ -159,19 +159,27 @@ static float val_to_c(float val)
|
||||
return TSENSE_T_MAX;
|
||||
}
|
||||
|
||||
float app_analog_get_temp()
|
||||
void app_temp_sample()
|
||||
{
|
||||
uint32_t sums[4] = {};
|
||||
int count = 0;
|
||||
for (int i = 0; i < AVERAGEBUF_DEPTH * 4; i += 4) {
|
||||
sums[0] += s_analog.adc_averagebuf[i];
|
||||
sums[1] += s_analog.adc_averagebuf[i + 1];
|
||||
sums[2] += s_analog.adc_averagebuf[i + 2];
|
||||
sums[3] += s_analog.adc_averagebuf[i + 3];
|
||||
if (s_analog.adc_averagebuf[i + 3] != 0) {
|
||||
sums[0] += s_analog.adc_averagebuf[i];
|
||||
sums[1] += s_analog.adc_averagebuf[i + 1];
|
||||
sums[2] += s_analog.adc_averagebuf[i + 2];
|
||||
sums[3] += s_analog.adc_averagebuf[i + 3];
|
||||
count++;
|
||||
}
|
||||
}
|
||||
s_analog.adc_averages[0] = (float) sums[0] / AVERAGEBUF_DEPTH;
|
||||
s_analog.adc_averages[1] = (float) sums[1] / AVERAGEBUF_DEPTH;
|
||||
s_analog.adc_averages[2] = (float) sums[2] / AVERAGEBUF_DEPTH;
|
||||
s_analog.adc_averages[3] = (float) sums[3] / AVERAGEBUF_DEPTH;
|
||||
if (count == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
s_analog.adc_averages[0] = (float) sums[0] / count;
|
||||
s_analog.adc_averages[1] = (float) sums[1] / count;
|
||||
s_analog.adc_averages[2] = (float) sums[2] / count;
|
||||
s_analog.adc_averages[3] = (float) sums[3] / count;
|
||||
|
||||
/* r_pt100, r_ref, internal_temp, v_ref_int */
|
||||
float refint = s_analog.adc_averages[3];
|
||||
@@ -193,15 +201,29 @@ float app_analog_get_temp()
|
||||
s_analog.oventemp_history_ptr = (s_analog.oventemp_history_ptr + 1) % OVENTEMP_HISTORY_DEPTH;
|
||||
|
||||
float sum = 0;
|
||||
int depth = 0;
|
||||
for (int i = 0; i < OVENTEMP_HISTORY_DEPTH; i++) {
|
||||
sum += s_analog.oventemp_history[i];
|
||||
if (s_analog.oventemp_history[i] > 0.0f) {
|
||||
sum += s_analog.oventemp_history[i];
|
||||
depth++;
|
||||
}
|
||||
}
|
||||
if (depth > 0) {
|
||||
sum /= depth;
|
||||
}
|
||||
sum /= OVENTEMP_HISTORY_DEPTH;
|
||||
s_analog.oven_temp = sum;
|
||||
}
|
||||
|
||||
float app_temp_read_oven()
|
||||
{
|
||||
return s_analog.oven_temp;
|
||||
}
|
||||
|
||||
float app_temp_read_soc()
|
||||
{
|
||||
return s_analog.soc_temp;
|
||||
}
|
||||
|
||||
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef *hadc)
|
||||
{
|
||||
// notify
|
||||
@@ -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
|
||||
+99
-16
@@ -31,6 +31,10 @@
|
||||
/* USER CODE END Includes */
|
||||
|
||||
/* Private typedef -----------------------------------------------------------*/
|
||||
typedef StaticTask_t osStaticThreadDef_t;
|
||||
typedef StaticQueue_t osStaticMessageQDef_t;
|
||||
typedef StaticTimer_t osStaticTimerDef_t;
|
||||
typedef StaticSemaphore_t osStaticMutexDef_t;
|
||||
/* USER CODE BEGIN PTD */
|
||||
|
||||
/* USER CODE END PTD */
|
||||
@@ -49,20 +53,79 @@
|
||||
/* USER CODE BEGIN Variables */
|
||||
|
||||
/* USER CODE END Variables */
|
||||
/* Definitions for defaultTask */
|
||||
osThreadId_t defaultTaskHandle;
|
||||
const osThreadAttr_t defaultTask_attributes = {
|
||||
.name = "defaultTask",
|
||||
.stack_size = 128 * 4,
|
||||
/* Definitions for mainTsk */
|
||||
osThreadId_t mainTskHandle;
|
||||
uint32_t defaultTaskBuffer[ 128 ];
|
||||
osStaticThreadDef_t defaultTaskControlBlock;
|
||||
const osThreadAttr_t mainTsk_attributes = {
|
||||
.name = "mainTsk",
|
||||
.cb_mem = &defaultTaskControlBlock,
|
||||
.cb_size = sizeof(defaultTaskControlBlock),
|
||||
.stack_mem = &defaultTaskBuffer[0],
|
||||
.stack_size = sizeof(defaultTaskBuffer),
|
||||
.priority = (osPriority_t) osPriorityNormal,
|
||||
};
|
||||
/* Definitions for heaterTsk */
|
||||
osThreadId_t heaterTskHandle;
|
||||
uint32_t heaterTskBuffer[ 128 ];
|
||||
osStaticThreadDef_t heaterTskControlBlock;
|
||||
const osThreadAttr_t heaterTsk_attributes = {
|
||||
.name = "heaterTsk",
|
||||
.cb_mem = &heaterTskControlBlock,
|
||||
.cb_size = sizeof(heaterTskControlBlock),
|
||||
.stack_mem = &heaterTskBuffer[0],
|
||||
.stack_size = sizeof(heaterTskBuffer),
|
||||
.priority = (osPriority_t) osPriorityNormal,
|
||||
};
|
||||
/* Definitions for guiTsk */
|
||||
osThreadId_t guiTskHandle;
|
||||
uint32_t guiTskBuffer[ 128 ];
|
||||
osStaticThreadDef_t guiTskControlBlock;
|
||||
const osThreadAttr_t guiTsk_attributes = {
|
||||
.name = "guiTsk",
|
||||
.cb_mem = &guiTskControlBlock,
|
||||
.cb_size = sizeof(guiTskControlBlock),
|
||||
.stack_mem = &guiTskBuffer[0],
|
||||
.stack_size = sizeof(guiTskBuffer),
|
||||
.priority = (osPriority_t) osPriorityHigh,
|
||||
};
|
||||
/* Definitions for guiEventQue */
|
||||
osMessageQueueId_t guiEventQueHandle;
|
||||
uint8_t guiEventQueBuffer[ 16 * 8 ];
|
||||
osStaticMessageQDef_t guiEventQueControlBlock;
|
||||
const osMessageQueueAttr_t guiEventQue_attributes = {
|
||||
.name = "guiEventQue",
|
||||
.cb_mem = &guiEventQueControlBlock,
|
||||
.cb_size = sizeof(guiEventQueControlBlock),
|
||||
.mq_mem = &guiEventQueBuffer,
|
||||
.mq_size = sizeof(guiEventQueBuffer)
|
||||
};
|
||||
/* Definitions for beepTimer */
|
||||
osTimerId_t beepTimerHandle;
|
||||
osStaticTimerDef_t beepTimerControlBlock;
|
||||
const osTimerAttr_t beepTimer_attributes = {
|
||||
.name = "beepTimer",
|
||||
.cb_mem = &beepTimerControlBlock,
|
||||
.cb_size = sizeof(beepTimerControlBlock),
|
||||
};
|
||||
/* Definitions for heaterMutex */
|
||||
osMutexId_t heaterMutexHandle;
|
||||
osStaticMutexDef_t heaterMutexControlBlock;
|
||||
const osMutexAttr_t heaterMutex_attributes = {
|
||||
.name = "heaterMutex",
|
||||
.cb_mem = &heaterMutexControlBlock,
|
||||
.cb_size = sizeof(heaterMutexControlBlock),
|
||||
};
|
||||
|
||||
/* Private function prototypes -----------------------------------------------*/
|
||||
/* USER CODE BEGIN FunctionPrototypes */
|
||||
|
||||
/* USER CODE END FunctionPrototypes */
|
||||
|
||||
void StartDefaultTask(void *argument);
|
||||
void app_task_main(void *argument);
|
||||
extern void app_task_heater(void *argument);
|
||||
extern void app_task_gui(void *argument);
|
||||
extern void app_beep_end(void *argument);
|
||||
|
||||
void MX_FREERTOS_Init(void); /* (MISRA C 2004 rule 8.1) */
|
||||
|
||||
@@ -104,6 +167,9 @@ void MX_FREERTOS_Init(void) {
|
||||
/* USER CODE BEGIN Init */
|
||||
|
||||
/* USER CODE END Init */
|
||||
/* Create the mutex(es) */
|
||||
/* creation of heaterMutex */
|
||||
heaterMutexHandle = osMutexNew(&heaterMutex_attributes);
|
||||
|
||||
/* USER CODE BEGIN RTOS_MUTEX */
|
||||
/* add mutexes, ... */
|
||||
@@ -113,17 +179,31 @@ void MX_FREERTOS_Init(void) {
|
||||
/* add semaphores, ... */
|
||||
/* USER CODE END RTOS_SEMAPHORES */
|
||||
|
||||
/* Create the timer(s) */
|
||||
/* creation of beepTimer */
|
||||
beepTimerHandle = osTimerNew(app_beep_end, osTimerOnce, NULL, &beepTimer_attributes);
|
||||
|
||||
/* USER CODE BEGIN RTOS_TIMERS */
|
||||
/* start timers, add new ones, ... */
|
||||
/* USER CODE END RTOS_TIMERS */
|
||||
|
||||
/* Create the queue(s) */
|
||||
/* creation of guiEventQue */
|
||||
guiEventQueHandle = osMessageQueueNew (16, 8, &guiEventQue_attributes);
|
||||
|
||||
/* USER CODE BEGIN RTOS_QUEUES */
|
||||
/* add queues, ... */
|
||||
/* USER CODE END RTOS_QUEUES */
|
||||
|
||||
/* Create the thread(s) */
|
||||
/* creation of defaultTask */
|
||||
defaultTaskHandle = osThreadNew(StartDefaultTask, NULL, &defaultTask_attributes);
|
||||
/* creation of mainTsk */
|
||||
mainTskHandle = osThreadNew(app_task_main, NULL, &mainTsk_attributes);
|
||||
|
||||
/* creation of heaterTsk */
|
||||
heaterTskHandle = osThreadNew(app_task_heater, NULL, &heaterTsk_attributes);
|
||||
|
||||
/* creation of guiTsk */
|
||||
guiTskHandle = osThreadNew(app_task_gui, NULL, &guiTsk_attributes);
|
||||
|
||||
/* USER CODE BEGIN RTOS_THREADS */
|
||||
/* add threads, ... */
|
||||
@@ -135,19 +215,22 @@ void MX_FREERTOS_Init(void) {
|
||||
|
||||
}
|
||||
|
||||
/* USER CODE BEGIN Header_StartDefaultTask */
|
||||
/* USER CODE BEGIN Header_app_task_main */
|
||||
/**
|
||||
* @brief Function implementing the defaultTask thread.
|
||||
* @brief Function implementing the mainTsk thread.
|
||||
* @param argument: Not used
|
||||
* @retval None
|
||||
*/
|
||||
/* USER CODE END Header_StartDefaultTask */
|
||||
void StartDefaultTask(void *argument)
|
||||
/* USER CODE END Header_app_task_main */
|
||||
__weak void app_task_main(void *argument)
|
||||
{
|
||||
/* USER CODE BEGIN StartDefaultTask */
|
||||
app_main_task(argument);
|
||||
vTaskDelete(NULL);
|
||||
/* USER CODE END StartDefaultTask */
|
||||
/* USER CODE BEGIN app_task_main */
|
||||
/* Infinite loop */
|
||||
for(;;)
|
||||
{
|
||||
osDelay(1);
|
||||
}
|
||||
/* USER CODE END app_task_main */
|
||||
}
|
||||
|
||||
/* Private application code --------------------------------------------------*/
|
||||
|
||||
+1
-1
@@ -123,7 +123,7 @@ void MX_TIM3_Init(void)
|
||||
Error_Handler();
|
||||
}
|
||||
sConfigOC.OCMode = TIM_OCMODE_PWM1;
|
||||
sConfigOC.Pulse = 32000;
|
||||
sConfigOC.Pulse = 0;
|
||||
sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
|
||||
sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
|
||||
if (HAL_TIM_PWM_ConfigChannel(&htim3, &sConfigOC, TIM_CHANNEL_1) != HAL_OK)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
##########################################################################################################################
|
||||
# File automatically-generated by tool: [projectgenerator] version: [3.16.0] date: [Mon Mar 06 21:48:34 CET 2023]
|
||||
# File automatically-generated by tool: [projectgenerator] version: [3.16.0] date: [Tue Mar 07 00:54:18 CET 2023]
|
||||
##########################################################################################################################
|
||||
|
||||
# ------------------------------------------------
|
||||
@@ -45,9 +45,10 @@ Core/Src/spi.c \
|
||||
Core/Src/tim.c \
|
||||
Core/Src/usart.c \
|
||||
Core/Src/oled.c \
|
||||
Core/Src/app.c \
|
||||
Core/Src/app_main.c \
|
||||
Core/Src/app_pid.c \
|
||||
Core/Src/app_analog.c \
|
||||
Core/Src/app_gui.c \
|
||||
Core/Src/app_temp.c \
|
||||
Core/Src/app_knob.c \
|
||||
Core/Src/app_buzzer.c \
|
||||
Core/Src/app_heater.c \
|
||||
|
||||
Reference in New Issue
Block a user