www.mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik Probleme mitADC im Atmega8


Autor: Penie Lydos (peniely)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Johannes M. (johnny-m)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: ... ... (docean) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
zweimal while(1) macht wenig sinn..

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Johannes M. (johnny-m)
Datum:

Bewertung
0 lesenswert
nicht 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).

Autor: Penie Lydos (peniely)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht 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.

Autor: Penie Lydos (peniely)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
zweimal while(1) macht wenig sinn..

wie meinst du!?!?

Autor: Johannes M. (johnny-m)
Datum:

Bewertung
0 lesenswert
nicht 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...

Autor: Penie Lydos (peniely)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Penie Lydos (peniely)
Datum:

Bewertung
0 lesenswert
nicht 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!!!!

Autor: Penie Lydos (peniely)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
bitte wie kann ich dann mein code formatieren?

Autor: Johannes M. (johnny-m)
Datum:

Bewertung
0 lesenswert
nicht 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!

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Penie Lydos (peniely)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
#include <avr/io.h>
#include <inttypes.h>
#include <util/delay.h>
#include <stdlib.h>



void init(void)
{
  DDRB = 0xff;
  DDRC = 0xff;
  DDRD = 0xff;
}
  
  
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 8 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 &= ~(1<<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;
  }
  
}

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

Autor: ... ... (docean) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
mit was debuggst du denn? Also welche Hardware/Software?

Autor: Penie Lydos (peniely)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
mit avr studio 4

Autor: Johannes M. (johnny-m)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Penie Lydos (peniely)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Penie Lydos (peniely)
Datum:

Bewertung
0 lesenswert
nicht lesenswert

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Penie Lydos (peniely)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wie ist der ARef Aufgang beschaltet?

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

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

ja tippfehler, ich meine portB

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Penie Lydos wrote:
>
Wie ist der ARef Aufgang beschaltet?
>
> AREF-Jumper ist gesetzt

Verzeih meine Unwissenheit: Das bedeutet jetzt was?

>
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)

Autor: Penie Lydos (peniely)
Datum:

Bewertung
0 lesenswert
nicht 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:
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.
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

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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
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.

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

Autor: Penie Lydos (peniely)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Penie Lydos (peniely)
Datum:

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

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
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.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.