Forum: Mikrocontroller und Digitale Elektronik Probleme mitADC im Atmega8


von Penie L. (peniely)


Lesenswert?

Hallo,

Ich habe ein kleines Problem mit meinem ADC und hoffe ihr könnt mir 
weiterhelfen.

Ich besitze ein STK 500 Board und möchte per AD-Wandler mit dem ATMEGA8 
über den PC0 Eingang einen Analogwert messen und auf Port D für jeder 
Wert ein Led einschalt.

Dafür habe ich etwa so den Schleifer auf dem PC0 Eingang verbindet (Wie 
im AVR GCC tutorial erklärt):

VCC-----+
        |
        |
     Sensor
        |
        +--------PC0
        |
       ---
       | |
       | |
       ---
        |
        +----------GND

Der code:

#include <avr/io.h>
#include <inttypes.h>
#include <util/delay.h>
#include <stdlib.h>



void init(void)
{
  DDRB = 0xff;
  DDRC = 0xff;
  DDRD = 0xff;
  ADCSRA = (1<<ADEN);
}


uint16_t readADC(uint8_t Mux_channel)
{
  uint8_t i;
  uint16_t result = 0;



  ADMUX = Mux_channel;  // Kanal des Multiplexers waehlen
  ADMUX = (1<<REFS0) | (1<<REFS1); //int. REF Versorgungsspannung 
auswählen
  ADMUX &= ~(1<<ADLAR);  //ergebnis rechtsbündig ausrichten


  //ADCSRA = (1<<ADEN);   // Den ADC aktivieren
  ADCSRA = (1<<ADPS0) | (1<<ADPS2); // Teilungsfaktor zwischen der 
Taktfrequenz und dem Eingangstakt des ADC auf 32 setzen Tmin = 20 , Tmax 
= 80
  ADCSRA |= (1<<ADSC);  // Den ADC initialisieren und einen sog. 
Dummyreadout machen

  _delay_us(40);


  while(ADCSRA & (1<<ADSC));
  result = ADCW;    // ADCW muss einmal gelesen werden,
    result = 0;            // sonst wird Ergebnis der nächsten Wandlung
                                    // nicht übernommen.



  // Jetzt 4x die analoge Spannung and Kanal channel auslesen
  // und dann Durchschnittswert ausrechnen.
  for(i=0; i<4; i++)
  {
    ADCSRA |= (1<<ADSC);  // Eine Single conversionWandlung

    while(ADCSRA & (1<<ADSC)); // Auf Abschluss der Konventierung 
abwarten

    result += ADCW;
  }


  //ADCSRA = (0<<ADEN);    // ADC wieder deaktivieren

  result /= 4;

  return result;
}

int main(void)
{

  init();
  while(1)
  {
    uint16_t result = readADC(0);  //Auslesen der analogen Spannungen an 
Pin 0,
                      // also ADC0. In result steht das Ergebnis.

    while(1)
    {
      PORTB = (result / 50) + 1;
    }
  }

}


Die Referenzspannung des Stk 500 Boards habe ich auf 11V gesetzt und den
Jumper auf AREF(Board) gejumpert. Mit dem Multimeter kann ich am Eingang
dann auch die Spannung wie gewünscht messen, nur mit meinem Programm 
gibt
leuchtet sofort nur die led 1 bis 5 und es ist alles. Ich habe schon 
alles ausprobiert aber finde den Fehler einfach nicht!

Zur Kontrolle habe ich mir mittlerweile auch schon die Zustände der 
Register ADC anzeigen lassen, scheint dass es kein wert im ADC ist.

Die Frequenz des Board ist auf 3,686 MHZ gesetzt!

Ich danke Ihnen im Voraus.

von Johannes M. (johnny-m)


Lesenswert?

Bitte nutze die Code-Formatierung des Forums!

Und das hier
> ADMUX = Mux_channel;  // Kanal des Multiplexers waehlen
> ADMUX = (1<<REFS0) | (1<<REFS1); //int. REF Versorgungsspannung
ist schon mal Blödsinn. Überlege, was die Anweisung in der zweiten Zeile 
mit dem macht, was Du in der ersten Zeile in ADMUX geschrieben hast.

> Die Referenzspannung des Stk 500 Boards habe ich auf 11V gesetzt
Eine Referenzspannung von 11 V gibt es nicht, der AVR kann maximal 
(A)VCC, und wie hoch das sein darf, steht im Datenblatt. Jedenfalls 
nicht 11 V.

