diff --git a/lambda-test/lambda-test.c b/lambda-test/lambda-test.c index 70284cf..6cf512b 100644 --- a/lambda-test/lambda-test.c +++ b/lambda-test/lambda-test.c @@ -30,8 +30,8 @@ #include "avrjunit.h" static const tableEntry testTable[] = { - {0, 0}, - {10, 10} + {10, 10}, + {20, 20} }; /* Module adc */ @@ -80,7 +80,7 @@ // loop_until_bit_is_set(UCSR0A, UDRE0); _delay_ms(10); - int16_t mV = getVoltage(PC1); + uint16_t mV = getVoltage(PC1); return mV > 4900; } @@ -183,34 +183,6 @@ return true; } -bool testAverageUp(void) { - int32_t value = 10; - int32_t avg = 0; - for (uint8_t i = 0; i < 14; i++) { - avg = average((value << 4), avg, 4); - } - - return divRoundNearest(avg, 16) == value; -} - -bool testAverageDown(void) { - int32_t value = 0; - int32_t avg = (10 << 4); - for (uint8_t i = 0; i < 14; i++) { - avg = average((value << 4), avg, 4); - } - - return divRoundNearest(avg, 16) == value; -} - -bool testAverageDoesNotWrap(void) { - int32_t value = 5000; - int32_t avg = (value << 4); - avg = average((value << 4), avg, 16); - - return divRoundNearest(avg, 16) == value; -} - bool testToLambdaValue(void) { int16_t lambda = toLambda(12); @@ -242,15 +214,15 @@ } bool testLookupLinInterBelow(void) { - int16_t value = lookupLinInter(-5, testTable, 2); + int16_t value = lookupLinInter(0, testTable, 2); - return value == 0; + return value == 10; } bool testLookupLinInterAbove(void) { - int16_t value = lookupLinInter(15, testTable, 2); + int16_t value = lookupLinInter(30, testTable, 2); - return value == 10; + return value == 20; } bool testLookupLinInterValue(void) { @@ -260,35 +232,35 @@ } bool testLookupLinInterInter(void) { - int16_t value = lookupLinInter(3, testTable, 2); + int16_t value = lookupLinInter(15, testTable, 2); - return value == 3; + return value == 15; } bool testToInfoLean(void) { - const char* info = toInfo(1901); + const char* info = toInfo(191); return ! strcmp(info, LEAN); } bool testToInfoOkay(void) { - assertTrue(0 == strcmp(toInfo(1900), OKAY)); - assertTrue(0 == strcmp(toInfo(1700), OKAY)); - assertTrue(0 == strcmp(toInfo(1501), OKAY)); + assertTrue(0 == strcmp(toInfo(190), OKAY)); + assertTrue(0 == strcmp(toInfo(170), OKAY)); + assertTrue(0 == strcmp(toInfo(151), OKAY)); return true; } bool testToInfoIdeal(void) { - assertTrue(0 == strcmp(toInfo(1500), IDEAL)); - assertTrue(0 == strcmp(toInfo(1400), IDEAL)); - assertTrue(0 == strcmp(toInfo(1300), IDEAL)); + assertTrue(0 == strcmp(toInfo(150), IDEAL)); + assertTrue(0 == strcmp(toInfo(140), IDEAL)); + assertTrue(0 == strcmp(toInfo(130), IDEAL)); return true; } bool testToInfoRich(void) { - const char* info = toInfo(1200); + const char* info = toInfo(129); return ! strcmp(info, RICH); } @@ -307,9 +279,6 @@ {"integers", "testDivRoundUpDenNeg", testDivRoundUpDenNeg}, {"integers", "testDivRoundUpBothNeg", testDivRoundUpBothNeg}, {"sensors", "testMeasure", testMeasure}, - {"sensors", "testAverageUp", testAverageUp}, - {"sensors", "testAverageDown", testAverageDown}, - {"sensors", "testAverageDoesNotWrap", testAverageDoesNotWrap}, {"sensors", "testToLambdaValue", testToLambdaValue}, {"sensors", "testToLambdaInter", testToLambdaInter}, {"sensors", "testToTempI", testToTempI}, diff --git a/lambda/adc.c b/lambda/adc.c index 5121112..10913db 100644 --- a/lambda/adc.c +++ b/lambda/adc.c @@ -37,7 +37,7 @@ sei(); } -int16_t getVoltage(uint8_t pin) { +uint16_t getVoltage(uint8_t pin) { ADMUX = (0b11110000 & ADMUX) | pin; diff --git a/lambda/adc.h b/lambda/adc.h index cdacb79..e4b9bb3 100644 --- a/lambda/adc.h +++ b/lambda/adc.h @@ -34,6 +34,6 @@ * 16x oversampling and taking in account the calibrated AREF and * ADC offset voltages. */ -int16_t getVoltage(uint8_t pin); +uint16_t getVoltage(uint8_t pin); #endif /* ADC_H_ */ diff --git a/lambda/sensors.c b/lambda/sensors.c index 6c666b2..fd34c7e 100644 --- a/lambda/sensors.c +++ b/lambda/sensors.c @@ -49,7 +49,7 @@ * and an amplification factor of 6.17. */ static const tableEntry tempOTable[] = { - { -57, -50 }, + // { -57, -50 }, { 454, 0 }, { 1403, 100 }, { 2264, 200 }, @@ -60,29 +60,32 @@ /** * Global variables holding averaged voltages. */ -int32_t lambdaVoltageAvg = 0; -int32_t tempIVoltageAvg = 0; -int32_t tempOVoltageAvg = 0; +uint32_t lambdaVoltageAvg = 4; +uint32_t tempIVoltageAvg = 4; +uint32_t tempOVoltageAvg = 4; /** - * Measures the "input" and "output" temperatures and the lambda value - * and displays the measured values. + * Measures the "input" and "output" temperatures and the lambda value, + * calculates an exponential moving average and displays the translated values. */ measurement measure(void) { - int32_t tempIVoltage = getVoltage(PC5); - tempIVoltageAvg = average((tempIVoltage << 4), tempIVoltageAvg, 4); + uint32_t tempIVoltage = getVoltage(PC5); + tempIVoltageAvg = tempIVoltage + tempIVoltageAvg - + ((tempIVoltageAvg - 4) >> 3); - int32_t tempOVoltage = getVoltage(PC0); - tempOVoltageAvg = average((tempOVoltage << 4), tempOVoltageAvg, 4); + uint32_t tempOVoltage = getVoltage(PC0); + tempOVoltageAvg = tempOVoltage + tempOVoltageAvg - + ((tempOVoltageAvg - 4) >> 3); // OP factor is 11 - int32_t lambdaVoltage = divRoundNearest(getVoltage(PC2), 11); - lambdaVoltageAvg = average((lambdaVoltage << 4), lambdaVoltageAvg, 4); + uint32_t lambdaVoltage = divRoundNearest(getVoltage(PC2), 11); + lambdaVoltageAvg = lambdaVoltage + lambdaVoltageAvg - + ((lambdaVoltageAvg - 4) >> 3); measurement meas; - meas.tempIVoltage = divRoundNearest(tempIVoltageAvg, 16); - meas.tempOVoltage = divRoundNearest(tempOVoltageAvg, 16); - meas.lambdaVoltage = divRoundNearest(lambdaVoltageAvg, 16); + meas.tempIVoltage = (tempIVoltageAvg >> 3); + meas.tempOVoltage = (tempOVoltageAvg >> 3); + meas.lambdaVoltage = (lambdaVoltageAvg >> 3); meas.tempI = toTempI(meas.tempIVoltage); meas.tempO = toTempO(meas.tempOVoltage); @@ -92,12 +95,12 @@ } void display(measurement meas) { - uint8_t lambdax10 = divRoundNearest(meas.lambda, 100); - div_t lambdaT = div(lambdax10, 10); + uint16_t lambdax100 = divRoundNearest(meas.lambda, 10); + div_t lambdaT = div(lambdax100, 100); char log[64]; snprintf(log, sizeof(log), - "Ti %3d C %4d - To %3d C %4d - L %4d %4d\r\n", + "Ti %3d C %4u - To %3d C %4u - L %4u %4u\r\n", meas.tempI, meas.tempIVoltage, meas.tempO, meas.tempOVoltage, meas.lambda, meas.lambdaVoltage); printString(log); @@ -105,39 +108,35 @@ char line0[17]; char line1[17]; snprintf(line0, sizeof(line0), "Ti %3dC To %3dC ", meas.tempI, meas.tempO); - snprintf(line1, sizeof(line1), "L %d.%01d %s ", - lambdaT.quot, abs(lambdaT.rem), toInfo(meas.lambda)); + snprintf(line1, sizeof(line1), "L %d.%02d %s ", + lambdaT.quot, abs(lambdaT.rem), toInfo(lambdax100)); lcd_setcursor(0, 1); lcd_string(line0); lcd_setcursor(0, 2); lcd_string(line1); } -int32_t average(int32_t value, int32_t average, uint8_t weight) { - return divRoundNearest(value + (average * weight), weight + 1); -} - -int16_t toTempI(int16_t mV) { +int16_t toTempI(uint16_t mV) { int temp = divRoundNearest(mV, 5); return temp; } -int16_t toTempO(int16_t mV) { +int16_t toTempO(uint16_t mV) { uint8_t length = sizeof(tempOTable) / sizeof(tempOTable[0]); int16_t temp = lookupLinInter(mV, tempOTable, length); return temp; } -int16_t toLambda(int16_t mV) { +int16_t toLambda(uint16_t mV) { uint8_t length = sizeof(lambdaTable) / sizeof(lambdaTable[0]); int16_t lambda = lookupLinInter(mV, lambdaTable, length); return lambda; } -int16_t lookupLinInter(int16_t mV, const tableEntry table[], uint8_t length) { +int16_t lookupLinInter(uint16_t mV, const tableEntry table[], uint8_t length) { if (mV < table[0].mV) { return table[0].value; } else if (mV > table[length - 1].mV) { @@ -151,24 +150,22 @@ } } - int16_t diffVoltage = table[i + 1].mV - table[i].mV; + uint16_t diffVoltage = table[i + 1].mV - table[i].mV; int16_t diffValue = table[i + 1].value - table[i].value; int16_t value = table[i].value + divRoundNearest( - (int32_t)(mV - table[i].mV) * diffValue, diffVoltage); + (uint32_t)(mV - table[i].mV) * diffValue, diffVoltage); return value; } -const char* toInfo(int16_t lambda) { - if (lambda > 1900) { +const char* toInfo(uint16_t lambda) { + if (lambda > 190) { return LEAN; - } else if (lambda > 1500 && lambda <= 1900) { + } else if (lambda > 150 && lambda <= 190) { return OKAY; - } else if (lambda >= 1300 && lambda <= 1500) { + } else if (lambda >= 130 && lambda <= 150) { return IDEAL; } else { return RICH; } } - - diff --git a/lambda/sensors.h b/lambda/sensors.h index cd44d69..a64148f 100644 --- a/lambda/sensors.h +++ b/lambda/sensors.h @@ -22,7 +22,7 @@ * Entry for the lookup tables. */ typedef struct { - const int16_t mV; + const uint16_t mV; const int16_t value; } tableEntry; @@ -30,11 +30,11 @@ * Measured values. */ typedef struct { - int16_t tempIVoltage; + uint16_t tempIVoltage; int16_t tempI; - int16_t tempOVoltage; + uint16_t tempOVoltage; int16_t tempO; - int16_t lambdaVoltage; + uint16_t lambdaVoltage; int16_t lambda; } measurement; @@ -51,19 +51,13 @@ void display(measurement); /** - * Creates an exponential moving average of the given value and - * average weighted by the given weight. - */ -int32_t average(int32_t value, int32_t average, uint8_t weight); - -/** * 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. * With the current circuit the measuring range is from about 3 to 990 °C * at 5000 mV OP supply and ADC reference voltage. */ -int16_t toTempI(int16_t mV); +int16_t toTempI(uint16_t mV); /** * Looks up the temperature in °C mapped to the given voltage measured at @@ -71,7 +65,7 @@ * With the current circuit and the LM358 the measuring range is from about * -40 to 375°C at 5000 mV OP supply and ADV reference voltage. */ -int16_t toTempO(int16_t mV); +int16_t toTempO(uint16_t mV); /** * Looks up the lambda value x1000 mapped to the given voltage measured at @@ -79,7 +73,7 @@ * 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(int16_t mV); +int16_t toLambda(uint16_t mV); /** * Returns the value corresponding to the given voltage @@ -87,13 +81,13 @@ * Thanks to http://stackoverflow.com/a/7091629/709426 and * http://en.wikipedia.org/wiki/Linear_interpolation */ -int16_t lookupLinInter(int16_t mV, const tableEntry table[], uint8_t length); +int16_t lookupLinInter(uint16_t mV, const tableEntry table[], uint8_t length); /** * Returns a descriptive term such as "Lean" for the given lambda value x1000. * For a wood fire, residual oxygen between 5% and 7% (lambda 1.3 and 1.5) is * a good value, below is rich and above is lean. */ -const char* toInfo(int16_t lambda); +const char* toInfo(uint16_t lambda); #endif /* SENSORS_H_ */