Hi!
Besteht die Gefahr, daß der Compiler mir da was wegoptimiert?
1
uint16_tADC_On_ReadAvg_Off(uint8_taverage)
2
{
3
uint32_tresult=0;
4
5
ADCSRA|=(1<<ADEN);
6
ADCSRA|=(1<<ADSC);// eine ADC-Wandlung
7
while(ADCSRA&(1<<ADSC)){}// auf Abschluss der Konvertierung warten
8
/* ADCW muss einmal gelesen werden, sonst wird Ergebnis der nächsten
9
Wandlung nicht übernommen. */
10
result=ADCW;
11
12
result=0;
13
14
for(uint8_ti=0;i<average;++i)
15
{
16
result+=ADC_Read();
17
}
18
19
ADCSRA&=~(1<<ADEN);
20
21
return(uint16_t)(result/average);
22
}
Diese zwei Zeilen
1
result=ADCW;
2
result=0;
machen mir Sorgen. Erkennt der Compiler, daß ich da einen Wert lese und
gleich wieder 0 rein schreibe und liest dann vielleicht erst gar nicht?
Mal so grundsätzlich: in welchen Fällen muß man sich Sorgen machen?
LG
Ernst
ADCW wird auf jeden Fall gelesen, da es im Headerfile wie alle IO-Regis-
ter als volatile deklariert ist. Wahrscheinlich wird der gelesene Wert
aber nicht in result geschrieben, was aber auch egal ist.
Da du den Inhalt von ADCW sowieso nicht weiterverwenden möchtest, kannst
du statt
Danke Dir Yalu!
Was passiert wenn ich nur ADCW; schreibe? Also, wie wird sowas
interpretiert?
wenn ich in die iom8.h schaue dann steht dort:
#define ADCW _SFR_IO16(0x04)
Nur werde ich aus dem _SFR_IO16(0x40) nicht schlau. Leider auch dann
nicht wenn ich in die sfr_defs.h schaue:
#define _SFR_IO16(io_addr) ((io_addr) + __SFR_OFFSET)
Sh*t, ich brauche ein libc Tutorial oder sowas...
Nano Oschi schrieb:> Was spricht gegen den simulator ?
Ich weiß nicht wie ich im Studio Werte für den Pin simuliere? Oder muß
ich das gar nicht wenn ich einen ADC simuliere?
Für den ADC muss man die PIN nicht extra einstellen. Der analoge Teil
des ADC wird, soweit ich das noch kenne gar nicht simuliert.
Es auch gar nicht mal nötig ADCW überhaupt zu lesen. Man kann auch eine
neue Wandlung anfangen ohne den alten Wert zu lesen.
Ernst B. schrieb:> Danke Dir Yalu!>> Was passiert wenn ich nur ADCW; schreibe? Also, wie wird sowas> interpretiert?
genauso wie wenn du einfach
i;
anstelle von
j = i;
schreibst.
Oder
sin( x );
anstelle von
y = sin( x );
Das ist ein arithmetischer Ausdruck, dessen Ergebnis verworfen wird.
Meistens warnen Compiler bei so etwas.
>> wenn ich in die iom8.h schaue dann steht dort:>> #define ADCW _SFR_IO16(0x04)
Das ist relativ uninteressant. Für dich als C Programmierer
repräsentiert ADCW das 16 Bit Register, aus dem du dir das ADC Ergebnis
abholen kannst. Wenn du so willst: eine Variable die 'magisch' den
aktuellen Wert des ADC enthält.
Ernst B. schrieb:> Was passiert wenn ich nur ADCW; schreibe? Also, wie wird sowas> interpretiert?
Jeder Ausdruck hat in C einen Wert. Ein Ausdruck ist also implizit ein
Lesezugriff.
Da der Wert aber nicht verwendet wird, könnte der Compiler ihn
wegoptimieren.
Allerdings sind IO-Register volatile definiert, d.h. ein Lesen oder
Schreiben erfolgt immer.
Peter
Ernst B. schrieb:> /* ADCW muss einmal gelesen werden, sonst wird Ergebnis der nächsten> Wandlung nicht übernommen. */
Wie kommst Du denn darauf?
Peter
Peter Dannegger schrieb:> Ernst B. schrieb:>> /* ADCW muss einmal gelesen werden, sonst wird Ergebnis der nächsten>> Wandlung nicht übernommen. */>> Wie kommst Du denn darauf?>>> Peter
Ich bilde mir ein das im Datenblatt gelesen zu haben. Aber jetzt finde
ich es nimmer. Sondern nur, daß die erste Wandlung länger dauert.
Aber irgendwo habe ich es gelesen...
LG
Ernst
Ernst B. schrieb:> Mal so grundsätzlich: in welchen Fällen muß man sich Sorgen machen?
Wenn im List-File kein Assembler-Code zu deinem C-Codeteil auftaucht,
ist das ein sicheres Zeichen für wegoptimierten Code. Allerdings ist das
dann auch kein Grund zur Sorge, sondern ein klarer Fall ;-)
Peter Dannegger schrieb:> Ernst B. schrieb:>> /* ADCW muss einmal gelesen werden, sonst wird Ergebnis der nächsten>> Wandlung nicht übernommen. */>> Wie kommst Du denn darauf?>>> Peter
Ich weiß es schon, hier im AVR-GCC Tutorial steht es:
http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial#Nutzung_des_ADC
Zitat: "...In der praktischen Anwendung wird man zum Programmstart den
ADC erst einmal grundlegend konfigurieren und dann auf verschiedenen
Kanälen messen. Diese beiden Dinge sollte man meist trennen, denn das
Einschalten des ADC und vor allem der Referenzspannung dauert ein paar
Dutzend Mikrosekunden. Außerdem ist das erste Ergebnis nach dem
Einschalten ungültig und muss verworfen werden. ..."
LG
Ernst
Im Datenblatt zum AVR steht nirgends das man den ADC nach einer Wandlung
auch auslesen muss, oder das das lesen den ADC irgendeinen Nebeneffekt
wie das löschen eines Flags hat.
Gut es gibt ggf. schon einen kleinen Nebeneffekt, indem beim Lesen von
ADCL der Wert von ADCH gepuffert wird. Danach wird dann der Puffer mit
dem lesen von ADCH auch wieder freigegeben. Es ist also nichts weiter
passiert, als das ggf. ein 16 Bit Zugriff woanders gestört wurde.
Benötigt wird das hier nicht, außer es wurde vorher mal nur ADCL
gelesen. Dann reich aber das lesen von ADCH aus.
Was man daher nicht machen sollte, ist es nur ADCL aber nicht ADCH lesen
- dann ließt man danach noch mal den alten Wert.
Ernst B. schrieb:> Zitat: "...In der praktischen Anwendung wird man zum Programmstart den> ADC erst einmal grundlegend konfigurieren und dann auf verschiedenen> Kanälen messen. Diese beiden Dinge sollte man meist trennen, denn das> Einschalten des ADC und vor allem der Referenzspannung dauert ein paar> Dutzend Mikrosekunden. Außerdem ist das erste Ergebnis nach dem> Einschalten ungültig und muss verworfen werden. ..."
Und wo steht da jetzt, daß man den Wert auslesen muß?
Rolf Magnus schrieb:> Ernst B. schrieb:>> Zitat: "...In der praktischen Anwendung wird man zum Programmstart den>> ADC erst einmal grundlegend konfigurieren und dann auf verschiedenen>> Kanälen messen. Diese beiden Dinge sollte man meist trennen, denn das>> Einschalten des ADC und vor allem der Referenzspannung dauert ein paar>> Dutzend Mikrosekunden. Außerdem ist das erste Ergebnis nach dem>> Einschalten ungültig und muss verworfen werden. ...">> Und wo steht da jetzt, daß man den Wert auslesen muß?
Da:
>> Außerdem ist das erste Ergebnis nach dem>> Einschalten ungültig und muss verworfen werden.
Die Formulierung "muss verworfen werden" verlangt ja nach einem aktiven
tun. Und auch drunter im Code steht es:
/* ADCW muss einmal gelesen werden, sonst wird Ergebnis der nächsten
Wandlung nicht übernommen. */
Da steht explizit, daß man es auslesen muß.
LG
Ernst
PuraVida schrieb:>>> Außerdem ist das erste Ergebnis nach dem>>> Einschalten ungültig und muss verworfen werden.>> Die Formulierung "muss verworfen werden" verlangt ja nach einem aktiven> tun. Und auch drunter im Code steht es:>>> /* ADCW muss einmal gelesen werden, sonst wird Ergebnis der nächsten> Wandlung nicht übernommen. */>> Da steht explizit, daß man es auslesen muß.
Da irrt das Tutorial. Tutorials werden auch nur von Menschen
geschrieben.
Sogar das Datenblatt enthält manchmal Fehler oder Unsinniges.
Der ADC hat keine FIFO, wie z.B. die UART. Eine neue Wandlung
überschreibt daher einfach den Inhalt. Ein Auslesen hat keinerlei
Effekt. Man kann auch beliebig oft den gleichen Wert auslesen, solange
die nächste Wandlung nicht abgeschlossen ist.
Peter
PuraVida schrieb:>> Und wo steht da jetzt, daß man den Wert auslesen muß?>> Da:>>>> Außerdem ist das erste Ergebnis nach dem>>> Einschalten ungültig und muss verworfen werden.>> Die Formulierung "muss verworfen werden" verlangt ja nach einem aktiven> tun.
Verwerfen heist doch nur, daß man es nicht verwendet.
> Und auch drunter im Code steht es:>>> /* ADCW muss einmal gelesen werden, sonst wird Ergebnis der nächsten> Wandlung nicht übernommen. */>> Da steht explizit, daß man es auslesen muß.
Das ist allerdings recht explizit. Ich konnte aber im Datenblatt keinen
Grund für diese Behauptung finden.
Hi Peter!
Ja, klar, können überall Fehler sein, wir sind ja nicht unfehlbar. Es
war nur die Antwort auf die Fragen wo ich das gelesen habe.
Ist mir nur recht wenn man es nicht verwerfen muß. Jetzt muß ich mich
nur noch schlau machen wie das mit der internen Spannungsreferenz ist.
Da steht einerseits im Datenblatt:
The first ADC conversion result after switching reference voltage source
may be inaccurate, and the user is advised to discard this result.
Fragt sich ob das auch gilt nach der Initialisierung des ADC also die
erstmalige Einstellung von AVCC als eine Art "switching the reference"
zu sehen ist. Ein- und Ausschalten des ADC wird da ja nicht drunter
fallen, oder?
Und dann muß ich nochmal schauen wie ich das mit der Start-Up-Time von
V-Bandgap mache die bis zu 70µs dauert. Da ist der gepostete Code sicher
zu schnell wenn ich das Verwerfen der ersten Messung rauswerfe.
LG
Ernst
Rolf Magnus schrieb:> Verwerfen heist doch nur, daß man es nicht verwendet.
Korrekt verworfen ist es erst, wenn das Ergebnis in's Dev/Null-Register
des µC geschoben wurde. :D
Den ADC-Init-Kram kann man doch einfach noch vor die anderen
Initialisierungen machen, also Referenz setzen und ne Dummy-Messung
starten.
Dann z.B. das LCD initialisieren, wo 15ms gewartet werden muß und dann
sollte sich alles eingeschwungen haben.
Peter
Hi
Diese Dummymessung wird hier total überbewertet. Soll sich doch mal
jeder selbst beantworten ob eine etwas ungenauere Messung in seinem
Programm überhaupt eine Auswirkung hat. Wesentlich sinnvoller ist in den
meisten Fällen eine Mittelwertbildung.
MfG Spess
spess53 schrieb:> Diese Dummymessung wird hier total überbewertet.
Das stimmt.
Wenn man sich mal kommerzielle Geräte anschaut, gibt es auch viele, wo
die Anzeigen beim Einschalten erstmal Unsinn anzeigen. Und früher sind
die Zeigerinsrumente auch gerne mal kurz auf Anschlag gesprungen. Keinen
stört sowas.
Und was nützt es, wenn zwar der ADC richtige mißt, aber der OPV davor
übersteuert und erst noch langsam seinen Arbeitspunkt finden muß.
Beim Einschalten zeigt man "Busy" an, solange die Meßwerte außerhalb des
Arbeitsbereiches liegen.
Und erst, wenn sie nach einer Wartezeit immer noch falsch sind, zeigt
man "Fault" an.
Peter