von ... .. (docean) Benutzerseite


Lesenswert?

zweimal while(1) macht wenig sinn..

von Karl H. (kbuchegg)


Lesenswert?

> Die Referenzspannung des Stk 500 Boards habe ich auf 11V gesetzt
> und den Jumper auf AREF(Board) gejumpert.

Autsch!

Dir ist anscheinend nicht klar, dass es eine Obergrenze für die 
Referenzspannung gibt. Wenn du extern eine Referenzspannung anlegst, 
dann darf die nicht.

Wenn du extern eine Referenzspannung anlegst, warum aktivierst du dann 
per MUX Register die interne Referenzspannung? Jetzt arbeiten 2 
Referenzspannungen gegeneinander

von Johannes M. (johnny-m)


Lesenswert?

Karl heinz Buchegger wrote:
>> Die Referenzspannung des Stk 500 Boards habe ich auf 11V gesetzt
>> und den Jumper auf AREF(Board) gejumpert.
>
> Autsch!
>
> Dir ist anscheinend nicht klar, dass es eine Obergrenze für die
> Referenzspannung gibt. Wenn du extern eine Referenzspannung anlegst,
> dann darf die nicht.
Ich vermute mal, dass das nur ein Tippfehler ist und 1,1 V heißen 
soll... Aber das wollte ich gern vom OP selber hören (bzw. lesen).

von Penie L. (peniely)


Angehängte Dateien:

Lesenswert?

Und das hier
> ADMUX = Mux_channel;  // Kanal des Multiplexers waehlen
> ADMUX = (1<<REFS0) | (1<<REFS1); //int. REF Versorgungsspannung
ist schon mal Blödsinn. Überlege, was die Anweisung in der zweiten Zeile
mit dem macht, was Du in der ersten Zeile in ADMUX geschrieben hast.

> Die Referenzspannung des Stk 500 Boards habe ich auf 11V gesetzt
Eine Referenzspannung von 11 V gibt es nicht, der AVR kann maximal
(A)VCC, und wie hoch das sein darf, steht im Datenblatt. Jedenfalls
nicht 11 V.

ADMUX = Mux_channel;

mit dem Zeile wird mein messende Kanal bestimmt, hier hole ich die 
entsprechende pinnummer

ADMUX = (1<<REFS0) | (1<<REFS1);
hier wähle ich die spannung reference für die ADC.
Ok 11 v war nicht gedacht sondern 5,5 v meinte ich.
Und wenn ich euch richtig verstehe sogar diese 5;5 v brauchte ich nicht 
mehr weil ich interne spannung benutze!
Aber trotz dies geht immer nicht.

von Penie L. (peniely)


Lesenswert?

zweimal while(1) macht wenig sinn..

wie meinst du!?!?

von Johannes M. (johnny-m)


Lesenswert?

Penie Lydos wrote:
> ADMUX = (1<<REFS0) | (1<<REFS1);
> hier wähle ich die spannung reference für die ADC.
...und löscht gleichzeitig die Kanalauswahl wieder!

>> zweimal while(1) macht wenig sinn..
> wie meinst du!?!?
Zeichne Dir bitte ein Ablaufdiagramm Deines Programms auf! Wenn Du so 
etwas nicht selber siehst, musst Du Dir erstmal über die 
Programmstruktur klar werden!

Ich habe fast den Eindruck, dass Du nicht weißt, dass eine 
"while(1)"-Schleife (zumindest ohne break) niemals wieder verlassen 
wird...

von Penie L. (peniely)


Lesenswert?

oh ye!!!
so dumm von mir.
jetzt sehe ich:
ADMUX |= (1<<REFS1) | (1<<REFS0);
und auch
>> zweimal while(1) macht wenig sinn..
ja fehler beseitig.

leider funktionniert immer nicht.

von Penie L. (peniely)


Lesenswert?

wenn ich debugge bleibt der cursor auf

<c>
#include <avr/io.h>
#include <inttypes.h>
#include <util/delay.h>
#include <stdlib.h>



void init(void)
{
  DDRB = 0xff;
  DDRC = 0xff;
  DDRD = 0xff;
  ADCSRA = (1<<ADEN);
}


