Spørsmål:
Array + Serial Monitor Problem
EoinScully
2016-03-23 21:36:37 UTC
view on stackexchange narkive permalink

Jeg har skrevet en Arduino-skisse som konverterer en analog spenning til en temperatur ved hjelp av en oppslagstabell - koden nedenfor. Jeg har nylig endret LUT til å inkludere flere verdier, men helt siden den gangen seriell skjerm vil ikke skrive ut feilsøkingsuttalelsene mine osv. Så jeg begrenset antall elementer i matrisen, og det var tilbake til det normale. Men når jeg skriver inn flere feilsøkingsuttalelser ved hjelp av den serielle skjermen, er det søppel før uttalelsene mine (fremdeles lesbare, men når jeg analyserer det selv) eller i begynnelsen blir ingenting skrevet ut. Jeg har sjekket at de to overføringshastighetene er de samme, men Jeg synes det er merkelig at hvis jeg tar noen av utskriftene mine (), går det greit. Testet alt annet med et "Hello World" -eksempel, men i de enkle eksemplene fungerer monitoren bra.

  / * ##### PROSJEKTBESKRIVELSE ##### Måler temperaturen med en Arduino og NTC Thermistor (10Kohms @ 25 ^ C) i en spenningsdelerkrets Siden responsen er ikke-lineær, brukes en oppslagstabell siden det er en ikke-lineær respons Verdiene i LUT er de forutsagte verdiene til ADC ved temperatur mellom 6 ^ C og 40 ^ C LUT er avledet fra kalibreringstestene * / // ##### CONSTANTS ##### const int constDelay = 3000; // konstant forsinkelse for programkonst int constNoOfAnaloguePins = 2; // antall analoge pinner som skal leses const int errReturn = 998; // feilverdi som returneres *** CHECK FOR CONSENTENT VALUE ACROSS FUNCTIONS *** // ##### VARIABLE DEKLARATIONS ##### float avgTempC; // float var for å lagre gjennomsnittet av flere tempavlesninger // ##### OPPSETTSPROSEDYRE ##### ugyldig oppsett () {// dette er oppsettdelen av prosjektet ditt - dette er for kode som bare kjøres EN gang ved oppstart for (int analogPinCounter = 0; analogPinCounter < constNoOfAnaloguePins; analogPinCounter ++) // for loop for å sette opp mange analoge pinner {
