PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Zwei Kanaele des ADC spinnen...



Minifriese
23.06.2005, 18:24
Moin moin!

Ich versuche zwei Werte ueber den ADC eines ATmega16 einzulesen, aber irgendwie klappt's nicht so wie ich will. Beide Kanaele einzeln gehen (Wenn ich den jeweils anderen Block unten auskommentiere). Wenn ich an beiden Kanaelen was anschliesse, gibt's auf x und w (auf beiden gleich) einen Mix der beiden Werte. Mach ich irgendwas falsch? Ich will keine Interrupts verwenden, nur pollen. Muss ich vielleicht trotzdem ADIF auslesen?? Eigentlich muesste doch das Warten auf ADSC==0 reichen?????
Kann jemand helfen?


int main(void) {
init();

while(1) {
ADMUX=(1<<MUX0); // Kanal 1 auswaehlen
ADCSR|=(1<<ADSC); // Messung starten
while((ADCSR&ADSC)==1) ; // Warten bis ADSC==0
w=ADCL+ADCH*256; // Ergebnis auslesen

ADMUX=(1<<MUX1)|(1<<MUX0); // Kanal 3 auswaehlen
ADCSR|=(1<<ADSC); // Messung starten
while((ADCSR&ADSC)==1) ; // Warten bis ADSC==0
x=ADCL+ADCH*256; // Ergebnis auslesen

print(w,0,x,200);
}
}

Nils

RCO
23.06.2005, 19:04
Also normalerweise wird es schon über ADIF gemacht:


while(!(ADCSRA & (1<<ADIF)));

Aber im Datenblatt steht:


ADSC will read as one as long as a conversion is in progress. When the conversion is
complete, it returns to zero. Writing zero to this bit has no effect.

Das es nicht läuft könnte aber auch daran liegen, dass es kein Register "ADCSR" beim Mega16 gibt ;-)
Versuchs mal mit ADCSRA!

Minifriese
23.06.2005, 20:51
Nabend,

Hab das Register auf ADCSRA geaendert, keine Ahnung warum mein Compiler das andere nicht angemeckert hat.
Ich hab jetzt mal nen anderen Kanal ausprobiert (1 und 5 statt 1 und 3), damit geht's. Sehr suspekt... Vielleicht eine kleine Ungenauigkeit im AVR-MUX :-)
Nils

PicNick
23.06.2005, 20:58
Ich muß mir das auch wenigstens noch dreimal im Datasheet durchlesen.
BasCom macht das so: Wenn er einen kanal mit Getadc(n) liest,
setzt er admux
macht eine Blindmessung
Und noch eine, und diesen wert gibt er dann her.

Offensichtlich läßt er sich gar nicht erst auf das Timing mit mux und adc-status ein

Betrachte ich als workaround, aber wenn's schön macht ?

Minifriese
23.06.2005, 21:05
Die Blindmessung mach der AVR bei der ersten Messung, jede weitere wird dann nur einmal ausgefuehrt. Und wenn sie fertig ist, geht erstens ADSC wieder auf Null und ADIF auf Eins. Ich hab beides als Wartekriterium ausprobiert, ging beides nicht, Effekt wie oben beschrieben. Mit dem anderen Kanal geht's aber, weiss der Geier wieso.
Nils

RCO
23.06.2005, 21:06
Also unter C gehts auf jeden Fall anders, du schaltest ja nur den kanal um, warum dann ne Blindmessung?
Ungenauigkeit glaub ich nciht, bei mir läuft der ADC des Mega16 bisher ohne irgendwelche Probleme, auch wenn ich ständig die Kanäle wechsle.
Wie ist der ADC denn sonst noch konfiguriert?

Minifriese
23.06.2005, 21:12
In meiner init():


ADCSRA=(1<<ADEN)|(1<<ADPS2)|(1<<ADPS1)|(0<<ADPS0);

Und diese Funktion wird in main() zyklisch aufgerufen:


void read_inputs(void) {
ADMUX=(1<<MUX0); // Kanal 1 auswaehlen
ADCSRA|=(1<<ADSC); // Messung starten
while(!(ADCSRA & (1<<ADIF))); // Warten bis ADSC==0
ADCSRA|=(1<<ADIF); // ADIF auf Null setzen !?!
w=ADCL+ADCH*256; // Ergebnis auslesen

ADMUX=(1<<MUX2)|(1<<MUX0); // Kanal 5 auswaehlen
ADCSRA|=(1<<ADSC); // Messung starten
while(!(ADCSRA & (1<<ADIF))); // Warten bis ADSC==0
ADCSRA|=(1<<ADIF); // ADIF auf Null setzen !?!
x=ADCL+ADCH*256; // Ergebnis auslesen
}

Der ATmega16 laeuft mit 8MHz. Das mit dem ADIF auf Null setzen, indem man ne Eins reinschreibt, steht so im Datenblatt...

Nils

Minifriese
01.07.2005, 17:13
Moin moin!

Ich kaempfe immer noch mit dem ADC. Irgendwie beeinflussen sich die Kanaele untereinander. Wenn ich an drei ADCs gleichzeitig verschiedene Werte anlege, bekomme ich auf zweien den gleichen Wert, je einen der beiden erwarteten. Also zum Beispiel ist
ADC0=522,
ADC1=470,
ADC2=1023.
Das kommt raus, wenn ich nur den jeweiligen Block im Code benutze und den Rest auskommentiere. So wie es unten steht, kommt aber dann raus:

ADC0=522,
ADC1=1023,
ADC2=1023.

Ich krieg einfach nicht raus, wieso. Der Code unten muesste doch stimmen, oder? Kann vielleicht mal jemand seinen funktionierenden Code fuer das Auslesen von mehreren ADCs posten???

Danke,
Nils



void read_inputs(void) {
ADMUX = 0x02; // Kanal 0 auswaehlen
ADCSRA |= (1<<ADSC); // Messung starten
while(!(ADCSRA & (1<<ADIF))); // Warten bis ADSC==0
ADCSRA |= (1<<ADIF); // ADIF auf Null setzen !?!
rohsollwert = ADCL+ADCH*256; // Ergebnis auslesen
sollwert = rohsollwert/1023.0*100; // In Prozent umrechnen

ADMUX = 0x01; // Kanal 1 auswaehlen
ADCSRA |= (1<<ADSC); // Messung starten
while(!(ADCSRA & (1<<ADIF))); // Warten bis ADSC==0
ADCSRA |= (1<<ADIF); // ADIF auf Null setzen !?!
rohistwertx = ADCL+ADCH*256; // Ergebnis auslesen
istwertx = rohistwertx/1023.0*100; // In Prozent umrechnen

ADMUX = 0x00; // Kanal 2 auswaehlen
ADCSRA |= (1<<ADSC); // Messung starten
while(!(ADCSRA & (1<<ADIF))); // Warten bis ADSC==0
ADCSRA |= (1<<ADIF); // ADIF auf Null setzen !?!
rohistwerty = ADCL+ADCH*256; // Ergebnis auslesen
istwerty = rohistwerty/1023.0*100; // In Prozent umrechnen
}

PicNick
01.07.2005, 18:54
rohsollwert = ADCL+ADCH*256; // Ergebnis auslesen

Ich bin nicht sicher, ob der C die beiden Werte H u.L dann in der richtigen Reihenfolge liest, und da ist der AVR heikel, weil er die Register sperrt.
Schau mal in das Assembler listing, zu Kontrolle

Minifriese
01.07.2005, 19:12
An der Stelle haette ich das Problem weniger vermutet, weil ja die Werte stimmen, wenn ich die Kanaele einzeln auslese. Also denke ich, dass dabei ADCL zuerst gelesen wird, wie im Datenblatt vorgeschrieben.

Habs gerade getestet, wenn ich die Zeile umdrehe, werden alle drei Werte als 520 angezeigt, auch wenn ich die Eingangsspannungen aendere...
Nils

Kjion
01.07.2005, 20:24
Hi,

sollte eigentlich so stimmen. Versuch doch mal das ganze folgendermaßen zu ändern:


void read_inputs(void) {
ADMUX = 0x02; // Kanal 0 auswaehlen
ADCSRA |= (1<<ADSC); // Messung starten
while(!(ADCSRA & (1<<ADIF))); // Warten bis ADSC==0
ADCSRA |= (1<<ADIF); // ADIF auf Null setzen !?!
rohsollwert = ADCL; // Ergebnis auslesen
rohsollwert |= (ADCH<<8);
sollwert = rohsollwert/1023.0*100; // In Prozent umrechnen

ADMUX = 0x01; // Kanal 1 auswaehlen
ADCSRA |= (1<<ADSC); // Messung starten
while(!(ADCSRA & (1<<ADIF))); // Warten bis ADSC==0
ADCSRA |= (1<<ADIF); // ADIF auf Null setzen !?!
rohistwertx = ADCL; // Ergebnis auslesen
rohistwertx |= (ADCH<<8);
istwertx = rohistwertx/1023.0*100; // In Prozent umrechnen

ADMUX = 0x00; // Kanal 2 auswaehlen
ADCSRA |= (1<<ADSC); // Messung starten
while(!(ADCSRA & (1<<ADIF))); // Warten bis ADSC==0
ADCSRA |= (1<<ADIF); // ADIF auf Null setzen !?!
rohistwerty = ADCL; // Ergebnis auslesen
rohistwerty |= (ADCH<<8);
istwerty = rohistwerty/1023.0*100; // In Prozent umrechnen
}

Ansonsten hätte ich auch keine Idee woran es liegen könnte...

MfG Kjion

Minifriese
01.07.2005, 20:45
Kann es vielleicht mit der Schaltung zusammenhaengen? Einer der drei Eingaenge ist der Mittelabgriff eines Potis an 5V, also fast ohne Fehlerquellen. Der kommt auch immer durch. Die anderen beiden sind die beiden Kanaele eines ADXL202. Und es ist immer immer einer der beiden ADXL-Kanaele, der sich "einem anderen Kanal anschliesst", anstatt seinen eigenen Wert durchzugeben...

Kann es sein, dass der ADC zum Beispiel einen zu geringen Eingangswiderstand hat und der ADXL dann Mist macht? Ist der empfindlich gegenueber sowas? Andererseits messe ich ja nacheinander, da sollte das eigentlich nix ausmachen...

Nils

skillii
05.07.2005, 16:10
ich denke nicht dass die ADC-Ports zu geringe Eingangswiderstände haben...
Versuch doch mal mit einem Voltmeter nachzumessen welche Spannungen die ADXL liefern ...
mfg

Minifriese
05.07.2005, 16:48
Hab ich schon gemacht, die Spannungen am ADXL sind so, wie sie sein sollen. Das muss irgendwie am AVR liegen. Hab bloss keine Ahnung wie...
Nils