uint16_t readADC(uint8_t Mux_channel)
{
  uint8_t i;
  uint16_t result = 0;



  ADMUX = Mux_channel;              // Kanal des Multiplexers waehlen
  ADMUX |= (1<<REFS0) | (1<<REFS1);        //int. REF 
Versorgungsspannung auswählen
  ADMUX &= ~(1<<ADLAR);              //ergebnis rechtsbündig ausrichten


  ADCSRA = (1<<ADEN);               // Den ADC aktivieren
  ADCSRA |= (1<<ADPS1) | (1<<ADPS0);         // Teilungsfaktor zwischen 
der Taktfrequenz und dem Eingangstakt des ADC auf 32 setzen Tmin = 20 , 
Tmax = 80
  ADCSRA |= (1<<ADSC);              // Den ADC initialisieren und einen 
sog. Dummyreadout machen

  _delay_us(40);


  while(ADCSRA & (1<<ADSC))
  {;}
  result = ADCW;                  // ADCW muss einmal gelesen werden,
    result = 0;                          // sonst wird Ergebnis der 
nächsten Wandlung
                                    // nicht übernommen.



  // Jetzt 4x die analoge Spannung and Kanal channel auslesen
  // und dann Durchschnittswert ausrechnen.
  for(i=0; i<4; i++)
  {
    ADCSRA |= (1<<ADSC);            // Eine Single conversionWandlung

    while(ADCSRA & (1<<ADSC));          // Auf Abschluss der 
Konventierung abwarten

    result += ADCW;
  }


  ADCSRA = (0<<ADEN);                // ADC wieder deaktivieren

  result /= 4;

  return result;
}

int main(void)
{

  init();
  while(1)
  {
    uint16_t result = readADC(0);  //Auslesen der analogen Spannungen an 
Pin 0,
                    // also ADC0. In result steht das Ergebnis.

      PORTB = (result / 50) + 1;
  }

}
</c>
leider bekomme ich immer gar nichst mit dem code!!!!

von Penie L. (peniely)


Lesenswert?

bitte wie kann ich dann mein code formatieren?

von Johannes M. (johnny-m)


Lesenswert?

Penie Lydos wrote:
> bitte wie kann ich dann mein code formatieren?
Indem Du zunächst mal das liest, was über dem Editierfenster unter den 
"Wichtigen Regeln" steht! Das ist doch nicht zu übersehen!

von Karl H. (kbuchegg)


Lesenswert?

>  ADCSRA = (0<<ADEN);                // ADC wieder deaktivieren

Das schaltet den ADC zwar aus, macht aber auch sonst noch so einiges 
(zumindest nicht das was du willst)

Warum benutzt du nicht einfach mal die readADC aus dem Tutorial so wie 
sie ist? Dann funktioniert sie nämlich. Und erst dann fängst du an sie 
zu verändern, wobei du nach jeder Änderung überprüfst, obs noch geht 
oder nicht.

von Penie L. (peniely)


Lesenswert?

1
#include <avr/io.h>
2
#include <inttypes.h>
3
#include <util/delay.h>
4
#include <stdlib.h>
5
6
7
8
void init(void)
9
{
10
  DDRB = 0xff;
11
  DDRC = 0xff;
12
  DDRD = 0xff;
13
}
14
  
15
  
16
uint16_t readADC(uint8_t Mux_channel) 
17
{
18
  uint8_t i;
19
  uint16_t result = 0;
20
  
21
  
22
  
23
  ADMUX = Mux_channel;              // Kanal des Multiplexers waehlen  
24
  ADMUX |= (1<<REFS0) | (1<<REFS1);        //int. REF Versorgungsspannung auswählen
25
  //ADMUX |= ~(1<<ADLAR);              //ergebnis rechtsbündig ausrichten
26
27
   
28
  ADCSRA = (1<<ADEN);               // Den ADC aktivieren
29
  ADCSRA |= (1<<ADPS1) | (1<<ADPS0);         // Teilungsfaktor zwischen der Taktfrequenz und dem Eingangstakt des ADC auf 8 setzen Tmin = 20 , Tmax = 80
30
  ADCSRA |= (1<<ADSC);              // Den ADC initialisieren und einen sog. Dummyreadout machen
31
  
32
//  _delay_us(40);
33
34
35
  while(ADCSRA & (1<<ADSC));
36
37
  result = ADCW;                  // ADCW muss einmal gelesen werden,
38
    result = 0;                          // sonst wird Ergebnis der nächsten Wandlung
39
                                    // nicht übernommen.
40
  
41
  
42
  
43
  // Jetzt 4x die analoge Spannung and Kanal channel auslesen
44
  // und dann Durchschnittswert ausrechnen.
45
  for(i=0; i<4; i++) 
46
  {    
47
    ADCSRA |= (1<<ADSC);            // Eine Single conversionWandlung
48
    
49
    while(ADCSRA & (1<<ADSC));          // Auf Abschluss der Konventierung abwarten
50
    
51
    result += ADCW;
52
  }
53
  
54
  ADCSRA &= ~(1<<ADEN);               // ADC wieder deaktivieren
55
  
56
  result /= 4;
57
  
58
  return result;
59
}
60
61
int main(void) 
62
{
63
64
  init();
65
66
  while(1)
67
  {
68
    uint16_t result = readADC(0);  //Auslesen der analogen Spannungen an Pin 0,
69
                    // also ADC0. In result steht das Ergebnis.        
70
    PORTB = (result / 50) + 1;
71
  }
72
  
73
}

