4 Potis an ATmega

Gast #3868696
Lesenswert?

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_t ADC_Read( uint8_t channel )
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
7
  }
8
  return ADCW;                    // ADC auslesen und zurückgeben
9
}
10

11
ISR(TIMER2_OVF_vect)                  // 1ms Takt
12
{
13
  switch (Analogkanal)
14
  {
15
    case 0:
16
      Poti_Fernsehpos = ADC_Read(0);
17
      Analogkanal += 1;
18
      break;
19
    case 1:
20
      Poti_Unten = ADC_Read(1);
21
      Analogkanal += 1;
22
      break;
23
    case 2:
24
      Poti_Kueche = ADC_Read(2);
25
      Analogkanal += 1;
26
      break;
27
    case 3:
28
      Poti_Esszimmer = ADC_Read(3);
29
      Analogkanal = 0;
30
      break;
31
  }
32
}
Gruß Alex
Angehängte Dateien:
#3868719
Lesenswert?

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.
Gast #3868727
Lesenswert?

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.
Gast #3868729
Lesenswert?

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
(Firma: matzetronics) #3868731
Lesenswert?

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.
Gast #3868762
Lesenswert?

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 ???
Gast #3868778
Lesenswert?

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
#3868802
Lesenswert?

spess53 schrieb:
> Dann bleibt immer noch die Frage zum ADC-Takt.
1
#if (F_CPU / 2) <= 200000
2
  #define ADC_DEFAULT_PRESCALER (1 << ADPS0)
3
#elif (F_CPU / 4) <= 200000
4
  #define ADC_DEFAULT_PRESCALER (1 << ADPS1)
5
#elif (F_CPU / 8) <= 200000
6
  #define ADC_DEFAULT_PRESCALER ((1 << ADPS1) | (1 << ADPS0))
7
#elif (F_CPU / 16) <= 200000
8
  #define ADC_DEFAULT_PRESCALER (1 << ADPS2)
9
#elif (F_CPU / 32) <= 200000
10
  #define ADC_DEFAULT_PRESCALER ((1 << ADPS2) | (1 << ADPS0))
11
#elif (F_CPU / 64) <= 200000
12
  #define ADC_DEFAULT_PRESCALER ((1 << ADPS2) | (1 << ADPS1))
13
#elif (F_CPU / 128) <= 200000
14
  #define ADC_DEFAULT_PRESCALER ((1 << ADPS2) | (1 << ADPS1) | (1 << ADPS0))
15
#endif

mfg.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren