Changeset - 9294a623e8e5
[Not reviewed]
cortex-f0
0 5 0
Ethan Zonca - 8 years ago 2016-04-23 22:15:22
ez@ethanzonca.com
Added support for both heaters and coolers as well as thermostatic control
5 files changed with 157 insertions and 14 deletions:
0 comments (0 inline, 0 general)
Makefile
Show inline comments
 
@@ -30,16 +30,18 @@ USER_INCLUDES = -Isystem
 

	
 
# USB_INCLUDES: includes for the usb library
 
USB_INCLUDES = -Imiddlewares/ST/STM32_USB_Device_Library/Core/Inc
 
USB_INCLUDES += -Imiddlewares/ST/STM32_USB_Device_Library/Class/CDC/Inc
 

	
 
# USER_CFLAGS: user C flags (enable warnings, enable debug info)
 
USER_CFLAGS = -Wall -g -ffunction-sections -fno-exceptions -fdata-sections -Os
 
USER_CFLAGS = -Wall -g -ffunction-sections -fno-exceptions -fdata-sections -Os --function-sections -fno-common
 
# USER_LDFLAGS:  user LD flags
 
USER_LDFLAGS = -fno-exceptions -ffunction-sections -fno-exceptions -fdata-sections -Wl,--gc-sections
 

	
 
USER_LDFLAGS += --static 
 

	
 
# TARGET_DEVICE: device to compile for
 
TARGET_DEVICE = STM32F042x6
 

	
 
#######################################
 
# end of user configuration
 
#######################################
config.h
Show inline comments
 
#ifndef CONFIG_H
 
#define CONFIG_H
 

	
 
// Temperature sensor type
 
//#define MAX31855_TC_SENSOR
 
#define MAX31865_RTD_SENSOR
 
#define MAX31855_TC_SENSOR
 
//#define MAX31865_RTD_SENSOR
 

	
 

	
 
// Virtual serial port transmit rate
 
#define VCP_TX_FREQ 1000
 

	
 
// Solid-state relay maximum on-time
display.c
Show inline comments
 
