Hallo,
ich habe einen Atmega128 und am Analog-Port habe ich ein Potentiometer
angeschlossen.
So sieht mein Programmcode aus:
uint8_t i;
uint16_t result;
ADCSRA = (1<<ADEN) | (1<<ADPS0)| (1<<ADPS1) | (1<<ADPS2);
ADMUX = 3;
ADMUX |= (1<<REFS0);
ADCSRA |= (1<<ADSC);
while(!(ADCSRA & (1<<ADIF)));
result = 0;
for(i=0;i<4;i++)
{
ADCSRA |= (1<<ADSC);
while(!(ADCSRA & (1<<ADIF)));
result += (ADCL + (ADCH<<8));
}
ADCSRA &= ~(1<<ADEN);
result >>= 2;
Messen tu ich nur unsinn. Muss ich da noch eine andere Beschaltung
vornehmen? Als ich mein Poti zu weit ausgesteuert habe, ist glaube ich
mein Netzteil in die Begrenzung gefahren.
>while(!(ADCSRA & (1<<ADIF)));
Das machst du auch lieber anders:
while(!(ADCSRA & (1<<ADSC)));
Oder setzt du das ADIF irgendwo zurück? Soweit ich mich erinnere, wird
das ADIF beim Sprung in die ISR zurückgesetzt.
Das ADIF Flag wird nicht automatisch mit Beginn
der Wandlung gelöscht.
Der Compiler bietet dir einen einfach Weg an, wie man
korrekt die beiden 8 Bit Register auslesen kann.
Mit: (ADCL + (ADCH<<8));
kannst du nicht wirklich die Reihenfolge kontrollieren,
in der auf die Register zugegriffen wird.
Machs doch so, wie im Tutorial gezeigt:
ADCSRA |= (1<<ADSC); // eine Wandlung "single conversion"
while ( ADCSRA & (1<<ADSC) ) {
; // auf Abschluss der Konvertierung warten
}
result += ADCW; // Wandlungsergebnisse aufaddieren
> Als ich mein Poti zu weit ausgesteuert habe, ist glaube> ich mein Netzteil in die Begrenzung gefahren.
Wie hast du denn das Poti verschaltet?
Bei normaler Verschaltung, ist es für das Netzteil
irrelevant, wie das Poti steht. Es zieht aus Sicht
des Netzteils unabhängig vom Potischleifer immer
gleich viel Strom.
@Rahul:
> while(!(ADCSRA & (1<<ADSC)));
Da ist ein "!" zu viel... Ansonsten völlig korrekt. ADSC wird nach
Beendigung der Wandlung automatisch gelöscht und ist bei der Abfrage
über Polling die einzig sinnvolle Möglichkeit.
Mit der Begrenzung vom Netzteil kann ich mir auch nur so vorstellen,
dass das Poti falsch angeschlossen ist.
Rahul, der Trollige wrote:
>>Musst du ins Tutorial schaun :-)> Ich steige auf BASCOM um, da brauch' ich weder Tutorium noch> Datenblatt...;-)
Soll ich Dir das glauben??? ;-)
...
@ johnny.m:
>> while(!(ADCSRA & (1<<ADSC)));
ist doch korrekt? Oder ist:
while(!(ADCSRA & 0x10));
etwas Anderes? Letzeres läuft bei mir in 'zig Applikationen korrekt!
@Sonic:
Das ADSC ist während der Wandlung gesetzt und wird am Ende der Wandlung
zurückgesetzt. Es ist also Unsinn, in der while-Schleife auf "nicht
gesetzt" zu überprüfen. Also muss die Negation weg, sonst ist die
Bedingung direkt nach dem Start des ADC schon nicht mehr erfüllt.
BTW: Hattest Du nicht immer diesen Tip mit den 40 µs warten vor jeder
Wandlung? Könnte es evtl daran liegen, dass Du eben diesen Fehler in
allen Deinen Programmen drin hast und immer versuchst, das Ergebnis zu
lesen, bevor es überhaupt da ist? Nur so als Hinweis... das kann so
nämlich nicht, wei Du behauptest, korrekt laufen!
Also 1. löschst du das ADIF indem du eine 1 (ADSC) in's ADCSRA
schreibst, und 2. starte ich die AD-Wandlung NACH der Pause. Das Ganze
habe ich nicht selbst erfunden, das ist aus irgendeinem Tutorial, weiß
auf die Schnelle leider nicht von welchem.
@Sonic:
Noch mal ganz präzise für Dich: Das ADSC-Bit (ADC Start Conversion) wird
gesetzt, um eine Wandlung zu starten. Während die Wandlung läuft, bleibt
dieses Bit gesetzt. Wenn man es in einer ansonsten leeren while-Schleife
auf "nicht gesetzt" abfragt, also mit "while(!(ADCSRA & (1 << ADSC)));",
dann wird diese Schleife gar nicht erst betreten, da das ADSC gesetzt
ist und die Bedingung für den Schleifeneintritt nicht erfüllt ist! Das
ADSC wird am Ende der Wandlung von der Hardware zurückgesetzt, und erst
dann darf das Ergebnis ausgelesen werden.
Wenn Du eine Wandlung mit "ADCSRA |= 1 << ADSC;" startest und nach der
von Dir so eisern verteidigten while-Schleife, die nie betreten wird,
das Ergebnis ausliest, dann hat dieses Ergebnis, wenn es überhaupt etwas
Sinnvolles ergibt, nichts mit der aktuellen Wandlung zu tun sondern
stammt im günstigsten Fall von der vorhergehenden Wandlung. Also LASS
DAS "!" IN DER SCHLEIFENBEDINGUNG WEG, ES IST SCHLICHT FALSCH!!! Die
Schleife muss lauten
Übrigens: Das ADIF wird bei jeder Read-Modify-Write-Zugriff auf ADCSRA
gelöscht, und das ist auch i.d.R. gar nicht verkehrt, denn es macht
meist wenig Sinn, im ADCSRA etwas zu ändern, und dabei einen anstehenden
Interrupt "stehenzulassen".
Oder ausführlich:
• Bit 4 – ADIF: ADC Interrupt Flag
This bit is set when an ADC conversion completes and the Data Registers
are updated.
The ADC Conversion Complete Interrupt is executed if the ADIE bit and
the I-bit in
SREG are set. ADIF is cleared by hardware when executing the
corresponding interrupt
handling vector. Alternatively, ADIF is cleared by writing a logical one
to the flag.
Beware that if doing a Read-Modify-Write on ADCSRA, a pending interrupt
can be disabled.
This also applies if the SBI and CBI instructions are used.
Zum Geier noch mal: ADSC != ADIF!!! Das sind zwei völlig verschiedene
Bits! Den ganzen Kram (und vor allem die Datenblattzitate, lesen kann
ich selber!) hättest Du Dir echt sparen können. Wenn Du das Polling mit
dem ADIF machst, dann ist das "!" korrekt. Aber erstens ist es Unsinnig,
mit dem ADIF zu pollen, weil es anschließend noch von Hand gelöscht
werden muss, und zweitens ist bei der (eigentlich einzig sinnvollen)
Polling-Variante, nämlich über das ADSC, das "!" falsch!!!
Das was Du oben geschrieben hast (while(!(ADCSRA & (1<<ADSC)));) ist nur
dann korrekt, wenn man entweder das "!" weglässt oder (nicht
empfehlenswert) das ADSC durch ADIF ersetzt. Jetzt klarer?
@Sonic
"while(!(ADCSRA & (1<<ADSC)));
ist doch korrekt? Oder ist:
while(!(ADCSRA & 0x10));
etwas Anderes? Letzeres läuft bei mir in 'zig Applikationen korrekt!"
ja, das ist was anderes
"ADIF is cleared by hardware when executing the
corresponding interrupt
handling vector. Alternatively, ADIF is cleared by writing a logical one
to the flag."
das solltest du in deinem Code auch so machen
Edit:
> ...weil es anschließend noch von Hand gelöscht werden muss,...
...wenn man sich nicht darauf verlässt, dass es tatsächlich beim
nächsten Setzen von ADSC eh gelöscht wird...
Aber wie gesagt: Nicht durcheinanderbringen. Das Codebeispiel oben
dürfte funktionieren, aber da steht es ja auch ganz anders, als weiter
oben die ganze Zeit behauptet. Und wenn Du jetzt noch das
"while(!(ADCSRA & 0x10))", was ja anscheinend dazu geführt hat, dass Du
alles durcheinandergeschmissen hast, durch ein "while(!(ADCSRA & (1 <<
ADIF)))" ersetzt, dann wird Dir das auch nicht wieder passieren... Da
weiß man nämlich sofort, was da gemacht wird.
Ok, nochmal: Das ADIF wird durch setzen von ADSC gelöscht.
Es wird nach erfolgter Conversion gesetzt und der INT wird ausgelöst.
Wo ist das Problem? Das iste eine gängige Methode per single-convertion
zu Messen.
>wenn man entweder das "!" weglässt oder (nicht empfehlenswert) das ADSC durch
ADIF ersetzt.
Wie ich sehe hast du mein Codebeispiel nicht ausprobiert.
>hättest Du Dir echt sparen können.
Bin halt fleißig! ;-)
Ich glaube, es soll jeder mit seiner Methode glücklich werden, ich bin's
mit meiner jedenfalls!
Vielleicht drücke ich mich unklar aus: Wenn Du mal gründlicher ins
Datenblatt geschaut hättest (anstatt hier rumzuzitieren, wass nix
bringt), dann hättest Du die Frage von 19:47 sofort selber beantworten
können. Da steht nämlich, welches Bit an welcher Stelle im ADCSRA steht,
und dann hättest Du auch gesehen, dass "0x10" nicht gleich "1 << ADSC"
ist, sondern gleich "1 << ADIF"! Da muss dann erst ein anderer
nachsehen...
> Wie ich sehe hast du mein Codebeispiel nicht ausprobiert.
Ach ja, ausprobiert habe ich es nicht, weil ich den ADC praktisch nie im
Polling-Verfahren abfrage. Aber ich habe es mir angesehen und sehe (wie
oben schon mal gesagt) keinen Grund, warum es nicht funktionieren
sollte. Allerdings sehe ich beim nochmaligen Durchgehen auch die Stelle,
an der wir angefangen haben, aneinander vorbeizureden, nämlich genau das
von mir erwähnte Posting von 19:47... Wie gesagt, bevor man so was
schreibt, sollte man schon eben ins Datenblatt schauen, dann erübrigt
sich sowas meist ganz schnell. Und Datenblätter lesen kannste ja...;-)
Muss ich mich denn selber zitieren?
>Ok, nochmal: Das ADIF wird durch setzen von ADSC gelöscht.
Ich löse durch setzen des ADSC ein Messung aus (dazu ist das bit
schließlich da!) und warte bis die Messung beendet ist, angezeigt durch
Wechsel von null auf eins des ADIF.
Liest du eigentlich meine Beiträge oder Codebeipiele durch?
Der Code ist ja auch OK. Und ich habe auch nie behauptet, dass das ADIF
nicht gelöscht wird, wenn ADSC gesetzt wird. Aber es gibt eben zwei
Möglichkeiten der Abfrage, und die sind hier ziemlich
durcheinandergewürfelt worden. Um das ganze zum Abschluss zu bringen:
1
ADCSRA|=1<<ADSC;
2
while(ADCSRA&(1<<ADSC));
3
//...
und
1
ADCSRA|=1<<ADSC;
2
while(!(ADCSRA&(1<<ADIF)));
3
//...
sind von der Funktion her äquivalent. Was nicht geht ist
1
ADCSRA|=1<<ADSC;
2
while(!(ADCSRA&(1<<ADSC)));
3
//...
Ich hoffe, jetzt sind alle Klarheiten restlos beseitigt... Und vergiss
nicht, in Deinem Code das "0x10" durch ein "1 << ADIF" zu ersetzen. Dann
kommen solche Fragen gar nicht erst mehr auf.
Good night...