diff --git a/lambda/Makefile b/lambda/Makefile index cb77e29..feaaa11 100644 --- a/lambda/Makefile +++ b/lambda/Makefile @@ -14,7 +14,7 @@ ## If you've split your program into multiple .c / .h files, ## include the additional source (in same directory) here -LOCAL_SOURCE = +LOCAL_SOURCE = sensors.c ## Here you can link to one more directory (and multiple .c files) EXTRA_SOURCE_DIR = /data/Work/AVR/AVR-Programming-master/AVR-Programming-Library/ diff --git a/lambda/lambda.c b/lambda/lambda.c index 5814ea6..048cdca 100644 --- a/lambda/lambda.c +++ b/lambda/lambda.c @@ -1,4 +1,9 @@ /* + * lambda.h + * + * Created on: 22.02.2015 + * Author: dode@luniks.net + * * TODO try starting ADC sample manually and wait for it to finish * TODO try to remove floating points * TODO refactoring - module? @@ -6,7 +11,6 @@ * TODO DIDR? * TODO unit tests, Jenkins? */ - #include #include #include @@ -15,48 +19,7 @@ #include #include #include "USART.h" -#include "lambda.h" - -#define AREF_MV 4850 -#define ADC_OFFSET_MV 7 -#define TMP_OP_OFFSET 441 - -static const char* lean = "Mager"; -static const char* ideal = "Ideal"; -static const char* rich = "Fett!"; - -/** - * Table used to look up the lambda value at 12 V heater voltage - * and 220°C exhaust gas temperature. Most values are approximated - * from the characteristic curve in the datasheet. - * TODO equation? real table? - */ -static const tableEntry lambdaTable[] = { - { 4, 2.0 }, - { 5, 1.9 }, - { 6, 1.8 }, - { 8, 1.7 }, - { 10, 1.6 }, - { 12, 1.5 }, - { 15, 1.4 }, - { 20, 1.3 }, - { 28, 1.2 }, - { 40, 1.1 }, - { 68, 1.025 }, - { 400, 1.0 }, - { 800, 0.98 }, - { 860, 0.9 }, - { 880, 0.8 } -}; - -static const tableEntry tempOTable[] = { - { -57, 10.22 }, // -50 C - { 455, 9.97 }, // 0 C - { 1403, 9.49 }, // 100 C - { 2264, 9.05 }, // 200 C - { 3047, 8.64 }, // 300 C - { 3762, 8.27 } // 400 C -}; +#include "sensors.h" float lambdaVoltageAvg = 0.0; float tempIVoltageAvg = 0.0; @@ -77,51 +40,6 @@ sei(); // enable global interrupts } -int main(void) { - - initUSART(); - setupADC(); - setupSleepMode(); - - // disable digital input on ADC0 - // http://www.openmusiclabs.com/learning/digital/atmega-adc/ - // DIDR0 = 0b00000011; - - // initial update - update(0.0, 0.0, 0.0); - - // main loop - while (1) { - run(); - _delay_ms(1000); - } - - return 0; -} - -void run(void) { - float lambdaVoltage = getVoltage(PC2) / 11.0; - lambdaVoltageAvg = (lambdaVoltage + lambdaVoltageAvg * 8) / 9; - - int tempIVoltage = getVoltage(PC5); - tempIVoltageAvg = (tempIVoltage + tempIVoltageAvg * 2) / 3; - - int tempOVoltage = getVoltage(PC0); - tempOVoltageAvg = (tempOVoltage + tempOVoltageAvg * 2) / 3; - - update(tempIVoltageAvg, tempOVoltageAvg, lambdaVoltageAvg); -} - -void update(float tempIVoltage, float tempOVoltage, float lambdaVoltage) { - int tempI = toTempI(tempIVoltage); - int tempO = toTempO(tempOVoltage); - int length = sizeof(lambdaTable) / sizeof(lambdaTable[0]); - float lambda = lookupLinInter(lambdaVoltage, lambdaTable, length); - // round(lambda * 10) / 10.0; - - display(tempIVoltage, tempI, tempOVoltage, tempO, lambdaVoltage, lambda); -} - void display( int tempIVoltage, int tempI, int tempOVoltage, int tempO, @@ -137,90 +55,43 @@ snprintf(line1, sizeof(line1), "L %s (%s)\r\n", lambdaStr, lambdaVoltageStr); printString(line0); printString(line1); + + int unused = 0; } -int getVoltage(int port) { +void measure(void) { + float lambdaVoltage = getVoltage(PC2) / 11.0; + lambdaVoltageAvg = (lambdaVoltage + lambdaVoltageAvg * 8) / 9; - ADMUX = (0b11110000 & ADMUX) | port; + int tempIVoltage = getVoltage(PC5); + tempIVoltageAvg = (tempIVoltage + tempIVoltageAvg * 2) / 3; - unsigned long overValue = 0; - for (int i = 0; i < 16; i++) { - sleep_mode(); - overValue += ADC; - } - float mV = ((overValue >> 2) * AREF_MV / 4096) + ADC_OFFSET_MV; + int tempOVoltage = getVoltage(PC0); + tempOVoltageAvg = (tempOVoltage + tempOVoltageAvg * 2) / 3; - return mV; + int tempI = toTempI(tempIVoltage); + int tempO = toTempO(tempOVoltage); + float lambda = toLambda(lambdaVoltage); + // round(lambda * 10) / 10.0; + + display(tempIVoltage, tempI, tempOVoltage, tempO, lambdaVoltage, lambda); } -/** - * 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. Returns 0 for negative voltages. - */ -int toTempI(float mV) { - if (mV < 0) { - return 0; +int main(void) { + + initUSART(); + setupADC(); + setupSleepMode(); + + // disable digital input on ADC0 + // http://www.openmusiclabs.com/learning/digital/atmega-adc/ + // DIDR0 = 0b00000011; + + // main loop + while (1) { + measure(); + _delay_ms(1000); } - int temp = round(mV / 5); - - return temp; + return 0; } - -int toTempO(float mV) { - if (mV < 0) { - return 0; - } - - int length = sizeof(tempOTable) / sizeof(tempOTable[0]); - float mVPerC = lookupLinInter(mV, tempOTable, length) / 5000 * AREF_MV; - int temp = round((mV - TMP_OP_OFFSET) / mVPerC); - - char buf[13]; - dtostrf(mVPerC, 5, 2, buf); - char str[14]; - snprintf(str, sizeof(str), "mV/C %s\r\n", buf); - printString(str); - - return temp; -} - -/** - * Returns the value corresponding to the given voltage - * from the lookup table using linear interpolation. - * Thanks to http://stackoverflow.com/a/7091629/709426 and - * http://en.wikipedia.org/wiki/Linear_interpolation - */ -float lookupLinInter(float mV, const tableEntry table[], int length) { - if (mV < table[0].mV) { - return table[0].value; - } else if (mV > table[length - 1].mV) { - return table[length - 1].value; - } - - int i = 0; - for (; i < length - 1; i++) { - if (table[i + 1].mV > mV) { - break; - } - } - - float diffVoltage = table[i + 1].mV - table[i].mV; - float diffValue = table[i + 1].value - table[i].value; - float value = table[i].value + - (mV - table[i].mV) * diffValue / diffVoltage; - - return value; -} - -const char* toInfo(float lambda) { - if (lambda > 1.5) { - return lean; - } else if (lambda > 1.3 && lambda <= 1.5) { - return ideal; - } else { - return rich; - } -} - diff --git a/lambda/lambda.elf b/lambda/lambda.elf index c571550..a350c71 100755 --- a/lambda/lambda.elf +++ b/lambda/lambda.elf Binary files differ diff --git a/lambda/lambda.h b/lambda/lambda.h deleted file mode 100644 index 79d1cca..0000000 --- a/lambda/lambda.h +++ /dev/null @@ -1,26 +0,0 @@ -/* - * lambda.h - * - * Created on: 22.02.2015 - * Author: dode - */ -typedef struct { - const int mV; - const float value; -} tableEntry; - -void run(void); - -void update(float tempIVoltage, float tempOVoltage, float lambdaVoltage); - -void display(int tempIVoltage, int tempI, int tempOVoltage, int tempO, float lambdaVoltage, float lambda); - -int getVoltage(int port); - -int toTempI(float mV); - -int toTempO(float mV); - -float lookupLinInter(float mV, const tableEntry table[], int length); - -const char* toInfo(float lambda); diff --git a/lambda/lambda.hex b/lambda/lambda.hex index 4919a31..90bd2f7 100644 --- a/lambda/lambda.hex +++ b/lambda/lambda.hex @@ -21,9 +21,9 @@ :10014000FEE6DB18D1844B381BF77C1D901DA4BB49 :10015000E424203284725E228100C9F124ECA1E5FE :100160003D2711241FBECFEFD8E0DEBFCDBF11E089 -:10017000A0E0B1E0E6E0F8E102C005900D92AE3BF0 -:10018000B107D9F721E0AEEBB1E001C01D92AA3C66 -:10019000B207E1F737D30C94010C32CF1895ECE796 +:10017000A0E0B1E0EEE7F6E102C005900D92A83AEA +:10018000B107D9F721E0A8EAB1E001C01D92A43B74 +:10019000B207E1F779D10C943D0B32CF1895ECE71B :1001A000F0E0808180648083EAE7F0E08081846011 :1001B0008083808180688083089583B7817F826097 :1001C00083BFEAE7F0E080818860808378940895B7 @@ -33,366 +33,340 @@ :10020000DEBF0FBECDBF982E892EAC966FAFAC97D8 :10021000AD967FAFAD97742E622E17012801C601EF :10022000B5016E012EE5C20ED11C860123E045E02A -:10023000AF963FAFAF97AE965FAFAE97A0D55E01DA +:10023000AF963FAFAF97AE965FAFAE97DCD45E019F :1002400081E5A80EB11C850123E045E0C201B101A2 -:1002500096D5AE965FADAE975F937F92AF963FAD6A +:10025000D2D4AE965FADAE975F937F92AF963FAD2F :10026000AF973F936F928F929F92AD969FADAD9750 :100270009F93AC962FADAC972F9380E091E09F9326 :100280008F931F9218E21F934E0189E2880E911CF2 -:100290009F928F9294D5BF92AF92DF92CF928CE1D2 +:100290009F928F92D0D4BF92AF92DF92CF928CE197 :1002A00091E09F938F931F921F938E010F5F1F4FBB -:1002B0001F930F9384D5C401D3D2C801D1D20FB6F6 +:1002B0001F930F93C0D4C4010DD1C8010BD10FB649 :1002C000F894DEBF0FBECDBFC259DF4F0FB6F89412 :1002D000DEBF0FBECDBFDF91CF911F910F91FF9079 :1002E000EF90DF90CF90BF90AF909F908F907F90D6 -:1002F0006F905F904F903F902F90089590917C0069 -:10030000907F982B90937C0020E130E080E090E09B -:10031000DC0143B7416043BF889543B74E7F43BF7D -:100320004091780050917900840F951FA11DB11D57 -:10033000215031092115310561F79C01AD0182E0A1 -:1003400056954795379527958A95D1F7A2EFB2E153 -:1003500099D22CE096958795779567952A95D1F750 -:10036000695F7F4F8F4F9F4FA8D376D3CB010895FE -:10037000CF92DF92EF92FF926B017C0120E030E0A0 -:10038000A901FED287FD0BC020E030E040EA50E436 -:10039000C701B601F9D2AAD45FD3CB0102C080E075 -:1003A00090E0FF90EF90DF90CF9008958F929F9212 -:1003B000AF92BF92CF92DF92EF92FF920F931F9373 -:1003C000CF93DF934B015C01EA0169016881798178 -:1003D000882777FD8095982F72D39B01AC01C501CA -:1003E000B401CED287FF05C06A817B818C819D815B -:1003F00081C086E08C9D80018D9D100D11240650DA -:1004000011090C0F1D1FF80160817181882777FD8C -:100410008095982F54D39B01AC01C501B401FFD343 -:1004200018160CF462C08E0180E090E0F1E0CF1A63 -:10043000D1089C012F5F3F4F79018C159D0584F4F5 -:10044000F80166817781882777FD8095982F37D3CB -:100450000A5F1F4FA5019401E2D318160CF043C0A8 -:1004600086E08E9DF0018F9DF00D11248E010E0F00 -:100470001F1F3697EC0FFD1FC081D181C280D38032 -:10048000E480F580BE01882777FD8095982F17D3EB -:100490009B01AC01C501B4010ED24B015C01A70167 -:1004A0009601F801628173818481958104D29B0158 -:1004B000AC01C501B401B7D34B015C01F801608107 -:1004C00071816C1B7D0B882777FD8095982FF7D263 -:1004D0009B01AC01C501B40157D29B01AC01C7011E -:1004E000B601EAD107C0C701A4CFF80162817381C8 -:1004F00084819581DF91CF911F910F91FF90EF90B3 -:10050000DF90CF90BF90AF909F908F9008954F92C3 -:100510005F926F927F928F929F92AF92BF92CF9293 -:10052000DF92EF92FF920F931F93CF93DF93CDB79C -:10053000DEB76B970FB6F894DEBF0FBECDBF6B0171 -:100540007C0120E030E0A9011BD287FD42C025E0FC -:1005500030E045E451E0C701B60128DF20E030E497 -:100560004CE955E411D220E030E947E955E45BD38A -:100570004B015C0120E030E84CED53E4C701B601CB -:100580009AD1A501940100D2B1D366D22B013C01CE -:100590007E018FE0E80EF11C870122E045E0C501F5 -:1005A000B401EDD3FF92EF9289E291E09F938F9394 -:1005B0001F928EE08F930E5011091F930F93FFD35C -:1005C000C8014ED10FB6F894DEBF0FBECDBFC20139 -:1005D00002C080E090E06B960FB6F894DEBF0FBECD -:1005E000CDBFDF91CF911F910F91FF90EF90DF90E2 -:1005F000CF90BF90AF909F908F907F906F905F90C3 -:100600004F9008952F923F924F925F926F927F92F8 -:100610008F929F92AF92BF92CF92DF92EF92FF9212 -:100620000F931F93CF93DF93CDB7DEB728970FB605 -:10063000F894DEBF0FBECDBF6D837E838F83988716 -:1006400029833A834B835C8393DE1C0169817A8121 -:100650008B819C815CDF4C012FE030E043E651E070 -:10066000C801B701A3DE5B016C0169817A818B81CE -:100670009C81F2D169837A838B839C836D817E8197 -:100680008F819885E9D1DC01CB01940149815A81A0 -:10069000B1019EDD28960FB6F894DEBF0FBECDBF28 -:1006A000DF91CF911F910F91FF90EF90DF90CF904E -:1006B000BF90AF909F908F907F906F905F904F9082 -:1006C0003F902F900895CF92DF92EF92FF920F9379 -:1006D0001F9382E090E012DEBC01882777FD8095B1 -:1006E000982FEDD120E030E040E351E44DD16B0193 -:1006F0007C0120E030E040E051E46091C60170915F -:10070000C7018091C8019091C9018DD29B01AC01B4 -:10071000C701B601D1D020E030E040E151E434D14E -:100720006093C6017093C7018093C8019093C9017B -:1007300085E090E0E3DDBC01882777FD8095982F68 -:10074000BED16B017C016091C2017091C3018091A7 -:10075000C4019091C5019B01AC01AED09B01AC01DD -:10076000C701B601A9D020E030E040E450E40CD14C -:100770006093C2017093C3018093C4019093C5013B -:1007800080E090E0BBDDBC01882777FD8095982F45 -:1007900096D16B017C016091BE017091BF01809187 -:1007A000C0019091C1019B01AC0186D09B01AC01BD -:1007B000C701B60181D020E030E040E450E4E4D04D -:1007C0009B01AC016093BE017093BF018093C00197 -:1007D0009093C101E090C601F090C7010091C8015B -:1007E0001091C9016091C2017091C3018091C4014F -:1007F0009091C50107DF1F910F91FF90EF90DF905F -:10080000CF90089515D0CBDCD8DCE12CF12C8701FA -:10081000A8019701C801B701F5DE55DF2FE38DE090 -:1008200093E0215080409040E1F700C00000F5CFF8 -:100830001092C5008CE08093C400E0ECF0E0808171 -:100840008260808388E18093C10086E08093C2004B -:1008500008959091C00095FFFCCF8093C600089545 -:100860001F93CF93DF93EC0110E0FE01E10FF11D28 -:100870008081882319F0EDDF1F5FF7CFDF91CF91E3 -:100880001F91089509D0A59F900DB49F900DA49F2E -:10089000800D911D11240895A29FB001B39FC00146 -:1008A000A39F700D811D1124911DB29F700D811D9C -:1008B0001124911D08955058BB27AA270ED075C149 -:1008C00066D130F06BD120F031F49F3F11F41EF46B -:1008D0005BC10EF4E095E7FB51C1E92F77D180F3BE -:1008E000BA17620773078407950718F071F49EF52D -:1008F0008FC10EF4E0950B2EBA2FA02D0B01B9017C -:1009000090010C01CA01A0011124FF27591B99F085 -:10091000593F50F4503E68F11A16F040A22F232F91 -:10092000342F4427585FF3CF469537952795A795E1 -:10093000F0405395C9F77EF41F16BA0B620B730B88 -:10094000840BBAF09150A1F0FF0FBB1F661F771FF9 -:10095000881FC2F70EC0BA0F621F731F841F48F4AE -:10096000879577956795B795F7959E3F08F0B3CF34 -:100970009395880F08F09927EE0F9795879508951E -:10098000D9D008F481E008950CD00FC107D140F010 -:10099000FED030F021F45F3F19F0F0C0511139C1A1 -:1009A000F3C014D198F39923C9F35523B1F3951BE0 -:1009B000550BBB27AA2762177307840738F09F5F80 -:1009C0005F4F220F331F441FAA1FA9F333D00E2EEF -:1009D0003AF0E0E830D091505040E695001CCAF75C -:1009E00029D0FE2F27D0660F771F881FBB1F261721 -:1009F00037074807AB07B0E809F0BB0B802DBF01F4 -:100A0000FF2793585F4F2AF09E3F510568F0B6C00C -:100A100000C15F3FECF3983EDCF3869577956795D0 -:100A2000B795F7959F5FC9F7880F911D96958795A4 -:100A300097F90895E1E0660F771F881FBB1F6217C3 -:100A400073078407BA0720F0621B730B840BBA0B81 -:100A5000EE1F88F7E095089504D06894B111D9C0CD -:100A60000895BCD088F09F5790F0B92F9927B751BF -:100A7000A0F0D1F0660F771F881F991F1AF0BA9562 -:100A8000C9F712C0B13081F0C3D0B1E00895C0C041 -:100A9000672F782F8827B85F39F0B93FCCF3869558 -:100AA00077956795B395D9F73EF4909580957095B5 -:100AB00061957F4F8F4F9F4F0895E89409C097FB32 -:100AC0003EF490958095709561957F4F8F4F9F4F25 -:100AD0009923A9F0F92F96E9BB279395F695879569 -:100AE00077956795B795F111F8CFFAF4BB0F11F42C -:100AF00060FF1BC06F5F7F4F8F4F9F4F16C08823D3 -:100B000011F096E911C0772321F09EE8872F762F08 -:100B100005C0662371F096E8862F70E060E02AF049 -:100B20009A95660F771F881FDAF7880F9695879535 -:100B300097F90895990F0008550FAA0BE0E8FEEF0A -:100B400016161706E807F907C0F012161306E40791 -:100B5000F50798F0621B730B840B950B39F40A268A -:100B600061F0232B242B252B21F408950A2609F468 -:100B7000A140A6958FEF811D811D089597F99F676C -:100B800080E870E060E008959FEF80EC0895002415 -:100B90000A941616170618060906089500240A94E2 -:100BA00012161306140605060895092E0394000C68 -:100BB00011F4882352F0BB0F40F4BF2B11F460FFF7 -:100BC00004C06F5F7F4F8F4F9F4F089557FD905820 -:100BD000440F551F59F05F3F71F04795880F97FB01 -:100BE000991F61F09F3F79F08795089512161306BB -:100BF0001406551FF2CF4695F1DF08C016161706EA -:100C00001806991FF1CF869571056105089408951E -:100C1000E894BB2766277727CB0197F908958ADFE9 -:100C200008F48FEF08950BD0C0CFB1DF28F0B6DF06 -:100C300018F0952309F0A2CFA7CF1124EACFC6DF81 -:100C4000A0F3959FD1F3950F50E0551F629FF001DF -:100C5000729FBB27F00DB11D639FAA27F00DB11D38 -:100C6000AA1F649F6627B00DA11D661F829F2227C1 -:100C7000B00DA11D621F739FB00DA11D621F839F48 -:100C8000A00D611D221F749F3327A00D611D231F1E -:100C9000849F600D211D822F762F6A2F11249F576C -:100CA00050408AF0E1F088234AF0EE0FFF1FBB1F8F -:100CB000661F771F881F91505040A9F79E3F51052E -:100CC00070F05CCFA6CF5F3FECF3983EDCF38695E7 -:100CD00077956795B795F795E7959F5FC1F7FE2BD9 -:100CE000880F911D9695879597F9089577DFE0F025 -:100CF0009E37D8F09639B8F49E3848F4672F782F8D -:100D00008827985FF9CF869577956795939595395C -:100D1000D0F3B62FB1706B0F711D811D20F4879534 -:100D200077956795939502C01CC073CF882371F4A3 -:100D3000772321F09850872B762F07C0662311F474 -:100D400099270DC09051862B70E060E02AF09A95AB -:100D5000660F771F881FDAF7880F9695879597F9A2 -:100D600008959F3F31F0915020F4879577956795CE -:100D7000B795880F911D9695879597F90895EF92ED -:100D80000F931F93CF93DF93E80147FF02C034E135 -:100D900001C034E0E42FFF27E7FDF095F7FF03C023 -:100DA000F195E195F109E32E022F2E2FAE01F7D137 -:100DB000CE01DF91CF911F910F91EF900895AEE09A -:100DC000B0E0E4EEF6E0F4C40D891E898F89988DB9 -:100DD00026E02C831A83098397FF02C080E090E805 -:100DE00001979E838D83AE01455E5F4F698D7A8D3D -:100DF000CE01019611D04D815E8157FD0AC02F8131 -:100E00003885421753070CF49A01F801E20FF31FDB -:100E100010822E96E4E0E8C4ACE0B0E0E1E1F7E057 -:100E2000B9C47C016B018A01FC011782168283819F -:100E300081FFB0C1CE0101964C01F7019381F6010B -:100E400093FD859193FF81916F01882309F49EC1E1 -:100E5000853239F493FD859193FF81916F0185323D -:100E600021F4B70190E006D4E8CF512C312C20E0DA -:100E70002032A0F48B3269F030F4803259F08332A2 -:100E800069F420612CC08D3239F0803339F421604F -:100E900026C02260246023C0286021C027FD27C00F -:100EA00030ED380F3A3078F426FF06C0FAE05F9E46 -:100EB000300D1124532E13C08AE0389E300D1124BA -:100EC000332E20620CC08E3221F426FD5FC12064D7 -:100ED00006C08C3611F4206802C0883641F4F60151 -:100EE00093FD859193FF81916F018111C1CF982F5F -:100EF0009F7D9554933028F40C5F1F4FFFE3F983D7 -:100F00000DC0833631F0833771F0833509F057C057 -:100F100021C0F801808189830E5F1F4F44244394D0 -:100F2000512C540114C03801F2E06F0E711CF8010D -:100F3000A080B18026FF03C0652D70E002C06FEF76 -:100F40007FEFC5012C878BD32C0183012C852F7754 -:100F5000222E16C03801F2E06F0E711CF801A0803D -:100F6000B18026FF03C0652D70E002C06FEF7FEFF8 -:100F7000C5012C8769D32C012C852068222E830182 -:100F800023FC19C0832D90E048165906A0F4B70140 -:100F900080E290E06FD33A94F5CFF50127FC85917C -:100FA00027FE81915F01B70190E064D331103A943C -:100FB000F1E04F1A51084114510479F7DEC084362C -:100FC00011F0893631F5F80127FF07C06081718182 -:100FD000828193810C5F1F4F08C0608171818827D7 -:100FE00077FD8095982F0E5F1F4F2F76B22E97FFBB -:100FF00009C090958095709561957F4F8F4F9F4F59 -:101000002068B22E2AE030E0A40166D3A82EA818EA -:1010100043C0853729F42F7EB22E2AE030E025C068 -:10102000F22FF97FBF2E8F36C1F018F4883579F092 -:10103000ADC0803719F0883721F0A8C02F2F20616C -:10104000B22EB4FE0DC08B2D8460B82E09C024FFD3 -:101050000AC09F2F9660B92E06C028E030E005C078 -:1010600020E130E002C020E132E0F801B7FE07C025 -:1010700060817181828193810C5F1F4F06C0608106 -:10108000718180E090E00E5F1F4FA40125D3A82E50 -:10109000A818FB2DFF77BF2EB6FE0BC02B2D2E7F81 -:1010A000A51450F4B4FE0AC0B2FC08C02B2D2E7E4D -:1010B00005C07A2C2B2D03C07A2C01C0752C24FF7F -:1010C0000DC0FE01EA0DF11D8081803311F4297EEF -:1010D00009C022FF06C07394739404C0822F8678DF -:1010E00009F0739423FD12C020FF06C05A2C73141C -:1010F00018F4530C5718732C731460F4B70180E282 -:1011000090E02C87B7D273942C85F6CF731410F42B -:10111000371801C0312C24FF11C0B70180E390E0E3 -:101120002C87A8D22C8522FF16C021FF03C088E59A -:1011300090E002C088E790E0B7010CC0822F86786B -:1011400051F021FD02C080E201C08BE227FD8DE25B -:10115000B70190E08FD2A51430F4B70180E390E09E -:1011600089D25A94F8CFAA94F401EA0DF11D808136 -:10117000B70190E07FD2A110F6CF332009F45DCE05 -:10118000B70180E290E076D23A94F7CFF7018681FA -:10119000978102C08FEF9FEF2C96E2E117C36F9209 -:1011A0007F929F92AF92BF92CF92DF92EF92FF9287 -:1011B0000F931F93CF93DF93CDB7DEB729970FB669 -:1011C000F894DEBF0FBECDBF6A01B22E102F0C33D4 -:1011D00020F4FF24F394F00E02C04CE3F42E0F2D04 -:1011E00027E0AE014F5F5F4F57D17981272F2970DC -:1011F000213031F0E1FC06C0E0FC06C060E005C033 -:101200006DE203C06BE201C060E2AE2DA07173FF1E -:1012100036C0662311F084E001C083E08B1510F422 -:10122000B81A01C0B12CA1110BC0F6018B2D90E2B0 -:10123000882319F091938150FBCFCB0CD11CB12C9A -:10124000662331F0F601608396012F5F3F4F6901FD -:10125000C6010396E2FE05C02EE4F601208331E4C8 -:1012600004C02EE6F601208331E631832283FC019F -:101270002B2D30E22223F1F131932150FBCF72FF6D -:1012800040C0662311F084E001C083E08B1510F4A8 -:10129000B81A01C0B12CA1110BC0F6018B2D90E240 -:1012A000882319F091938150FBCFCB0CD11CB12C2A -:1012B000662331F0F601608396012F5F3F4F69018D -:1012C000C6010396E2FE07C029E4F60120832EE45E -:1012D000218326E406C029E6F60120832EE6218339 -:1012E00026E62283FC012B2D30E2222319F03193D4 -:1012F0002150FBCFFC01EB0DF11D10828EEF9FEF13 -:10130000B7C0B1E0611101C0B0E04B2F50E018163A -:10131000190624F49C012F5F3F4F02C021E030E00A -:10132000240F351F112329F0412F50E04F5F5F4FED -:1013300002C040E050E0420F531F2B2D30E0421717 -:10134000530714F4B41A01C0B12C2E2D287159F48E -:10135000F6012B2D30E2222319F031932150FBCFDF -:10136000CB0CD11CB12CBB2331F0F601608396016C -:101370002F5F3F4F6901A1110BC0F6012B2D30E308 -:10138000222319F031932150FBCFCB0CD11CB12C6F -:10139000F80E0A81372F3071A32E74FF03C001337A -:1013A00009F4FA941F142CF42F2D293018F028E09A -:1013B00001C021E0682F392F97FF02C060E030E0C4 -:1013C000462F532F612C712C3EE2932EBC01621BE1 -:1013D00071099B01DC01A41BB50BE1E0F0E0EC0F0F -:1013E000FD1FAE0FBF1FE12EF12CF194E194F10827 -:1013F0004F3FFFEF5F0731F4F6019082B6016F5F58 -:101400007F4F6B01841795074CF02417350734F490 -:10141000BD01660D771DFB01118101C010E3415034 -:101420005109FFEF6F1A7F0AB6016F5F7F4F4E15AC -:101430005F0524F0F60110836B01DACF48175907D6 -:1014400039F4063320F4053319F4A11001C011E377 -:10145000F6011083FB018B2D90E2882319F0919304 -:101460008150FBCFFB01EB0DF11D108280E090E07D -:1014700029960FB6F894DEBF0FBECDBFDF91CF9196 -:101480001F910F91FF90EF90DF90CF90BF90AF90A2 -:101490009F907F906F900895283008F027E03327C1 -:1014A000DA01990F311D87FD916000966105710584 -:1014B00039F432602E5F3D9330E32A95E1F70895C9 -:1014C0009F3F30F080387105610509F03C5F3C5F5B -:1014D0003D93913008F08068911DDF93CF931F9367 -:1014E0000F93FF92EF92192F987F9695E92F96957B -:1014F0009695E90FFF27EE53FF4F99273327EE24E8 -:10150000FF24A701E70105900894079428F4360FFB -:10151000E71EF81E491F511D660F771F881F991F70 -:101520000694A1F70590079428F4E70EF81E491FCA -:10153000561FC11D770F881F991F661F0694A1F7BC -:101540000590079428F4F80E491F561FC71FD11D98 -:10155000880F991F661F771F0694A1F705900794BF -:1015600020F4490F561FC71FD81F990F661F771FFA -:10157000881F0694A9F784911095177041F0D695AD -:10158000C79557954795F794E7941A95C1F7E8E6FC -:10159000F0E06894159015913591659195910590BD -:1015A0007FE27395E118F10A430B560BC90BD00982 -:1015B000C0F7E10CF11E431F561FC91FD01D7EF45A -:1015C000703311F48A95E6CFE894015030F0080F9B -:1015D0000AF40027021708F4202F2395022F7A33EC -:1015E00028F079E37D932A95E9F710C07D932A9539 -:1015F00089F6069497956795379517951794E1188E -:10160000F10A430B560BC90BD00998F023957E9134 -:1016100073957A3308F070E37C932013B8F77E91CA -:1016200070617D9330F0839571E37D9370E32A952B -:10163000E1F71124EF90FF900F911F91CF91DF916F -:10164000992787FD90950895FC01059061507040A1 -:101650000110D8F7809590958E0F9F1F0895FC017B -:101660006150704001900110D8F7809590958E0FD1 -:101670009F1F08950F931F93CF93DF93182F092F68 -:10168000EB018B8181FD03C08FEF9FEF20C082FFB4 -:1016900010C04E815F812C813D81421753077CF43D -:1016A000E881F9819F012F5F3F4F398328831083A1 -:1016B00006C0E885F985812F0995892B29F72E81A8 -:1016C0003F812F5F3F4F3F832E83812F902FDF91EC -:1016D000CF911F910F910895FA01AA27283051F157 -:1016E000203181F1E8946F936E7F6E5F7F4F8F4F53 -:1016F0009F4FAF4FB1E03ED0B4E03CD0670F781FB2 -:10170000891F9A1FA11D680F791F8A1F911DA11D96 -:101710006A0F711D811D911DA11D20D009F46894CF -:101720003F912AE0269F11243019305D3193DEF677 -:10173000CF010895462F4770405D4193B3E00FD02D -:10174000C9F7F6CF462F4F70405D4A3318F0495D18 -:1017500031FD4052419302D0A9F7EACFB4E0A695FB -:101760009795879577956795BA95C9F7009761051D -:10177000710508959B01AC010A2E06945795479573 -:1017800037952795BA95C9F7620F731F841F951F68 -:10179000A01D08952F923F924F925F926F927F9279 -:1017A0008F929F92AF92BF92CF92DF92EF92FF9271 -:1017B0000F931F93CF93DF93CDB7DEB7CA1BDB0B1D -:1017C0000FB6F894DEBF0FBECDBF09942A883988C2 -:1017D00048885F846E847D848C849B84AA84B984C9 -:1017E000C884DF80EE80FD800C811B81AA81B981D5 -:1017F000CE0FD11D0FB6F894DEBF0FBECDBFED01E9 -:061800000895F894FFCFEB -:101806005469202533642043202564202020546F0A -:101816002025336420432025640D0A004C202573BF -:101826002020282573290D0A006D562F4320257385 -:101836000D0A004D6167657200496465616C00467A -:101846006574742100C7011F851F417B050AD717E0 -:1018560041D808CDCC1041E70B713D0A41B20EECE0 -:1018660051044104000000004005003333F33F06F5 -:10187600006666E63F08009A99D93F0A00CDCCCCAF -:101886003F0C000000C03F0F003333B33F14006627 -:1018960066A63F1C009A99993F2800CDCC8C3F4400 -:1018A600003333833F90010000803F200348E17AF4 -:0E18B6003F5C036666663F7003CDCC4C3F007E +:1002F0006F905F904F903F902F9008952F923F9274 +:100300004F925F926F927F928F929F92AF92BF9225 +:10031000CF92DF92EF92FF920F931F93CF93DF93D1 +:1003200000D000D0CDB7DEB782E090E0E5D0BC01D0 +:10033000882777FD8095982FFED220E030E040E3BB +:1003400051E45ED22B013C0120E030E040E051E47A +:100350006091B0017091B1018091B2019091B301AF +:100360009ED39B01AC01C301B201E2D120E030E099 +:1003700040E151E445D26093B0017093B1018093A4 +:10038000B2019093B30185E090E0B6D09C838B835B +:10039000BC01882777FD8095982FCDD24B015C0159 +:1003A0006091AC017091AD018091AE019091AF016F +:1003B0009B01AC01BDD19B01AC01C501B401B8D119 +:1003C00020E030E040E450E41BD26093AC01709335 +:1003D000AD018093AE019093AF0180E090E08CD0AE +:1003E0001C01BC01882777FD8095982FA4D26B0152 +:1003F0007C016091A8017091A9018091AA0190915E +:10040000AB019B01AC0194D19B01AC01C701B601CA +:100410008FD120E030E040E450E4F2D16093A801B5 +:100420007093A9018093AA019093AB01C501B40117 +:100430009DD09A838983C701B60157D14C01C3016E +:10044000B2014ED15B016C01830172019401A101E3 +:1004500069817A818B819C81BBDE0F900F900F9018 +:100460000F90DF91CF911F910F91FF90EF90DF9050 +:10047000CF90BF90AF909F908F907F906F905F9044 +:100480004F903F902F9008950DD089DE96DE36DF95 +:100490002FE38DE093E0215080409040E1F700C0D1 +:1004A0000000F5CF1092C5008CE08093C400E0EC12 +:1004B000F0E080818260808388E18093C10086E0E3 +:1004C0008093C20008959091C00095FFFCCF809367 +:1004D000C60008951F93CF93DF93EC0110E0FE0157 +:1004E000E10FF11D8081882319F0EDDF1F5FF7CF49 +:1004F000DF91CF911F91089590917C00907F982B70 +:1005000090937C0020E130E080E090E0DC0143B794 +:10051000416043BF889543B74E7F43BF4091780009 +:1005200050917900840F951FA11DB11D21503109F3 +:100530002115310561F79C01AD0182E05695479583 +:10054000379527958A95D1F7A8E8B3E1D7D02CE065 +:1005500096958795779567952A95D1F7695F7F4F2F +:100560008F4F9F4FE6D1B4D1CB01089520E030E00A +:1005700040EA50E445D1F6D2ABD1CB0108958F9239 +:100580009F92AF92BF92CF92DF92EF92FF920F9322 +:100590001F93CF93DF934B015C01EA0169016881EE +:1005A0007981882777FD8095982FC5D19B01AC0173 +:1005B000C501B40121D187FF05C06A817B818C818F +:1005C0009D8181C086E08C9D80018D9D100D112440 +:1005D000065011090C0F1D1FF801608171818827D9 +:1005E00077FD8095982FA7D19B01AC01C501B4017F +:1005F00052D218160CF462C08E0180E090E0F1E057 +:10060000CF1AD1089C012F5F3F4F79018C159D05B2 +:1006100084F4F80166817781882777FD8095982F8B +:100620008AD10A5F1F4FA501940135D218160CF02C +:1006300043C086E08E9DF0018F9DF00D11248E0148 +:100640000E0F1F1F3697EC0FFD1FC081D181C28096 +:10065000D380E480F580BE01882777FD8095982FB0 +:100660006AD19B01AC01C501B40161D04B015C01B1 +:10067000A7019601F801628173818481958157D029 +:100680009B01AC01C501B4010AD24B015C01F80128 +:10069000608171816C1B7D0B882777FD8095982F79 +:1006A0004AD19B01AC01C501B401AAD09B01AC01A8 +:1006B000C701B6013DD007C0C701A4CFF8016281D0 +:1006C000738184819581DF91CF911F910F91FF906C +:1006D000EF90DF90CF90BF90AF909F908F90089554 +:1006E0002FE030E04DE451E04ACF26E030E049E22F +:1006F00051E045DF37D2ECD0CB01089509D0A59F5A +:10070000900DB49F900DA49F800D911D112408950C +:10071000A29FB001B39FC001A39F700D811D112442 +:10072000911DB29F700D811D1124911D0895505887 +:10073000BB27AA270ED075C166D130F06BD120F04F +:1007400031F49F3F11F41EF45BC10EF4E095E7FB1A +:1007500051C1E92F77D180F3BA1762077307840775 +:10076000950718F071F49EF58FC10EF4E0950B2EED +:10077000BA2FA02D0B01B90190010C01CA01A001F3 +:100780001124FF27591B99F0593F50F4503E68F14E +:100790001A16F040A22F232F342F4427585FF3CF8F +:1007A000469537952795A795F0405395C9F77EF460 +:1007B0001F16BA0B620B730B840BBAF09150A1F0A9 +:1007C000FF0FBB1F661F771F881FC2F70EC0BA0F2F +:1007D000621F731F841F48F4879577956795B795B7 +:1007E000F7959E3F08F0B3CF9395880F08F09927AF +:1007F000EE0F979587950895D9D008F481E0089574 +:100800000CD00FC107D140F0FED030F021F45F3F93 +:1008100019F0F0C0511139C1F3C014D198F39923E4 +:10082000C9F35523B1F3951B550BBB27AA276217B4 +:100830007307840738F09F5F5F4F220F331F441FF9 +:10084000AA1FA9F333D00E2E3AF0E0E830D0915031 +:100850005040E695001CCAF729D0FE2F27D0660F1E +:10086000771F881FBB1F261737074807AB07B0E85D +:1008700009F0BB0B802DBF01FF2793585F4F2AF073 +:100880009E3F510568F0B6C000C15F3FECF3983E53 +:10089000DCF3869577956795B795F7959F5FC9F7D0 +:1008A000880F911D9695879597F90895E1E0660F59 +:1008B000771F881FBB1F621773078407BA0720F0D2 +:1008C000621B730B840BBA0BEE1F88F7E09508953B +:1008D00004D06894B111D9C00895BCD088F09F5756 +:1008E00090F0B92F9927B751A0F0D1F0660F771F7C +:1008F000881F991F1AF0BA95C9F712C0B13081F05C +:10090000C3D0B1E00895C0C0672F782F8827B85FA3 +:1009100039F0B93FCCF3869577956795B395D9F7BC +:100920003EF490958095709561957F4F8F4F9F4FC6 +:100930000895E89409C097FB3EF4909580957095D2 +:1009400061957F4F8F4F9F4F9923A9F0F92F96E91B +:10095000BB279395F695879577956795B795F11190 +:10096000F8CFFAF4BB0F11F460FF1BC06F5F7F4F2D +:100970008F4F9F4F16C0882311F096E911C077233F +:1009800021F09EE8872F762F05C0662371F096E848 +:10099000862F70E060E02AF09A95660F771F881F17 +:1009A000DAF7880F9695879597F90895990F0008BB +:1009B000550FAA0BE0E8FEEF16161706E807F90731 +:1009C000C0F012161306E407F50798F0621B730BCC +:1009D000840B950B39F40A2661F0232B242B252B4D +:1009E00021F408950A2609F4A140A6958FEF811DF0 +:1009F000811D089597F99F6780E870E060E0089591 +:100A00009FEF80EC089500240A9416161706180626 +:100A10000906089500240A94121613061406050602 +:100A20000895092E0394000C11F4882352F0BB0F93 +:100A300040F4BF2B11F460FF04C06F5F7F4F8F4FF6 +:100A40009F4F089557FD9058440F551F59F05F3F31 +:100A500071F04795880F97FB991F61F09F3F79F0E0 +:100A600087950895121613061406551FF2CF469562 +:100A7000F1DF08C0161617061806991FF1CF8695E4 +:100A80007105610508940895E894BB2766277727C8 +:100A9000CB0197F908958ADF08F48FEF08950BD002 +:100AA000C0CFB1DF28F0B6DF18F0952309F0A2CF50 +:100AB000A7CF1124EACFC6DFA0F3959FD1F3950FFE +:100AC00050E0551F629FF001729FBB27F00DB11DD2 +:100AD000639FAA27F00DB11DAA1F649F6627B00D62 +:100AE000A11D661F829F2227B00DA11D621F739F4B +:100AF000B00DA11D621F839FA00D611D221F749F59 +:100B00003327A00D611D231F849F600D211D822F9F +:100B1000762F6A2F11249F5750408AF0E1F08823E6 +:100B20004AF0EE0FFF1FBB1F661F771F881F9150F3 +:100B30005040A9F79E3F510570F05CCFA6CF5F3FB4 +:100B4000ECF3983EDCF3869577956795B795F79526 +:100B5000E7959F5FC1F7FE2B880F911D96958795AE +:100B600097F9089577DFE0F09E37D8F09639B8F41A +:100B70009E3848F4672F782F8827985FF9CF86959D +:100B80007795679593959539D0F3B62FB1706B0F24 +:100B9000711D811D20F4879577956795939502C007 +:100BA0001CC073CF882371F4772321F09850872BD2 +:100BB000762F07C0662311F499270DC09051862B1C +:100BC00070E060E02AF09A95660F771F881FDAF7C9 +:100BD000880F9695879597F908959F3F31F091502A +:100BE00020F4879577956795B795880F911D969511 +:100BF000879597F90895EF920F931F93CF93DF9303 +:100C0000E80147FF02C034E101C034E0E42FFF27D0 +:100C1000E7FDF095F7FF03C0F195E195F109E32EAB +:100C2000022F2E2FAE01F7D1CE01DF91CF911F9170 +:100C30000F91EF900895AEE0B0E0E0E2F6E0F4C48A +:100C40000D891E898F89988D26E02C831A8309834C +:100C500097FF02C080E090E801979E838D83AE01EC +:100C6000455E5F4F698D7A8DCE01019611D04D8121 +:100C70005E8157FD0AC02F813885421753070CF457 +:100C80009A01F801E20FF31F10822E96E4E0E8C407 +:100C9000ACE0B0E0EDE4F6E0B9C47C016B018A01A0 +:100CA000FC0117821682838181FFB0C1CE010196BB +:100CB0004C01F7019381F60193FD859193FF81919A +:100CC0006F01882309F49EC1853239F493FD859123 +:100CD00093FF81916F01853221F4B70190E006D432 +:100CE000E8CF512C312C20E02032A0F48B3269F077 +:100CF00030F4803259F0833269F420612CC08D3297 +:100D000039F0803339F4216026C02260246023C08A +:100D1000286021C027FD27C030ED380F3A3078F425 +:100D200026FF06C0FAE05F9E300D1124532E13C03B +:100D30008AE0389E300D1124332E20620CC08E3292 +:100D400021F426FD5FC1206406C08C3611F42068B2 +:100D500002C0883641F4F60193FD859193FF81919D +:100D60006F018111C1CF982F9F7D9554933028F446 +:100D70000C5F1F4FFFE3F9830DC0833631F08337DB +:100D800071F0833509F057C021C0F8018081898353 +:100D90000E5F1F4F44244394512C540114C038015A +:100DA000F2E06F0E711CF801A080B18026FF03C035 +:100DB000652D70E002C06FEF7FEFC5012C878BD3EC +:100DC0002C0183012C852F77222E16C03801F2E0EA +:100DD0006F0E711CF801A080B18026FF03C0652D45 +:100DE00070E002C06FEF7FEFC5012C8769D32C0143 +:100DF0002C852068222E830123FC19C0832D90E0CE +:100E000048165906A0F4B70180E290E06FD33A94F7 +:100E1000F5CFF50127FC859127FE81915F01B70190 +:100E200090E064D331103A94F1E04F1A5108411424 +:100E3000510479F7DEC0843611F0893631F5F801B6 +:100E400027FF07C060817181828193810C5F1F4FF2 +:100E500008C060817181882777FD8095982F0E5F8B +:100E60001F4F2F76B22E97FF09C0909580957095F1 +:100E700061957F4F8F4F9F4F2068B22E2AE030E060 +:100E8000A40166D3A82EA81843C0853729F42F7E65 +:100E9000B22E2AE030E025C0F22FF97FBF2E8F3628 +:100EA000C1F018F4883579F0ADC0803719F0883773 +:100EB00021F0A8C02F2F2061B22EB4FE0DC08B2DC3 +:100EC0008460B82E09C024FF0AC09F2F9660B92EF7 +:100ED00006C028E030E005C020E130E002C020E19B +:100EE00032E0F801B7FE07C0608171818281938191 +:100EF0000C5F1F4F06C06081718180E090E00E5F43 +:100F00001F4FA40125D3A82EA818FB2DFF77BF2EB5 +:100F1000B6FE0BC02B2D2E7FA51450F4B4FE0AC0D4 +:100F2000B2FC08C02B2D2E7E05C07A2C2B2D03C0C1 +:100F30007A2C01C0752C24FF0DC0FE01EA0DF11DB5 +:100F40008081803311F4297E09C022FF06C073948A +:100F5000739404C0822F867809F0739423FD12C025 +:100F600020FF06C05A2C731418F4530C5718732C16 +:100F7000731460F4B70180E290E02C87B7D27394C9 +:100F80002C85F6CF731410F4371801C0312C24FFD0 +:100F900011C0B70180E390E02C87A8D22C8522FFF6 +:100FA00016C021FF03C088E590E002C088E790E00A +:100FB000B7010CC0822F867851F021FD02C080E27B +:100FC00001C08BE227FD8DE2B70190E08FD2A5141E +:100FD00030F4B70180E390E089D25A94F8CFAA9414 +:100FE000F401EA0DF11D8081B70190E07FD2A110DC +:100FF000F6CF332009F45DCEB70180E290E076D2DF +:101000003A94F7CFF7018681978102C08FEF9FEF67 +:101010002C96E2E117C36F927F929F92AF92BF929C +:10102000CF92DF92EF92FF920F931F93CF93DF93B4 +:10103000CDB7DEB729970FB6F894DEBF0FBECDBF90 +:101040006A01B22E102F0C3320F4FF24F394F00E1B +:1010500002C04CE3F42E0F2D27E0AE014F5F5F4F2F +:1010600057D17981272F2970213031F0E1FC06C05A +:10107000E0FC06C060E005C06DE203C06BE201C0A9 +:1010800060E2AE2DA07173FF36C0662311F084E0DC +:1010900001C083E08B1510F4B81A01C0B12CA11166 +:1010A0000BC0F6018B2D90E2882319F091938150AB +:1010B000FBCFCB0CD11CB12C662331F0F601608341 +:1010C00096012F5F3F4F6901C6010396E2FE05C0FE +:1010D0002EE4F601208331E404C02EE6F6012083DD +:1010E00031E631832283FC012B2D30E22223F1F102 +:1010F00031932150FBCF72FF40C0662311F084E092 +:1011000001C083E08B1510F4B81A01C0B12CA111F5 +:101110000BC0F6018B2D90E2882319F0919381503A +:10112000FBCFCB0CD11CB12C662331F0F6016083D0 +:1011300096012F5F3F4F6901C6010396E2FE07C08B +:1011400029E4F60120832EE4218326E406C029E663 +:10115000F60120832EE6218326E62283FC012B2D37 +:1011600030E2222319F031932150FBCFFC01EB0D2B +:10117000F11D10828EEF9FEFB7C0B1E0611101C089 +:10118000B0E04B2F50E01816190624F49C012F5F95 +:101190003F4F02C021E030E0240F351F112329F01A +:1011A000412F50E04F5F5F4F02C040E050E0420FE0 +:1011B000531F2B2D30E04217530714F4B41A01C00B +:1011C000B12C2E2D287159F4F6012B2D30E222235B +:1011D00019F031932150FBCFCB0CD11CB12CBB2388 +:1011E00031F0F601608396012F5F3F4F6901A11135 +:1011F0000BC0F6012B2D30E3222319F0319321503F +:10120000FBCFCB0CD11CB12CF80E0A81372F3071DB +:10121000A32E74FF03C0013309F4FA941F142CF4B5 +:101220002F2D293018F028E001C021E0682F392F38 +:1012300097FF02C060E030E0462F532F612C712CE5 +:101240003EE2932EBC01621B71099B01DC01A41BD1 +:10125000B50BE1E0F0E0EC0FFD1FAE0FBF1FE12E7C +:10126000F12CF194E194F1084F3FFFEF5F0731F467 +:10127000F6019082B6016F5F7F4F6B01841795076F +:101280004CF02417350734F4BD01660D771DFB01C2 +:10129000118101C010E341505109FFEF6F1A7F0A1D +:1012A000B6016F5F7F4F4E155F0524F0F601108386 +:1012B0006B01DACF4817590739F4063320F40533A8 +:1012C00019F4A11001C011E3F6011083FB018B2D6D +:1012D00090E2882319F091938150FBCFFB01EB0D35 +:1012E000F11D108280E090E029960FB6F894DEBFE1 +:1012F0000FBECDBFDF91CF911F910F91FF90EF9067 +:10130000DF90CF90BF90AF909F907F906F900895A7 +:10131000283008F027E03327DA01990F311D87FDC7 +:10132000916000966105710539F432602E5F3D933E +:1013300030E32A95E1F708959F3F30F0803871053A +:10134000610509F03C5F3C5F3D93913008F0806897 +:10135000911DDF93CF931F930F93FF92EF92192F5D +:10136000987F9695E92F96959695E90FFF27EE536E +:10137000FF4F99273327EE24FF24A701E7010590AB +:101380000894079428F4360FE71EF81E491F511DD4 +:10139000660F771F881F991F0694A1F70590079481 +:1013A00028F4E70EF81E491F561FC11D770F881F2E +:1013B000991F661F0694A1F70590079428F4F80E6C +:1013C000491F561FC71FD11D880F991F661F771F02 +:1013D0000694A1F70590079420F4490F561FC71FE4 +:1013E000D81F990F661F771F881F0694A9F784914D +:1013F0001095177041F0D695C79557954795F79476 +:10140000E7941A95C1F7E8E6F0E068941590159115 +:1014100035916591959105907FE27395E118F10AF8 +:10142000430B560BC90BD009C0F7E10CF11E431F4B +:10143000561FC91FD01D7EF4703311F48A95E6CF74 +:10144000E894015030F0080F0AF40027021708F45E +:10145000202F2395022F7A3328F079E37D932A9564 +:10146000E9F710C07D932A9589F6069497956795BC +:10147000379517951794E118F10A430B560BC90BD2 +:10148000D00998F023957E9173957A3308F070E334 +:101490007C932013B8F77E9170617D9330F0839533 +:1014A00071E37D9370E32A95E1F71124EF90FF90AB +:1014B0000F911F91CF91DF91992787FD9095089506 +:1014C000FC010590615070400110D8F7809590950F +:1014D0008E0F9F1F0895FC01615070400190011014 +:1014E000D8F7809590958E0F9F1F08950F931F93A7 +:1014F000CF93DF93182F092FEB018B8181FD03C060 +:101500008FEF9FEF20C082FF10C04E815F812C8142 +:101510003D81421753077CF4E881F9819F012F5FD9 +:101520003F4F39832883108306C0E885F985812FD2 +:101530000995892B29F72E813F812F5F3F4F3F83EC +:101540002E83812F902FDF91CF911F910F910895BE +:10155000FA01AA27283051F1203181F1E8946F93E4 +:101560006E7F6E5F7F4F8F4F9F4FAF4FB1E03ED08A +:10157000B4E03CD0670F781F891F9A1FA11D680F28 +:10158000791F8A1F911DA11D6A0F711D811D911D5B +:10159000A11D20D009F468943F912AE0269F1124D0 +:1015A0003019305D3193DEF6CF010895462F477034 +:1015B000405D4193B3E00FD0C9F7F6CF462F4F708F +:1015C000405D4A3318F0495D31FD4052419302D0ED +:1015D000A9F7EACFB4E0A695979587957795679593 +:1015E000BA95C9F700976105710508959B01AC0193 +:1015F0000A2E06945795479537952795BA95C9F7BA +:10160000620F731F841F951FA01D08952F923F9294 +:101610004F925F926F927F928F929F92AF92BF9202 +:10162000CF92DF92EF92FF920F931F93CF93DF93AE +:10163000CDB7DEB7CA1BDB0B0FB6F894DEBF0FBE0B +:10164000CDBF09942A88398848885F846E847D8458 +:101650008C849B84AA84B984C884DF80EE80FD805A +:101660000C811B81AA81B981CE0FD11D0FB6F894D0 +:0E167000DEBF0FBECDBFED010895F894FFCF91 +:10167E005469202533642043202564202020546F94 +:10168E002025336420432025640D0A004C20257349 +:10169E002020282573290D0A00C7FF000048C2C765 +:1016AE0001000000007B050000C842D80800004879 +:1016BE0043E70B00009643B20E0000C8430400003F +:1016CE0000004005003333F33F06006666E63F0830 +:1016DE00009A99D93F0A00CDCCCC3F0C000000C037 +:1016EE003F0F003333B33F14006666A63F1C009ACB +:1016FE0099993F2800CDCC8C3F44003333833F90E3 +:10170E00010000803F200348E17A3F5C0366666675 +:08171E003F7003CDCC4C3F00ED :00000001FF diff --git a/lambda/sensors.c b/lambda/sensors.c new file mode 100644 index 0000000..cf87b12 --- /dev/null +++ b/lambda/sensors.c @@ -0,0 +1,125 @@ +/* + * sensors.c + * + * Created on: 02.03.2015 + * Author: dode@luniks.net + * + * TODO put defines in makefile + */ +#include +#include +#include +#include +#include "sensors.h" + +// #define AREF_MV 4850 +#define AREF_MV 5000 +#define ADC_OFFSET_MV 7 +// #define TMP_OP_OFFSET_MV 441 +#define TMP_OP_OFFSET_MV 454 + +static const char* lean = "Mager"; +static const char* ideal = "Ideal"; +static const char* rich = "Fett!"; + +/** + * Table used to look up the lambda value at 12 V heater voltage + * and 220°C exhaust gas temperature. Most values are approximated + * from the characteristic curve in the datasheet. + * TODO equation? real table? + */ +static const tableEntry lambdaTable[] = { + { 4, 2.0 }, + { 5, 1.9 }, + { 6, 1.8 }, + { 8, 1.7 }, + { 10, 1.6 }, + { 12, 1.5 }, + { 15, 1.4 }, + { 20, 1.3 }, + { 28, 1.2 }, + { 40, 1.1 }, + { 68, 1.025 }, + { 400, 1.0 }, + { 800, 0.98 }, + { 860, 0.9 }, + { 880, 0.8 } +}; + +static const tableEntry tempOTable[] = { + { -57, -50 }, + { 455, 0 }, + { 1403, 100 }, + { 2264, 200 }, + { 3047, 300 }, + { 3762, 400 } +}; + +int getVoltage(int port) { + + ADMUX = (0b11110000 & ADMUX) | port; + + unsigned long overValue = 0; + for (int i = 0; i < 16; i++) { + sleep_mode(); + overValue += ADC; + } + float mV = ((overValue >> 2) * AREF_MV / 4096) + ADC_OFFSET_MV; + + return mV; +} + +float toLambda(float mV) { + int length = sizeof(lambdaTable) / sizeof(lambdaTable[0]); + float lambda = lookupLinInter(mV, lambdaTable, length); + + return lambda; +} + +int toTempI(float mV) { + int temp = round(mV / 5); + + return temp; +} + +int toTempO(float mV) { + int length = sizeof(tempOTable) / sizeof(tempOTable[0]); + float c = lookupLinInter(mV, tempOTable, length); + int temp = round(c); + + return temp; +} + +float lookupLinInter(float mV, const tableEntry table[], int length) { + if (mV < table[0].mV) { + return table[0].value; + } else if (mV > table[length - 1].mV) { + return table[length - 1].value; + } + + int i = 0; + for (; i < length - 1; i++) { + if (table[i + 1].mV > mV) { + break; + } + } + + float diffVoltage = table[i + 1].mV - table[i].mV; + float diffValue = table[i + 1].value - table[i].value; + float value = table[i].value + + (mV - table[i].mV) * diffValue / diffVoltage; + + return value; +} + +const char* toInfo(float lambda) { + if (lambda > 1.5) { + return lean; + } else if (lambda > 1.3 && lambda <= 1.5) { + return ideal; + } else { + return rich; + } +} + + diff --git a/lambda/sensors.h b/lambda/sensors.h new file mode 100644 index 0000000..03536cc --- /dev/null +++ b/lambda/sensors.h @@ -0,0 +1,33 @@ +/* + * sensors.h + * + * Created on: 02.03.2015 + * Author: dode@luniks.net + */ +typedef struct { + const int mV; + const float value; +} tableEntry; + +int getVoltage(int port); + +float toLambda(float mV); + +/** + * 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. + */ +int toTempI(float mV); + +int toTempO(float mV); + +/** + * Returns the value corresponding to the given voltage + * from the lookup table using linear interpolation. + * Thanks to http://stackoverflow.com/a/7091629/709426 and + * http://en.wikipedia.org/wiki/Linear_interpolation + */ +float lookupLinInter(float mV, const tableEntry table[], int length); + +const char* toInfo(float lambda);