Forum: Compiler & IDEs ADC Mega 128


von Florian M. (skywalker79)


Lesenswert?

Hallo,

ich versuche mich grade daran, den ADC vom Mega 128 in Gang zu bringen. 
Nach langem lesen vom Forum und dem Tutorial bin ich zu folgenden 
Quellcode gekommen:

#include <avr/io.h>



uint8_t i;
uint16_t result = 0;

void adc_init_ch0(void)     // Initialisierung von ADC-Kanal 0
{
  ADMUX = 0x00;       // Spannungsmessung an PA0
  ADCSRA = (1<<ADEN)|(1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0); // ADC aktiviert, 
ADC Freilaufmodus, Vorteiler auf 128
  ADMUX |= (1<<REFS0)|(1<<REFS1);  // Interne Referenzspannung nutzen
  SFIOR = 0;            // Spezialfunktionen Ausschalten
}



void main(void)
{
  adc_init_ch0();

  ADCSRA |= (1<<ADSC);
  while (ADCSRA & (1<<ADSC)) // Dummy-Messung um den ADC warmlaufen zu 
lassen
  {
    ;
  }


  for(i=0;i<2;i++)
  {
    ADCSRA |= (1<<ADSC);                              // eine Wandlung 
"single conversion"
    while ( ADCSRA & (1<<ADSC) ) // auf Abschluss der Konvertierung 
warten
    {
      ;
    }
    result += ADCW;    / Wandlungsergebnisse aufaddieren
  }
    ADCSRA &= ~(1<<ADEN);                       // ADC deaktivieren

    result /= 2;           // Summe durch zwei teilen = arithm. 
Mittelwert


}

Testweise versuch ich den gemessenen Wert mit einem Referenzwert zu 
vergleichen und lasse je nachdem ob er höher oder niedriger als der 
gemessene Wert ist, eine LED leuchten.
Leider bekomme ich hierbei keine nachvollziehbaren Ergebnisse. Könnt Ihr 
mir sagen, ob der Code bis jetzt so richtig ist, bzw. was ich daran 
verbessern kann?

mfg Florian

von Magnus Müller (Gast)


Lesenswert?

> Testweise versuch ich den gemessenen Wert mit einem Referenzwert zu
> vergleichen und lasse je nachdem ob er höher oder niedriger als der
> gemessene Wert ist, eine LED leuchten.
> Leider bekomme ich hierbei keine nachvollziehbaren Ergebnisse. Könnt Ihr
> mir sagen, ob der Code bis jetzt so richtig ist, bzw. was ich daran
> verbessern kann?

Der Code ist nicht vollständig.

* wo ist die Auswertung deines gemittelten Wertes?
* wo werden die LEDs abhängig vom Ergebnis gesetzt?
* warum läuft das (Test-)Programm nicht in einer Schleife?
* was meinst du mit "keine nachvollziehbaren Ergebnisse"?

Gruß,
Magnetus

von Florian M. (skywalker79)


Lesenswert?

Aufgerufen wird die Messung durch Übermittlung eines Zahlenwertes per 
RS232.

if (UDR1=='4')
  {
  uart_puts (status4); // Messung aktiviert
  adc_ch0();           // ruft Unterprogramm adc auf
  }


  if (UDR1=='5')
  {
  uart_puts (status5); // Messung gestoppt
  adc_ch1();           // ruft Unterprogramm adc auf
  }

das ganze läuft in einer Endlosschleife. Es soll also bei 
Zeichenübermittlung immer eine Messung durchgeführt werden.
mit adc_ch0 bzw. adc_ch1 wird das oben schon geschriebene aufgerufen.

void adc_ch0(void)
{
  adc_init_ch0();

  ADCSRA |= (1<<ADSC);
  while (ADCSRA & (1<<ADSC))                            // Dummy-Messung 
um den ADC warmlaufen zu lassen
  {
    ;
  }


  for(i=0;i<2;i++)
  {
    ADCSRA |= (1<<ADSC);                              // eine Wandlung 
"single conversion"
    while ( ADCSRA & (1<<ADSC) )                     // auf Abschluss 
der Konvertierung warten
    {
      ;
    }
    result += ADCW;                                   // 
Wandlungsergebnisse aufaddieren
  }
    ADCSRA &= ~(1<<ADEN);                                // ADC 
deaktivieren

    result /= 2;                                          // Summe durch 
zwei teilen = arithm. Mittelwert

    if (result < (2*1023)/5)
      batt_blinky();
  if (result > (2*1023)/5)
      uart_blinky();

}

hier mal nur für Kanal 0.
Mit keine nachvollziehbaren Ergebnisse meinte ich, das mal batt_blinky() 
und mal uart_blinky() aufgerufen wird, obwohl immer dieselbe Spannung am 
ADC hängt. Im Moment ist das zu Testzwecken einfach Masse.

von Karl H. (kbuchegg)


Lesenswert?

Da würde ich dir doch mal vorschlagen, das ganze abzuspecken,
extrem zu vereinfachen und den UART (den du offensichtlich
schon in Betrieb hast) dazu zu benutzen, die Messergebnisse
auszugeben. Wenn du das nicht willst, würde ich mal den
Messwert komplett auf einen Port ausgeben.

Mit extrem abspecken meine ich:
Nur einen Kanal messen
Eine simple Schleife in main, die
  * den ADC anwirft
  * auf das Ergebnis wartet
  * das Ergebnis auf Port oder UART ausgibt

von Karl H. (kbuchegg)


Lesenswert?

>    ADCSRA &= ~(1<<ADEN);                                // ADC
> deaktivieren

Ich seh zwar, dass du den ADC deaktivierst, ich seh aber nirgends
wo du den ADC aktivierst.

von Magnus Müller (Gast)


Lesenswert?

Karl heinz Buchegger wrote:
>>    ADCSRA &= ~(1<<ADEN);                                // ADC
>> deaktivieren
>
> Ich seh zwar, dass du den ADC deaktivierst, ich seh aber nirgends
> wo du den ADC aktivierst.

Das macht er gleich zu Beginn...

void adc_ch0(void)
{
  adc_init_ch0();
  ...
  ADCSRA = (1<<ADEN)|(1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0); // ADC aktiviert
  ...
}

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Magnus Müller wrote:

> Das macht er gleich zu Beginn...

>
1
>   ADCSRA = (1<<ADEN)|(1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0); // ADC aktiviert
2
>

...mit dem höchstmöglichen Prescaler.  Wenn der ATmega128 mit seinen
standardmäßigen 1 MHz läuft, tickert der ADC dann mit 8 kHz.  Da wäre
es kein Wunder, dass die Ergebnisse nicht mehr zuverlässig sind.
Nicht nur, dass eine Messung endlos lange dauert, ich wage zu
bezweifeln, dass die sample&hold-Schaltung im Eingang die Spannung so
lange festklemmen kann.

von Florian M. (skywalker79)


Lesenswert?

Hallo,

so ich hab den Code jetzt mal ganz zusammengekürzt und lasse jetzt eine 
LED angehen bzw. ausgehen, wenn ich 2,5V bzw. 0V anlege.
Das funktioniert soweilt.
Also denk ich mal, das mein erster Code wohl zu kompliziert war und ich 
nie zum Messen gekommen bin

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.