summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore11
-rw-r--r--Makefile2
-rw-r--r--bridge.c72
-rw-r--r--bridge.h9
-rw-r--r--command.c82
-rw-r--r--controller.c105
-rw-r--r--controller.h9
-rw-r--r--ferment.c130
-rw-r--r--main.c14
9 files changed, 298 insertions, 136 deletions
diff --git a/.gitignore b/.gitignore
index 6769eb2..39274f6 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,6 +1,11 @@
*.o
-*.flash
-*.eeprom
-*.map
+*.elf
+*.eep
+*.lss
+*.lst
*.orig
+*.hex
+*.sym
+*.map
*.?#?
+/.dep
diff --git a/Makefile b/Makefile
index 4adeef6..e7d7a19 100644
--- a/Makefile
+++ b/Makefile
@@ -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
diff --git a/command.c b/command.c
index 41472c7..7d8c515 100644
--- a/command.c
+++ b/command.c
@@ -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);
- }
-}
diff --git a/main.c b/main.c
new file mode 100644
index 0000000..a78e585
--- /dev/null
+++ b/main.c
@@ -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 (;;) ;
+}