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

Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt. Bitte hier nur auf die ursprüngliche Frage antworten, für neue Fragen einen neuen Beitrag erstellen.

Formatierung
  • [c]C-Code[/c]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] – Link zu einem Artikel
  • Verweis auf einen anderen Beitrag: Rechtsklick auf dessen Beitrags-ID (#8078628), „Adresse kopieren“, in den Text einfügen

Mehr zur Formatierung

Längeren Sourcecode als Anhang, nicht in den Text. JPG nur für Fotos und Scans; Zeichnungen und Screenshots als PNG oder GIF. Siehe Bildformate.

Schon registriert? Anmelden

Wird nicht angezeigt. Wir schicken dir einen Link; sobald du damit bestätigst, erscheint dein Beitrag.

Mit dem Abschicken legst du einen kostenlosen Account an und erkennst die Nutzungsbedingungen und die Datenschutzerklärung an.