Atmega328P ADC Problem

Gast #5491295
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
Gast #5491444
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?
Gast #5491460
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?
Gast #5491503
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.
Gast #5491520
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)
#5491535
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
Gast #5491547
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.
#5491699
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
Gast #5492528
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?

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