ATmega16: ADC0 Wert schwankt obwohl konst. Spannung anliegt

Gast #3163782
Lesenswert?

Hallo zusammen,

versuche zur Zeit eine Messwerterfassung mit dem ATmeag16A zu 
realisieren.
Dabei versuche ich mittels Poti (10k) die Eingangsspannung von 0 .... 5 
V zu simmulieren um später z.B. Drucksensoren anschließen zu können.
Mit drei Poti's gehe ich auf die ADC - Eingänge ADC0, ADC1, ADC2.
2 der 3 Kanäle funktionieren auch soweit ganz gut aber bei einem der 3 
treten ziemlich starke Schwankungen auf, obwohl ich am Eingang eine 
konstante Poti - Spannung anliegen habe.
Habe schon versucht einen 100nF Kondensator zwischen Analogeingang 
(ADC0) und GND zu setzen, kein Erfolg.
Auch sonst habe ich einen weiteren 100nF Kondensator an AREF und 
zwischen AVCC und GND, kein Erfolg.

Kann mir vielleicht jemand helfen bei meinem Problem?


Danke schonmal im Voraus.

Gruß David
Angehängte Dateien:
Moderator (Firma: Titel) Persönliche Seite #3163794
Lesenswert?

David schrieb:
> aber bei einem der 3 treten ziemlich starke Schwankungen auf
Bei welchem?

Und warum schreibst du da so einen Spaghetti-Code? Du machst dreimal 
fast das selbe, da wäre ein Schleife oder ein Zustandsautomat die 
richtige Lösung. Und wenn du jetzt sagst "Zustandsautomat? Zu 
kompliziert!" dann lass dir gesagt sein: du hast schon einen gebaut. 
Aber eben einen umständlichen:
1
    if (ADMUX & (1<<MUX0))         
2
      :
3
      ADMUX &= ~(1<<MUX0);
4
      ADMUX |= (1<<MUX1);
5
    }  
6
    else
7
    {
8
      if (ADMUX & (1<<MUX1))
9
        :
10
        ADMUX &= ~(1<<MUX0);
11
        ADMUX &= ~(1<<MUX1);
12
        ADMUX |= (1<<MUX2);
13

14
      }  
15
      else
16
      {
17
        if(ADMUX & (1<<MUX2))
18
          :
19
          ADMUX &= ~(1<<MUX2);
20
          ADMUX |= (1<<MUX0);
21
          _delay_ms(100);
22
        }
23
      }
24
    }
Das ist ein Automat, weil bei jedem Schleifendurchlauf anhand der 
"Zustandvariablen" ADMUX ausgesucht wird, welcher Kanal jetzt gewandelt 
werden soll.


BTW, das finde ich allerliebst:
1
    if (ADMUX & (1<<MUX0))  // erster wert jeder Wandlung verwerfen, damit sich ADC Multiplexer einschwingen kann
Leider hast du da offenbar das Datenblatt nicht ganz oder nicht an der 
richtigen Stelle gelesen. Das wäre ja ein total vermurkster uC, wenn man 
nach dem Umschalten des MUX jedesmal eine Wandlung wegwerfen müsste...
Gast #3163820
Lesenswert?

Also das Problem mit dem Schwanken habe ich denke ich hinbekommen bzw. 
meinen Fehler erkannt: Es lag an MUX 2 , danke Thomas ;)


Mit dem Automaten verstehe ich allerdings noch nicht so ganz, wie kann 
ich denn die ADC - Kanäle anders ansteuern?

Mein Porblem was ich jetzt habe ist diese hier:

if((ADMUX & (1<<MUX0)) && (ADMUX & (1<<MUX1)))
.
.
.

Was daran ist falsch?


Sorry habe noch nicht so viel Ahnung von µC, bin noch nicht so lange 
dabei.
Angehängte Dateien:
#3163844
Lesenswert?

Falsch ist das nicht, nur unelegant. Weil du mehrmals fast identischen 
Code wiederholt hast. Wirklich elegant wäre, den ADC Interrupt zu 
nutzen:
1
#include <avr/interrupt.h>
2
#include <stdint.h>
3

4
// Werte vom ADC, für die vier Kanäle
5
static volatile uint16_t adc_value[4];
6

7
// Unterbrechung vom ADC
8
ISR(ADC_vect) {
9
    // Lese den ADC aus
10
    uint8_t channel = ADMUX & 7;  
11
    adc_value[channel] = ADC;
12

13
    // Schalte auf den nächsten Kanal um.
14
    if (++channel > 3) {
15
        channel=0;
16
    }
17
    ADMUX=(ADMUX & ~7) | channel;
18

19
    // Starte nächste Messung
20
    ADCSRA |= (1<<ADSC); 
21
}
22

23
void main() {
24
    // Initialisiere den ADC
25
    ADCSRA = (1<<ADEN) | (1<<ADPS2) | (1<<ADPS1) | (1<<ADPS0) | (1<<ADIE) | (1<<ADSC); 
26
    ADMUX = REF_VCC;
27

28
    // Erlaube Unterbrechungen
29
    sei();
30

31
    uint8_t channel=0;
32
    while(1) {
33
       _delay_ms(100);
34
       // gib den Wert von adc_value[channel] hier aus
35
       ...
36
       // Zum nächsten Kanal wechseln
37
       if (++channel > 3) {
38
        channel=0;
39
       }
40
    }
41
}
Gast #3163864
Lesenswert?

Hi

>Wirklich elegant wäre, den ADC Interrupt zu nutzen:

Noch eleganter wäre es mit Timergesteuertem Autotrigger.


>    if (++channel > 3) {
>        channel=0;

Er braucht aber nur Channel 0,1 und 2.

@David (Gast)

Den Prescaler würde ich auf 128 erhöhen. Damit liegst du dann im 
empfohlenen Bereich von 50...200kHz für den ADC-Takt.

MfG Spess

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