diff options
-rw-r--r-- | .gitignore | 11 | ||||
-rw-r--r-- | Makefile | 2 | ||||
-rw-r--r-- | bridge.c | 72 | ||||
-rw-r--r-- | bridge.h | 9 | ||||
-rw-r--r-- | command.c | 82 | ||||
-rw-r--r-- | controller.c | 105 | ||||
-rw-r--r-- | controller.h | 9 | ||||
-rw-r--r-- | ferment.c | 130 | ||||
-rw-r--r-- | main.c | 14 |
9 files changed, 298 insertions, 136 deletions
@@ -1,6 +1,11 @@ *.o -*.flash -*.eeprom -*.map +*.elf +*.eep +*.lss +*.lst *.orig +*.hex +*.sym +*.map *.?#? +/.dep @@ -73,7 +73,7 @@ FORMAT = ihex # Target file name (without extension). -TARGET = ferment +TARGET = main # Object files directory diff --git a/bridge.c b/bridge.c new file mode 100644 index 0000000..5f1806b --- /dev/null +++ b/bridge.c @@ -0,0 +1,72 @@ +#include <avr/io.h> +#include <util/delay.h> + +#include "bridge.h" + +/* port D + * + * 4 1- (NMOS, inverted) + * 5 1+ (PMOS) + * 6 2- (NMOS, inverted) + * 7 2+ (PMOS) + * + */ + +#define D_1_MINUS (1 << 4) +#define D_1_PLUS (1 << 5) +#define D_2_MINUS (1 << 6) +#define D_2_PLUS (1 << 7) + +enum bridge_state { + BRIDGE_OFF, + BRIDGE_HEATING, + BRIDGE_COOLING +}; + +static enum bridge_state bridge_state; + +/* Turns the H-bridge off, putting the output + * into high impedance mode. */ +void bridge_off(void) +{ + if (bridge_state == BRIDGE_OFF) + return; + + PORTD |= D_1_MINUS | D_2_MINUS; + PORTD &= ~(D_1_PLUS | D_2_PLUS); + _delay_ms(100); + bridge_state = BRIDGE_OFF; +} + +/* Turns the H-bridge on, setting 1+ 2- */ +void bridge_on_heat(void) +{ + if (bridge_state == BRIDGE_HEATING) + return; + + bridge_off(); + bridge_state = BRIDGE_HEATING; + PORTD |= D_1_PLUS; + PORTD &= ~D_2_MINUS; +} + +/* Turns the H-bridge on, setting 1- 2+ */ +void bridge_on_cool(void) +{ + if (bridge_state == BRIDGE_COOLING) + return; + + bridge_off(); + bridge_state = BRIDGE_COOLING; + PORTD |= D_2_PLUS; + PORTD &= ~D_1_MINUS; +} + +/* Initializes the output port needed for the H-bridge */ +void bridge_init(void) +{ + PORTD |= D_1_MINUS | D_2_MINUS; + PORTD &= ~(D_1_PLUS | D_2_PLUS); + DDRD |= D_1_PLUS | D_1_MINUS | D_2_PLUS | D_2_MINUS; + bridge_state = BRIDGE_OFF; +} diff --git a/bridge.h b/bridge.h new file mode 100644 index 0000000..21bbfc3 --- /dev/null +++ b/bridge.h @@ -0,0 +1,9 @@ +#ifndef BRIDGE_H +#define BRIDGE_H + +void bridge_off(void); +void bridge_on_heat(void); +void bridge_on_cool(void); +void bridge_init(void); + +#endif @@ -1,10 +1,88 @@ #include <avr/io.h> #include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include "controller.h" #include "serial.h" -uint16_t serial_rx_cb(char *buffer, uint16_t len) +static void handle_set(char *buffer, uint16_t len) { - return 1; + const char *error_msg = "ERR Invalid number for temperature\r\n"; + const char *error_msg2 = "ERR Temperature out of range.\r\n"; + const char *success_msg = "OK Temperature set.\r\n"; + const char *input; + char *endptr; + long temperature; + + if (len < 2) { + serial_send(error_msg, strlen(error_msg), 0); + return; + } + + input = buffer + 1; + temperature = strtol(input, &endptr, 10); + if (input[0] == '\r' || input[0] == '\n' || + (endptr[0] != '\r' && endptr[0] != '\n')) { + serial_send(error_msg, strlen(error_msg), 0); + return; + } + + if (controller_set(temperature)) { + serial_send(error_msg2, strlen(error_msg2), 0); + return; + } + + serial_send(success_msg, strlen(success_msg), 0); } +static void handle_off(char *buffer, uint16_t len) +{ + const char *success_msg = "OK Powered down.\r\n"; + + controller_off(); + serial_send(success_msg, strlen(success_msg), 0); +} + +static void handle_get(char *buffer, uint16_t len) +{ + char response[128]; + + snprintf(response, sizeof(response), "OK t=%ld\r\n", controller_get()); + serial_send(response, strlen(response), 0); +} + +uint16_t serial_rx_cb(char *buffer, uint16_t len) +{ + const char *error_msg = "ERR Unknown command\r\n"; + switch(buffer[len-1]) { + case '\r': + case '\n': + serial_send("\r\n", 2, 0); + break; + default: + /* If we didn't get a line break, just echo and return */ + serial_send(&buffer[len-1], 1, 0); + return 0; + } + + switch(buffer[0]) { + case 's': + case 'S': + handle_set(buffer, len); + break; + case 'g': + case 'G': + handle_get(buffer, len); + break; + case 'o': + case 'O': + handle_off(buffer, len); + break; + default: + serial_send(error_msg, strlen(error_msg), 0); + } + + return len; +} diff --git a/controller.c b/controller.c new file mode 100644 index 0000000..29ac0ab --- /dev/null +++ b/controller.c @@ -0,0 +1,105 @@ +#include <avr/io.h> +#include <avr/interrupt.h> + +#include "controller.h" + +#include "bridge.h" + +static void adc_init(void) +{ + /* Configure the ADC */ + ADMUX = (1 << REFS1) | (1 << REFS0); + /* select channel x (0 for now) */ + ADMUX |= 0x0; + ADCSRA = (1 << ADEN) | (1 << ADIE) + | (1 << ADPS2) | (1 << ADPS1) + | (1 << ADPS0); +} + +/* Initializes TIMER1 */ +static void timer_init(void) +{ + TCCR1B = (1 << WGM12) | (1 << CS12) | (1 << CS10); + OCR1A = 7200; + TIMSK|=(1<<OCIE1A); +} + +static volatile char controller_in_init; +static volatile char controller_active; +static volatile long controller_target_temp; +static volatile char controller_num_iterations; +static volatile uint16_t controller_measured_temp; + +void controller_init(void) +{ + controller_active = 0; + controller_in_init = 1; + + bridge_init(); + adc_init(); + timer_init(); +} + +int controller_set(long target) +{ + if (target < 50 || target > 974) + return 1; + + controller_target_temp = target; + controller_num_iterations = 1; + controller_active = 1; + return 0; +} + +long controller_get(void) +{ + return controller_measured_temp; +} + +void controller_off(void) +{ + controller_active = 0; + bridge_off(); +} + +ISR(TIMER1_COMPA_vect) +{ + /* Start adc measurement */ + ADCSRA |= (1<<ADSC); +} + +ISR(ADC_vect) +{ + if (controller_in_init) { + controller_measured_temp = ADCW; + controller_in_init = 0; + } else { + controller_measured_temp = (0.8 * controller_measured_temp) + + (0.2 * ADCW); + } + + if (! controller_active) + return; + + controller_num_iterations--; + if (controller_num_iterations) + return; + + controller_num_iterations = 60; + + if ((long)controller_measured_temp < controller_target_temp - 20) { + /* Cooling required */ + bridge_on_cool(); + return; + } + + if ((long)controller_measured_temp > controller_target_temp + 20) { + /* Heating required */ + bridge_on_heat(); + return; + } + + /* Temperature is roughly okay, turn bridge off until next + * measurement. */ + bridge_off(); +} diff --git a/controller.h b/controller.h new file mode 100644 index 0000000..0b65a73 --- /dev/null +++ b/controller.h @@ -0,0 +1,9 @@ +#ifndef CONTROLLER_H +#define CONTROLLER_H + +void controller_init(void); +int controller_set(long target); +long controller_get(void); +void controller_off(void); + +#endif diff --git a/ferment.c b/ferment.c deleted file mode 100644 index 1d282d2..0000000 --- a/ferment.c +++ /dev/null @@ -1,130 +0,0 @@ -//#define F_CPU 7372800UL -#include <stdint.h> -#include <string.h> -#include <avr/io.h> -#include <avr/interrupt.h> -#include <avr/sleep.h> -#include <avr/pgmspace.h> -#include <avr/eeprom.h> -#include <util/delay.h> - -#include "serial.h" -#include "stdio.h" -#include "pid.h" - -/* port D - * - * 4 1- (NMOS, inverted) - * 5 1+ (PMOS) - * 6 2- (NMOS, inverted) - * 7 2+ (PMOS) - * - */ - -#define D_1_MINUS (1 << 4) -#define D_1_PLUS (1 << 5) -#define D_2_MINUS (1 << 6) -#define D_2_PLUS (1 << 7) - -const int target_temp = 30; -volatile uint16_t adc_res; -volatile uint8_t adc_new; - -struct PID_DATA pid_data; - -/* Turns the H-bridge off, putting the output - * into high impedance mode. */ -static void bridge_off(void) -{ - PORTD |= D_1_MINUS | D_2_MINUS; - PORTD &= ~(D_1_PLUS | D_2_PLUS); -} - -/* Turns the H-bridge on, setting 1+ 2- */ -static void bridge_on_heat(void) -{ - bridge_off(); - _delay_ms(100); - PORTD |= D_1_PLUS; - PORTD &= ~D_2_MINUS; -} - -/* Turns the H-bridge on, setting 1- 2+ */ -static void bridge_on_cool(void) -{ - bridge_off(); - _delay_ms(100); - PORTD |= D_2_PLUS; - PORTD &= ~D_1_MINUS; -} - -/* Initializes the output port needed for the H-bridge */ -static void bridge_init(void) -{ - bridge_off(); - DDRD |= D_1_PLUS | D_1_MINUS | D_2_PLUS | D_2_MINUS; -} - -/* initializes ADC */ -static void adc_init(void) -{ - adc_new = 0; - ADMUX = (1 << REFS1) | (1 << REFS0); - /* select channel x (0 for now) */ - ADMUX |= 0x0; - ADCSRA = (1 << ADEN) | (1 << ADIE) | (1 << ADPS2) | (1 << ADPS1) | (1 << ADPS0); -} - -/* reads ADC */ -static void start_temp_conv(void) -{ - ADCSRA |= (1<<ADSC); -} - -/* ADC completion interrupt */ -ISR(ADC_vect) -{ - adc_res = ADCW; - adc_new = 1; -} - -/* ADC results to temperature conversion routine */ -int adc_to_centigrade(uint16_t adc_val) { - return 0; -} - -/* Initializes TIMER1 */ -static void timer_init(void) -{ - TCCR1B = (1 << WGM12) | (1 << CS12) | (1 << CS10); - OCR1A = 7200; - TIMSK|=(1<<OCIE1A); -} - -ISR(TIMER1_COMPA_vect) -{ - serial_send("*\r\n", 3, 1); - start_temp_conv(); -} - -int main(void) -{ - char params[12]; - - serial_init(); - adc_init(); - timer_init(); - bridge_init(); - - sei(); - - bridge_on_cool(); - while (1) { - if (adc_new) { - sprintf(params, "%u\r\n", adc_res); - serial_send(params, strlen(params), 1); - adc_new = 0; - } - _delay_ms(100); - } -} @@ -0,0 +1,14 @@ +#include <avr/interrupt.h> + +#include "serial.h" +#include "controller.h" + +int main(void) +{ + serial_init(); + serial_toggle_verbose(); + controller_init(); + + sei(); + for (;;) ; +} |