pinMode (analogPinCounter, INPUT); // angi pin-modus for den analoge termistorinngangen} // end for analogReference (INTERNAL); // bruk intervallvotumet på 1.1V for ADC-oppløsningen Serial.begin (9600); // baud rate for seriell skjerm} // end Setup-funksjon // ##### LOOP PROCEDURE ##### void loop () {// dette er hoveddelen av prosjektet - legg all kontinuerlig kjørende kode her for ( int analoguePinCounter = 0; analogPinCounter < constNoOfAnaloguePins; analoguePinCounter ++) // for loop for å ta tempavlesninger fra hver analoge pin {// få LPF gjennomsnittlig avlesning over 25 prøver avgTempC = LPF (analogPinCounter, 25); // skriv ut avlesningene hvis (avgTempC < float (errReturn)) // det ikke har vært noen vikarer utenfor området *** KONTROLLER VERDIEN RETURERT FRA LPF HVIS FEIL *** {Serial.print (analogPinCounter); Serial.print ("| Gjennomsnittlig temperaturavlesning ="); Serial.print (avgTempC, 2); Serial.println ("degC."); Serial.println ("-------------------------"); } ellers // avgTempC har returnert X som indikerer en feil {Serial.print (analogPinCounter); Serial.println ("** FEIL I LESING GJENNOMSNITT TEMP **"); Serial.println ("-------------------------"); forsinkelse (10); } // slutt hvis forsinkelse (constDelay / 2); // vent X / 2 sekunder til du går videre til neste sensor} // slutt for forsinkelse (constDelay); // vent X sekunder til neste sløyfe} // slutt Loop-funksjon / * ##### LAV PASS FILTERBESKRIVELSE ##### Denne funksjonen er en LPF for utjevning av signaler eller gjennomsnitt. Den bruker en statisk buffer for å lagre den siste "n" -avlesninger, og hver gang den kalles, blir den eldste avlesningen kastet, den nye avlesningen lagt til, og stakkens gjennomsnittsverdi returneres. Bufferstørrelsen kan justeres av brukeren, men er begrenset mellom 2 og 50
En initialiseringsfunksjon fyller hele bufferen med inngangsverdien. Dette er nyttig når LPF-funksjonen kalles for første gang. Merk: For å oppfylle definisjonen av en ekte LPF, må denne funksjonen kalles med jevne mellomrom. * / // ##### FUNKSJON FOR FILTER MED LAV PASS ##### float LPF (int pinAnalogue, int bufferSize) {// ## PRE PROCESSOR ## #define bufferCap 75 // maximum buffer capacity // ## CONSTANTS ## const int constMAXERRORS = 5; // maks antall feil som kan oppstå const int errReturn = 998; // verdi retur hvis det er en feil // ## VARIABLES ## float tempC; // var for å lagre øyeblikkelig temp statisk floatbuffer [bufferCap]; // array for å fungere som en "stabel" med temp-verdier *** TRENGER DET Å VÆRE STATISK NÅ? *** float tempSum; // for å lagre summen av temperaturen float output; // returverdi av LPF som er gjennomsnittet av tempavlesningene int errCounter = 0; // initialiser feilteller til 0 // sørg for at bufferstørrelsen er mellom området bufferSize = constrain (bufferSize, 2, bufferCap); for (int i = 0; i<bufferSize; i ++) // for loop for å lagre temps i buffer array {tempC = getTempFloat (pinAnalogue); // ringefunksjon for å få temperatur fra pin hvis ((tempC > -errReturn) && (tempC < errReturn)) // ingen feil {buffer [i] = tempC; // lagre temp-verdi i matrisen} annet // feil {errCounter ++; // økningsteller for antall feilavlesninger i--; // reduksjonsteller for å ikke hoppe over en prøveindeks hvis (errCounter > constMAXERRORS) {return (errReturn + 1.0); // returner feilverdien + 1} // slutt hvis} // slutt hvis forsinkelse (25); // tillate ADC å slå seg ned} // end for // beregne gjeldende stakk gjennomsnittlig tempSum = 0; // initialiser sum totalt
for (int i = 0; i<bufferSize; i ++) // gå gjennom stack array {tempSum = tempSum + buffer [i]; // total opp målinger} // slutt for // gjennomsnittlig sumoutput = tempSum / bufferSize; retur (utgang); } // slutt LPF-funksjon / * ##### FÅ TEMP FLOAT BESKRIVELSE ##### Denne funksjonen konverterer en termistoravlesning til en tilsvarende temp i ^ C Termistoren er innlemmet i en spenningsdelerkrets: + Vref --- [Termistor] --- + - [1,8K] --- GND | ADC @ thermPin ADC-verdier ble beregnet eksternt fra kalibreringstabellen ved hjelp av: ADC = 1023 * 10000 / (Rtherm + 10000) LUT er en serie med heltallskonstanter som inneholder de forutsagte ADC-verdiene for alle temperaturer mellom + 6 ^ C til + 40,5 ^ C. Matriseindeksen starter på null, som tilsvarer en temperatur på + 6 ^ C. En lineær interpolasjon mellom de to nærmeste oppføringene utføres for å gi en finere utgangsoppløsning. * / float getTempFloat (int thermPin) {// ## CONSTANTS ## / * 1K8 * / const int constLUTArraySize = 431; const int LUT_Therm [constLUTArraySize] = // LUT inneholder ADC-verdier {223, 224, 225, 226, 227, 228, 229, 230, 231, 232, // 7 ^ C til 7.9 ^ C 233, 234, 235, 236 , 237, 238, 239, 240, 241, 242, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 255, 256, 257, 258, 259, 260, 261, 263, 264 , 265, 266, 267, 268, 269, 271, 272, 273, 274, 275, 277, 278, 279, 280, 281, 283, 284, 285, 286, 287, 289, 290, 291, 292, 294 , 295, 296, 297, 299, 300, 301, // 13 ^ C til 13,9 ^ C 302, 304, 305, 306, 308, 309, 310, 312, 313, 314, 315, 317, 318, 319, 321, 322, 323, 325, 326, 327, 329, 330, 332, 333, 334, 336, 337, 338, 340, 341, 343, 344, 345, 347, 348, 350, 351, 353, 354, 355, 357, 358, 360, 361, 363, 364, 366, 367, 369, 370,
371, 373, 374, 376, 377, 379, 380, 382, 383, 385,        387, 388, 390, 391, 393, 394, 396, 397, 399, 400,        402, 404, 405, 407, 408, 410, 411, 413, 415, 416,        418, 419, 421, 423, 424, 426, 428, 429, 431, 433,        434, 436, 438, 439, 441, 443, 444, 446, 448, 449,        451, 453, 454, 456, 458, 460, 461, 463, 465, 466,        468, 470, 472, 473, 475, 477, 479, 480, 482, 484,        486, 488, 489, 491, 493, 495, 497, 498, 500, 502,        504, 506, 507, 509, 511, 513, 515, 517, 519, 520,        522, 524, 526, 528, 530, 532, 534, 535, 537, 539,        541, 543, 545, 547, 549, 551, 553, 555, 557, 559,        560, 562, 564, 566, 568, 570, 572, 574, 576, 578,         580, 582, 584, 586, 588, 590, 592, 594, 596, 598,        600, 602, 604, 606, 608, 611, 613, 615, 617, 619,        621, 623, 625, 627, 629, 631, 633, 635, 638, 640,        642, 644, 646, 648, 650, 652, 655, 657, 659, 661,        663, 665, 667, 670, 672, 674, 676, 678, 680, 683,        685, 687, 689, 691, 694, 696, 698, 700, 702, 705,        707, 709, 711, 714, 716, 718, 720, 723, 725, 727,        729, 732, 734, 736, 738, 741, 743, 745, 747, 750,         752, 754, 757, 759, 761, 764, 766, 768, 771, 773,        775, 778, 780, 782, 785, 787, 789, 792, 794, 796,        799, 801, 803, 806, 808, 811, 813, 815, 818, 820,        822, 825, 827, 830, 832, 834, 837, 839, 842, 844,        847, 849, 851, 854, 856, 859, 861, 864, 866, 868,        871, 873, 876, 878, 881, 883, 886, 888, 891, 893,        896, 898, 901, 903, 906, 908, 911, 913, 916, 918,         921, 923, 926, 928, 931, 933, 936, 938, 941, 943,        946, 948, 951, 953, 956, 958, 961, 963, 966, 969,        971, 974, 976, 979, 981, 984, 987, 989, 992, 994,        997, 999, 1002, 1005, 1007, 1010, 1012, 1015, 1017, 1020, //40^C to 49.9^C        1023                                                     //50^C      };      const int errReturn = 998; //error value that is returned      //##VARIABLES##
flyte _tempC; // mellomresultater + endelig temperaturreturverdi int ADC_Lo; // den lavere ADC-samsvaringsverdien int ADC_Hi; // den høyere ADC-samsvaringsverdien flyter Temp_Lo; // det lavere tallet som samsvarer med temperaturen int mapTemp_Lo; // det nedre tallet som skal legges inn i kartfunksjonen flyter Temp_Hi; // det høyere antall samsvarende temperatur int mapTemp_Hi; // det høyere tallet som vil bli lagt inn i kartfunksjonen // prep ADC på den bestemte analoge pinnen for å sortere ut multiplexing etc analogRead (thermPin); forsinkelse (10); // få rå ADC-verdi fra VDR int thermValue = analogRead (thermPin); //Serial.println(thermValue); /*Serial.print("PinNo: "); Serial.println (thermPin); * / Serial.print ("ADC:"); Serial.println (thermValue); // returner dummyverdi hvis sensoravlesningen faller utenfor LUT hvis (thermValue < LUT_Therm [0]) // mindre enn den minste ADC-verdien _tempC = -errReturn-1; // under dummy-verdi ellers hvis (thermValue > LUT_Therm [constLUTArraySize-1]) // mer enn den største ADC-verdien _tempC = errReturn + 1; // over dummy-verdi ellers // verdi faller i LUT-området {for (int i = 0; i<constLUTArraySize; i ++) // gå gjennom LUT og se etter en samsvar {if (LUT_Therm [i] > thermValue) // LUT-verdi er større enn avlesningen {// finn nærmeste høyere ADC-verdi ADC_Hi = LUT_Therm [i]; // registrere nærmeste høyere temperatur Temp_Hi = float (i / 10) + 13.0; // konverter til temp // få nærmeste lavere temperatur - ta den nederste tabellgrensen i betraktning hvis (i! = 0) // generelt tilfelle -> så lenge det ikke er den første oppføringen {ADC_Lo = LUT_Therm [i-1 ]; // lagre forrige matriseelement som lav Temp_Lo = float (i / 10) + 13,0 - 0,1; // konvertere til temp
} annet // spesialtilfelle ->-teller = 0 dvs. første matriseoppføring {ADC_Lo = LUT_Therm [i]; // lagre det første matriseelementet Temp_Lo = i - float (i / 10) + 13.0; // konvertere til temp} // slutt hvis // interpolere temperaturverdien for større presisjon // NB! Kartfunksjonen bruker ikke matematikk med flytende punkt, så int-verdiene til temp multipliseres med 100 og resultatet blir deretter delt på 100 mapTemp_Lo = Temp_Lo * 100; mapTemp_Hi = Temp_Hi * 100; _tempC = float (map (thermValue, ADC_Lo, ADC_Hi, mapTemp_Lo, mapTemp_Hi)) / 100; gå i stykker; // exit for loop etter at kampen er oppdaget} // end if} // end for} // end if return (_tempC); } // slutt getTempFloat-funksjon  

