Forum: Mikrocontroller und Digitale Elektronik Atmega328P ADC Problem


von Neuling (Gast)


Lesenswert?

Hallo zusammen,


ich habe zwar gehofft das Problem alleine lösen zu können, komme aber 
einfach nicht weiter.

Mein ADC des Atmega328P gibt immer den Höchstwert (1023) aus.

Zum Testen hatte ich zunächst eine "komplexere" Schaltung, die ich jetzt 
aber verworfen habe. Nun lese ich die Spannung an einem 
Potentiometerabgriff ein und möchte ab einem bestimmten Grenzwert eine 
LED leuchten lassen.

Mein Code sieht momentan so aus:
1
#include <avr/io.h>
2
3
void ADC_init(void) {
4
  ADMUX |= (1 << REFS0);  //reference voltage on AVCC mit externen Kondensator 100nF an GND
5
  
6
  ADMUX &= ~(1<<MUX0);    // Einstellen Kanal 0
7
  ADMUX &= ~(1<<MUX1);
8
  ADMUX &= ~(1<<MUX2);
9
  ADMUX &= ~(1<<MUX3);
10
  
11
  ADCSRA = (1 << ADEN);  // ADC enablen
12
  ADCSRA |= (1<<ADPS2) | (1 << ADPS1) | (1 << ADPS0);  // Prescaler auf 128 da 16MHz Takt
13
  
14
  ADCSRA |= (1 << ADSC);  // Dummy
15
  while (ADCSRA & (1<<ADSC) ){  // auf Abschluss der Konvertierung warten
16
  }
17
  (void) ADCW;
18
}
19
20
21
22
int main(void) {
23
  
24
  uint16_t PotentiometerWert;
25
  uint16_t Grenzwert;
26
  
27
  Grenzwert= 0b10000000;
28
  
29
  
30
  DDRD |= (1 << DDD2);  
31
  
32
  PRR &= ~(1<<PRADC);    // Datenblatt sagt dieses Bit muss auf 0 gesetzt werden, obwohl kein Beispiel im Internet dies tut...
33
  
34
  ADC_init();
35
36
  while (1) {
37
    
38
    ADCSRA |= (1 << ADSC);  // Start Conversion
39
    while (ADCSRA & (1<<ADSC) ) {   // auf Abschluss der Konvertierung warten
40
    }
41
     
42
    PotentiometerWert= ADCW; 
43
    
44
    if (PotentiometerWert >= Grenzwert) 
45
    {
46
      PORTD |= (1<<PORTD2); 
47
    }
48
    
49
    else 
50
    {
51
      PORTD &= ~(1<<PORTD2); 
52
    }
53
  
54
    return (0); 
55
  }
56
}

Den Atmega328P verwende ich mit einem Arduino Uno Board, daher müsste an 
AVcc bereits Vcc anliegen. Zusätzlich habe ich an den ARef Pin einen 
100nF Kondensator auf GND gelegt. Dass ich den Höchstwert erhalte, habe 
ich getestet, indem ich die IF-Bedingung auf 1023 gesetzt habe und die 
LED immer noch leuchtete.


Ich habe auch gelesen, dass meine Input-Pins einen internen PULLUP 
geschaltet haben könnten. Deshalb habe ich es mit "MCUCR |= (1<<PUD);" 
probiert, um alle Pull-Ups von vorneherein abzuschalten, ohne Erfolg.


Leider weiß ich nun wirklich nicht mehr, woran es liegen könnte, habe 
schon einiges versucht. Eine Idee war noch, dass AVcc wohl doch nicht 
auf 5V liegt und ich deshalb den Höchstwert auslese, aber die Arduino 
Pinbelegung bestätigt dies nicht. Die Suchfunktion hat mir auch keine 
passende Lösung gegeben.


Kann mir vielleicht jemand einen Tipp oder Anhaltspunkt geben?

Ich hoffe meine Formatierung ist in Ordnung, dies ist mein erster Post. 
Für Stilverbesserungen bin ich auch dankbar.

Mit freundlichen Grüßen

von S. Landolt (Gast)


Lesenswert?

Was hat es mit diesem
>     return (0);
auf sich? Ich würde das mal auskommentieren.

von Neuling (Gast)


Lesenswert?

Ja, das kann man einfach ignorieren.

von S. Landolt (Gast)


Lesenswert?

Also, wenn ich das bei mir auskommentiere, dann läuft es.
(Allerdings nicht auf einem Arduino, sondern, festhalten, auf einem 
STK200)

von Thomas E. (thomase)


Lesenswert?

Neuling schrieb:
> Ja, das kann man einfach ignorieren.

