diff --git a/lambda-test/adc-test.c b/lambda-test/adc-test.c index 396ca3f..e8951b8 100644 --- a/lambda-test/adc-test.c +++ b/lambda-test/adc-test.c @@ -21,8 +21,7 @@ // AVCC is set as AREF assertTrue(bit_is_set(ADMUX, REFS0)); // digital inputs are disabled - uint8_t adcPorts = (1 << ADC_TEMPI) | (1 << ADC_TEMPO) | (1 << ADC_LAMBDA); - assertTrue((DIDR0 & adcPorts) == adcPorts); + assertTrue(DIDR0 == 0b00111111); // ADC clock prescaler/8 uint8_t prescalerBy8 = (1 << ADPS1) | (1 << ADPS0); assertTrue((ADCSRA & prescalerBy8) == prescalerBy8); diff --git a/lambda-test/alert-test.c b/lambda-test/alert-test.c index ed0f9e7..89078bb 100644 --- a/lambda-test/alert-test.c +++ b/lambda-test/alert-test.c @@ -22,7 +22,7 @@ oscCount = 0; // alert with two beeps with a length of 2 and tone 31 - alert(2, 2, 31, "a", "b"); + alert(2, 2, 31, "a", "b", false); oscillateBeep(); oscillateBeep(); @@ -91,7 +91,7 @@ beepLength = 0; oscCount = 0; - alert(1, 2, 31, "a", "b"); + alert(1, 2, 31, "a", "b", false); assertTrue(beepCount == 1); assertTrue(beepLength == 2); @@ -111,7 +111,7 @@ beepLength = 0; oscCount = 0; - alert(1, 2, 31, "a", "b"); + alert(1, 2, 31, "a", "b", true); assertTrue(beepCount == 1); assertTrue(beepLength == 2); @@ -124,6 +124,14 @@ assertTrue(beepCount == 0); assertTrue(oscCount == 0); assertTrue(bit_is_clear(TCCR1A, COM1A0)); + assertTrue(isAlertActive()); + + alert(1, 2, 31, "a", "b", false); + + assertTrue(isAlertActive()); + + cancelAlert(); + assertFalse(isAlertActive()); return true; diff --git a/lambda-test/display-test.c b/lambda-test/display-test.c index f026ea0..fe4c77c 100644 --- a/lambda-test/display-test.c +++ b/lambda-test/display-test.c @@ -49,7 +49,7 @@ position = 0; updatePending = false; - alert(1, 1, 31, "", ""); + alert(1, 1, 31, "", "", false); assertTrue(isAlertActive()); cycleDisplay(); @@ -130,7 +130,7 @@ extern bool updatePending; updatePending = true; - alert(1, 1, 31, "", ""); + alert(1, 1, 31, "", "", false); assertTrue(isAlertActive()); // update should be skipped if alert is active diff --git a/lambda-test/interrupts-test.c b/lambda-test/interrupts-test.c index 238d595..af98d50 100644 --- a/lambda-test/interrupts-test.c +++ b/lambda-test/interrupts-test.c @@ -22,6 +22,9 @@ // test that the beep output pin is enabled assertTrue(bit_is_set(DDRB, PB1)); + // test that the oxygen sensor heating control output pin is enabled + assertTrue(bit_is_set(DDRB, PB1)); + return true; } diff --git a/lambda-test/sensors-test.c b/lambda-test/sensors-test.c index 2df4ae3..cc5bd35 100644 --- a/lambda-test/sensors-test.c +++ b/lambda-test/sensors-test.c @@ -72,13 +72,13 @@ } bool testToLambdaValue(void) { - int16_t lambda = toLambda(132); + uint16_t lambda = toLambda(132); return lambda == 1500; } bool testToLambdaInter(void) { - int16_t lambda = toLambda(550); + uint16_t lambda = toLambda(550); return lambda == 1073; } diff --git a/lambda/Makefile b/lambda/Makefile index 69df61a..0fb356a 100644 --- a/lambda/Makefile +++ b/lambda/Makefile @@ -13,7 +13,7 @@ MAIN = lambda.c ## en: 0 (default), de: 1 -LANG = 0 +LANG = 1 ## If you've split your program into multiple .c / .h files, ## include the additional source (in same directory) here diff --git a/lambda/TODO b/lambda/TODO index a5a43b3..b996cd7 100644 --- a/lambda/TODO +++ b/lambda/TODO @@ -11,4 +11,6 @@ * 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) \ No newline at end of file +- Put button and beeper pins in pins.h (watch out with OCR1A) +- AVcc should be connected to Vcc via an LC network +- ADC 5 and 4 use digital power while ADC 3-0 use analog power! \ No newline at end of file diff --git a/lambda/adc.c b/lambda/adc.c index b865a86..bfb56d4 100644 --- a/lambda/adc.c +++ b/lambda/adc.c @@ -23,7 +23,7 @@ ADMUX |= (1 << REFS0); // disable digital input on the ADC inputs // http://www.openmusiclabs.com/learning/digital/atmega-adc/ - DIDR0 |= (1 << ADC_TEMPI) | (1 << ADC_TEMPO) | (1 << ADC_LAMBDA); + DIDR0 = 0b00111111; // ADC clock prescaler/8 ADCSRA |= (1 << ADPS1) | (1 << ADPS0); // enable ADC diff --git a/lambda/alert.c b/lambda/alert.c index f205339..916874c 100644 --- a/lambda/alert.c +++ b/lambda/alert.c @@ -19,6 +19,7 @@ uint8_t oscCount = 0; static bool alertActive = false; +static bool keepActive = false; void oscillateBeep(void) { if (beepCount == 0) { @@ -33,7 +34,7 @@ // turn beep off TCCR1A &= ~(1 << COM1A0); beepCount--; - if (beepCount == 0) { + if (beepCount == 0 && ! keepActive) { alertActive = false; } } @@ -49,32 +50,36 @@ } void alert(uint8_t const beeps, uint8_t const length, uint16_t const tone, - const char* const line0, const char* const line1) { + const char* const line0, const char* const line1, + bool const keep) { OCR1A = tone; if (TCNT1 >= tone) TCNT1 = 0; alertActive = true; oscCount = 0; beepCount = beeps; beepLength = length; + keepActive = keep; displayText(line0, line1); } void alert_P(uint8_t const beeps, uint8_t const length, uint16_t const tone, - PGM_P const line0_P, PGM_P const line1_P) { + PGM_P const line0_P, PGM_P const line1_P, bool const keep) { char line0[17]; char line1[17]; strncpy_P(line0, line0_P, sizeof(line0)); strncpy_P(line1, line1_P, sizeof(line1)); - alert(beeps, length, tone, line0, line1); + alert(beeps, length, tone, line0, line1, keep); } -void cancelAlert(void) { +void cancelAlert(bool const all) { beepCount = 0; oscCount = 0; // turn beep off TCCR1A &= ~(1 << COM1A0); - alertActive = false; + if (! keepActive || all) { + alertActive = false; + } } bool isAlertActive(void) { diff --git a/lambda/alert.h b/lambda/alert.h index 20b4e95..6aad976 100644 --- a/lambda/alert.h +++ b/lambda/alert.h @@ -26,22 +26,23 @@ /** * Beeps the given number of beeps with the given length and tone and displays * the given two texts on the first and second line of the display, - * respectively. + * respectively, and keeps the alert active or not regardless of the beeps. */ void alert(uint8_t beeps, uint8_t length, uint16_t tone, - const char* line0, const char* line1); + const char* line0, const char* line1, bool keep); /** * Like alert(), but line0_P and line1_P are expected to be static pointers to * strings stored in program space like so: PSTR("string"). */ void alert_P(uint8_t beeps, uint8_t length, uint16_t tone, - PGM_P line0_P, PGM_P line1_P); + PGM_P line0_P, PGM_P line1_P, bool keep); /** - * Stops beeping and blocking display updates. + * Stops beeping and blocking display updates. If all is true, also alerts with + * where keep was true are cancelled. */ -void cancelAlert(void); +void cancelAlert(bool all); /** * Returns true if an alert is active, false otherwise. diff --git a/lambda/command.c b/lambda/command.c index 5aee933..02c7ffa 100644 --- a/lambda/command.c +++ b/lambda/command.c @@ -14,6 +14,7 @@ #include #include #include +#include "interrupts.h" #include "sensors.h" #include "display.h" #include "alert.h" @@ -38,13 +39,16 @@ split(data, " ", fields, fieldCount); if (strcmp_P(fields[0], PSTR("se")) == 0) { // simulation enable + simulation = true; + resetTime(); resetDisplay(); resetRules(); - simulation = true; + setHeatingOn(true); beep(1, 2, 31); } else if (strcmp_P(fields[0], PSTR("sd")) == 0) { // simulation disable + resetTime(); resetDisplay(); resetRules(); simulation = false; @@ -60,6 +64,16 @@ logging = false; beep(1, 2, 31); } + else if (strcmp_P(fields[0], PSTR("he")) == 0) { + // oxygen sensor heating enable + setHeatingOn(true); + beep(1, 2, 31); + } + else if (strcmp_P(fields[0], PSTR("hd")) == 0) { + // oxygen sensor heating disable + setHeatingOn(false); + beep(1, 2, 31); + } else if (strcmp_P(fields[0], PSTR("cm")) == 0) { // cycle menu cycleDisplay(); @@ -68,7 +82,7 @@ // test alert char buf[16]; strcpy_P(buf, PSTR("Beep Beep Beep!")); - alert(3, 10, 15, buf, fields[1]); + alert(3, 10, 15, buf, fields[1], false); } else if (strcmp_P(fields[0], PSTR("tb")) == 0) { // test beep @@ -84,7 +98,9 @@ } else if (simulation) { Measurement meas = readMeas(fields, fieldCount); - updateMeas(meas); + if (getHeatingState() == HEATING_READY) { + updateMeas(meas); + } reason(meas); } } diff --git a/lambda/display.c b/lambda/display.c index 079334d..10dd84e 100644 --- a/lambda/display.c +++ b/lambda/display.c @@ -26,8 +26,8 @@ uint8_t position = MENU_OFF; bool updatePending = false; -Measurement measLatest = {0, 0, 0}; -Measurement measMax = {0, 0, 2000}; +Measurement measLatest = {0, 0, 2000, 0}; +Measurement measMax = {0, 0, 2000, 0}; static char lastLine0[17]; static char lastLine1[17]; @@ -62,7 +62,7 @@ updatePending = true; if (isAlertActive()) { // button pressed during alert - cancelAlert(); + cancelAlert(false); return; } position++; @@ -110,8 +110,8 @@ void logMeas(Measurement const meas) { char log[64]; snprintf(log, sizeof(log), - "Ti %3d C - To %3d C - L %4u \r\n", - meas.tempI, meas.tempO, meas.lambda); + "Ti %3d C - To %3d C - L %u - C %4u\r\n", + meas.tempI, meas.tempO, meas.lambda, meas.current); printString(log); } diff --git a/lambda/interrupts.c b/lambda/interrupts.c index 91288d1..454389a 100644 --- a/lambda/interrupts.c +++ b/lambda/interrupts.c @@ -12,19 +12,20 @@ #include #include #include +#include #include "interrupts.h" #include "sensors.h" #include "display.h" #include "alert.h" static volatile bool buttonPressed = false; -static volatile uint8_t intCount = 0; +static volatile uint32_t time = 0; /** - * Called every 16 ms. + * Called about every 16.4 ms. */ ISR(TIMER0_OVF_vect) { - intCount++; + time++; oscillateBeep(); if (bit_is_clear(PINB, PB0) && ! buttonPressed) { buttonPressed = true; @@ -34,14 +35,17 @@ } } -bool hasIntCount(uint8_t const count, bool const reset) { - if (intCount >= count) { - if (reset) { - intCount = 0; - } - return true; - } else { - return false; +uint32_t getTime(void) { + uint32_t atomicTime; + ATOMIC_BLOCK(ATOMIC_FORCEON) { + atomicTime = time; + } + return atomicTime; +} + +void resetTime(void) { + ATOMIC_BLOCK(ATOMIC_FORCEON) { + time = 0; } } @@ -51,6 +55,9 @@ // enable beep output pin DDRB |= (1 << PB1); + + // enable oxygen sensor heating control output pin + DDRB |= (1 << PB2); } void setupSleepMode(void) { @@ -76,7 +83,7 @@ void initTimers(void) { // timer in normal mode is default - // timer0 clock prescaler/64 = 15.625 kHz overflowing every 16 ms + // timer0 clock prescaler/64 = 15.625 kHz overflowing every 16.4 ms TCCR0B |= (1 << CS01) | (1 << CS00); // timer1 Clear Timer on Compare Match mode, TOP OCR1A diff --git a/lambda/interrupts.h b/lambda/interrupts.h index 5df2368..37ebcd6 100644 --- a/lambda/interrupts.h +++ b/lambda/interrupts.h @@ -11,11 +11,17 @@ #ifndef INTERRUPTS_H_ #define INTERRUPTS_H_ +#define SECOND 61 + /** - * Returns true if the current timer interrupt count is equal or greater to - * the given count and resets it if the given boolean is true. + * Returns the time in units of about 16.4 ms since last reset. */ -bool hasIntCount(uint8_t count, bool reset); +uint32_t getTime(void); + +/** + * Resets the time to 0. + */ +void resetTime(void); /** * Sets up ports. diff --git a/lambda/lambda.c b/lambda/lambda.c index f5badd6..f10f0e6 100644 --- a/lambda/lambda.c +++ b/lambda/lambda.c @@ -23,6 +23,7 @@ #include #include #include +#include #include "usart.h" #include "lcdroutines.h" #include "adc.h" @@ -47,18 +48,24 @@ initInterrupts(); initTimers(); - alert_P(1, 2, 31, PSTR(MSG_WELCOME), PSTR("")); + alert_P(1, 2, 31, PSTR(MSG_WELCOME), PSTR(""), false); + // spend some time on being polite + _delay_ms(3000); + setHeatingOn(true); Measurement meas; // main loop - while (1) { - if (hasIntCount(62, true) && ! isSimulation()) { + while (true) { + if (getTime() % SECOND == 0 && ! isSimulation() && + getHeatingState() != HEATING_FAULT) { meas = measure(); if (isLogging()) { logMeas(meas); } - updateMeas(meas); + if (getHeatingState() == HEATING_READY) { + updateMeas(meas); + } reason(meas); } if (isUSARTReceived()) { diff --git a/lambda/messages.h b/lambda/messages.h index 6540b3b..2b90403 100644 --- a/lambda/messages.h +++ b/lambda/messages.h @@ -27,10 +27,15 @@ #define MSG_AIRGATE_50_0 "Air gate 50%" #define MSG_AIRGATE_25_0 "Air gate 25%" #define MSG_AIRGATE_CLOSE_0 "Close air gate" - #define MSG_AIRGATE_CLOSE_1 "Turn off heating" #define MSG_TOO_RICH_0 "Too rich, open" #define MSG_TOO_RICH_1 "air gate" #define MSG_FIRE_OUT_0 "Fire out?" + #define MSG_HEATING_UP_0 "Oxygen sensor" + #define MSG_HEATING_UP_1 "heating up..." + #define MSG_HEATING_READY_0 "Oxygen sensor" + #define MSG_HEATING_READY_1 "ready" + #define MSG_HEATING_FAULT_0 "Oxygen sensor" + #define MSG_HEATING_FAULT_1 "heating fault!" #elif LANG == 1 @@ -47,10 +52,15 @@ #define MSG_AIRGATE_50_0 "Luftschieber 50%" #define MSG_AIRGATE_25_0 "Luftschieber 25%" #define MSG_AIRGATE_CLOSE_0 "Luftschieber zu" - #define MSG_AIRGATE_CLOSE_1 "Heizung aus" #define MSG_TOO_RICH_0 "Zu fett, Luft-" #define MSG_TOO_RICH_1 "schieber oeffnen" #define MSG_FIRE_OUT_0 "Feuer aus?" + #define MSG_HEATING_UP_0 "Lambdasonde" + #define MSG_HEATING_UP_1 "waermt auf..." + #define MSG_HEATING_READY_0 "Lambdasonde" + #define MSG_HEATING_READY_1 "bereit" + #define MSG_HEATING_FAULT_0 "Lambdasonden-" + #define MSG_HEATING_FAULT_1 "heizung Fehler!" #endif diff --git a/lambda/pins.h b/lambda/pins.h index 328abbd..71748b6 100644 --- a/lambda/pins.h +++ b/lambda/pins.h @@ -11,11 +11,13 @@ #define PINS_H_ /** ADC pin for the type K thermocouple signal */ -#define ADC_TEMPI PC5 +#define ADC_TEMPI PC2 /** ADC pin for the PT1000 resistance thermometer signal */ -#define ADC_TEMPO PC4 // prototype: PC0 +#define ADC_TEMPO PC0 /** ADC pin for the LSM 11 oxygen sensor signal */ -#define ADC_LAMBDA PC3 // prototype: PC2 +#define ADC_LAMBDA PC1 +/** ADC pin for the LSM 11 oxygen sensor heating current */ +#define ADC_HEATING PC3 /* Pins for the LCD */ #define LCD_PORT PORTD diff --git a/lambda/rules.c b/lambda/rules.c index 129d119..94c0ea0 100644 --- a/lambda/rules.c +++ b/lambda/rules.c @@ -8,10 +8,11 @@ #include #include "alert.h" #include "integers.h" +#include "interrupts.h" #include "rules.h" #include "messages.h" -#define BEEPS 60 +#define BEEPS 30 #define LENGTH 20 #define TONE 31 @@ -19,11 +20,11 @@ #define DIR_BURN_UP 1 #define DIR_BURN_DOWN -1 -uint16_t age = 0; +uint8_t age = 0; int8_t dir = 0; -static Measurement rulesMeasMax = {0, 0, 2000}; -static Measurement rulesMeasPrev = {0, 0, 2000}; +static Measurement rulesMeasMax = {0, 0, 2000, 0}; +static Measurement rulesMeasPrev = {0, 0, 2000, 0}; /** * Reminds to set the air gate to 50% when the fire is still building up @@ -32,7 +33,7 @@ static void airgate50(bool* const fired, int8_t const dir, Measurement const meas) { if (! *fired && dir == DIR_BURN_UP && meas.tempI >= 500) { - alert_P(BEEPS, LENGTH, TONE, PSTR(MSG_AIRGATE_50_0), PSTR("")); + alert_P(BEEPS, LENGTH, TONE, PSTR(MSG_AIRGATE_50_0), PSTR(""), false); *fired = true; } } @@ -44,7 +45,7 @@ static void airgate25(bool* const fired, int8_t const dir, Measurement const meas) { if (! *fired && dir == DIR_BURN_DOWN && meas.tempI < 800) { - alert_P(BEEPS, LENGTH, TONE, PSTR(MSG_AIRGATE_25_0), PSTR("")); + alert_P(BEEPS, LENGTH, TONE, PSTR(MSG_AIRGATE_25_0), PSTR(""), false); *fired = true; } } @@ -56,8 +57,9 @@ static void airgateClose(bool* const fired, int8_t const dir, Measurement const meas) { if (! *fired && dir == DIR_BURN_DOWN && meas.tempI < 400) { + setHeatingOn(false); alert_P(BEEPS, LENGTH, TONE, - PSTR(MSG_AIRGATE_CLOSE_0), PSTR(MSG_AIRGATE_CLOSE_1)); + PSTR(MSG_AIRGATE_CLOSE_0), PSTR(""), false); *fired = true; } } @@ -68,9 +70,10 @@ */ static void tooRich(bool* const fired, int8_t const dir, Measurement const meas) { - if (! *fired && meas.tempI >= 100 && meas.lambda < 1200) { + if (! *fired && meas.tempI >= 100 && meas.lambda < 1200 && + getHeatingState() == HEATING_READY) { alert_P(BEEPS, LENGTH, TONE, - PSTR(MSG_TOO_RICH_0), PSTR(MSG_TOO_RICH_1)); + PSTR(MSG_TOO_RICH_0), PSTR(MSG_TOO_RICH_1), false); *fired = true; } if (meas.lambda >= 1300) { @@ -85,7 +88,7 @@ Measurement const meas) { if (! *fired && dir == DIR_BURN_UP && meas.tempI < 100 && rulesMeasMax.tempI - meas.tempI > 25) { - alert_P(BEEPS, LENGTH, TONE, PSTR(MSG_FIRE_OUT_0), PSTR("")); + alert_P(BEEPS, LENGTH, TONE, PSTR(MSG_FIRE_OUT_0), PSTR(""), false); *fired = true; } if (meas.tempI >= 125) { @@ -93,10 +96,39 @@ } } +static void heatingReady(bool* const fired, int8_t const dir, + Measurement const meas) { + if (! isHeatingOn() || getHeatingState() == HEATING_READY) { + return; + } + if (meas.current <= HEATING_READY_MA && meas.current > HEATING_DISCONN_MA) { + setHeatingState(HEATING_READY); + alert_P(3, 10, TONE, PSTR(MSG_HEATING_READY_0), + PSTR(MSG_HEATING_READY_1), false); + } +} + +static void heatingFault(bool* const fired, int8_t const dir, + Measurement const meas) { + if (! isHeatingOn() || getHeatingState() == HEATING_FAULT) { + return; + } + if (meas.current > HEATING_SHORT_MA || meas.current < HEATING_DISCONN_MA || + (getTime() > SECOND * 120 && meas.current > HEATING_READY_MA)) { + // short circuit or disconnected or did not warm up within 2 minutes + setHeatingOn(false); + setHeatingState(HEATING_FAULT); + alert_P(BEEPS, LENGTH, TONE, PSTR(MSG_HEATING_FAULT_0), + PSTR(MSG_HEATING_FAULT_1), true); + } +} + /** * Array of rules. */ Rule rules[] = { + {false, heatingReady}, + {false, heatingFault}, {false, airgate50}, {false, airgate25}, {false, airgateClose}, @@ -107,13 +139,13 @@ // called about every second void reason(Measurement const meas) { - // apply the rules about every 10 seconds - if (age % 10 == 0) { + // apply the rules about every 10 seconds to every 10th measurement + // if (age % 10 == 0) { size_t rulesSize = sizeof(rules) / sizeof(rules[0]); for (size_t i = 0; i < rulesSize; i++) { rules[i].cond(&(rules[i].fired), dir, meas); } - } + // } age++; @@ -134,18 +166,15 @@ } rulesMeasMax.tempI = MAX(rulesMeasMax.tempI, meas.tempI); - rulesMeasMax.tempO = MAX(rulesMeasMax.tempO, meas.tempO); - rulesMeasMax.lambda = MIN(rulesMeasMax.lambda, meas.lambda); } void resetRules(void) { rulesMeasPrev.tempI = 0; rulesMeasPrev.tempO = 0; rulesMeasPrev.lambda = 2000; + rulesMeasPrev.current = 0; rulesMeasMax.tempI = 0; - rulesMeasMax.tempO = 0; - rulesMeasMax.lambda = 2000; age = 0; dir = DIR_NONE; diff --git a/lambda/sensors.c b/lambda/sensors.c index fd4b18b..ebaa14c 100644 --- a/lambda/sensors.c +++ b/lambda/sensors.c @@ -8,15 +8,21 @@ * */ +#include #include #include #include +#include #include "adc.h" +#include "alert.h" #include "sensors.h" #include "integers.h" +#include "interrupts.h" #include "pins.h" #include "messages.h" +static int8_t heatingState = HEATING_OFF; + /** * Table used to look up the lambda value at 12 V heater voltage * and 220°C exhaust gas temperature. Most values are approximated @@ -85,24 +91,26 @@ meas.tempI = toTempI(tempIVoltageAvg >> 3); meas.tempO = toTempO(tempOVoltageAvg >> 3); meas.lambda = toLambda(lambdaVoltageAvg >> 3); + meas.current = toCurrent(getVoltage(ADC_HEATING)); return meas; } Measurement readMeas(char* const fields[], size_t const size) { Measurement meas; - if (size < 3) { + if (size < 4) { return meas; } meas.tempI = atoi(fields[0]); meas.tempO = atoi(fields[1]); meas.lambda = atoi(fields[2]); + meas.current = atoi(fields[3]); return meas; } int16_t toTempI(uint16_t const mV) { - int temp = divRoundNearest(mV, 5); + int16_t temp = divRoundNearest(mV, 5); return temp; } @@ -114,13 +122,19 @@ return temp; } -int16_t toLambda(uint16_t const mV) { +uint16_t toLambda(uint16_t const mV) { size_t size = sizeof(lambdaTable) / sizeof(lambdaTable[0]); int16_t lambda = lookupLinInter(mV, lambdaTable, size); return lambda; } +uint16_t toCurrent(uint16_t const mV) { + uint16_t current = mV * (1000 / SHUNT_MILLIOHMS); + + return current; +} + int16_t lookupLinInter(uint16_t const mV, TableEntry const table[], size_t const size) { if (mV < table[0].mV) { @@ -155,3 +169,27 @@ return MSG_RICH; } } + +void setHeatingOn(bool on) { + if (on) { + PORTB |= (1 << PB2); + heatingState = HEATING_UP; + alert_P(1, 2, 31, PSTR(MSG_HEATING_UP_0), PSTR(MSG_HEATING_UP_1), true); + } else { + PORTB &= ~(1 << PB2); + heatingState = HEATING_OFF; + cancelAlert(true); + } +} + +bool isHeatingOn(void) { + return bit_is_set(PORTB, PB2); +} + +void setHeatingState(int8_t state) { + heatingState = state; +} + +int8_t getHeatingState(void) { + return heatingState; +} diff --git a/lambda/sensors.h b/lambda/sensors.h index 31f229b..c3c497c 100644 --- a/lambda/sensors.h +++ b/lambda/sensors.h @@ -13,6 +13,16 @@ #include +#define SHUNT_MILLIOHMS 100 +#define HEATING_READY_MA 1500 +#define HEATING_SHORT_MA 9000 +#define HEATING_DISCONN_MA 100 + +#define HEATING_FAULT -1 +#define HEATING_OFF 0 +#define HEATING_UP 1 +#define HEATING_READY 2 + /** * Entry for the lookup tables. */ @@ -27,7 +37,8 @@ typedef struct { int16_t tempI; int16_t tempO; - int16_t lambda; + uint16_t lambda; + uint16_t current; } Measurement; /** @@ -66,7 +77,12 @@ * With the current circuit and the AD8551 the measuring range is from about * lambda 1.0 to 2.0 at 5000 mV OP supply and ADC reference voltage. */ -int16_t toLambda(uint16_t mV); +uint16_t toLambda(uint16_t mV); + +/** + * Returns the current of the oxygen sensor heating in mA. + */ +uint16_t toCurrent(uint16_t mv); /** * Returns the value corresponding to the given voltage @@ -83,4 +99,25 @@ */ char* toInfo(uint16_t lambda); +/** + * Turns the heating of the oxygen sensor on or off. + */ +void setHeatingOn(bool on); + +/** + * Returns true if the heating of the oxygen sensor is turned on, + * false otherwise. + */ +bool isHeatingOn(void); + +/** + * Sets the state of the heating of the oxygen sensor to the given value. + */ +void setHeatingState(int8_t state); + +/** + * Returns the state of the heating of the oxygen sensor. + */ +int8_t getHeatingState(void); + #endif /* SENSORS_H_ */