I denne spesielle skissen blir det ikke sett utdata på seriell skjerm. Har noen kommet over dette før eller har noen ideer om hvordan jeg kan fikse dette?

Prøv å sette dataene for `LUT_Therm` i program eller komprimere det på en eller annen måte
... fordi det høres ut som om du har gått tom for lagringsplass.
Tre svar:
sa_leinad
2016-03-23 22:36:18 UTC
view on stackexchange narkive permalink

Du har sannsynligvis gått tom for RAM.

Du har 431 heltall bare i oppslagstabellen. Det tilsvarer 862 byte SRAM. Du har også en buffer på 75 flottører, som tilsvarer 300 byte. Dette kommer i tillegg til alle dine andre variabler og funksjonsanrop.

Arduino Uno har bare 2KB SRAM.

Løsninger:
1) Flytt LUT til Flash (dvs. programplass) ved hjelp av PROGMEM-nøkkelordet (like før tilsvarer sign):

  const int LUT_Therm [constLUTArraySize] PROGMEM = // LUT inneholder ADC-verdier  

2) Bruk en Arduino med større SRAM-mengde.

  • Arduino Mega - 8KB SRAM
  • Arduino ZERO - 32KB SRAM
  • Arduino Due - 96KB SRAM
  • Arduino MKR 1000 / 1010/1400 / ZERO - 32KB SRAM
