Hallo,
ich möchte gerne 4 Poti an einem ATMega betreiben und die Analogwerte im
Programm verwenden. Allerdings habe ich das Problem, das mir die Werte
nicht richtig eingelesen werden.
Wenn ich an einem Poti drehen, dann ändern sich auch die anderen Werte
ein wenig.
Hab ich einen Denkfehler im Schaltungsaufbau, oder hab ich einen Fehler
in der Programmierung.
Hier der Ausschnitt des Codes.
Die Funktion wird alle 1ms aufgerufen
1
uint16_tADC_Read(uint8_tchannel)
2
{
3
// Kanal waehlen, ohne andere Bits zu beeinflußen
4
ADMUX=(ADMUX&~(0x1F))|(channel&0x1F);
5
ADCSRA|=(1<<ADSC);// eine Wandlung "single conversion"
6
while(ADCSRA&(1<<ADSC)){// auf Abschluss der Konvertierung warten
Bis darauf, dass du den GND Pin 53 nicht angeschlossen hast, seh ich
erst mal nichts schlimmes.
Ich denke, dein Problem hängt mit der Sample und Hold Stufe im ADC
zusammen. Wenn du den Kanal wechselst, muss sich erst ein kleiner
Kondensator in der S&H Stufe auf den neuen Spannungswert einstellen. Das
dauert seine Zeit. Beginnst du zu früh damit, den ADC zu starten, dann
ist der Kondensator noch nicht auf die neue Spannung eingestellt und du
hast ein kleines 'Übersprechen'.
Ich würd die Sache anders aufziehen.
In der ISR würde ich die Reihenfolge umdrehen
1
ISR( ... )
2
{
3
ADC starten und auf fertig warten
4
Wert vom ADC holen und auf die richtige Variable verteilen
5
Den Mutiplexer auf den nächsten Kanal einstellen
6
}
Auf die Art hat die S&H Stufe Zeit bis zum nächsten ISR Aufruf (nach
1ms) um sich auf den neuen Kanal einzustellen. Die eigentliche Wandlung
findet dann erst im nächsten ISR Aufruf statt. Bis dahin hat sich aber
die ganze analoge Eingangsstufe schon auf die neue Spannung vom nächsten
Poti eingestellt.
Hi
Mit welchem Takt läuft dein ADC?
Außerdem dürfte die Belastung von ADREF mit 2,5k etwas zu hoch sein.
Ein 100n Kerko von den ADC-Eingängen nach Masse dürfte auch nicht
schaden.
MfG Spess
Ist Analogkanal volatile deklariert? Ansonsten höchst ineffektiv, in der
ISR auf das Ende der Wandlung zu warten. Sinnvoller wäre, den ADC
freilaufend zu konfigurieren und den ADCC-Interrupt nutzen. Spart auch
den Timer.
Super für die schnell Hilfe,
den Pin 53 hab ich ja voll übersehen. Werde ich dann mal auf GND
brücken.
Die Routine werde ich auch anpassen und dann hoffe ich es passt.
Ist es sinnvoll einen Kanal mehrere mal auszulesen und dann einen
Mittelwert zu bilden, oder sind diese recht stabil. Ich habe 25 Gang
Potis eingesetzt.
Gruß ALex
Es schadet nicht, an AREF noch einen 100nF gegen Masse zu legen, um die
Referenz stabiler und störunanfälliger zu machen.
Ein weiterer Trick, um den internen S&H Kondensator schnell umzuladen,
ist es, an jeden AD Eingang noch einen externen C gegen Masse zu legen.
Das kann z.B. ein 1nF-10nF sein. Dieser wird beim Umschalten des Mux
rapide in den internen C geladen und verringert so das 'Mitziehen' von
Nachbarkanälen.
Loipe schrieb:> Ist es sinnvoll einen Kanal mehrere mal auszulesen und dann einen> Mittelwert zu bilden, oder sind diese recht stabil
Eigentlich sollten sie nach den o.a. Massnahmen schon recht stabil sein.
Ich mache meistens nur ein '2-fach Oversampling', d.h. ich addiere das
neue Ergebnis zum vorigen Ergebnis und teile dann durch 2. Dann steht
das alles recht stabil.
Schalte deine Potis "oben" an VCC und miss auch gegen Vcc. Dann hast du
auch kein Problem, dass dir was zusammenbricht. Eine besondere Referenz
brauchst du nicht.Es werden nur Verhältnisse gemessen. Die sind bei
jeder Spannung gleich.
mfg.
Oh, das sehe ich erst jetzt: AREF kann auf keinen Fall eine Last von
2,5K versorgen. Das ist viel zu viel Strom.
Du musst also entweder die Potis über einen Opamp als Spannungsfolger
aus AREF speisen oder dich für z.B. Vcc als AREF entscheiden.
Edit: thomase war schneller :-)
Und wenn ich 4 100k Potis verwende, kann ich dann AREF verwenden ?
Den ADC habe ich wie folgt Initialisiert.
void ADC_Init(void) {
// die Versorgungsspannung AVcc als Refernz wählen:
ADMUX = (1<<REFS0);
// oder interne Referenzspannung als Referenz für den ADC wählen:
// ADMUX = (1<<REFS1) | (1<<REFS0);
// Bit ADFR ("free running") in ADCSRA steht beim Einschalten
// schon auf 0, also single conversion
ADCSRA = (1<<ADPS1) | (1<<ADPS0); // Frequenzvorteiler
ADCSRA |= (1<<ADEN); // ADC aktivieren
/* nach Aktivieren des ADC wird ein "Dummy-Readout" empfohlen, man
liest
also einen Wert und verwirft diesen, um den ADC "warmlaufen zu
lassen" */
ADCSRA |= (1<<ADSC); // eine ADC-Wandlung
while (ADCSRA & (1<<ADSC) ) { // auf Abschluss der
Konvertierung warten
}
/* ADCW muss einmal gelesen werden, sonst wird Ergebnis der nächsten
Wandlung nicht übernommen. */
(void) ADCW;
}
Mir ist gerade aufgefallen, dass ich gegen die falsche
Versorgungsspannung messe. Ich habe im Programm AVCC eingestellt. Dort
muss ich auf interne Referenz stellen, oder ???
Loipe schrieb:> Mir ist gerade aufgefallen, dass ich gegen die falsche> Versorgungsspannung messe. Ich habe im Programm AVCC eingestellt. Dort> muss ich auf interne Referenz stellen, oder ???
Nein, du brauchst keine extra Referenz. Nimm AVcc für die Potis und als
Referenz.
mfg.
Hi
>ADCSRA = (1<<ADPS1) | (1<<ADPS0);
Das ist ein Prescaler von 8. Wenn du wirklich 14,7456MHz hast ist das
ein ADC-Takt von 1,843 MHz. Das ist viel zu hoch. Setze den Prescaler
auf 128.
MfG Spess