diff --git a/lambda-test/Makefile b/lambda-test/Makefile index f319fa6..6a08fcb 100644 --- a/lambda-test/Makefile +++ b/lambda-test/Makefile @@ -19,7 +19,7 @@ ## Here you can link to one more directory (and multiple .c files) EXTRA_SOURCE_DIR = ../lambda/ EXTRA_SOURCE_FILES = USART.c interrupts.c adc.c sensors.c integers.c \ -lcdroutines.c display.c +lcdroutines.c display.c alert.c command.c ##########------------------------------------------------------########## ########## Programmer Defaults ########## diff --git a/lambda-test/lambda-test.c b/lambda-test/lambda-test.c index 8aa962f..5b435d7 100644 --- a/lambda-test/lambda-test.c +++ b/lambda-test/lambda-test.c @@ -304,7 +304,7 @@ // TODO assertions bool testCycle(void) { - cycle(); + cycleDisplay(); return true; } @@ -318,7 +318,7 @@ // TODO assertions bool testUpdate(void) { measurement meas = {0, 0, 0, 0, 0, 0}; - update(meas); + updateMeas(meas); return true; } @@ -326,7 +326,7 @@ // TODO test display() with no display connected? bool testDisplay(void) { measurement meas = {0, 0, 0, 0, 0, 0}; - display(meas, " "); + displayMeas(meas, " "); return true; } diff --git a/lambda/Makefile b/lambda/Makefile index 6d6b6b9..85e8557 100644 --- a/lambda/Makefile +++ b/lambda/Makefile @@ -9,13 +9,15 @@ BAUD = 9600 ## Also try BAUD = 19200 or 38400 if you're feeling lucky. +SIMULATION = 1 + ## This is where your main() routine lives MAIN = lambda.c ## If you've split your program into multiple .c / .h files, ## include the additional source (in same directory) here LOCAL_SOURCE = USART.c interrupts.c adc.c sensors.c integers.c lcdroutines.c \ -display.c alert.c +display.c alert.c command.c ## Here you can link to one more directory (and multiple .c files) EXTRA_SOURCE_DIR = diff --git a/lambda/alert.c b/lambda/alert.c index 3388603..25b31f4 100644 --- a/lambda/alert.c +++ b/lambda/alert.c @@ -10,25 +10,28 @@ #include #include "USART.h" #include "alert.h" +#include "sensors.h" +#include "display.h" uint8_t oscCount = 0; uint8_t beepCount = 0; -uint8_t beepLength = 0; +uint16_t beepLength = 0; +bool alertActive = false; -void oscillate(void) { +void oscillateBeep(void) { if (beepCount == 0) { return; } if (oscCount == 0) { // turn beep on - DDRB |= (1 << PB1); + TCCR1A |= (1 << COM1A0); } if (oscCount == beepLength) { // turn beep off - DDRB &= ~(1 << PB1); + TCCR1A &= ~(1 << COM1A0); beepCount--; if (beepCount == 0) { - // clear alert + alertActive = false; } } oscCount == beepLength * 2 ? oscCount = 0 : oscCount++; @@ -41,9 +44,18 @@ } void alert(uint8_t beeps, uint8_t length, char* line0, char* line1) { + alertActive = true; oscCount = 0; beepCount = beeps; beepLength = length; - // set alert - // set display text + displayText(line0, line1); +} + +void cancelAlert(void) { + TCCR1A &= ~(1 << COM1A0); + alertActive = false; +} + +bool isAlertActive(void) { + return alertActive; } diff --git a/lambda/alert.h b/lambda/alert.h index bfae948..85eec2b 100644 --- a/lambda/alert.h +++ b/lambda/alert.h @@ -8,10 +8,14 @@ #ifndef ALERT_H_ #define ALERT_H_ -void oscillate(void); +void oscillateBeep(void); void beep(uint8_t beeps, uint8_t length); void alert(uint8_t beeps, uint8_t length, char* line0, char* line1); +void cancelAlert(void); + +bool isAlertActive(void); + #endif /* ALERT_H_ */ diff --git a/lambda/command.c b/lambda/command.c new file mode 100644 index 0000000..f617d36 --- /dev/null +++ b/lambda/command.c @@ -0,0 +1,50 @@ +/* + * command.c + * + * Created on: 02.05.2015 + * Author: dode@luniks.net + */ + +#include +#include +#include +#include +#include "sensors.h" +#include "display.h" +#include "alert.h" +#include "command.h" + +bool simulation = false; + +void command(char* data) { + char* fields[8]; + char* token = strtok(data, " "); + uint8_t index = 0; + while (token != NULL) { + fields[index++] = token; + token = strtok(NULL, " "); + } + if (strcmp(fields[0], "sien") == 0) { + simulation = true; + beep(1, 2); + } + else if (strcmp(fields[0], "sidi") == 0) { + simulation = false; + beep(1, 2); + } + else if (strcmp(fields[0], "menu") == 0) { + cycleDisplay(); + // updateMeas(meas); + } + else if (strcmp(fields[0], "tsal") == 0) { + alert(3, 20, "Beep Beep Beep!", fields[1]); + } + else if (simulation) { + measurement meas = readMeas(fields); + updateMeas(meas); + } +} + +bool isSimulation(void) { + return simulation; +} diff --git a/lambda/command.h b/lambda/command.h new file mode 100644 index 0000000..71e0546 --- /dev/null +++ b/lambda/command.h @@ -0,0 +1,15 @@ +/* + * command.h + * + * Created on: 02.05.2015 + * Author: dode@luniks.net + */ + +#ifndef COMMAND_H_ +#define COMMAND_H_ + +void command(char* data); + +bool isSimulation(void); + +#endif /* COMMAND_H_ */ diff --git a/lambda/display.c b/lambda/display.c index cdbfa3c..0b3d7eb 100644 --- a/lambda/display.c +++ b/lambda/display.c @@ -15,6 +15,7 @@ #include "integers.h" #include "sensors.h" #include "display.h" +#include "alert.h" #define MAX(x, y) (((x) > (y)) ? (x) : (y)) #define MIN(x, y) (((x) < (y)) ? (x) : (y)) @@ -25,17 +26,26 @@ uint8_t position = MENU_OFF; -measurement measMin = {0, 20, 0, 20, 0, 2000}; -measurement measMax = {0, 0, 0, 0, 0, 0}; +measurement measMin = {0, 20, 0, 20, 0, 1000}; +measurement measMax = {0, 0, 0, 0, 0, 2000}; -void cycle(void) { +void cycleDisplay(void) { + if (isAlertActive()) { + // button pressed during alert + cancelAlert(); + return; + } + beep(1, 2); position++; if (position > MENU_MAX_VALUES) { position = MENU_OFF; } } -void update(measurement meas) { +void updateMeas(measurement meas) { + if (isAlertActive()) { + return; + } measMin.tempI = MIN(measMin.tempI, meas.tempI); measMin.tempO = MIN(measMin.tempO, meas.tempO); measMin.lambda = MAX(measMin.lambda, meas.lambda); @@ -45,15 +55,15 @@ measMax.lambda = MIN(measMax.lambda, meas.lambda); if (position == MENU_MIN_VALUES) { - display(measMin, "|<"); + displayMeas(measMin, "|<"); } else if (position == MENU_MAX_VALUES) { - display(measMax, ">|"); + displayMeas(measMax, ">|"); } else { - display(meas, " "); + displayMeas(meas, " "); } } -void print(measurement meas) { +void printMeas(measurement meas) { char log[64]; snprintf(log, sizeof(log), "Ti %3d C %4u - To %3d C %4u - L %4u %4u\r\n", @@ -62,7 +72,7 @@ printString(log); } -void display(measurement meas, char* hint) { +void displayMeas(measurement meas, char* hint) { uint16_t lambdax100 = divRoundNearest(meas.lambda, 10); div_t lambdaT = div(lambdax100, 100); @@ -76,3 +86,11 @@ lcd_setcursor(0, 2); lcd_string(line1); } + +void displayText(char* line0, char* line1) { + lcd_clear(); + lcd_setcursor(0, 1); + lcd_string(line0); + lcd_setcursor(0, 2); + lcd_string(line1); +} diff --git a/lambda/display.h b/lambda/display.h index 8dcc686..de2bb4c 100644 --- a/lambda/display.h +++ b/lambda/display.h @@ -11,22 +11,27 @@ /** * Cycles through the "menu" (display options). */ -void cycle(void); +void cycleDisplay(void); /** * Updates the measurements, tracks min and max values since last start/reset * and displays the selected measurement values. */ -void update(measurement); +void updateMeas(measurement); /** * Formats the given measurement values and prints them via USART. */ -void print(measurement); +void printMeas(measurement); /** * Formats the given measurement values and displays them on an 16x2 LCD. */ -void display(measurement, char*); +void displayMeas(measurement, char*); + +/** + * Displays the given two lines of text. + */ +void displayText(char*, char*); #endif /* DISPLAY_H_ */ diff --git a/lambda/interrupts.c b/lambda/interrupts.c index f2044d5..76db62d 100644 --- a/lambda/interrupts.c +++ b/lambda/interrupts.c @@ -13,6 +13,9 @@ // pull-up resistor for the mouton // INT0 and INT1 are assigned to the LCD, a bit of a shame PORTB |= (1 << PB0); + + // enable beep output pin + DDRB |= (1 << PB1); } void setupSleepMode(void) { @@ -26,6 +29,11 @@ // enable timer 0 overflow interrupt TIMSK0 |= (1 << TOIE0); + // enable RC complete interrupt 0 + UCSR0B |= (1 << RXCIE0); + // enable data register empty interrupt 0 + // UCSR0B |= (1 << UDRIE0); + // enable global interrupts sei(); } @@ -36,11 +44,13 @@ TCCR0B |= (1 << CS01) | (1 << CS00); // toggle pin PB1 on compare match - TCCR1A |= (1 << COM1A0); + // TCCR1A |= (1 << COM1A0); // CTC mode, TOP OCR1A TCCR1B |= (1 << WGM12); // timer clock prescaler/8 TCCR1B |= (1 << CS11); - // toggles PB1 at 3.9 kHz generating a 1.95 kHz beep + // toggles PB1 at 7.8 kHz generating a 3.9 kHz beep + // OCR1A = 16; + // less noisy OCR1A = 32; } diff --git a/lambda/lambda.c b/lambda/lambda.c index 87258d6..606df42 100644 --- a/lambda/lambda.c +++ b/lambda/lambda.c @@ -19,6 +19,7 @@ #include #include +#include #include #include #include @@ -30,25 +31,43 @@ #include "integers.h" #include "display.h" #include "alert.h" +#include "command.h" volatile bool buttonPressed = false; +volatile bool usartReceived = false; volatile uint8_t intCount = 0; +volatile uint8_t dataCount = 0; + +char usartData[64]; /** * Called every 16 ms. */ ISR(TIMER0_OVF_vect) { intCount++; - oscillate(); + oscillateBeep(); if (bit_is_clear(PINB, PB0) && ! buttonPressed) { buttonPressed = true; - cycle(); - beep(3, 3); + cycleDisplay(); } else if (bit_is_set(PINB, PB0)) { buttonPressed = false; } } +ISR(USART_RX_vect) { + if (bit_is_set(UCSR0A, RXC0) && ! usartReceived) { + char data = UDR0; + loop_until_bit_is_set(UCSR0A, UDRE0); + UDR0 = data; + if (dataCount < sizeof(usartData) - 1 && data != '\n' && data != '\r') { + usartData[dataCount++] = data; + } else { + usartData[dataCount++] = 0; + usartReceived = true; + } + } +} + /** * Does initialization and measures, displays and logs the measurements * infinitely. @@ -62,19 +81,29 @@ initInterrupts(); initTimers(); + alert(1, 2, " Hello! ", ""); + + measurement meas; + // memset(&meas, 0, sizeof(meas)); + // main loop while (1) { - measurement meas; - if (intCount >= 61) { + if (intCount >= 62 && ! isSimulation()) { intCount = 0; // causes a click in the beep, because of sleep mode? meas = measure(); - update(meas); - print(meas); + printMeas(meas); + updateMeas(meas); } if (buttonPressed) { // update display immediately - update(meas); + updateMeas(meas); + } + if (usartReceived) { + command(usartData); + memset(usartData, 0, sizeof(usartData)); + dataCount = 0; + usartReceived = false; } } diff --git a/lambda/sensors.c b/lambda/sensors.c index ae0038d..74e1298 100644 --- a/lambda/sensors.c +++ b/lambda/sensors.c @@ -11,7 +11,9 @@ #include #include +#include #include +#include "USART.h" #include "adc.h" #include "sensors.h" #include "integers.h" @@ -92,6 +94,15 @@ return meas; } +measurement readMeas(char* fields[]) { + measurement meas; + meas.tempI = strtol(fields[0], NULL, 10); + meas.tempO = strtol(fields[1], NULL, 10); + meas.lambda = strtol(fields[2], NULL, 10); + + return meas; +} + int16_t toTempI(uint16_t mV) { int temp = divRoundNearest(mV, 5); diff --git a/lambda/sensors.h b/lambda/sensors.h index fa53989..299fa44 100644 --- a/lambda/sensors.h +++ b/lambda/sensors.h @@ -40,11 +40,18 @@ /** * Measures the "input" and "output" temperatures and the lambda value - * and displays the measured values. + * and returns them. */ measurement measure(void); /** + * Reads measurement data from the given array of strings, used to simulate + * a burnoff with data logged during real burnoffs. The voltages are not used, + * the space separated fields are tempI, tempO and lambda. + */ +measurement readMeas(char* usartData[]); + +/** * Returns the temperature for the given voltage of a type K thermocouple * amplified with an AD8495 (5 mV/°C). Type K thermocouple voltages are * about linear between 0 and 800°C.