www.mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik ADC bei Atmega32


Autor: Christoph A. (shadowrunner93)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Hi Leute!

Ich versuche schon seit geraumer Zeit den internen ADC des Atmega32 zum 
laufen zu bekommen.

Ich benutze das STK500. Die Frequenz ist bei internen 4 Mhz.

Bei diesem Code habe ich testweise die interne Referenzspannungsquelle 
ausgewählt, um zu sehen obs klappt. Aber an dem AREF Pin liegt keine 
Spannung an. Woran könnte das liegen?

Hier ist mein Code:

#include <avr/io.h>

#define LOOP 5
#define COMM_ANODE_R 1
#define COMM_ANODE_M 1
#define COMM_ANODE_L 1

uint16_t readout();
void sev_segm_l(uint16_t number);
void sev_segm_m(uint16_t number);
void sev_segm_r(uint16_t number);

unsigned char digits[] = { 0b00111111,    // 0
                           0b00000110,    // 1
                           0b01011011,    // 2
                           0b01001111,    // 3
                           0b01100110,    // 4
                           0b01101101,    // 5
                           0b01111101,    // 6
                           0b00000111,    // 7
                           0b01111111,    // 8
                           0b01101111,    // 9
                           0b01000000     // alles andere
                         };



void main()
{

  DDRB=0xFF; // als Ausgang
  DDRC=0xFF; 
  DDRD=0xFF; 
  
  uint16_t erg;

  erg=readout();
  //einmal zum Warmlaufen
  
  while(1)
  {

    for(int i=0;i<LOOP;i++)
      erg+=readout();
  
    erg/=LOOP;  //Durchschnittswert aus LOOP Durchgängen

    erg/=10;

    sev_segm_l(erg/100);
    // die letzte Stelle des Ergebnises
    sev_segm_m((erg%100)/10);
    // die mittlere Stelle...
    sev_segm_r(erg%10);
    // usw.

  }
}

uint16_t readout()
{
  
  uint16_t erg;
  
  ADCSRA |= (1<<ADEN); // ADC wird aktiviert

  ADCSRA |= (1<<ADPS2) | (1<<ADPS0); // Frequenzteiler von 32 (4Mhz/32=125khz)
  
  ADMUX |= (1<<REFS0) | (1<<REFS1); // Interne Referenz

  ADCSRA |= (1<<ADSC); // "Warmlaufrunde" für ADC

  while(ADCSRA & (1<<ADSC) )
  {
    //auf Abschluss der Konvertierung warten  
  }
  
  erg=ADCW;
  
  ADCSRA |= (0<<ADEN);//ADC deaktivieren  

  return erg;
}


void sev_segm_l(uint16_t number)
{

  if(COMM_ANODE_L)
  {
    if( number < 10 )
      PORTD = ~digits[number];
    else
      PORTD = ~digits[10];
  }
  else
  {
    if( number < 10 )
      PORTD = digits[number];
    else
      PORTD = digits[10];
  }
}


void sev_segm_m(uint16_t number)
{
  if(COMM_ANODE_M)
  {
    if( number < 10 )
      PORTC = ~digits[number];
    else
      PORTC = ~digits[10];
  }
  else
  {
    if( number < 10 )
      PORTC = digits[number];
    else
      PORTC = digits[10];
  }
}

void sev_segm_r(uint16_t number)
{

  if(COMM_ANODE_R)
  {
    if( number < 10 )
      PORTB = ~digits[number];
    else
      PORTB = ~digits[10];
  }
  else
  {
    if( number < 10 )
      PORTB = digits[number];
    else
      PORTB = digits[10];
  }
}


Mfg

Autor: Tobi (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
ADCSRA |= (0<<ADEN);//ADC deaktivieren

diese Zeile macht nicht, was sie soll!

Ein Bit wird so gelöscht:
  ADCSRA &= ~(1<<ADEN);//ADC deaktivieren

MfG

Autor: Christoph A. (shadowrunner93)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Tobi schrieb:
> ADCSRA |= (0<<ADEN);//ADC deaktivieren
>
> diese Zeile macht nicht, was sie soll!
>
> Ein Bit wird so gelöscht:
>   ADCSRA &= ~(1<<ADEN);//ADC deaktivieren
>
> MfG

Sry, da hab' ich nicht nachgedacht...

Aber an dem liegts nicht...
Dann ist halt der ADC die ganze Zeit eingeschaltet ;)

