Forum: Mikrocontroller und Digitale Elektronik ADC XMega128A1


von Thomass (Gast)


Lesenswert?

Hallo alle zusammen,
ich habe ein kleines Problem mit dem AD Wandler beim XMega128A1.
Ich möchte dass mir der angelegte Spannungswert an PortA Pin0 mit dem AD 
Wandler ausgewertet wird. Leider verändert sich der angezeigte Wert 
nicht (der Wert bleibt gleich) in Abhängigkeit von der angelegten 
Spannung.
Das heißt der Quellcode müsste fehlerhaft sein. Leider finde ich den 
Fehler nicht. Kann mir jemand helfen? Vielen Dank im Voraus :)

Mein Quellcode:

#include <avr/io.h>
#include <avr/interrupt.h>

double x= 0;
unsigned char temp;

void adc_init(void)
{
   ADCA.CTRLA = 0x41;
   ADCA.CTRLB = 0x04;
   ADCA.REFCTRL = 0x02;
   ADCA.EVCTRL = 0x00;
   ADCA.PRESCALER = 0x00;
   ADCA.CH0.CTRL = 0x00;
   ADCA.CH0.MUXCTRL = 0x00;
   ADCA.CH0.INTCTRL = 0x03;
   PMIC.CTRL = 0x07;
   sei();

}

void Osi_init(void)
{
    OSC.CTRL =3;
    while(OSC.STATUS != 3);
    CCP = 0xD8;
    CLK.CTRL = 1;

}

ISR(ADCA_CH0_vect)
{
  temp = ADCA.CH0.RES;
  x = (double)temp;
  ADCA.CH0.CTRL = 0x80;
}


int main(void)
{
PORTA.DIRCLR = 0xff;
adc_init();
Osi_init();
ADCA.CH0.CTRL = 0x80;
while(1){}
}

von Ralfi (Gast)


Lesenswert?

x volatile machen.

von Ralfi (Gast)


Lesenswert?

Und warum ist x ein double reicht nicht int.

von GG (Gast)


Lesenswert?

Hallo,
Du mußt das Ergebniss-Register zeimal lesen, zuerst High dann Low.

So  ähnlich:

tmp = ADCA.CH0.RESL;
tmp += ADCA.CH0.RESH<<8;
sum += tmp;


Gruß GG

von Thomass (Gast)


Lesenswert?

Hallo,
vielen Dank für Eure Hilfe.
Habe die Variable volatile deklariert (volatile int x reicht natürlich 
auch aus!) sowie das RESH und RESL Register ausgelesen.

Der Fehler bleibt aber leider dennoch derselbe:
Bei angelegten 0V wird z.B der Wert x= 100 ausgelesen.
Bei 0,7V wird ebenfalls x=100 ausgelesen.
Wie kann das sein?Woran kanns noch liegen?

von Simon K. (simon) Benutzerseite


Lesenswert?

Das mit dem .RES ist schon völlig in Ordnung so, das braucht man nicht 
einzeln auslesen.

Was mir aber zuerst mal spanisch vorkommt ist, dass du für das Ergebnis 
des Wandlers ein unsigned char bereitstellst.
Dann würde ich dir nahe legen statt 0x41 lieber Bitnamen zu benutzen.

Wofür aktivierst du denn die DMA Unterstützung überhaupt? In CTRLA 
braucht erst mal nur das ENABLE gesetzt zu werden.
Dann stellst du den Wandler auf 8 Bit, das heißt, du musst NUR das RESL 
Register für deinen 8 Bit Wert auslesen. Außerdem setzt du nicht das 
Free Running Bit. Das heißt, du musst den Wandler vor jeder Wandlung 
auch aktivieren, damit er wandelt.
PRESCALER ist bei dir auf /4 gesetzt. Mit welchem Takt läuft dein 
Prozessor? Das könnte einen zu schnellen ADC Takt ergeben.
Außerdem setzt du das Channel Control Register komplett auf 0, das 
heißt, du misst nicht am Ausgangspin, sondern du musst eine interne ADC 
Quelle.
Und was hat der PMIC eigentlich damit zu tun?

Preisfrage: Hast du dir überhaupt mal das Datenblatt angeguckt? Dein 
Code macht nicht mal annähernd das, was du möchtest.

von Thomass (Gast)


Lesenswert?

danke erstmal,

also habe deine Hinweise soweit umgesetzt. Ich habe einen internen Takt 
von 32KHZ eingestellt. Und ja habe mir das Manual angeguckt ;)
Irgendwie bekomme ich das trotz deiner Hinweise nicht hin. Es wird immer 
noch der selbe Wert bei verschiedenen Spannungswerten angezeigt.

Wenn ich so falsch mit meinem Programm liege (bin ja auch 
Anfänger),wärst du so nett und könntest hier den richtigen Code pinnen?
Danke schon mal

von Simon K. (simon) Benutzerseite


Lesenswert?

Wie sieht dein Code denn jetzt aus? Poste doch noch mal mit den 
Verbesserungen.

von Thomass (Gast)


Lesenswert?

#include <avr/io.h>
#include <avr/interrupt.h>

volatile int temp = 0;

void Osi_init(void)
     {
          OSC.CTRL =7;    //interner 32KHz Oszillator
    while(OSC.STATUS != 7);
    CCP = 0xD8;
    CLK.CTRL = 0;

     }


void adc_init(void)
{
  ADCA.CTRLA = 0x01;
  ADCA.CTRLB = 0x0C;
  ADCA.REFCTRL = 0x02;
  ADCA.EVCTRL = 0x00;
  ADCA.PRESCALER = 0x00;  //PRescaler = 4
  ADCA.CH0.CTRL = 0x00;
  ADCA.CH0.MUXCTRL = 0x00;
  ADCA.CH0.INTCTRL = 0x03;
  PMIC.CTRL = 0x07;  //gibt Interrupt Level frei
  sei();
}


ISR(ADCA_CH0_vect)
{
  temp = ADCA.CH0.RESL;
}


int main( void )
{
        PORTA.DIRCLR = 0x00;
  adc_init();
  Port_init();
  Osi_init();
  ADCA.CH0.CTRL = 0x80;
  while(1){}

}

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.