slash-dev
2016-03-23 22:57:54 UTC
view on stackexchange narkive permalink

Bruk makroen F () for alle strengene du skriver med dobbel sitat. Bytt linjer slik:

  Serial.println ("degC.");  

... til dette:

  Serial.println (F ("degC."));  

Dette vil spare omtrent 100 byte RAM.

Og som BrettAM foreslo, legg tabellen inn i PROGMEM:

  const int LUT_Therm [constLUTArraySize] PROGMEM = // LUT inneholder ADC-verdier {223, 224, 225, 226, 227, 228, 229, 230, 231, 232, // 7 ^ C til 7.9 ^ C  

Dette krever at du endrer hvordan du får tilgang til arrayet, fra dette:

  if (thermValue < LUT_Therm [0]) / / mindre enn den minste ADC-verdien  

... til dette:

  hvis (thermValue < (int) pgm_read_word (&LUT_Therm [0])) / / mindre enn den minste ADC-verdien  

Legg merke til rollebesetningen, funksjonsanropet og ampersand viklet rundt ønsket matriseelement. Du må erstatte all bruk av matrisen med denne sekvensen. Du kan også lese den inn i en lokal int og deretter bruke den normalt:

  int lut_therm = (int) pgm_read_word (LUT_Therm [i]); // les den inn hvis (lut_therm > thermValue) // LUT-verdien er større enn avlesningen  

Dette sparer nesten 1000 byte RAM! Den rapporterte binære skissestørrelsen går opp med samme mengde [1] .

Jeg måtte trekke bordet ut fra innsiden getTempFloat , til filomfanget. Her er den komplette skissen med disse modene:

  / * ##### PROSJEKTBESKRIVELSE ##### Måler temperatur med en Arduino og NTC termistor (10Kohms @ 25 ^ C) i en spenning delerkrets Siden responsen er ikke-lineær, brukes en oppslagstabell siden det er en ikke-lineær respons Verdiene i LUT er de forutsagte verdiene til ADC ved temperatur mellom 6 ^ C og 40 ^ CLUT er avledet fra kalibreringstestene * /// ##### KONSTANTER #####