Mfg

Autor: gast (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>Aber an dem AREF Pin liegt keine
>Spannung an. Woran könnte das liegen?
das sie intern ist. versuch doch einfach mal was einzulesen und das mit 
einer messung mit multimeter zu vergleichen.

Autor: Christoph A. (shadowrunner93)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
gast schrieb:
>>Aber an dem AREF Pin liegt keine
>>Spannung an. Woran könnte das liegen?
> das sie intern ist. versuch doch einfach mal was einzulesen und das mit
> einer messung mit multimeter zu vergleichen.

Das verstehe ich nicht ganz. Wird die zu messende Spannung am AREF-Pin 
ausgegeben? Wohl eher nicht oder? ;)

Nach meinem Code gibt der ATmega32 eine Dezimale 8 aus, unabhängig davon 
was ich einlese. Habe ich im Code irgendeinen Denkfehler?

Mfg

Autor: spess53 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi

>das sie intern ist. versuch doch einfach mal was einzulesen und das mit
>einer messung mit multimeter zu vergleichen.

VREF liegt am entprechenden PIN an (wenn richtig eingestellt), und muss 
dort auch zu messen sein.

MfG Spess

Autor: Spezi (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

Du solltest die Initialisierung und den Wandler-Vorgang des ADC 
voneinander trennen. Es macht keinen Sinn, bei jedem Aufruf von 
"readout()" den Wandler neu zu initialisieren. Das macht man einmal beim 
Start des Programms in "main". Auch das Abschalten des ADC nach jeder 
Wandlung ist nicht sinnvoll; er bleibt an und ist so lange inaktiv, bis 
eine neue Conversion (ADEN=1) gestartet wird.
Nur wenn sich der Eingangs-Kanal ändert, wird ADMUX mit dem neuen 
Kanalwert beschrieben.

Autor: Christoph A. (shadowrunner93)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
spess53 schrieb:
> Hi
>
>>das sie intern ist. versuch doch einfach mal was einzulesen und das mit
>>einer messung mit multimeter zu vergleichen.
>
> VREF liegt am entprechenden PIN an (wenn richtig eingestellt), und muss
> dort auch zu messen sein.
>
> MfG Spess

Genau deshalb wundere ich mich ja dass an dem AREF-Pin keine Spannung 
anliegt.
Stimmen die Einstellung die ich vorgenommen habe?

Meine derzeitige Konfiguration:

An Vcc --> +5V
An GND --> GND
An AVcc -->+5V
An AGND --> GND

So müsste es doch klappen wenn ich als Referenzquelle AVCC einstelle 
oder irre ich mich?

Wie sieht es mit den Fusebits usw aus? Habe ich die richtig gesetzt? (im 
1. Beitrag habe ich Screens angehängt)

Mfg
Christoph

Autor: Christoph A. (shadowrunner93)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Spezi schrieb:
> Hallo,
>
> Du solltest die Initialisierung und den Wandler-Vorgang des ADC
> voneinander trennen. Es macht keinen Sinn, bei jedem Aufruf von
> "readout()" den Wandler neu zu initialisieren. Das macht man einmal beim
> Start des Programms in "main". Auch das Abschalten des ADC nach jeder
> Wandlung ist nicht sinnvoll; er bleibt an und ist so lange inaktiv, bis
> eine neue Conversion (ADEN=1) gestartet wird.
> Nur wenn sich der Eingangs-Kanal ändert, wird ADMUX mit dem neuen
> Kanalwert beschrieben.

Okay, danke für den Tipp.

Aber an es müsste doch trotzdem funktionieren oder? xD

Mfg

Autor: holger (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>So müsste es doch klappen wenn ich als Referenzquelle AVCC einstelle
>oder irre ich mich?

Wenn du AVCC einstellst kommt an AREF nichts raus.
Wozu auch?

>#define COMM_ANODE_R 1

>  if(COMM_ANODE_R)
>  {
>  }
>  else
>  {}

Schönen toten Code hast du dir da gebastelt.
if(COMM_ANODE_R) ist immer wahr. Das else kommt
nie zum Zug. Bestenfalls optimiert der Compiler
den else Zweig komplett weg.

>  while(1)
>  {
>
>    for(int i=0;i<LOOP;i++)
>      erg+=readout();

erg in der main() Loop sollte auch irgendwann
mal wieder auf 0 gesetzt werden. Sonst addierst du
da immer wieder Reste deiner Rechnung mit auf.

Autor: Spezi (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> ADMUX |= (1<<REFS0) | (1<<REFS1); // Interne Referenz

Damit wird die interne Referenz-Spannung ausgewählt (2.56V). AVcc als 
Referenz ist eine andere Einstellung. (REFS0 = 1, REFS1 = 0)

> VREF liegt am entprechenden PIN an (wenn richtig eingestellt), und muss
> dort auch zu messen sein.

Dies gilt für Vref = AVcc und für Vref = 2.56V intern. Siehe 
Blockschaltbild des ADC im Datenblatt.

Hast Du den richtigen A/D-Eingangskanal ausgewählt, der für das STK500 
passt? Zumindest sind laut Software alle Pins von Port A auf Eingang 
geschaltet ...

Läuft der Rest des Programmes denn korrekt?

Holger wrote:
>Wenn du AVCC einstellst kommt an AREF nichts raus.
>Wozu auch?

Dann schau Dir das ADC-Blockschaltbild an, wann Aref Spannung führt (FET 
ist eingeschaltet). Dann sollte die Antwort, die ich oben nannte, klar 
sein. (Spannung liegt an Aref an, wenn REFS0 = 1 ist.) Sonst würde der 
empfohlene externe Kondensator an diesem Pin auch wenig Sinn machen ...

Autor: Christoph A. (shadowrunner93)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
holger schrieb:
>>So müsste es doch klappen wenn ich als Referenzquelle AVCC einstelle
>>oder irre ich mich?
>
> Wenn du AVCC einstellst kommt an AREF nichts raus.
> Wozu auch?

Hmm, ich glaube so ganz habe ich die Funktion von dem AREF nicht 
kapiert.

Ist das jetzt ein Ein- oder Ausgang?

Könntest du mir die Funktion des Pins bitte erklären?

holger schrieb:
>>#define COMM_ANODE_R 1
>
>>  if(COMM_ANODE_R)
>>  {
>>  }
>>  else
>>  {}
>
> Schönen toten Code hast du dir da gebastelt.
> if(COMM_ANODE_R) ist immer wahr. Das else kommt
> nie zum Zug. Bestenfalls optimiert der Compiler
> den else Zweig komplett weg.

^^

Es sei denn ich ändere das define, wenn ich Siebensegm.Anzeigen habe die 
nicht COMM-ANODE sind, verstehst du? xD
Somit muss ich es nicht in allen 3 Funktionen umändern wenn ich den Code 
vearbeiten will.

holger schrieb:
>erg in der main() Loop sollte auch irgendwann
>mal wieder auf 0 gesetzt werden. Sonst addierst du
>da immer wieder Reste deiner Rechnung mit auf.

Danke!
Ich glaube du hast damit voll ins Schwarze getroffen..
Ich hatte schon eine Vermutung dass ich irgendeinen schweren Denkfehler 
eingebaut habe...

Ausprobieren kann ich es allerdings heute nicht mehr, jeder braucht 
seinen Schlaf ;)

Also dann Gute Nacht, ich meld' mich morgen wieder obs geklappt hat!

Mfg

Autor: Christoph A. (shadowrunner93)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Verfolgt diesen Thread noch jemand?

Mfg

Autor: Bernd (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Denke du verfolgst diesen Thread. Wie weit bist du nun gekommen ?

Autor: Gast (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Also dann Gute Nacht, ich meld' mich morgen wieder obs geklappt hat!
 Du bist am Zug.

Autor: Christoph A. (shadowrunner93)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Schande über mich, dass mit dem ADC funktioniert immer noch nicht.
Ich habe auch nicht weiter daran herumgewerkelt, ich hatte andere 
Projekte am laufen.

Hier nochmal mein neuer Code:
#include <avr/io.h>

//#define COMM_ANODE_R 0
//#define COMM_ANODE_M 0
//#define COMM_ANODE_L 0

void ADC_init(void);
uint16_t ADC_read(uint8_t kanal);

//void sev_segm_l(uint16_t number);
//void sev_segm_m(uint16_t number);
//void sev_segm_r(uint16_t number);

unsigned char digits[] = { 0b00111111,    // 0
                           0b00000110,    // 1
                           0b01011011,    // 2
                           0b01001111,    // 3
                           0b01100110,    // 4
                           0b01101101,    // 5
                           0b01111101,    // 6
                           0b00000111,    // 7
                           0b01111111,    // 8
                           0b01101111,    // 9
                           0b01000000     // alles andere
                         };



void main()
{
  
  //Ports als Ausgänge/Eingänge definieren
  DDRA=0x00;
  DDRB=0xFF; 
  DDRC=0xFF; 
  DDRD=0xFF; 

  uint16_t erg;  
  
  //ADC initalisieren
  ADC_init;

  while(1)
  {
    erg=ADC_read(0);
    //Auch wenn PORTB nur 8 Ausgänge hat
    //muss es trotzdem was anderes
    //als 0 ausgeben
    PORTB=erg;
  }  
}



void ADC_init(void)
{
  //Diese Funktion aktiviert den ADC

  ADCSRA |= (1<<ADEN); //ADC aktivieren und

  ADCSRA |= (1<<ADPS2) | (1<<ADPS1); //Teilungsfaktor auf 8 stellen
}

uint16_t ADC_read(uint8_t kanal)
{
  ADMUX=kanal; //Kanal des Multiplexers wählen:

  ADMUX |= (1<<REFS0); //AVCC als Referenz

  ADCSRA |= (1<<ADSC); //Messung starten

  while(bit_is_set(ADCSRA,ADSC)); // Auf Ergebnis warten:

  return ADCW;
}


/*

void sev_segm_l(uint16_t number)
{

  if(COMM_ANODE_L)
  {
    if( number < 10 )
      PORTD = ~digits[number];
    else
      PORTD = ~digits[10];
  }
  else
  {
    if( number < 10 )
      PORTD = digits[number];
    else
      PORTD = digits[10];
  }
}


void sev_segm_m(uint16_t number)
{
  if(COMM_ANODE_M)
  {
    if( number < 10 )
      PORTC = ~digits[number];
    else
      PORTC = ~digits[10];
  }
  else
  {
    if( number < 10 )
      PORTC = digits[number];
    else
      PORTC = digits[10];
  }
}

void sev_segm_r(uint16_t number)
{

  if(COMM_ANODE_R)
  {
    if( number < 10 )
      PORTB = ~digits[number];
    else
      PORTB = ~digits[10];
  }
  else
  {
    if( number < 10 )
      PORTB = digits[number];
    else
      PORTB = digits[10];
  }
}

*/

Egal was ich an den Pin0 am PORTA anlege, alle Ausgänge des PORTB 
bleiben auf Low.

Hier meine Beschaltung;

VCC=5V
GND=GND
AVCC=5V
AGND=GND
PINA0=Analoge Spannung

Doch dieses Mal liegt am AREF-Pin AVCC an. Das heißt die 
Referenzspannung müsste da sein.

Mfg

Autor: Christoph A. (shadowrunner93)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Da ihr zu dem Code nichts zu sagen habt, gehe ich davon aus dass er in 
Ordnung ist.

Dann kann es also nur an der Umgebung liegen.

Den ATMega32 habe ich dem linken roten Slot des STK500 drinnen.

Was muss ich bei dem Setzten der FUSEBITS beachten? Gibt es welche die 
den ADC im Weg stehen könnten?

Mfg

Autor: Andreas R. (rebirama)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich hab mal deinen Code kommentiert:
uint16_t ADC_read(uint8_t kanal)
{
  ADMUX=kanal; //Kanal des Multiplexers wählen und Ref auf Extern!

  ADMUX |= (1<<REFS0); //AVCC als Referenz

  ADCSRA |= (1<<ADSC); //Messung starten

  while(bit_is_set(ADCSRA,ADSC)); // Auf Ergebnis warten:

  return ADCW;
}

Dadurch schaltest du die Referenz bei jeder Messung einmal um. Das macht 
Probleme, da man nach dem Umschalten kurz (125µs oder so) warten muss.

Besser:
uint16_t ADC_read(uint8_t kanal)
{
  ADMUX=kanal |(1<<REFS0); //Kanal des Multiplexers wählen und Ref auf AVCC

  ADCSRA |= (1<<ADSC); //Messung starten

  while(bit_is_set(ADCSRA,ADSC)); // Auf Ergebnis warten:

  return ADCW;
}

Und ich bin grad unsicher, aber muss es nicht  "ADC_init();" statt 
"ADC_init;" heißen?

Autor: Christoph A. (shadowrunner93)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Andreas R. schrieb:
> Ich hab mal deinen Code kommentiert:
>
>
> uint16_t ADC_read(uint8_t kanal)
> {
>   ADMUX=kanal; //Kanal des Multiplexers wählen und Ref auf Extern!
> 
>   ADMUX |= (1<<REFS0); //AVCC als Referenz
> 
>   ADCSRA |= (1<<ADSC); //Messung starten
> 
>   while(bit_is_set(ADCSRA,ADSC)); // Auf Ergebnis warten:
> 
>   return ADCW;
> }
> 
>
> Dadurch schaltest du die Referenz bei jeder Messung einmal um. Das macht
> Probleme, da man nach dem Umschalten kurz (125µs oder so) warten muss.


Echt unglaublich wieviele Genies sich hier in den Foren aufhalten. (Das 
ist jetzt kein Sarkasmus^^)

Die Funktion ist jetzt so umgeändert, dass der Kanal automatisch 0 ist.

Ich glaube damit hast du mein Problem gelöst, bin mir noch nicht ganz 
sicher..
Ich melde mich wieder! (diesmal sicher xD)

Autor: Christoph A. (shadowrunner93)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Also es sieht so aus als ob es funktionert ;)

Ich glaube die grobe Wandlung von 10bit in 8bit macht dem µC Probleme.
Dafür muss ich noch eine Lösung finden. Aber schonmal vielen Dank!!

Hier ist mein derzeitiger Code:
void main()
{
  
  //Ports als Ausgänge/Eingänge definieren
  DDRA=0x00;
  DDRB=0xFF; 
  DDRC=0xFF; 
  DDRD=0xFF; 
  
  uint8_t erg;  
  
  //ADC initalisieren
  ADC_init();

  while(1)
  {
    erg=ADC_read();
    //Auch wenn PORTB nur 8 Ausgänge hat
    //muss es trotzdem was anderes
    //als 0 ausgeben
    PORTB=erg;
  }  
}



void ADC_init()
{
  //Diese Funktion aktiviert den ADC

  ADCSRA |= (1<<ADEN) | (1<<ADPS2) | (1<<ADPS1);//ADC aktivieren und

  ADMUX |= (1<<REFS0);//AVCC als Referenz

}

uint16_t ADC_read()
{

  ADCSRA |= (1<<ADSC);//Messung starten

  while(bit_is_set(ADCSRA,ADSC));// Auf Ergebnis warten:

  return ADCW;
}

Autor: Bernd (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Nur mal nen Vorschlag, weil der Thread schon so lange läuft :-)

ADC Readout gemittelt:
uint16_t getAdcValue (void)
{
    uint8_t AdcCount = 0;
    uint32_t AdcSum = 0;

    for (AdcCount = 0; AdcCount < 128; AdcCount ++)  {
        ADCSRA |= (1 << ADSC);            // AD Wandler starten
        while (ADCSRA & (1 << ADSC));     // AD Wandlung fertig ?
        AdcSum += ADC;                    // Mittelwert über 128 Messungen
    }
    return (uint16_t) (((((AdcSum >> 7)
}
Bei ADC Init, prescaler beachten:
ADC Init
    
    // enable ADC, ADC clock /128 = 144 kHz
    ADCSRA = (1<<ADEN) | (1<<ADPS2) | (1<<ADPS1) | (1<<ADPS0);  

Autor: Bernd (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Sorry, das mit den 4 MHz hatte ich nicht gesehen also prescale Tipp 
zurück :-)

Autor: Bernd (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Und noch was... warum werden blos immer wieder die beiden ADC Register 
getrennt betrachten... das Ergebnis beider Register steht in ADC.

Autor: Thomas O. (kosmos)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
das Ergebniss kann aber je nach Einstellung des ADLAR Bits verschieden 
aussehen.

Keine Ahnung ob der Compiler gleich einen 16 bit Wert draus macht.

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.