@@ -70,13 +70,16 @@ void display_process(therm_settings_t* s
 
            }
 

	
 
            switch(goto_mode) {
 

	
 
                case MODE_HEAT:
 
                {
 
                    ssd1306_drawstring("-> heat     ", 1, 40);
 
                    if(set->val.plant_type == PLANT_HEATER)
 
                        ssd1306_drawstring("-> heat     ", 1, 40);
 
                    else
 
                        ssd1306_drawstring("-> cool     ", 1, 40);
 
                } break;
 

	
 
                case MODE_SETUP:
 
                {
 
                    ssd1306_drawstring("-> setup    ", 1, 40);
 
                } break;
 
@@ -98,13 +101,13 @@ void display_process(therm_settings_t* s
 
            if(SW_BTN_PRESSED) {
 
                switch(goto_mode) {
 
                    case MODE_HEAT:
 
                        status->state = STATE_PREHEAT;
 
                        break;
 
                    case MODE_SETUP:
 
                        status->state = STATE_SETP;
 
                        status->state = STATE_SETMODE;
 
                        break;
 
                    case MODE_RESET:
 
                        status->state = STATE_RESET;
 
                        reset_mode = RESET_REBOOT;
 
                        break;
 
					#ifdef BOOTLOADER_SHORTCUT
 
@@ -131,12 +134,79 @@ void display_process(therm_settings_t* s
 

	
 
            // Event Handler
 
            // N/A
 

	
 
        } break;
 

	
 

	
 

	
 
        case STATE_SETMODE:
 
        {
 
            // Write text to OLED
 
            // [ therm :: set mode ]
 
            // [ m =          ]
 
            ssd1306_drawstring("Control Mode", 0, 40);
 
            ssd1306_drawlogo();
 

	
 
            if(set->val.control_mode == MODE_PID)
 
                ssd1306_drawstring("PID       ", 1, 60);
 
            else
 
                ssd1306_drawstring("Thermostat", 1, 60);
 

	
 
            ssd1306_drawstring("Press to accept", 3, 40);
 
            
 
            // Button handler
 
            if(SW_BTN_PRESSED) {
 
                status->state = STATE_SETPLANTTYPE;
 
            }
 
            else if (!HAL_GPIO_ReadPin(SW_UP)) {
 
                set->val.control_mode = MODE_PID;
 
            }
 
            else if(!HAL_GPIO_ReadPin(SW_DOWN)) {
 
                set->val.control_mode = MODE_THERMOSTAT;
 
            }
 
            // Event Handler
 
            // N/A
 
 
 
        } break;
 

	
 

	
 
        case STATE_SETPLANTTYPE:
 
        {
 
            // Write text to OLED
 
            // [ therm :: set mode ]
 
            // [ m =          ]
 
            ssd1306_drawstring("Plant Type", 0, 40);
 
            ssd1306_drawlogo();
 

	
 
            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;
 
                else
 
                    status->state = STATE_SETBOOTTOBREW;
 
            }
 
            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_SETP:
 
        {
 
            // Write text to OLED
 
            // [ therm :: set p ]
 
            // [ p = 12         ]
 
            ssd1306_drawstring("Proportional", 0, 40);
 
@@ -375,14 +445,18 @@ void display_process(therm_settings_t* s
 

	
 
        case STATE_MAINTAIN:
 
        {
 
            // Write text to OLED
 
            // [ therm : ready to brew ]
 
            // [ 30 => 120 C           ]
 
            ssd1306_drawstring("Preheated!", 0, 0);
 
            //ssd1306_drawlogo();
 

	
 
            if(set->val.plant_type == PLANT_HEATER)
 
                ssd1306_drawstring("Preheated!", 0, 0);
 
            else
 
                ssd1306_drawstring("Precooled!", 0, 0);
 

	
 
            draw_setpoint(status);
 
            status->pid_enabled = 1;
 
            status->setpoint = set->val.setpoint_brew;
 

	
 
            // Button handler
 
            if(SW_BTN_PRESSED) {
main.c
Show inline comments
 
@@ -86,25 +86,26 @@ int main(void)
 
 
    // 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 
 
 
    // Main loop
 
    while(1)
 
    {
 
        // Process sensor inputs
 
 
        if(HAL_GetTick() - last_led > 400) 
 
        {
 
            last_led = HAL_GetTick();
 
        }
 
 
        if((HAL_GetTick() - last_pid > PID_PERIOD))
 
        if(set.val.control_mode == MODE_PID && (HAL_GetTick() - last_pid > PID_PERIOD))
 
        {
 
 
            #ifdef MAX31865_RTD_SENSOR
 
            max31865_readtemp(spi_get(), &set, &status);
 
			#else
 
			max31855_readtemp(spi_get(), &set, &status); // Read MAX31855
 
@@ -112,12 +113,16 @@ int main(void)
 
 
 
            if(status.pid_enabled) 
 
            {
 
                // Get ssr output for next time
 
                int16_t power_percent = pid_update(&set, &status, &pid_state);
 
 
                if(set.val.plant_type == PLANT_HEATER)
 
                    power_percent *= -1;
 
 
                //power-percent is 0-1000?
 
                ssr_output = power_percent; //(((uint32_t)SSR_PERIOD * (uint32_t)10 * (uint32_t)100) * power_percent) / (uint32_t)1000000;
 
 
 
            	// put ssr output on display
 
                ssd1306_drawstring("      ", 0, 90); //fixme: this is bad, but I can't get the old digits to clear otherwise
 
@@ -131,38 +136,86 @@ int main(void)
 
            }
 
 
            last_pid = HAL_GetTick();
 
        }
 
 
        // Kill SSR once the desired on-time has elapsed
 
        if(HAL_GetTick() - last_ssr_on > ssr_output || ssr_output <= 0)
 
        if(set.val.control_mode == MODE_PID && (HAL_GetTick() - last_ssr_on > ssr_output || ssr_output <= 0))
 
        {
 
            HAL_GPIO_WritePin(SSR_PIN, 0);
 
            HAL_GPIO_WritePin(LED_POWER, 0);
 
        }
 
 
 
        // Every 200ms, set the SSR on unless output is 0
 
        if(HAL_GetTick() - last_ssr_on > SSR_PERIOD)
 
        if(set.val.control_mode == MODE_PID && HAL_GetTick() - last_ssr_on > SSR_PERIOD)
 
        {
 
 
            // Only support heating (ssr_output > 0) right now
 
            // Heat or cool, if we need to 
 
            if(ssr_output > 0) 
 
            {
 
 
                HAL_GPIO_WritePin(SSR_PIN, 1);
 
                HAL_GPIO_WritePin(LED_POWER, 1);
 
                last_ssr_on = HAL_GetTick();
 
            }
 
            else {
 
                // Make sure everything is off
 
                HAL_GPIO_WritePin(SSR_PIN, 0);
 
                HAL_GPIO_WritePin(LED_POWER, 0);
 
            }
 
            
 
        }
 
        
 
 
        // Thermostatic control
 
        if(set.val.control_mode == MODE_THERMOSTAT && HAL_GetTick() - last_thermostat > SSR_PERIOD)
 
        {
 
 
            #ifdef MAX31865_RTD_SENSOR
 
            max31865_readtemp(spi_get(), &set, &status);
 
			#else
 
			max31855_readtemp(spi_get(), &set, &status); // Read MAX31855
 
			#endif
 
 
            // 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)
 
                plant_on = 1;
 
 
            // EMZ: TODO: Refactor to output_enabled or something
 
            if(status.pid_enabled && 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
 
                char tempstr[6];
 
                itoa(ssr_output, tempstr, 10);
 
                ssd1306_drawstring(tempstr, 0, 90);
 
 
 
 
                HAL_GPIO_WritePin(SSR_PIN, 1);
 
                HAL_GPIO_WritePin(LED_POWER, 1);
 
            }
 
            else
 
            {
 
                HAL_GPIO_WritePin(SSR_PIN, 0);
 
                HAL_GPIO_WritePin(LED_POWER, 0);
 
            }
 
            
 
            last_thermostat = HAL_GetTick();
 
        }
 
 
 
        // Transmit temperature over USB-CDC on a regular basis
 
        if(HAL_GetTick() - last_vcp_tx > VCP_TX_FREQ)
 
        {
 
            // Print temp to cdc
 
            char tempstr[16];
 
            itoa_fp(status.temp, status.temp_frac, tempstr);
states.h
Show inline comments
 
@@ -24,25 +24,29 @@ typedef union
 
        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;
 
    } 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_SETP,
 
    STATE_SETI,
 
    STATE_SETD,
 
    STATE_SETSTEPS,
 
    STATE_SETWINDUP,
 
    STATE_SETBOOTTOBREW,
 
@@ -53,12 +57,22 @@ enum state {
 
    STATE_MAINTAIN,
 

	
 
    STATE_TC_ERROR,
 
	STATE_RESET,
 
};
 

	
 
enum control_mode {
 
    MODE_PID = 0,
 
    MODE_THERMOSTAT,
 
};
 

	
 
enum plant_type {
 
    PLANT_HEATER = 0,
 
    PLANT_COOLER,
 
};
 

	
 
enum GOTO_MODE {
 
	#ifdef BOOTLOADER_SHORTCUT
 
	MODE_BOOTLOADER,
 
	#endif
 
	MODE_HEAT,
 
	MODE_SETUP,
0 comments (0 inline, 0 general)