const int constDelay = 3000; // konstant forsinkelse for programkonst int constNoOfAnaloguePins = 2; // antall analoge pinner som skal lesekonst int errReturn = 998; // feilverdi som returneres *** CHECK FOR CONSENTENT VALUE ACROSS FUNCTIONS *** // ##### VARIABLE DEKLARATIONS ##### float avgTempC; // float var for å lagre gjennomsnittet av flere tempavlesninger // ##### OPPSETTSPROSEDYRE ##### ugyldig oppsett () {// dette er oppsettdelen av prosjektet ditt - dette er for kode som bare kjøres EN gang ved oppstart for (int analoguePinCounter = 0; analogPinCounter < constNoOfAnaloguePins; analogPinCounter ++) // for loop for å sette opp mange analoge pinner {pinMode (analogPinCounter, INPUT); // angi pin-modus for den analoge termistorinngangen} // end for analogReference (INTERNAL); // bruk intervallvotumet på 1.1V for ADC-oppløsningen Serial.begin (9600); // baud rate for seriell skjerm} // end Setup-funksjon // ##### LOOP PROCEDURE ##### void loop () {// dette er hoveddelen av prosjektet - legg all kontinuerlig kjørende kode her for ( int analoguePinCounter = 0; analogPinCounter < constNoOfAnaloguePins; analogPinCounter ++) // for loop for å ta tempavlesninger fra hver analog pin {// få LPF gjennomsnittlig avlesning over 25 prøver avgTempC = LPF (analogPinCounter, 25); // skriv ut avlesningene hvis (avgTempC < float (errReturn)) // det ikke har vært noen vikarer utenfor området *** KONTROLLER VERDIEN RETURERT FRA LPF HVIS FEIL *** {Serial.print (analogPinCounter); Serial.print (F ("| Gjennomsnittlig temperaturavlesning =")); Serial.print (avgTempC, 2); Serial.println (F ("degC.")); Serial.println (F ("-------------------------"); } ellers // avgTempC har returnert X som indikerer en feil {Serial.print (analogPinCounter); Serial.println (F ("** FEIL I LESING GJENNOMSNITT TEMP **")); Serial.println (F ("-------------------------"); forsinkelse (10); } // slutt hvis forsinkelse (constDelay / 2); // vent X / 2 sekunder til du går videre til neste sensor
} // slutt for forsinkelse (constDelay); // vent X sekunder til neste sløyfe} // slutt Loop-funksjon / * ##### LAV PASS FILTER BESKRIVELSE ##### Denne funksjonen er en LPF for utjevning av signaler eller gjennomsnittsverdier. Den bruker en statisk buffer for å lagre den siste " n "avlesninger, og hver gang det kalles, blir den eldste avlesningen kastet, den nye avlesningen lagt til, og stakkens gjennomsnittsverdi returneres. Bufferstørrelsen kan justeres av brukeren, men er begrenset mellom 2 og 50 En initialiseringsfunksjon fyller hele buffer med inngangsverdien. Dette er nyttig når LPF-funksjonen kalles for første gang. Merk: For å oppfylle definisjonen av en ekte LPF, må denne funksjonen kalles med jevne mellomrom. * /// ##### LOW PASS FILTER FUNCTION ### ## float LPF (int pinAnalogue, int bufferSize) {// ## PRE PROCESSOR ## #define bufferCap 75 // maximum buffer capacity // ## CONSTANTS ## const int constMAXERRORS = 5; // maks antall feil som kan oppstå // ## VARIABLES ## float tempC; // var for å lagre øyeblikkelig temp statisk floatbuffer [bufferCap]; // array for å fungere som en "stabel" med temp-verdier *** TRENGER DET Å VÆRE STATISK NÅ? *** float tempSum; // for å lagre summen av temperaturen float output; // returverdi av LPF som er gjennomsnittet av tempavlesningene int errCounter = 0; // initialiser feilteller til 0 // sørg for at bufferstørrelsen er mellom området bufferSize = constrain (bufferSize, 2, bufferCap); for (int i = 0; i<bufferSize; i ++) // for loop for å lagre temps i buffer array {tempC = getTempFloat (pinAnalogue); // ringefunksjon for å få temperatur fra pin hvis ((tempC > -errReturn) && (tempC < errReturn)) // ingen feil {buffer [i] = tempC; // lagre temp-verdi i matrisen} annet // feil {errCounter ++; // økningsteller for antall feilavlesninger i--; // reduksjonsteller for å ikke hoppe over en prøveindeks hvis (errCounter > constMAXERRORS) {return (errReturn + 1.0); // returner feilverdien + 1
} // slutt hvis} // slutt hvis forsinkelse (25); // tillate ADC å slå seg ned} // end for // beregne gjeldende stakk gjennomsnittlig tempSum = 0; // initialiser sum totalt for (int i = 0; i<bufferSize; i ++) // gå gjennom stack array {tempSum = tempSum + buffer [i]; // total opp målinger} // slutt for // gjennomsnittlig sumoutput = tempSum / bufferSize; retur (utgang);} // slutt LPF-funksjon / * ##### FÅ TEMP FLOAT BESKRIVELSE ##### Denne funksjonen konverterer en termistoravlesning til en tilsvarende temp i ^ C Termistoren er innlemmet i en spenningsdelerkrets: + Vref --- [Thermistor] --- + - [1.8K] --- GND | ADC @ thermPinADC Verdier ble beregnet eksternt fra kalibreringstabellen ved bruk av: ADC = 1023 * 10000 / (Rtherm + 10000) LUT er en serie med heltallskonstanter som inneholder de forutsagte ADC-verdiene for alle temperaturer mellom + 6 ^ C til + 40,5 ^ C .Arrayindeksen starter på null, som tilsvarer en temperatur på + 6 ^ CA lineær interpolasjon mellom de to nærmeste oppføringene blir utført for å gi en finere utgangsoppløsning. * /// ## CONSTANTS ## / * 1K8 * / const int LUT_Therm [] PROGMEM = // LUT inneholder ADC-verdier {223, 224, 225, 226, 227, 228, 229, 230, 231, 232, // 7 ^ C til 7.9 ^ C 233, 234, 235, 236, 237 , 238, 239, 240, 241, 242, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 255, 256, 257, 258, 259, 260, 261, 263, 264, 265 , 266, 267, 268, 269, 271, 272, 273, 274, 275, 277, 278, 279, 280, 281, 283, 284, 285, 286, 287, 289, 290, 291, 292, 294, 295 , 296, 297, 299, 300, 301, // 13 ^ C til 13,9 ^ C 302, 304, 305, 306, 308, 309, 310, 312, 313, 314, 315, 3 17, 318, 319, 321, 322, 323, 325, 326, 327, 329, 330, 332, 333, 334, 336, 337, 338, 340, 341, 343, 344, 345, 347, 348, 350, 351, 353, 354, 355, 357, 358, 360, 361, 363, 364, 366, 367, 369, 370, 371, 373, 374, 376, 377, 379, 380, 382, ​​383, 385, 387, 388, 390, 391, 393, 394, 396, 397, 399, 400, 402, 404, 405, 407, 408, 410, 411, 413, 415, 416,
418, 419, 421, 423, 424, 426, 428, 429, 431, 433,  434, 436, 438, 439, 441, 443, 444, 446, 448, 449,  451, 453, 454, 456, 458, 460, 461, 463, 465, 466,  468, 470, 472, 473, 475, 477, 479, 480, 482, 484,  486, 488, 489, 491, 493, 495, 497, 498, 500, 502,  504, 506, 507, 509, 511, 513, 515, 517, 519, 520,  522, 524, 526, 528, 530, 532, 534, 535, 537, 539,  541, 543, 545, 547, 549, 551, 553, 555, 557, 559,  560, 562, 564, 566, 568, 570, 572, 574, 576, 578,   580, 582, 584, 586, 588, 590, 592, 594, 596, 598,  600, 602, 604, 606, 608, 611, 613, 615, 617, 619,  621, 623, 625, 627, 629, 631, 633, 635, 638, 640,  642, 644, 646, 648, 650, 652, 655, 657, 659, 661,  663, 665, 667, 670, 672, 674, 676, 678, 680, 683,  685, 687, 689, 691, 694, 696, 698, 700, 702, 705,  707, 709, 711, 714, 716, 718, 720, 723, 725, 727,  729, 732, 734, 736, 738, 741, 743, 745, 747, 750,   752, 754, 757, 759, 761, 764, 766, 768, 771, 773,  775, 778, 780, 782, 785, 787, 789, 792, 794, 796,  799, 801, 803, 806, 808, 811, 813, 815, 818, 820,  822, 825, 827, 830, 832, 834, 837, 839, 842, 844,  847, 849, 851, 854, 856, 859, 861, 864, 866, 868,  871, 873, 876, 878, 881, 883, 886, 888, 891, 893,  896, 898, 901, 903, 906, 908, 911, 913, 916, 918,   921, 923, 926, 928, 931, 933, 936, 938, 941, 943,  946, 948, 951, 953, 956, 958, 961, 963, 966, 969,  971, 974, 976, 979, 981, 984, 987, 989, 992, 994,  997, 999, 1002, 1005, 1007, 1010, 1012, 1015, 1017, 1020, //40^C to 49.9^C  1023                                                     //50^C};const int constLUTArraySize = sizeof(LUT_Therm)/sizeof(LUT_Therm[0]);float getTempFloat (int thermPin){  //##VARIABLES##  float _tempC; //intermediate results + final temperature return value  int ADC_Lo; //the lower ADC matching value  int ADC_Hi; //the higher ADC matching value  float Temp_Lo; //the lower number matching temperature  int mapTemp_Lo; //the lower number that will be entered into the map function  float Temp_Hi; //the higher  number matching temperature
int mapTemp_Hi; // det høyere tallet som vil bli lagt inn i kartfunksjonen // prep ADC på den bestemte analoge pinnen for å sortere ut multiplexing etc analogRead (thermPin); forsinkelse (10); // få rå ADC-verdi fra VDR int thermValue = analogRead (thermPin); //Serial.println(thermValue); /*Serial.print (F ("PinNo:")); Serial.println (thermPin); * / Serial.print (F ("ADC:")); Serial.println (thermValue); // returner dummy-verdi hvis sensoravlesningen faller utenfor LUT hvis (thermValue < (int) pgm_read_word (&LUT_Therm [0])) // mindre enn den minste ADC-verdien _tempC = -errReturn-1; // under dummy-verdi ellers hvis (thermValue > (int) pgm_read_word (LUT_Therm [constLUTArraySize-1])) // mer enn den største ADC-verdien _tempC = errReturn + 1; // dummy-verdi over rekkevidde ellers // verdi faller i LUT-område {int prev_lut_therm = 0; for (int i = 0; i<constLUTArraySize; i ++) // gå gjennom LUT og se etter en match {int lut_therm = (int) pgm_read_word (LUT_Therm [i]); hvis (lut_therm > thermValue) // LUT-verdien er større enn avlesningen {// finn nærmeste høyere ADC-verdi ADC_Hi = lut_therm; // registrere nærmeste høyere temperatur Temp_Hi = float (i / 10) + 13.0; // konverter til temp // få nærmeste lavere temperatur - ta den nederste tabellgrensen i betraktning hvis (i! = 0) // generelt tilfelle -> så lenge det ikke er første oppføring {ADC_Lo = prev_lut_therm; // lagre forrige matriseelement som lav Temp_Lo = float (i / 10) + 13,0 - 0,1; // konvertere til temp} annet // spesiell sak -> counter = 0 dvs. første matriseoppføring {ADC_Lo = lut_therm; // lagre det første matriseelementet Temp_Lo = i - float (i / 10) + 13.0; // konverter til temp} // slutt hvis // interpolerer temperaturverdien for større presisjon
// NB kartfunksjonen bruker ikke matematikk med flytende punkt, så int-verdiene til temp multipliseres med 100 og deretter blir resultatet deretter delt med 100 mapTemp_Lo = Temp_Lo * 100; mapTemp_Hi = Temp_Hi * 100; _tempC = float (map (thermValue, ADC_Lo, ADC_Hi, mapTemp_Lo, mapTemp_Hi)) / 100; gå i stykker; // exit for loop etter at kampen er oppdaget} // end if prev_lut_therm = lut_therm; } // slutt for} // slutt hvis retur (_tempC);} // slutt getTempFloat-funksjon  

