@@ -37,17 +37,18 @@
#define DEFAULT_BOOT_TO_BREW 0
#define DEFAULT_TEMP_UNITS TEMP_UNITS_FAHRENHEIT
#define DEFAULT_WINDUP_GUARD 10
#define DEFAULT_K_P 10
#define DEFAULT_K_I 1
#define DEFAULT_K_D 1
#define DEFAULT_TEMP_OFFSET 0
#define DEFAULT_IGNORE_ERROR 0
#define DEFAULT_SETPOINT_BREW 70
#define DEFAULT_SETPOINT_STEAM 70
#define DEFAULT_HYSTERESIS 1
#endif
// vim:softtabstop=4 shiftwidth=4 expandtab
@@ -16,25 +16,25 @@ static uint8_t sw_right_last = 0;
// Buttonpress macros
#define SW_BTN_PRESSED (sw_btn_last == 0 && sw_btn == 1) // rising edge on buttonpress
#define SW_UP_PRESSED (sw_up_last == 0 && sw_up == 1)
#define SW_DOWN_PRESSED (sw_down_last == 0 && sw_down == 1)
#define SW_LEFT_PRESSED (sw_left_last == 0 && sw_left == 1)
#define SW_RIGHT_PRESSED (sw_right_last == 0 && sw_right == 1)
// States
static uint8_t trigger_drawsetpoint = 1;
static int16_t last_temp = 21245;
static int16_t last_temp_frac = 21245;
static int16_t last_state = STATE_IDLE;
static int16_t last_state = 123;
static uint8_t goto_mode = MODE_HEAT;
static uint8_t reset_mode = RESET_REBOOT;
// Display state machine
void display_process(therm_settings_t* set, therm_status_t* status)
{
uint8_t state_changed = status->state != last_state;
last_state = status->state;
uint8_t temp_changed = status->temp != last_temp || status->temp_frac != last_temp_frac;
@@ -181,38 +181,67 @@ void display_process(therm_settings_t* s
if(set->val.plant_type == PLANT_HEATER)
ssd1306_drawstring("Heater", 1, 60);
else
ssd1306_drawstring("Cooler", 1, 60);
ssd1306_drawstring("Press to accept", 3, 40);
// Button handler
if(SW_BTN_PRESSED) {
if(set->val.control_mode == MODE_PID)
status->state = STATE_SETP;
status->state = STATE_SETBOOTTOBREW;
status->state = STATE_SETHYSTERESIS;
}
else if (!HAL_GPIO_ReadPin(SW_UP)) {
set->val.plant_type = PLANT_COOLER;
else if(!HAL_GPIO_ReadPin(SW_DOWN)) {
set->val.plant_type = PLANT_HEATER;
// Event Handler
// N/A
} break;
case STATE_SETHYSTERESIS:
// Write text to OLED
ssd1306_drawstring("Hysteresis", 0, 40);
ssd1306_drawlogo();
char tempstr[6];
itoa(set->val.hysteresis, tempstr, 10);
ssd1306_drawstring("H=", 1, 45);
ssd1306_drawstring(" ", 1, 57);
ssd1306_drawstring(tempstr, 1, 57);
else {
user_input((uint16_t*)&set->val.hysteresis);
case STATE_SETP:
// [ therm :: set p ]
// [ p = 12 ]
ssd1306_drawstring("Proportional", 0, 40);
itoa(set->val.k_p, tempstr, 10);
ssd1306_drawstring("P=", 1, 45);
@@ -31,24 +31,25 @@ void flash_restore(therm_settings_t* tor
void flash_load_defaults(therm_settings_t* torestore) {
torestore->val.boottobrew = DEFAULT_BOOT_TO_BREW;
torestore->val.temp_units = DEFAULT_TEMP_UNITS;
torestore->val.windup_guard = DEFAULT_WINDUP_GUARD;
torestore->val.k_p = DEFAULT_K_P;
torestore->val.k_i = DEFAULT_K_I;
torestore->val.k_d = DEFAULT_K_D;
torestore->val.temp_offset = DEFAULT_TEMP_OFFSET;
torestore->val.ignore_error = DEFAULT_IGNORE_ERROR;
torestore->val.setpoint_brew = DEFAULT_SETPOINT_BREW;
torestore->val.setpoint_steam = DEFAULT_SETPOINT_STEAM;
torestore->val.hysteresis = DEFAULT_HYSTERESIS;
static void __flash_write(therm_settings_t* tosave)
// Erase mem
HAL_FLASH_Unlock();
// Erase the FLASH pages
FLASH_EraseInitTypeDef erase;
erase.TypeErase = TYPEERASE_PAGES;
erase.PageAddress = (uint32_t) eeprom;
erase.NbPages = 1;
@@ -83,24 +83,26 @@ int main(void)
HAL_Delay(2000);
ssd1306_clearscreen();
// Soft timers
uint32_t last_ssr_on = 0;
uint32_t last_vcp_tx = 0;
uint32_t last_led = 0;
uint32_t last_pid = 0;
uint32_t last_thermostat = 0;
int16_t ssr_output = 0; // Duty cycle of ssr, 0 to SSR_PERIOD
uint8_t thermostat_plant_on = 0;
// Main loop
while(1)
// Process sensor inputs
if(HAL_GetTick() - last_led > 400)
last_led = HAL_GetTick();
if(set.val.control_mode == MODE_PID && (HAL_GetTick() - last_pid > PID_PERIOD))
@@ -171,34 +173,38 @@ int main(void)
#ifdef MAX31865_RTD_SENSOR
max31865_readtemp(spi_get(), &set, &status);
#else
max31855_readtemp(spi_get(), &set, &status); // Read MAX31855
// TODO: Migrate this FxP conversion to the readtemp code or similar
int8_t temp_frac = status.temp_frac > 9 ? status.temp_frac / 10 : status.temp_frac;
temp_frac = status.temp > 0 ? temp_frac : temp_frac * -1;
int32_t temp = (status.temp * 10) + temp_frac;
uint8_t plant_on = 0;
// EMZ FIXME: This could be way simpler
if(set.val.plant_type == PLANT_HEATER && status.setpoint * 10 < temp)
plant_on = 1;
else if(set.val.plant_type == PLANT_COOLER && status.setpoint * 10 > temp)
if(set.val.plant_type == PLANT_HEATER && status.setpoint * 10 < temp - set.val.hysteresis * 10)
thermostat_plant_on = 1;
else if(set.val.plant_type == PLANT_HEATER && status.setpoint * 10 > temp + set.val.hysteresis * 10)
thermostat_plant_on = 0;
if(set.val.plant_type == PLANT_COOLER && status.setpoint * 10 > temp + set.val.hysteresis * 10)
else if(set.val.plant_type == PLANT_COOLER && status.setpoint * 10 < temp - set.val.hysteresis * 10)
// EMZ: TODO: Refactor to output_enabled or something
if(status.pid_enabled && plant_on)
if(status.pid_enabled && thermostat_plant_on)
// EMZ TODO: functionalize this
// put ssr output on display
ssd1306_drawstring(" ", 0, 90); //fixme: this is bad, but I can't get the old digits to clear otherwise
itoa(ssr_output, tempstr, 10);
ssd1306_drawstring(tempstr, 0, 90);
HAL_GPIO_WritePin(SSR_PIN, 1);
HAL_GPIO_WritePin(LED_POWER, 1);
@@ -20,39 +20,41 @@ typedef union
uint32_t boottobrew;
uint32_t temp_units;
uint32_t windup_guard;
uint32_t k_p;
uint32_t k_i;
uint32_t k_d;
int32_t temp_offset;
uint32_t ignore_error;
int32_t setpoint_brew;
int32_t setpoint_steam;
uint32_t control_mode;
uint32_t plant_type;
uint32_t hysteresis;
} val;
uint16_t data[128];
} therm_settings_t;
enum tempunits {
TEMP_UNITS_CELSIUS = 0,
TEMP_UNITS_FAHRENHEIT,
};
enum state {
STATE_IDLE = 0,
STATE_SETMODE,
STATE_SETPLANTTYPE,
STATE_SETHYSTERESIS,
STATE_SETP,
STATE_SETI,
STATE_SETD,
STATE_SETSTEPS,
STATE_SETWINDUP,
STATE_SETBOOTTOBREW,
STATE_SETUNITS,
STATE_SETTEMPOFFSET,
STATE_PREHEAT,
STATE_MAINTAIN,
Status change: