Hi, Ho,
ich stehe gerade mal wieder kurz vor einem Nervenzusammenbruch.
Die "lächerliche" Aufgabenstellung
Ich habe hier einen Atmega88 auf einem Stk-500. Dort möchte ich am PC0
einen Analogwert lesen. Ist das Ergebnis größer 500, soll led2 angehen,
sonst aus bleiben. led1 zeigt mir nur an, das eine messung beendet
wurde. Ich habe die pins gemessen, soweit ok. Die CPU läuft mit 8Mhz,
Takt intern
Ich habe das Gefühl, das er eine Messung macht und dann wars das. led1
geht nach start auch an. led2 geht auch manchmal an (entsprechend dem
wert), aber danach passiert mit led2 nichts mehr.
wenn du den ADC nicht im Free-Running Mode betreibst, musst du nach
einer Messung eine neue Messung mit
ADCSRA |= (1<<ADSC);
initieren, ansonsten wird halt, wie von dir beschrieben, nur eine
Messung durchgeführt.
Gruß, Muggel
Hi,
im Free-Running Mode ist ADSC permanent auf 1, also darfst du nicht ADSC
abfragen, sonder musst auf das ADC-Interrupt Flag schauen (ADIF). Wenn
das Flag 1 ist, wurde eine Konvertierung beendet. Du musst dann das Flag
noch clearen (1 schreiben) oder du machst anstatt deiner
Polling-Geschichte eine Interrupt-Routine daraus, die nach jeder
AD-Wandlung deinen Code ausführt.
Gruß, Muggel
kann_nichts schrieb:> Ich will natürlich den free-running-mode. Ich denke, ich habe ihn durch>
1
>ADCSRB=0;
2
>
Das sehe ich nicht so.
Damit hast du nur gesagt, was die Trigger Source sein soll. Aber du hast
nicht festgelegt, dass der ADC auf einen Trigger reagieren soll.
Dazu müsstest du ADATE in ADCSRA auch noch setzen. Siehe Datenblatt,
Beschreibung zu den ADTS2:0 Bits
1
If ADATE in ADCSRA is written to one, the value of these bits selects
2
which source will trigger an ADC conversion. If ADATE is cleared, the
3
ADTS2:0 settings will have no effect."
Bis jetzt konnte ich auf den Free Running Modus allerdings immer
verzichten. Geht ganz leicht
1
...
2
3
ADCSRA|=(1<<ADSC);// erste Messung anstossen
4
5
while(1)
6
{
7
while(ADCSRA&(1<<ADSC))// Warte bis fertig
8
;
9
10
adc_val=ADCW;// Wert holen
11
12
ADCSRA|=(1<<ADSC);// und stoss gleich die nächste Messung an
13
14
if(adc_val>500)
15
PORTD&=~(1<<PD3);
16
else
17
PORTD|=(1<<PD3);
18
}// while
Der Trick liegt in der Erkentniss, dass die Auswertung auch Zeit
braucht. Während ich mir also in aller Ruhe den Wert zu Gemüte führe und
damit was tue, kann der ADC schon die nächste Messung machen. Der Teil
"Warte bis fertig" ist in den meisten Fällen reine Absicherung, denn
wenn das Programm wieder an diese Stelle kommt, ist die Chance recht
groß, dass der ADC bereits lange mit seiner Messung fertig ist.
Uff,
das wichtigste zu erst. Es funktioniert jetzt. Euch allen vielen Dank.
Trotzdem bleiben noch Fragen
1)
1
adc_val=(ADCH<<8)+ADCL;
Diese Zeile funktioniert nicht. Es gibt zwar keinen Fehler, trotzdem
werden keine weiteren Messungen durchgeführt.
1
adc_val=ADCW;
Mit dieser Zeile funktioniert es. ADCW ist aber im datasheet nicht
erwähnt.
2) Free-Running-Mode
Offensichtlich habe ich den bisher noch nicht richtig verstanden gehabt.
Bedeutet es, das ohne passende ISR und die Flags (ADATE und ADIE) sich
der ADC nur im "Single Mode" befindet?
3) einen anderen Kanal auswählen
Wenn ich jetzt den Kanal wechseln will (ADMUX), reicht es aus, vor dem
Aufruf von ADCSRA |= ( 1 << ADSC ); ADMUX zu ändern, oder muss ich ADEN
erst abschalten.
@Karl Heinz Buchegger
Du hast völlig recht in Sachen "FRM". Ich hatte das Prinzip einfach
anders verstanden. Ich ging davon aus, das der ADC permanent eine
Wandlung macht und wenn man das Ergebnis nicht ausliest, wird es durch
die nächste Wandlung einfach überschrieben.
Jetzt habe ich verstanden, das ich diesen Modus nicht brauche.
kann_nichts schrieb:> ADCW ist aber im datasheet nicht> erwähnt.
ADCW ist ein künstlicher Konstrukt. Normalerweise werden in den
Headerfiles der avr-libc 16-bit-Pseudoregister unter Weglassen der
nachgestellten "H" und "L" gebildet, also TCCR1A wird als
Kombination aus TCCR1AL und TCCR1AH gebildet usw. Allerdings ergibt
sich hierbei für den Wandlerwert des ADCs der Name ADC. Dieser Name
kollidiert jedoch mit dem Befehl ADC (add with carry) im Assembler-
modus (für den das <avr/io.h> ebenfalls benutzbar ist). Aus diesem
Grunde wurde ein alternativer Namen ADCW eingeführt, wobei im
Assemblermodus nur ADCW zur Verfügung steht, während unter C sowohl
ADC als auch ADCW äquivalent nutzbar sind.
Der Vorteil der 16-bit-Pseudoregister ist, dass bei den Registern,
bei denen für das Lesen oder Schreiben der Teilregister eine bestimmte
Reihenfolge einzuhalten ist, der Compiler automatisch die richtige
Reihenfolge generiert. Bei
1
adc_val=(ADCH<<8)+ADCL;
dagegen ist die Lesereihenfolge unbestimmt und kann sich selbst
zwischen verschiedenen Compilerversionen oder Optimierungseinstellungen
unterscheiden, da es für die einzelnen Terme eines Ausdrucks keine
festgelegte Auswertereihenfolge gibt (mit wenigen Ausnahmen für
Sonderfälle wie den Komma-Operator, die wir aber hier außer Acht
lassen können).
> while( ADCSRA & (1 << ADSC)) // Warte bis fertig>Der Teil>"Warte bis fertig" ist in den meisten Fällen reine Absicherung, denn>wenn das Programm wieder an diese Stelle kommt, ist die Chance recht>groß, dass der ADC bereits lange mit seiner Messung fertig ist.
aber hardwaremässig ist das Bit in ADSC solange 1, bis die Konvertierung
abgeschlossen ist und wird automatisch auf 0 gesetzt. Ergeben sich
dennoch parktische Vorteile den Ausdruck in einer while-Schleife zu
verarbeiten?