Legg merke til teknikken for å erklære LUT_Therm array, ved hjelp av tomme [] parenteser (linje 135).

Det etterfølges av const int arraystørrelse (linje 182) som blir "beregnet" fra arrayet erklæring: (Total array size) / (size of one array element). Hvis du noen gang endrer oppslagstabellen, trenger du ikke telle elementene for hånd. La kompilatoren gjøre det for deg! :)


[1] Selv om IDE rapporterer om økt binær skissestørrelse, er den totale opplastede størrelsen uendret:
 PROGMEM søkeordtekstdata bssNei 5948 894 483Ja 6810 32 483 

Som du kan se, flyttes 862 byte for denne tabellen fra delen data til text -delen. De opplastede HEX-filene er identiske med 93.737 byte.

Jeg har en side om [å sette ting i PROGMEM] (http://www.gammon.com.au/progmem).
“_Den binære skissestørrelsen øker med samme beløp_”. Det er feil. Initialiserte matriser spiser like mye blits, enten de er PROGMEM eller ikke.
@EdgarBonet, sant, men * rapportert * programstørrelse øker med samme beløp. Prøv det! :) Bare slett PROGMEM-nøkkelordet. Selv om den ikke ville kjøre riktig, endres størrelsen som er rapportert i byggeloggen. Må ha noe å gjøre med hvilke seksjoner som legges sammen?
... nå lurer jeg på hvilket nummer som er riktig ...
Din avr-størrelse må være ødelagt. Med PROGMEM får jeg en programstørrelse på 6646 byte (.tekst: 6604 byte, .data: 42 byte). Hvis jeg fjerner PROGMEM, får jeg 6644 byte (.text: 5606, .data: 1038). Jeg sjekket HEX-filstørrelsen (tingene som faktisk overføres_ til Arduino-blitsen), og i begge tilfeller er den rapporterte programstørrelsen riktig. Løs svaret ditt.
@EdgarBonet, min avr-størrelse er ikke ødelagt. Kanskje IDE ikke rapporterer som du forventet. Jeg har lagt til en fotnote med detaljer for å adressere kommentaren din. Det er en gjenstand for hvordan IDE legger til delene, som jeg mistenkte.
Edgar Bonet
2016-03-24 16:34:29 UTC
view on stackexchange narkive permalink

