Hi,
ich habe gewisse Troubles, am ATmega1284P eine Mittelwertbildung aus
gemessenen ADC Werten zu bekommen. Das sequentielle Auslesen von ADC
Werten ist kein Problem, einzig und allein beim Aufsummieren dieser
Werte und anschließender Mittelwertbildung erreiche ich nicht das
gewünschte Ergebnis.
Anbei die schaltungstechnischen Eckdaten:
- Analogspannung liegt über einen externen Multiplexer (MUX_A0-MUX_A2
sowie EN_ADC10MUX) am ADC0 an
- Es wird eine externe Referenzspannung 2.560V verwendet
- Das LCD Display ist an 6 Pins von Port C und 2 Pins von Port B
angeschlossen (4Bit Daten, 3Bit Control, 1Bit LED Beleuchtung via
Transistor geschaltet)
Nach dem Einschalten des ADCs wird eine Dummy-Wandlung durchgeführt,
alle weiteren Messungen werden verwertet. Am ADC0 Eingang liegt eine
Spannung von 1.94V an. Als LCD Library wurde die von Peter Fleury
eingebunden.
Hier mal der entsprechende Code (die ADC_COUNTS sind bewusst auf 1
gesetzt), der ein funktionierendes Ergebnis liefert:
sprintf(str_adc_value,"%04.0f",adc_value);// Format adc_value as string and save as str_adc_value
69
sprintf(str_adc_voltage,"%4.2f",adc_voltage);// Format adc_voltage as string and save as str_adc_voltage
70
lcd_gotoxy(13,0);// Set cursor to pos. 13, line 0
71
lcd_puts(str_adc_value);// Write str_adc_value to LCD display
72
lcd_gotoxy(13,1);// Set cursor to pos. 13, line 1
73
lcd_puts(str_adc_voltage);// Write str_adc_voltage to LCD display
74
adc_value=0;// Reset adc_value
75
_delay_ms(1000);// Wait 1000ms
76
}
77
return0;
78
}
Ergebnis am LCD Display:
ADC value : 0777
ADC voltage: 1.94V
Ersetze ich jetzt folgende Zeile
1
adc_value=ADCW;
durch
1
adc_value+=ADCW;
bekomme ich folgendes, seltsames Ergebnis am LCD Display:
ADC value: 3885
ADC voltage: 9.71V
adc_value ist als double definiert, damit es bei der Mittelwertbildung
nicht zu Problemen kommt, wenn Kommastellen auftreten. Ich habe auch
schon probiert, AREF und ADC_COUNTS als double und uint8_t zu definieren
mit dem gleichen Ergebnis. Der angezeigte Wert ist bei Mittelwertbildung
immer um den Faktor 4 zu hoch. Kann mir wer von euch bei diesem Problem
weiterhelfen?
LG, Michael
Ps: Sollte der obige Source-Code als "zu lang für einen Beitrag" gelten,
bitte um kurze Nachricht, dann änder ich es umgehend auf einen Anhang -
da es mein erster Beitrag ist, bitte um Nachsicht.
Michael S. schrieb:> adc_value ist als double definiert, damit es bei der Mittelwertbildung> nicht zu Problemen kommt, wenn Kommastellen auftreten.
Erster Schritt wäre, die ganze Floatingpointrechnerei rauszuschmeißen.
Nicht ohne Grund hat die Referenzspannung einen Wert von 2560 mV. Wenn
du deine ganze Rechnung mal etwas zusammenfasst und in mV betrachtest
kürzt sich da vieles weg und du kannst bei einer passenden Wahl von
ACD_COUNTS wunderbar in Integer rechnen, ohne dabei irgendwelche
Probleme mit Nachkommastellen zu bekommen.
Michael S. schrieb:> adc_value ist als double definiert, damit es bei der Mittelwertbildung> nicht zu Problemen kommt,
beim GCC gibt es gar kein double. double wird als single gerechnet.
Gruß Anja
Michael S. schrieb:> while (ADCSRA & (1<<ADSC)) // Wait for the conversion to complete
vielleicht ist vFloatibg point nicht sinnvoll
aber in der Zeile fehlt weiterhin ein Semikolon
Vielen Dank für die raschen Antworten,
der Punkt der Fließkomma-Rechnerei ist durchaus zu überdenken,
allerdings verlangt der Compiler nach "double" wenn man sprintf
verwendet und für die Ausgangsformatierung "4.2f" angibt. Definiert man
die Eingangsvariable als "float", so meckert er mit der Warnmeldung
"format '%4.2f' expects type 'double', but argument 3 has type 'float'"
- aus dem Grund habe ich hier double ausgewählt.
Bezüglich des fehlenden Semikolons muss ich euch enttäuschen - hier ist
auch im AVR-GCC-Tutorial unter
http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial/Analoge_Ein-_und_Ausgabe#Nutzung_des_ADC
die Zeile ohne Semikolon angegeben - und ich bilde mir ein, das auch so
in einem Atmel Datenblatt gelesen zu haben - dementsprechend weiß ich
jetzt nicht ganz, was richtig ist.
@Uwe: Vielen Dank für deinen Link, ich werde ihn mir mal zu Gemüte
führen ...
LG, Michael
Michael S. schrieb:> der Punkt der Fließkomma-Rechnerei ist durchaus zu überdenken,
richtig.
> allerdings verlangt der Compiler nach "double" wenn man sprintf> verwendet und für die Ausgangsformatierung "4.2f" angibt.
Na ja.
Aber eigentlich zwingt dich ja keiner dazu "4.2f" anzugeben.
D.h. das ist eine etwas lahme Begründung, warum da Floating Point
gerechnet wird.
> Definiert man> die Eingangsvariable als "float", so meckert er mit der Warnmeldung> "format '%4.2f' expects type 'double', but argument 3 has type 'float'"> - aus dem Grund habe ich hier double ausgewählt.
Das ist letzten Endes egal.
Es geht um die Grundsatzfrage: Gleitkomma oder nicht.
Ob float oder double ist dann sekundär. Vor allem auch deshalb, weil
double beim gcc auf einem AVR dasselbe wie float ist.
> Bezüglich des fehlenden Semikolons muss ich euch enttäuschen - hier ist> auch im AVR-GCC-Tutorial unter> http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial/Analoge_Ein-_und_Ausgabe#Nutzung_des_ADC> die Zeile ohne Semikolon angegeben
1) nachdenken, was das Semikolon eigentlich tut
2) Schau noch einmal genau, wodurch sich die Dinge im Tutorial
von deinen unterscheiden (Ich gebe zu, es ist durch die Farbgebung
nicht so gut zu sehen. Wenn du fertig bist, werde ich das mal ein
wenig umformatieren, so dass man das auch besser sieht)
3) darüber nachdenken, was die C-Regeln zu diesem Fall sagen, und
wie der Compiler das was du geschrieben hast, lesen wird
Was eng damit zusammenhängt: Welche Konsequenzen hat das für
deine Programmlogik: Was sollte eigentlich an dieser Stelle
geschehen und was passiert statt dessen.
Karl Heinz Buchegger schrieb:> 2) Schau noch einmal genau, wodurch sich die Dinge im Tutorial> von deinen unterscheiden (Ich gebe zu, es ist durch die Farbgebung> nicht so gut zu sehen. Wenn du fertig bist, werde ich das mal ein> wenig umformatieren, so dass man das auch besser sieht)> 3) darüber nachdenken, was die C-Regeln zu diesem Fall sagen, und> wie der Compiler das was du geschrieben hast, lesen wird> Was eng damit zusammenhängt: Welche Konsequenzen hat das für> deine Programmlogik: Was sollte eigentlich an dieser Stelle> geschehen und was passiert statt dessen.
Alles klar, der Tip mit der schlechten Farbgebung war Gold wert. Werd
ich gleich mal ändern.
LG, Michael
Michael S. schrieb:> ADCSRA |= (1<<ADSC); // Start ADC conversion> while (ADCSRA & (1<<ADSC)) // Wait for the conversion to complete> adc_value = ADCW; // Write ADCW value to adc_value
Das ist keine Mittelwertbildung, dafür musst du auch aufsummieren, also