Nein. Das gehört da nicht hin, denn der Compiler ignoriert das nicht. 
Also, was soll der Sch...?

von Joachim B. (jar)


Lesenswert?

S. Landolt schrieb:
> Also, wenn ich das bei mir auskommentiere, dann läuft es.
> (Allerdings nicht auf einem Arduino

auskommentiert würde es auch auf dem Arduino laufen!

Entweder Arduino stile

setup()
loop()

oder

AVR

while(1)
und never return!

von Neuling (Gast)


Lesenswert?

> Allerdings nicht auf einem Arduino, sondern, festhalten, auf einem
> STK200

Du hast auch den Atmega328P verwendet? Das ist interessant, 
normalerweise sollte das return 0 keine Rolle spielen. Es liegt also an 
meiner Hardware, wenn ich das richtig deute. Oder kann doch irgendwie 
mein Eingang auf 5V gezogen sein und ich muss das auf andere Weise 
umstellen?

von S. Landolt (Gast)


Lesenswert?

Nicht die leiseste Ahnung, ich habe keinen Arduino (sonst hätte ich es 
ja auf ihm ausprobiert).

von Neuling (Gast)


Lesenswert?

Okay, tut mir leid.

Dann kann man es nicht ignorieren. Sorry für den Sch...

Es funktioniert leider dennoch nicht...

von Joachim B. (jar)


Lesenswert?

Neuling schrieb:
> normalerweise sollte das return 0 keine Rolle spielen.

das erkläre bitte mal!

while(1) hast du ja, aber was passiert wohl bei return?

Das darf da nicht sein!

von Timmo H. (masterfx)


Lesenswert?

Neuling schrieb:
> normalerweise sollte das return 0 keine Rolle spielen
Oh doch. Das return(0) springt wieder zu main(). Das hört sich zwar 
unproblematisch an, aber nach der Initialisierung hat der ADC beim 
ersten Auslesen erstmal Murks raus. Ersten ausgelesenen Wert verwerfen 
und dann in einer while(1) ohne return weiter machen

von Neuling (Gast)


Lesenswert?

>das erkläre bitte mal!


Jetzt sehe ich, dass das return innerhalb der while-Schleife war. Das 
ist natürlich blöd! Ihr habt vollkommen Recht.

Leider will es dennoch nicht funktionieren. Kann es sein, dass irgendein 
Bit beim Arduino gesetzt ist, dass ich clearen muss?

von Stefan S. (chiefeinherjar)


Lesenswert?

Der springende Punkt ist der, dass dein Return INNERHALB der 
While-Schleife steht. Wäre es außerhalb - eine Instanz tiefer - dann 
wäre es tatsächlich wirkungslos.

von Timmo H. (masterfx)


Lesenswert?

Neuling schrieb:
> (void) ADCW;
Was soll das tun?

von Neuling (Gast)


Lesenswert?

>Was soll das tun?

Das habe ich aus dem ADC Tutorial - 
https://www.mikrocontroller.net/articles/AVR-GCC-Tutorial/Analoge_Ein-_und_Ausgabe#ADC_.28Analog_Digital_Converter.29 
aus Verzweiflung übernommen, da es nicht funktionierte.

von Thomas E. (thomase)


Lesenswert?

Timmo H. schrieb:
> Was soll das tun?

Damit wird lesend auf die ADC-Register zugegriffen.

Das gesamte Dummy-Read:
1
ADCSRA |= (1 << ADSC);
2
while (ADCSRA & (1<<ADSC));
3
(void) ADCW;

ist überflüssig, schadet aber auch nicht.

von Timmo H. (masterfx)


Lesenswert?

Neuling schrieb:
>>Was soll das tun?
>
> Das habe ich aus dem ADC Tutorial -
> https://www.mikrocontroller.net/articles/AVR-GCC-T...
> aus Verzweiflung übernommen, da es nicht funktionierte.
Also wenn man das Beispiel aus dem Tutorial 1:1 übernimmt, funzt es bei 
mir auf dem 328p. Solltest du vielleicht auch mal machen

von Neuling (Gast)


Lesenswert?

>Also wenn man das Beispiel aus dem Tutorial 1:1 übernimmt, funzt es bei
>mir auf dem 328p. Solltest du vielleicht auch mal machen

Habe ich eben auch mal probiert, ohne Erfolg. Ich schätze mal irgendeine 
Eigenheit vom Arduino verhindert das Funktionieren. Ich meine es ist 
schon verdächtig, dass ich immer den Höchstwert einlese.

von Thomas E. (thomase)


Lesenswert?

Neuling schrieb:
> Ich meine es ist
> schon verdächtig, dass ich immer den Höchstwert einlese.

Vielleicht hast du auch nur das Poti falsch angeschlossen.
Wie hoch ist denn deine Referenzspannug tatsächlich? Kannst du mit nem 
Multimeter an Aref messen.

von Neuling (Gast)


Lesenswert?

> Kannst du mit nem Multimeter an Aref messen.

Ich werde morgen einmal nachmessen.

Außerdem will ich noch einmal ein Standardprojekt mit Arduino-Code 
(analogRead()) testen, ob da das gleiche Problem besteht, da ich mich 
nicht mehr richtig erinnern kann. (Ich wollte mich von 
Arduino-Programmierung entfernen, habe ansonsten nur mit STM32 (Cortex 
M3)  Erfahrung)

von Timmo H. (masterfx)


Lesenswert?

Neuling schrieb:
>>Also wenn man das Beispiel aus dem Tutorial 1:1 übernimmt, funzt
> es bei
>>mir auf dem 328p. Solltest du vielleicht auch mal machen
>
> Habe ich eben auch mal probiert, ohne Erfolg. Ich schätze mal irgendeine
> Eigenheit vom Arduino verhindert das Funktionieren. Ich meine es ist
> schon verdächtig, dass ich immer den Höchstwert einlese.
Habs auch auf einen Arduino geschossen

von Einer K. (Gast)


Lesenswert?

Als Kontrollleuchte habe LED_BULITIN an Pin 13 verwendet

Hier einmal in Arduino Fassung:
1
void ADC_init(void) 
2
{
3
  ADMUX = (1 << REFS0);  //reference voltage on AVCC mit externen Kondensator 100nF an GND
4
5
  /* 0 ist ADC0
6
  ADMUX &= ~(1<<MUX0);    // Einstellen Kanal 0
7
  ADMUX &= ~(1<<MUX1);
8
  ADMUX &= ~(1<<MUX2);
9
  ADMUX &= ~(1<<MUX3);
10
 */ 
11
  ADCSRA  = (1 << ADEN);  // ADC enablen
12
  ADCSRA |= (1<<ADPS2) | (1 << ADPS1) | (1 << ADPS0);  // Prescaler auf 128 da 16MHz Takt
13
  ADCSRB  = 0;
14
}
15
16
int ADC_read()
17
{
18
 ADCSRA |= (1 << ADSC);  // Start Conversion
19
 while (ADCSRA & (1<<ADSC) );  // auf Abschluss der Konvertierung warten
20
 return ADCW; ;
21
}
22
23
void setup() 
24
{
25
  Serial.begin(9600);
26
  Serial.println("Start");
27
  DDRB |= (1 << PB5); 
28
  ADC_init();
29
  ADC_read();// dummy read
30
}
31
32
void loop() 
33
{
34
  int Grenzwert = 500;
35
  int PotentiometerWert = ADC_read();
36
  Serial.println(PotentiometerWert);
37
  if (PotentiometerWert >= Grenzwert) 
38
  {
39
     PORTB |= (1<<PB5); 
40
  }else 
41
  {
42
     PORTB &= ~(1<<PB5); 
43
  }
44
  
45
  delay(1000);
46
}



--------------------------------------
Und einmal für den Rest der Welt:
1
#include <avr/io.h>
2
3
void ADC_init(void) 
4
{
5
  ADMUX = (1 << REFS0);  //reference voltage on AVCC mit externen Kondensator 100nF an GND
6
7
  /* 0 ist ADC0
8
  ADMUX &= ~(1<<MUX0);    // Einstellen Kanal 0
9
  ADMUX &= ~(1<<MUX1);
10
  ADMUX &= ~(1<<MUX2);
11
  ADMUX &= ~(1<<MUX3);
12
 */ 
13
  ADCSRA  = (1 << ADEN);  // ADC enablen
14
  ADCSRA |= (1<<ADPS2) | (1 << ADPS1) | (1 << ADPS0);  // Prescaler auf 128 da 16MHz Takt
15
  ADCSRB  = 0;
16
}
17
18
int ADC_read()
19
{
20
 ADCSRA |= (1 << ADSC);  // Start Conversion
21
 while (ADCSRA & (1<<ADSC) );  // auf Abschluss der Konvertierung warten
22
 return ADCW; ;
23
}
24
25
int main(void) 
26
{
27
  DDRB |= (1 << PB5); 
28
  ADC_init();
29
  ADC_read();// dummy read
30
31
      for(;;) 
32
      {
33
        int Grenzwert = 500;
34
        int PotentiometerWert = ADC_read();
35
        if (PotentiometerWert >= Grenzwert) 
36
        {
37
           PORTB |= (1<<PB5); 
38
        }else 
39
        {
40
           PORTB &= ~(1<<PB5); 
41
        }
42
      }
43
   return 0;
44
}

Beide Versionen geprüft und als funktionsfähig erklärt.

Schöner geht immer, soll allerdings nicht meine Baustelle sein.

von Sourcen Aesthet (Gast)


Lesenswert?

Arduino Fanboy D. schrieb:
> Schöner geht immer, soll allerdings nicht meine Baustelle sein.

Wenn nur andere Leute auch solch "unschöne" Listings
liefern würden (das ist Ordnung pur gegenüber dem
Chaos von Anderen!).

von Einer K. (Gast)


Lesenswert?

Danke, für die Blumen!

Das ist purer Eigennutz.
Denn allzu schlampige Arbeit fällt einem auf die Zehen.

von Daniel B. (daniel_3d)


Lesenswert?

Kann es sein, dass die LED auf Masse geschaltet wird?

Gruß Daniel

von Daniel B. (daniel_3d)


Lesenswert?

1
#define F_CPU 8000000
2
#include <avr/io.h>
3
4
5
int main(void) {
6
    
7
  // ADC-Setup    Register komplett hingeschrieben, dann muss ich nur noch 1 und 0 eintragen
8
  ADMUX = 0<<REFS1 | 1<<REFS0 | 0<<ADLAR | 0<<MUX3 | 0<<MUX2 | 0<<MUX1 | 0<<MUX0;          // Vcc Ref
9
  ADCSRA = 1<<ADEN | 1<<ADSC | 0<<ADATE | 0<<ADIF | 0<<ADIE | 1<<ADPS2 | 1<<ADPS1 | 1<<ADPS0;    // 62,5 kHz
10
  while (ADCSRA & 1<<ADSC) {}        // Warten bis die Dummy-Wandlung abgeschlossen ist
11
  (void) ADC;                // Dummy-Ergebnis verwerfen
12
  
13
  DDRB |= (1<<5);    // Onboard-LED ist an PB5 High-Active
14
  DDRB |= (1<<1);    // Hier schalte ich PORTB1 auf HIGH als Ausgang
15
  PORTB |= (1<<1);  // Hier schalte ich PORTB1 auf HIGH als Spannungsversorgung für das Poti
16
  
17
  uint16_t Grenzwert = 0;
18
  
19
    while (1) {
20
        
21
    Grenzwert = 500;
22
    
23
    ADCSRA |= (1<<ADSC);        // ADC starten
24
    while ( ADCSRA & 1<<ADSC ) {}    // Warten bis die Wandlung abgeschlossen ist
25
    
26
    if (ADC > Grenzwert) {
27
      PORTB |= (1<<5);
28
    }  
29
      else {
30
        PORTB &= ~(1<<5);
31
      }
32
   
33
    } // Ende while (1)
34
} // Ende int main(void)

Ich habe dir mal ein paar Zeilen getippt.
Läuft auf einem Pro Mini - Klon von Pollin (810366) mit ATmega168PA oder 
ATmega328PA.
Ich erinnere mich noch an meine ersten Gehversuche mit den Atmels und 
wäre auch heilfroh über ein paar einfache Zeilen Code gewesen.

Das Poti hängt an GND und über PB2 an Vcc. Der Abgriff geht auf ADC0.

Hoffe ich konnte dir helfen.

Gruß Daniel

von Neuling (Gast)


Lesenswert?

Guten Tag zusammen,


erstmal vielen Dank and Daniel und Arduino Fanboy, dass ihr euch die 
Zeit genommen habt. Auch ein Danke an Thomas. Das Nachmessen hat 
wirklich ergeben, dass an ARef 0V lagen (wobei mein DMM schrecklich 
ist). Tja woran lags? Ich habe mit meiner tollen Noise Reduction den 
ARef Pin auf Masse gezogen, da ich  auf dem Breadboard den Kondensator 
kurzgeschlossen habe. Dämlich ich weiß. Jedenfalls bin ich froh, dass es 
nicht der Code war (das return war doof kopiert und hätte ich niemals an 
diese Stelle geschrieben).

>Kann es sein, dass die LED auf Masse geschaltet wird?


Was wäre daran verwerflich?

von Daniel B. (daniel_3d)


Lesenswert?

Neuling schrieb:
> Was wäre daran verwerflich?

Überhaupt nichts :-)

Aber du würdest den Fehler dann vielleicht an der falschen Stelle 
suchen.

Freut mich, dass es jetzt klappt.

Gruß Daniel

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.