Jeg gikk gjennom programmet ditt og fant noen feil du kanskje vil fikse. Tenk bare en av disse (sløsing med RAM) er virkelig relatert til problemet ditt, men uansett, her går det:

Fist, det er to problemer med LPF () . Beskrivelsen sier at dette er et rullende gjennomsnittlig lavpasfilter. Dette er feil: en rullemiddel vil ta en enkeltlesning og deretter rapportere gjennomsnittet av de siste n målingene. Denne funksjonen tar derimot n målinger og rapporterer gjennomsnittet. Dette gjør en stor forskjell: et rullende gjennomsnitt må lagre de siste n verdiene i statisk minne, mens funksjonen din gjør dette uten god grunn. Du kaster bort 300 byte RAM.

Her er en reimplementering av LPF () som gjør det samme som ditt uten å kaste bort RAM. Jeg endret navnet for å være mer konsistent med det virkelige formålet:

  / * * Ta 'tell' temperaturavlesninger fra 'pin' og returner gjennomsnitt. * Returnerer NaN (ikke et tall) hvis for mange målinger var feil. * / float getAvgTemp (int pin, int count) {const int MAXERRORS = 5; // maks antall feil som kan oppstå float temp; // gjeldende temperaturavlesning floTempSum = 0; // sum av temperaturer int errCounter = 0; // antall feilavlesninger for (int i = 0; i < count; i ++) {// Prøv å få en gyldig lesing. gjør {temp = getTempFloat (pin); hvis (isnan (temp)) errCounter ++; forsinkelse (25); // la ADC legge seg} mens (isnan (temp) && errCounter < = MAXERRORS); // For mange feil: returner en feil. hvis (errCounter > MAXERRORS) returnerer NAN; tempSum + = temp; } return tempSum / count;}  

Her bruker jeg NaN (ikke et tall) som en feilindikator, da den er klart klarere enn en tilfeldig verdi utenfor området.

Det er også noen feil i getTempFloat():

  • pgm_read_word (LUT_Therm [constLUTArraySize-1]) og pgm_read_word (LUT_Therm [i]) fungerer ikke: du må passere pgm_read_word () kode> adressen hvor du skal lese.
  • float (i / 10) gjør ikke det du vil: den beregner i / 10 som en heltall-divisjon (dvs. forkaste brøkdelen), og deretter konverterer resultatet til en flottør. Hvis du vil ha en flytende punktinndeling, bør du sørge for at minst ett av argumentene er en float. Det vanlige uttrykket er i/10.0.

Her er en versjon av getTempFloat () med disse problemene løst, og også noe forenklet:

  float getTempFloat (int pin) { int i, lutval, prev_lutval; // Ta en analog lesning. analogRead (pin); // dummyavlesning for å avgjøre MUX-forsinkelsen (10); int adc = analogRead (pin); Serial.print (F ("ADC:")); Serial.println (adc); // Finn i slik at adc ligger mellom LUT [i-1] og LUT [i]. for (i = 0; i < constLUTArraySize; i ++) {prev_lutval = lutval; lutval = pgm_read_word (&LUT_Therm [i]); hvis (lutval > = adc) pause; } // Spesielt tilfelle: adc == LUT [0]. hvis (i == 0 && adc == lutval) returnerer 13.0; // Rapporter en feil hvis den er utenfor området. hvis (i == 0 || i == constLUTArraySize) returnerer NAN; // Returner interpolert temperatur. floatfraksjon = float (adc - prev_lutval) / (lutval - prev_lutval); return 13.0 + (i-1 + fraksjon) / 10.0;}  

Addendum

Jeg har lagt merke til noen flere problemer og inkonsekvenser med programmet ditt.

Drift av termistoren fra den interne referansen

I oppsett () skriver du

analogReference (INTERNAL); // bruk intervallstemplet på 1.1V for ADC-oppløsningen

og deretter, i en kommentar lenger nede, har du skjematisk

+ Vref-- - [Thermistor] --- + - [1.8K] --- GND

Dette antyder at du driver spenningsdeleren fra den interne spenningsreferansen til MCU. Du bør ikke gjøre det, ettersom databladene viser: "Merk at V REF er en kilde med høy impedans, og at bare en kapasitiv belastning skal være koblet til et system."

Forholdet mellom ADC lese- og termistormotstand

I samme kommentar som ovenfor skrev du:

ADC = 1023 * 10000 / (Rtherm + 10000)

Faktoren er faktisk 1024, ikke 1023. Igjen, se databladet. Og tallet 10000 skal være 1800 , dvs. motstanden du har satt mellom ADC-inngangen og GND. Jeg forstår at du kanskje bare har endret verdien og glemt å oppdatere en av kommentarene. Men du må betrakte en villedende kommentar som en feil, spesielt hvis den ikke er i samsvar med den faktiske koden.

For denne typen måling får du den beste presisjonen hvis nedtrekksmotstanden har en verdi nær motstanden til termistoren. . Kommentaren i begynnelsen av programmet sier at termistoren har 10 kΩ @ 25 ° C. Dette betyr at hvis du er mest interessert i området rundt 25 ° C, er en 10 kΩ nedtrekk bedre enn 1,8 kΩ.

Forholdet mellom matriseindeks og temperatur

Kommentaren før LUT sier:

Arrayindeksen starter på null, som tilsvarer en temperatur på + 6 ^ C

Så, den aller første linjen i LUT har kommentaren

// 7 ^ C til 7.9 ^ C

Og senere implementering av getTempFloat () antar at indeks 0 betyr 13 ° C. Du bør ordne dette og gjøre alt konsistent.

BTW, LUT-verdiene dine går helt opp til 1023. En avlesning på 1023 vil bety ADC-spenningen er høyere enn 1022,5 / 1024 × V REF . Hvilken tur vil antyde at termistoren har en motstand lavere enn 14,6 Ω (forutsatt en nedtrekk på 10 kΩ). Jeg synes dette er tvilsomt.

Fjerning av LUT

Siden programmet er ment å kjøre veldig sakte ( constDelay = 3000 ), har du råd til å gjøre komplekse beregninger i det. Du kan få samme presisjon med en måte mindre LUT hvis du bruker en høyere ordreinterpolasjon. For en funksjon som samples med konstante trinn, er Catmull – Romspline enkel å implementere og er mye bedre enn lineær interpolasjon.

Eller du kan fjerne LUT helt og bruke et analytisk uttrykk i stedet . Hvis du hentet LUT fra et slikt uttrykk, hvorfor ikke bruke det i programmet? Hvis LUT kommer fra eksperimentelle data, kan du prøve å gjøre en empirisk tilpasning, dvs. en vilkårlig funksjon som passer nøye med dataene. Den mest åpenbare (men kanskje ikke den beste) empiriske funksjonen ville være et polynom. Nedenfor er et eksempel på en slik funksjon som gir deg LUT med god nøyaktighet ved bruk av et 6. graders polynom. Det antar at den første LUT-oppføringen er for en temperatur på 7 ° C:

  float getTempFloat (int pin) {const float T0 = 7; // temperatur ved begynnelsen av området int adc = analogRead (pin); flyte x = (adc-223.) / (1023.-223.) * 2 - 1; // skalere til [-1: 1] hvis (x < -1 || x > 1) returnerer NAN; // utenfor området flyte y = 1,474 - x * (0,533 - x * (0,732 - x * 0,458)); return T0 + 26.107 + x * (19.287 - x * (3.596 - x * y));}  

Dette kan faktisk være enda mer nøyaktig enn din LUT-baserte funksjon, slik at LUT er laget av heltallverdier, mens kalibreringskurven åpenbart bør være kontinuerlig.

Tusen takk for poengene dine, noen ville jeg ikke ha vurdert. Ja, jeg har endret tempområdet så noen kommentarer ikke gir mening. Er den analoge referansen (interne) samtalen ikke bruk av 1.1V for å få en bedre oppløsning mellom ADC-trinn og ved å bruke Arduinos 3.3V strøm ut som Vref, og jeg har funnet ut at en 1k8ohm motstand gir meg en rekkevidde på 7-50degC ( men som vist ovenfor kan jeg ta feil!). Jeg bruker dette som en hudtemperaturlogger, så vikarer vil være i området 30-40degC. Jeg er fortsatt usikker på hvor mange målinger per minutt jeg vil ha, men interpolasjonen ser finere ut. Takk


Denne spørsmålet ble automatisk oversatt fra engelsk.Det opprinnelige innholdet er tilgjengelig på stackexchange, som vi takker for cc by-sa 3.0-lisensen den distribueres under.
Loading...