diff --git a/lambda-test/alert-test.c b/lambda-test/alert-test.c index e6a621e..5a91f8c 100644 --- a/lambda-test/alert-test.c +++ b/lambda-test/alert-test.c @@ -14,10 +14,11 @@ /* Module alert */ -static bool testOscillateBeep(void) { - extern uint8_t beepCount; - extern uint8_t oscCount; +extern uint8_t beepCount; +extern uint16_t beepLength; +extern uint8_t oscCount; +static bool testOscillateBeep(void) { beepCount = 0; oscCount = 0; @@ -64,10 +65,6 @@ } static bool testBeep(void) { - extern uint8_t beepCount; - extern uint16_t beepLength; - extern uint8_t oscCount; - beepCount = 0; beepLength = 0; oscCount = 0; @@ -83,10 +80,6 @@ } static bool testAlert(void) { - extern uint8_t beepCount; - extern uint16_t beepLength; - extern uint8_t oscCount; - beepCount = 0; beepLength = 0; oscCount = 0; @@ -103,10 +96,6 @@ } static bool testCancelAlert(void) { - extern uint8_t beepCount; - extern uint16_t beepLength; - extern uint8_t oscCount; - beepCount = 0; beepLength = 0; oscCount = 0; diff --git a/lambda-test/command-test.c b/lambda-test/command-test.c index afa4b7a..8474463 100644 --- a/lambda-test/command-test.c +++ b/lambda-test/command-test.c @@ -17,6 +17,8 @@ /* Module command */ +extern uint8_t position; + static bool testIsSimulation(void) { setupPorts(); setHeatingOn(false); @@ -58,8 +60,6 @@ } static bool testCycleDisplay(void) { - extern uint8_t position; - cancelAlert(true); assertTrue(position == 0); diff --git a/lambda-test/display-test.c b/lambda-test/display-test.c index 3535d74..24fe5d2 100644 --- a/lambda-test/display-test.c +++ b/lambda-test/display-test.c @@ -16,13 +16,16 @@ /* Module display */ +extern uint8_t position; +extern bool updatePending; + +extern uint8_t beepCount; +extern uint16_t beepLength; + +extern Measurement measLatest; +extern Measurement measMax; // = {0, 0, 2000}; + static bool testCycle(void) { - extern uint8_t position; - extern bool updatePending; - - extern uint8_t beepCount; - extern uint16_t beepLength; - cancelAlert(true); position = 0; updatePending = false; @@ -49,9 +52,6 @@ } static bool testCycleCancelAlert(void) { - extern uint8_t position; - extern bool updatePending; - position = 0; updatePending = false; @@ -67,10 +67,6 @@ } static bool testUpdateMeas(void) { - extern bool updatePending; - extern Measurement measLatest; - extern Measurement measMax; // = {0, 0, 2000}; - updatePending = false; // initial measurements @@ -107,10 +103,6 @@ } static bool testResetMeas(void) { - extern bool updatePending; - extern Measurement measLatest; - extern Measurement measMax; - updatePending = false; resetDisplay(); @@ -124,8 +116,6 @@ } static bool testUpdateDisplayIfPending(void) { - extern bool updatePending; - updatePending = true; updateDisplayIfPending(); @@ -135,8 +125,6 @@ } static bool testUpdateDisplayIfPendingAlertActive(void) { - extern bool updatePending; - updatePending = true; alert(1, 1, 31, "", "", false); assertTrue(isAlertActive()); diff --git a/lambda-test/rules-test.c b/lambda-test/rules-test.c index 4205398..b9880ea 100644 --- a/lambda-test/rules-test.c +++ b/lambda-test/rules-test.c @@ -13,12 +13,13 @@ #include "alert.h" #include "interrupts.h" +/* Module rules */ + extern uint16_t age; extern int8_t dir; +extern uint8_t airgate; extern Rule rules[]; -/* Module rules */ - static bool testAirgate50(void) { Measurement meas = {0, 0, 0}; @@ -54,6 +55,7 @@ dir = 1; reason(meas); assertTrue(rules[0].fired); + assertTrue(50 == airgate); cancelAlert(false); @@ -95,6 +97,7 @@ dir = -1; reason(meas); assertTrue(rules[1].fired); + assertTrue(25 == airgate); cancelAlert(false); @@ -136,6 +139,7 @@ dir = -1; reason(meas); assertTrue(rules[2].fired); + assertTrue(0 == airgate); cancelAlert(false); @@ -149,21 +153,14 @@ setHeatingState(HEATING_READY); - meas.tempI = 99; - meas.lambda = 2000; - resetRules(); - reason(meas); - assertFalse(rules[3].fired); - meas.tempI = 100; meas.lambda = 2000; - resetRules(); reason(meas); assertFalse(rules[3].fired); - meas.tempI = 99; - meas.lambda = 1199; + meas.tempI = 101; + meas.lambda = 2000; resetRules(); reason(meas); assertFalse(rules[3].fired); @@ -172,7 +169,23 @@ meas.lambda = 1199; resetRules(); reason(meas); + assertFalse(rules[3].fired); + + meas.tempI = 101; + meas.lambda = 1199; + resetRules(); + airgate = 100; + reason(meas); + assertFalse(rules[3].fired); + assertTrue(100 == airgate); + + meas.tempI = 101; + meas.lambda = 1199; + resetRules(); + airgate = 50; + reason(meas); assertTrue(rules[3].fired); + assertTrue(100 == airgate); meas.lambda = 1300; age = 0; @@ -184,6 +197,51 @@ return true; } +static bool testTooLean(void) { + + Measurement meas = {0, 0, 0}; + dir = 0; + + setHeatingState(HEATING_READY); + + meas.tempI = 500; + meas.lambda = 1601; + resetRules(); + reason(meas); + assertFalse(rules[4].fired); + + meas.tempI = 501; + meas.lambda = 1300; + resetRules(); + reason(meas); + assertFalse(rules[4].fired); + + meas.tempI = 501; + meas.lambda = 1601; + resetRules(); + airgate = 50; + reason(meas); + assertFalse(rules[4].fired); + assertTrue(50 == airgate); + + meas.tempI = 501; + meas.lambda = 1601; + resetRules(); + airgate = 100; + reason(meas); + assertTrue(rules[4].fired); + assertTrue(50 == airgate); + + meas.lambda = 1500; + age = 0; + reason(meas); + assertFalse(rules[4].fired); + + cancelAlert(false); + + return true; +} + static bool testFireOut(void) { resetRules(); @@ -193,27 +251,27 @@ meas.tempI = 50; age = 0; reason(meas); - assertFalse(rules[4].fired); + assertFalse(rules[5].fired); meas.tempI = 100; age = 0; reason(meas); - assertFalse(rules[4].fired); + assertFalse(rules[5].fired); meas.tempI = 125; age = 0; reason(meas); - assertFalse(rules[4].fired); + assertFalse(rules[5].fired); meas.tempI = 99; age = 0; reason(meas); - assertTrue(rules[4].fired); + assertTrue(rules[5].fired); meas.tempI = 125; age = 0; reason(meas); - assertFalse(rules[4].fired); + assertFalse(rules[5].fired); cancelAlert(false); @@ -438,6 +496,7 @@ static const char testAirgate25_P[] PROGMEM = "testAirgate25"; static const char testAirgateClose_P[] PROGMEM = "testAirgateClose"; static const char testTooRich_P[] PROGMEM = "testTooRich"; +static const char testTooLean_P[] PROGMEM = "testTooLean"; static const char testFireOut_P[] PROGMEM = "testFireOut"; static const char testHeatingReady_P[] PROGMEM = "testHeatingReady"; static const char testHeatingFaultNoconn_P[] PROGMEM = "testHeatingFaultNoconn"; @@ -453,6 +512,7 @@ {class, testAirgate25_P, testAirgate25}, {class, testAirgateClose_P, testAirgateClose}, {class, testTooRich_P, testTooRich}, + {class, testTooLean_P, testTooLean}, {class, testFireOut_P, testFireOut}, {class, testHeatingReady_P, testHeatingReady}, {class, testHeatingFaultNoconn_P, testHeatingFaultNoconn}, diff --git a/lambda/TODO b/lambda/TODO index bfcc46b..ea873a1 100644 --- a/lambda/TODO +++ b/lambda/TODO @@ -6,11 +6,9 @@ - Take in account F_CPU everywhere CPU speed matters * Functionality +- Show fire dir and (recommended) airgate position? * Circuit -- Look at oxygen sensor voltage with voltmeter/oscilloscope - is the voltage - really so unstable? -- Put button and beeper pins in pins.h (watch out with OCR1A) - AVCC should be connected to VCC via an LC network * Release/put in Makefile? diff --git a/lambda/alert.c b/lambda/alert.c index 916874c..2b58d93 100644 --- a/lambda/alert.c +++ b/lambda/alert.c @@ -13,6 +13,7 @@ #include "alert.h" #include "sensors.h" #include "display.h" +#include "pins.h" uint8_t beepCount = 0; uint16_t beepLength = 0; @@ -28,11 +29,11 @@ } if (oscCount == 0) { // turn beep on - TCCR1A |= (1 << COM1A0); + TCCR1A |= (1 << PIN_BEEPER_TOGGLE); } if (oscCount == beepLength) { // turn beep off - TCCR1A &= ~(1 << COM1A0); + TCCR1A &= ~(1 << PIN_BEEPER_TOGGLE); beepCount--; if (beepCount == 0 && ! keepActive) { alertActive = false; @@ -76,7 +77,7 @@ beepCount = 0; oscCount = 0; // turn beep off - TCCR1A &= ~(1 << COM1A0); + TCCR1A &= ~(1 << PIN_BEEPER_TOGGLE); if (! keepActive || all) { alertActive = false; } diff --git a/lambda/display.c b/lambda/display.c index 3a03c21..b31bf76 100644 --- a/lambda/display.c +++ b/lambda/display.c @@ -21,6 +21,7 @@ #include "display.h" #include "alert.h" #include "messages.h" +#include "rules.h" #define MENU_OFF 0 #define MENU_MAX_VALUES 1 @@ -66,7 +67,7 @@ snprintf(line1, sizeof(line1), "L %d.%02d %s %s", lambdaT.quot, abs(lambdaT.rem), toInfo(lambdax100), hint); } else { - snprintf(line1, sizeof(line1), "L -%12s", hint); + snprintf(line1, sizeof(line1), "L -%11s", hint); } setText(line0, line1); } @@ -79,7 +80,7 @@ div_t ampsT = div(ampsx100, 100); char line1[17]; - snprintf(line1, sizeof(line1), "%d.%02dA", ampsT.quot, abs(ampsT.rem)); + snprintf(line1, sizeof(line1), "%d.%02d Amp", ampsT.quot, abs(ampsT.rem)); setText(MSG_HEATING_CURRENT, line1); } @@ -130,7 +131,7 @@ updatePending = false; if (position == MENU_MAX_VALUES) { - displayMeas(measMax, "|>"); + displayMeas(measMax, " ^"); } else if (position == MENU_LAST_TEXT) { setText(lastLine0, lastLine1); } else if (position == MENU_CURRENT) { @@ -138,7 +139,13 @@ } else if (position == MENU_TIME) { displayTime(); } else { - displayMeas(measLatest, " "); + char* hint; + switch (getDir()) { + case DIR_BURN_UP: hint = " >"; break; + case DIR_BURN_DOWN: hint = " <"; break; + default: hint = " -"; break; + } + displayMeas(measLatest, hint); } } } diff --git a/lambda/interrupts.c b/lambda/interrupts.c index 7993902..6779e27 100644 --- a/lambda/interrupts.c +++ b/lambda/interrupts.c @@ -18,6 +18,7 @@ #include "sensors.h" #include "display.h" #include "alert.h" +#include "pins.h" static volatile bool buttonPressed = false; static volatile uint32_t ints = 0; @@ -72,14 +73,14 @@ } void setupPorts(void) { - // pull-up resistor for the mouton - PORTB |= (1 << PB0); + // pull-up resistor for the menu button + PORT |= (1 << PIN_BUTTON); // enable beep output pin - DDRB |= (1 << PB1); + DDR |= (1 << PIN_BEEPER); - // enable oxygen sensor heating control output pin - DDRB |= (1 << PB2); + // enable oxygen sensor heater control output pin + DDR |= (1 << PIN_HEATER); } void setupSleepMode(void) { @@ -112,7 +113,7 @@ TCCR1B |= (1 << WGM12); // timer1 clock prescaler/8 TCCR1B |= (1 << CS11); - // toggles PB1 at 7.8 kHz generating a 3.9 kHz beep + // timer1 Compare Match at 7.8 kHz generating a 3.9 kHz beep // OCR1A = 15; // 2 kHz is less noisy on the small piezo beeper OCR1A = 31; diff --git a/lambda/lambda.c b/lambda/lambda.c index ddcbefe..70b6768 100644 --- a/lambda/lambda.c +++ b/lambda/lambda.c @@ -51,7 +51,6 @@ // spend some time on being polite while (getTime() < 3) {} setHeatingOn(true); - while (getTime() < 4) {} uint32_t ints = 0; Measurement meas; diff --git a/lambda/pins.h b/lambda/pins.h index 71748b6..931b6cd 100644 --- a/lambda/pins.h +++ b/lambda/pins.h @@ -7,6 +7,8 @@ * Author: dode@luniks.net */ +#include + #ifndef PINS_H_ #define PINS_H_ @@ -19,6 +21,19 @@ /** ADC pin for the LSM 11 oxygen sensor heating current */ #define ADC_HEATING PC3 +/** Port for menu button, beeper and oxygen sensor heater */ +#define PORT PORTB +/** DDR for menu button, beeper and oxygen sensor heater */ +#define DDR DDRB +/** Pin for the menu button */ +#define PIN_BUTTON PB0 +/** Pin for the beeper */ +#define PIN_BEEPER PB1 +/** Toggle beeper pin OC1A/PB1 */ +#define PIN_BEEPER_TOGGLE COM1A0 +/** Pin for the oxygen sensor heater */ +#define PIN_HEATER PB2 + /* Pins for the LCD */ #define LCD_PORT PORTD #define LCD_DDR DDRD diff --git a/lambda/rules.c b/lambda/rules.c index 9bad3f5..9d801be 100644 --- a/lambda/rules.c +++ b/lambda/rules.c @@ -16,16 +16,17 @@ #define LENGTH 20 #define TONE 31 -#define DIR_NONE 0 -#define DIR_BURN_UP 1 -#define DIR_BURN_DOWN -1 - uint8_t age = 0; int8_t dir = 0; +uint8_t airgate = 100; static Measurement rulesMeasMax = {0, 0, 2000, 0}; static Measurement rulesMeasPrev = {0, 0, 2000, 0}; +int8_t getDir(void) { + return dir; +} + /** * Reminds to set the air gate to 50% when the fire is still building up * and the temperature has reached 500°C. @@ -33,6 +34,7 @@ static void airgate50(bool* const fired, int8_t const dir, Measurement const meas) { if (! *fired && dir == DIR_BURN_UP && meas.tempI >= 500) { + airgate = 50; alert_P(BEEPS, LENGTH, TONE, PSTR(MSG_AIRGATE_50_0), PSTR(""), false); *fired = true; } @@ -45,6 +47,7 @@ static void airgate25(bool* const fired, int8_t const dir, Measurement const meas) { if (! *fired && dir == DIR_BURN_DOWN && meas.tempI < 800) { + airgate = 25; alert_P(BEEPS, LENGTH, TONE, PSTR(MSG_AIRGATE_25_0), PSTR(""), false); *fired = true; } @@ -56,8 +59,9 @@ */ static void airgateClose(bool* const fired, int8_t const dir, Measurement const meas) { - if (! *fired && dir == DIR_BURN_DOWN && meas.tempI < 400) { + if (! *fired && dir == DIR_BURN_DOWN && meas.tempI < 450) { setHeatingOn(false); + airgate = 0; alert_P(BEEPS, LENGTH, TONE, PSTR(MSG_AIRGATE_CLOSE_0), PSTR(""), false); *fired = true; @@ -65,13 +69,13 @@ } /** - * Notifies that the combustion is too rich and to open the air gate - * if possible. + * Notifies that the combustion is too rich and to open the air gate. */ static void tooRich(bool* const fired, int8_t const dir, Measurement const meas) { - if (! *fired && meas.tempI >= 100 && meas.lambda < 1200 && - getHeatingState() == HEATING_READY) { + if (! *fired && meas.tempI > 100 && meas.lambda < 1200 && + getHeatingState() == HEATING_READY && airgate < 100) { + airgate = 100; alert_P(BEEPS, LENGTH, TONE, PSTR(MSG_TOO_RICH_0), PSTR(MSG_TOO_RICH_1), false); *fired = true; @@ -82,6 +86,22 @@ } /** + * Notifies that the combustion is lean (again) and to set the air gate to 50%. + */ +static void tooLean(bool* const fired, int8_t const dir, + Measurement const meas) { + if (! *fired && meas.tempI > 500 && meas.lambda > 1600 && + getHeatingState() == HEATING_READY && airgate > 50) { + airgate = 50; + alert_P(BEEPS, LENGTH, TONE, PSTR(MSG_AIRGATE_50_0), PSTR(""), false); + *fired = true; + } + if (meas.lambda <= 1500) { + *fired = false; + } +} + +/** * Notifies that the fire might have gone out at the beginning of building up. */ static void fireOut(bool* const fired, int8_t const dir, @@ -144,7 +164,6 @@ } // TODO what if fired up again without reset? -// TODO what if reset during burndown? /** * Rules applied to every nth averaged measurement @@ -154,6 +173,7 @@ {false, airgate25}, {false, airgateClose}, {false, tooRich}, + {false, tooLean}, {false, fireOut} }; @@ -215,6 +235,7 @@ age = 0; dir = DIR_NONE; + airgate = 100; size_t rulesSize = sizeof(rules) / sizeof(rules[0]); for (size_t i = 0; i < rulesSize; i++) { diff --git a/lambda/rules.h b/lambda/rules.h index 660deb5..a3db885 100644 --- a/lambda/rules.h +++ b/lambda/rules.h @@ -11,6 +11,10 @@ #include #include "sensors.h" +#define DIR_NONE 0 +#define DIR_BURN_UP 1 +#define DIR_BURN_DOWN -1 + /** * An attempt to create some sort of rule "object". */ @@ -20,6 +24,12 @@ } Rule; /** + * Returns the "direction" of the fire, i.e. DIR_BURN_DOWN when it is burning + * down. + */ +int8_t getDir(void); + +/** * Applies all rules against the given measurements. */ void reason(Measurement meas); diff --git a/lambda/sensors.h b/lambda/sensors.h index 145d352..ba77c5e 100644 --- a/lambda/sensors.h +++ b/lambda/sensors.h @@ -13,7 +13,6 @@ #include -/* 0.1 Ohm 10% measured 0.111 Ohm */ #define SHUNT_MILLIOHMS 100 #define HEATING_READY_MA 1400 #define HEATING_SHORT_MA 7500