Jetzt habe ich mir dieser code vom AVR GCC tutorial eins zu eins 
kopiert. Leider ist immer mein ADC value beim debuggen 0x0000

von ... .. (docean) Benutzerseite


Lesenswert?

mit was debuggst du denn? Also welche Hardware/Software?

von Penie L. (peniely)


Lesenswert?

mit avr studio 4

von Johannes M. (johnny-m)


Lesenswert?

Penie Lydos wrote:
> mit avr studio 4
Und woher soll das AVRStudio Informationen über Deine Hardware haben? 
Das AVRStudio kann keine analoge Peripherie simulieren! Du kannst bei 
der Simulation höchstens von Hand Werte in ADCH/ADCL schreiben, die dann 
verarbeitet werden.

Dass da in der Simulation immer 0 rauskommt, ist völlig normal.

von Penie L. (peniely)


Lesenswert?

zuerst vielen dank für alle die Tipp

ok,
habe ich es getan, per hand die werte einzugeben.

für ADCL (50)--> 23 ----> portB 0x01
ADCL (100)--> 46 ----> portB 0x02
ADCL (150)--> 96 ----> portB 0x03
ADCL (200)--> 8C ----> portB 0x03
ADCL (255)--> FF ----> portB 0x06


weiss jemand warum es keine unterschied am portb Ausgang für die beiden 
werte gibt?

DCL (150)--> 96 ----> portB 0x03
ADCL (200)--> 8C ----> portB 0x03

Und es ist immer mir noch nicht klar warum es auf den Hardware AVR mit 
prozessor atmega nicht lauft.

von Penie L. (peniely)


Lesenswert?

atmega8

von Karl H. (kbuchegg)


Lesenswert?

> ok,
> habe ich es getan, per hand die werte einzugeben.
>
> für ADCL (50)--> 23 ----> portB 0x01
> ADCL (100)--> 46 ----> portB 0x02
> ADCL (150)--> 96 ----> portB 0x03
> ADCL (200)--> 8C ----> portB 0x03
> ADCL (255)--> FF ----> portB 0x06

Das passt aber immer noch nicht mit deiner Formel zusammen

    PORTB = (result / 50) + 1;

     50 / 50   macht 1, dann noch 1 dazu macht 2
    100 / 50   macht 2, dann noch 1 dazu macht 3

Hast du dir schon mal direkt die Werte für result angesehen?

> Und es ist immer mir noch nicht klar warum es auf den Hardware AVR mit
> prozessor atmega nicht lauft.

Könnte auch ein Hardware-Problem sein.
Speist du deine Spannung am richtigen Pin ein?
Wie ist der ARef Aufgang beschaltet?

> und auf Port D für jeder Wert ein Led einschalt.

vielleicht nur ein Tippfehler, aber: du gibst am Port B aus

von Penie L. (peniely)


Lesenswert?

1
Wie ist der ARef Aufgang beschaltet?

AREF-Jumper ist gesetzt
1
Speist du deine Spannung am richtigen Pin ein?

und mein mein Analog spanung lese ich am pin pc0
1
 vielleicht nur ein Tippfehler, aber: du gibst am Port B aus

ja tippfehler, ich meine portB

von Karl H. (kbuchegg)


Lesenswert?

Penie Lydos wrote:
>
1
Wie ist der ARef Aufgang beschaltet?
>
> AREF-Jumper ist gesetzt

