simple 2-state regulator

fake-chip
Ondřej Hruška 2 years ago
parent f093936970
commit e576d5847c
  1. 121
      Core/Src/app.c
  2. 2
      Makefile

@ -22,20 +22,23 @@ static volatile uint16_t adc_values[4];
const float V_REFINT = 1.23f; const float V_REFINT = 1.23f;
#define AVERAGEBUF_DEPTH 32 #define AVERAGEBUF_DEPTH 16
#define OVENTEMP_HISTORY_DEPTH 10
static struct App { static struct App {
bool heating;
int16_t set_temp;
int16_t wheel_normed;
float oven_temp; float oven_temp;
float soc_temp; float soc_temp;
float v_sensor; float v_sensor;
// float v_current_reference;
// float sensor_current;
// float r_sensor;
uint16_t wheel; uint16_t wheel;
bool push; bool push;
uint16_t adc_averagebuf[AVERAGEBUF_DEPTH * 4]; uint16_t adc_averagebuf[AVERAGEBUF_DEPTH * 4];
uint8_t averagebuf_ptr; uint8_t averagebuf_ptr;
float adc_averages[4]; float adc_averages[4];
float oventemp_history[OVENTEMP_HISTORY_DEPTH];
uint8_t oventemp_history_ptr;
} s_app = {}; } s_app = {};
#define TSENSE_LOOKUP_LEN 101 #define TSENSE_LOOKUP_LEN 101
@ -146,12 +149,13 @@ static const float TSENSE_LOOKUP[TSENSE_LOOKUP_LEN] = {
0.223001998051553f, 0.223001998051553f,
}; };
static float val_to_c(float val){ static float val_to_c(float val)
{
// TODO use binary search.. lol // TODO use binary search.. lol
for (int i = 1; i < TSENSE_LOOKUP_LEN; i++) { for (int i = 1; i < TSENSE_LOOKUP_LEN; i++) {
float cur = TSENSE_LOOKUP[i]; float cur = TSENSE_LOOKUP[i];
if (cur >= val) { if (cur >= val) {
float prev = TSENSE_LOOKUP[i-1]; float prev = TSENSE_LOOKUP[i - 1];
float ratio = (val - prev) / (cur - prev); float ratio = (val - prev) / (cur - prev);
return TSENSE_T_MIN + ((float) i + ratio) * TSENSE_T_STEP; return TSENSE_T_MIN + ((float) i + ratio) * TSENSE_T_STEP;
@ -160,7 +164,8 @@ static float val_to_c(float val){
return TSENSE_T_MAX; return TSENSE_T_MAX;
} }
void calculate_analog_values() { void calculate_analog_values()
{
uint32_t sums[4] = {}; uint32_t sums[4] = {};
for (int i = 0; i < AVERAGEBUF_DEPTH * 4; i += 4) { for (int i = 0; i < AVERAGEBUF_DEPTH * 4; i += 4) {
sums[0] += s_app.adc_averagebuf[i]; sums[0] += s_app.adc_averagebuf[i];
@ -168,10 +173,10 @@ void calculate_analog_values() {
sums[2] += s_app.adc_averagebuf[i + 2]; sums[2] += s_app.adc_averagebuf[i + 2];
sums[3] += s_app.adc_averagebuf[i + 3]; sums[3] += s_app.adc_averagebuf[i + 3];
} }
s_app.adc_averages[0] = (float)sums[0] / AVERAGEBUF_DEPTH; s_app.adc_averages[0] = (float) sums[0] / AVERAGEBUF_DEPTH;
s_app.adc_averages[1] = (float)sums[1] / AVERAGEBUF_DEPTH; s_app.adc_averages[1] = (float) sums[1] / AVERAGEBUF_DEPTH;
s_app.adc_averages[2] = (float)sums[2] / AVERAGEBUF_DEPTH; s_app.adc_averages[2] = (float) sums[2] / AVERAGEBUF_DEPTH;
s_app.adc_averages[3] = (float)sums[3] / AVERAGEBUF_DEPTH; s_app.adc_averages[3] = (float) sums[3] / AVERAGEBUF_DEPTH;
/* r_pt100, r_ref, internal_temp, v_ref_int */ /* r_pt100, r_ref, internal_temp, v_ref_int */
float refint = s_app.adc_averages[3]; float refint = s_app.adc_averages[3];
@ -184,15 +189,26 @@ void calculate_analog_values() {
s_app.soc_temp = (v25 - v_tsen) / avg_slope + 25.f; s_app.soc_temp = (v25 - v_tsen) / avg_slope + 25.f;
s_app.v_sensor = s_app.adc_averages[0] * scale; // good for debug/tuning s_app.v_sensor = s_app.adc_averages[0] * scale; // good for debug/tuning
// using a voltage divider, so assuming the reference resistor is measured well, // using a voltage divider, so assuming the reference resistor is measured well,
// we can just use the ratio and the exact voltage value is not important. // we can just use the ratio and the exact voltage value is not important.
s_app.oven_temp = val_to_c(s_app.adc_averages[0] / s_app.adc_averages[1]); float actual_temp = val_to_c(s_app.adc_averages[0] / s_app.adc_averages[1]);
s_app.oventemp_history[s_app.oventemp_history_ptr] = actual_temp;
s_app.oventemp_history_ptr = (s_app.oventemp_history_ptr + 1) % OVENTEMP_HISTORY_DEPTH;
float sum = 0;
for (int i = 0; i < OVENTEMP_HISTORY_DEPTH; i++) {
sum += s_app.oventemp_history[i];
}
sum /= OVENTEMP_HISTORY_DEPTH;
s_app.oven_temp = sum;
} }
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc) void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef *hadc)
{ {
// notify // notify
memcpy((void*) &s_app.adc_averagebuf[s_app.averagebuf_ptr * 4], (const void*) adc_values, 8); memcpy((void *) &s_app.adc_averagebuf[s_app.averagebuf_ptr * 4], (const void *) adc_values, 8);
s_app.averagebuf_ptr = (s_app.averagebuf_ptr + 1) % AVERAGEBUF_DEPTH; s_app.averagebuf_ptr = (s_app.averagebuf_ptr + 1) % AVERAGEBUF_DEPTH;
} }
@ -201,7 +217,7 @@ static void hw_init()
HAL_ADCEx_Calibration_Start(&hadc1); HAL_ADCEx_Calibration_Start(&hadc1);
/* Start periodic reading of the ADC channels */ /* Start periodic reading of the ADC channels */
HAL_ADC_Start_DMA(&hadc1, (uint32_t*)(void*)adc_values, 4); HAL_ADC_Start_DMA(&hadc1, (uint32_t *) (void *) adc_values, 4);
/* Enable the rotary encoder */ /* Enable the rotary encoder */
HAL_TIM_Encoder_Start(&htim4, TIM_CHANNEL_ALL); HAL_TIM_Encoder_Start(&htim4, TIM_CHANNEL_ALL);
@ -219,15 +235,8 @@ void app_main_task(void *argument)
hw_init(); hw_init();
/* Infinite loop */ /* Infinite loop */
bool invert = 0; for (;;) {
for(;;) //HAL_GPIO_TogglePin(LED_GPIO_Port, LED_Pin);
{
HAL_GPIO_TogglePin(LED_GPIO_Port, LED_Pin);
s_app.wheel = htim4.Instance->CNT;
s_app.push = 0 == HAL_GPIO_ReadPin(KNOB_PUSH_GPIO_Port, KNOB_PUSH_Pin);
calculate_analog_values();
// printf("Knob %d (P=%d), ADC %.2f %.2f %.2f %.2f, oven %.2f°C, soc %.2f°C, divider %.3f V \r\n", // printf("Knob %d (P=%d), ADC %.2f %.2f %.2f %.2f, oven %.2f°C, soc %.2f°C, divider %.3f V \r\n",
// (int) s_app.wheel, s_app.push, // (int) s_app.wheel, s_app.push,
@ -238,33 +247,69 @@ void app_main_task(void *argument)
// s_app.v_sensor // s_app.v_sensor
// ); // );
invert = !invert; calculate_analog_values();
for (int i = 0; i < 50; i++) {
uint16_t old_wheel = s_app.wheel;
s_app.wheel = htim4.Instance->CNT;
int16_t wheel_change = (int16_t)(s_app.wheel - old_wheel);
fb_clear(); if (wheel_change != 0) {
if (s_app.push) { s_app.wheel_normed += wheel_change;
fb_rect(s_app.wheel % FBW, 0, 15, 15, 1); if (s_app.wheel_normed < 0) {
} else { s_app.wheel_normed = 0;
if (invert) { }
fb_frame(s_app.wheel % FBW, 0, 15, 15, 2, 1); if (s_app.wheel_normed > 500) {
} else { s_app.wheel_normed = 500;
fb_frame(s_app.wheel % FBW, 0, 15, 15, 1, 1); }
s_app.set_temp = (s_app.wheel_normed / 2) * 5;
}
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);
} }
char tmp[100]; // regulation
sprintf(tmp, "%d°C", (int) s_app.oven_temp);
fb_text(0, 20, tmp, 0, 1); float set_f = (float) s_app.set_temp;
fb_blit(); 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;
}
vTaskDelay(100); HAL_GPIO_WritePin(HEATER_GPIO_Port, HEATER_Pin, s_app.heating);
/*
// beep // beep
htim2.Instance->ARR = 12000 + (int16_t)s_app.wheel * 100; htim2.Instance->ARR = 12000 + (int16_t)s_app.wheel * 100;
htim2.Instance->CCR1 = htim2.Instance->ARR/2; htim2.Instance->CCR1 = htim2.Instance->ARR/2;
vTaskDelay(50); vTaskDelay(50);
htim2.Instance->ARR = 0; htim2.Instance->ARR = 0;
*/
// feed dogs // feed dogs
HAL_IWDG_Refresh(&hiwdg); HAL_IWDG_Refresh(&hiwdg);

@ -154,7 +154,7 @@ C_INCLUDES = \
# compile gcc flags # compile gcc flags
ASFLAGS = $(MCU) $(AS_DEFS) $(AS_INCLUDES) $(OPT) -Wall -fdata-sections -ffunction-sections ASFLAGS = $(MCU) $(AS_DEFS) $(AS_INCLUDES) $(OPT) -Wall -fdata-sections -ffunction-sections
CFLAGS += $(MCU) $(C_DEFS) $(C_INCLUDES) $(OPT) -Wall -fdata-sections -ffunction-sections CFLAGS += $(MCU) $(C_DEFS) $(C_INCLUDES) $(OPT) -Wall -Wextra -fdata-sections -ffunction-sections
ifeq ($(DEBUG), 1) ifeq ($(DEBUG), 1)
CFLAGS += -g -gdwarf-2 CFLAGS += -g -gdwarf-2

Loading…
Cancel
Save