Verzeih meine Unwissenheit: Das bedeutet jetzt was?

>
1
Speist du deine Spannung am richtigen Pin ein?
>
> und mein mein Analog spanung lese ich am pin pc0

Von PC0 liest dein Program. Aber hängt deine zu messende Spannung auch 
am physischen Pin PC0? (Ist mir auch schon passiert, dass ich mich bei 
den Pins verzählt habe)

von Penie L. (peniely)


Lesenswert?

>Von PC0 liest dein Program. Aber hängt deine zu messende Spannung auch
>am physischen Pin PC0? (Ist mir auch schon passiert, dass ich mich bei
>den Pins verzählt habe)

ja meine zu messende spannung ist am PC0  angeschlossen.

>AREF-Jumper ist gesetzt

>Verzeih meine Unwissenheit: Das bedeutet jetzt was?

ich habe so gelassen wie gekauft (fängt gerade mit AVR). Weil ich im 
Dadenblatt dass gelesen habe:
1
Die analoge Spannung AREF liefert die Referenzspannung für den on-chip A/D-Konverter des AVR. Wenn der AREF-Jumper gesetzt ist, ist die On-Board analog Referenzspannung mit dem AREF-Pin des AVR ver-bunden. Die On-Board Referenzspannung kann über AVR Studio von 0V bis 6V eingestellt werden, jedoch nicht über VTARGET.
2
Wenn der AREF-Jumper nicht gesetzt ist, muß dem AVR die Referenz-spannung von einer externen Spannungsquelle über die PORTE/AUX-Leiste zugeführt werden (siehe Abbildung 3.6). Abbildung 3.25 zeigt die AREF-Jumper Einstellungsmöglichkeiten.

danke

von Karl H. (kbuchegg)


Lesenswert?

Wenn ich das jetzt richtig verstehe, dann hast du gleichzeitig

* von extern eine Referenzspannung zugeführt
  (weil der Jumper gesteckt ist).

* per Programm die interne Referenzspannung ausgewählt.

-> also bekriegen sich 2 Referenzspannungserzeuger.

(Nur so aus Neugier: Auf welche Referenzspannung hast du den das STK500 
mithilfe des AVR-Studio programmiert?)

Zieh mal den Jumper ab.

Ich denke mal, dass hier
1
Wenn der AREF-Jumper nicht gesetzt ist, muß dem AVR die
2
Referenz-spannung von einer externen Spannungsquelle über die
3
PORTE/AUX-Leiste zugeführt werden (siehe Abbildung 3.6). Abbildung 3.25
4
zeigt die AREF-Jumper Einstellungsmöglichkeiten.

ist etwas unglücklich formuliert.

Dein Mega8 hat grundsätzlich 2 Möglichkeiten für die Referenzspannung.

Die interne: hier erzeugt sich der Chip selber die Referenzspannung. Das 
hat aber nichts mit besagtem Jumper zu tun. ARef ist ein Ausgang, an dem 
die benutzte Referenzspannung herausgeführt wird (zb um sie zu 
stabilisieren)

Die externe: hier benutzt der Chip die Referenzspannung, die ihm am ARef 
Pin angeboten wird. Dafür muss dann der Jumper gesetzt sein, da dein 
STK500 diese Referenzspannung erzeugen muss oder aber die 
Referenzspannung wird über PORTE/AUX eingespeist. Auf jeden Fall aber 
muss das Programm in so einem Fall den Mega8 auf externe 
Referenzspannung umschalten.

Wenn auf dem STK500 der AREF-Jumper nicht gesetzt ist, muss also 
entweder dem AVR die Referenzspannung von einer externen Spannungsquelle 
zugeführt werden, oder aber der Chip erzeugt sich die Referenzspannung 
chipintern selber. Dein Programm stellt letztere Variante ein (interne 
Generierung der Referenzspannung), also darfst du auf keinen Fall an 
ARef eine von aussen zugeführte Spannung anschliessen -> Jumper bleibt 
offen

von Penie L. (peniely)


Lesenswert?

>(Nur so aus Neugier: Auf welche Referenzspannung hast du den das STK500
>mithilfe des AVR-Studio programmiert?)
 2,56 volt.
Wenn ich richtig verstehe muss ich mein AREF-Jumper nicht setzen.

von Penie L. (peniely)


Lesenswert?

ok und danke für alle die Erklärungen,
leider funktioniert troztdem noch nicht

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.