Forum: Mikrocontroller und Digitale Elektronik Probleme mit ADC auf Mega8 und Mega88


von Willi W. (williwacker)


Lesenswert?

Hallo Leute,

ich habe ein Problem mit dem AD-Wandler beim Mega8 und Mega88. Der unten 
angehängte Code soll auf beiden Controllern laufen. Der Code läuft in 
einem Interrupt, der alle 3ms aufgerufen wird. Unter bestimmten 
Umständen kann der Abstand auch kürzer sein, aber in ca. 1s wird der 
Interrupt 333 mal aufgerufen.

Mich interessieren 2 AD-Kanäle, Kanal 6 und Kanal 7. Über Kanal 6 messe 
ich die Betriebsspannung und über Kanal 7 einen Widerstand. Die externe 
Beschaltung ist ok, der gemessene Spannungswert am AD-Eingang entspricht 
den Erwartungen.

Der Ablauf ist nun so:

Am Ende des Durchlaufs wird der jeweils andere Kanal gestartet. Beim 
erneuten Aufruf wird geprüft, welcher Kanal gewandelt wurde und der 
Messwert wird entsprechend weiterverarbeitet, anschließend wird wieder 
der andere Kanal angestoßen, die ISR terminiert und so geht es fort.

Soweit so gut. Jetzt habe ich nur ein Problem: Ich lese oben den ADMUX 
ein und sehe, welcher Kanal gewandelt wurde. Es kommt so ca. alle paar 
Sekunden vor, dass ich den Wert für Kanal 7 einlese, anschließend aber 
im ADMUX Kanal 6 steht und entsprechend ist auch der eingelesene Wert 
falsch. Das lässt sich auf dem mega88 nachweisen, für den mega8 weiß ich 
es nicht (Debugmöglichkeiten!)

Ich habe ein wenig mit den Einstellungen gespielt und die Einstellungen 
für den ADPS für den mega88 sind so wie sie sind ertestet optimal, das 
heißt, der oben beschriebene Fall tritt relativ selten auf. Laut 
Dokumentation müsste der Prescaler den ADC aber viel zu schnell takten ?

Kennt sich jemand mit diesem Problem aus? Kennt jemand Abhilfe? Ein 
Workaround schwebt mir schon vor, aber eigentlich möchte ich das Problem 
nicht umgehen sondern lösen.

Danke und Ciao
WilliWacker

<code>
interrupt [TIM1_COMPA_vect] void timer1_comp_isr(void)
{
  byte chnl;

  // Alle anderen Interrupts freigeben, damit wird dieser Interrupt 
unterbrechbar!
  ENABLE_INTERRUPTS;

  // Bearbeiten der letzten Wandlung:
  // Wenn die Wandlung nicht nicht beendet ist, dann wieder raus
  if ( (1<<ADIF) & ADCSRA ) // AD-Wandlung beendet ?
  {
    // Welche Wandlung wurde beim letzten Aufruf gestartet 
6=PowerSupply   7=Matte
    activatedADChannel = ADMUX & 0x07;
    if ( activatedADChannel == AD_CHANNEL_POWER_SUPPLY )
    {
       b_wV = ADCH; // Daten 8 bit linksorientiert

       // Übernahme Messwert und Filterung; Annahme: langsame Änderung; 
kurze Einbrüche
       // oder Peaks interessieren uns hier nicht (das macht die 
Hardware)

  // ...

    }
    else // Matte
    {
       b_wM = ADCH; // Daten 8 bit linksorientiert

  // ...

    } // else Matte
  } // else AD-Wandlung beendet

  chnl = AD_CHANNEL_POWER_SUPPLY;
  if (activatedADChannel == AD_CHANNEL_POWER_SUPPLY )
  {
    chnl = AD_CHANNEL_MAT_VOLTAGE;
  }
  ADCSRA =   ( 1<<ADEN )   // ADC aktivieren
           | ( 0<<ADSC )   // Konvertierung noch nicht starten
#ifdef MEGA8
           | ( 0<<ADFR )   // NICHT Free Running Select
#endif
#ifdef MEGA88
           | ( 0<<ADATE)   // NICHT Free Running Select / AutoTrigger 
Disabled
#endif
           | ( 1<<ADIF )   // ADC Interrupt Flag löschen (durch 
Schreiben einer Eins)
           | ( 0<<ADIE )   // Keinen Interrupt bei Wandlungsende 
auslösen

                           // Frequenzvorteiler:

#ifdef MEGA8               // beim mega8:
           | ( 6<<ADPS0);  // ADPS2==1 & ADPS1==1 & ADPS0==0 ==> 
Teiler=64
                           // bei 8MHz-Takt --> ADC-Takt=125kHz
#endif MEGA8
#ifdef MEGA88              // beim mega88:
           | ( 0<<ADPS0);  // ADPS2==0 & ADPS1==1 & ADPS0==0 ==> 
Teiler=4
                           // bei 8MHz-Takt --> ADC-Takt=2MHz
                           // Dieser Wert wurde nach den Methoden der 
Experimentellen
                           // Informatik ermittelt (bei diesem Wert 
treten keine
                           // Fehlmessungen mehr auf.
#endif MEGA88

#ifdef MEGA88
  ADCSRB = 0; // beschreibt die Triggereigenschaften, hat der mega8 erst 
gar nicht
#endif MEGA88
  ADMUX =   chnl           // channel=0..7 (hier aber nur 6 und 7 
möglich)
          | (1<<ADLAR)     // Ergebnis linksshiften, damit stehen die 
uns
                           // interessierenden 8 bit in ADCH
          | (0<<REFS1)     // Verwende AREF als Referenzspannung
          | (0<<REFS0);
  ADCSRA |= (1<<ADSC);     // starte ADC-Wandlung

}
</code>

von Werner A. (homebrew)


Lesenswert?

ich hab mal gehört, das man nicht direkt nach dem setzen von admux 
auslesen sollte, da die internen schalter wohl ne zeit brauchen.
setz doch probehalber mal nach dem auslesen das admux schonmal auf den 
nächsten kanal.

von Willi W. (williwacker)


Lesenswert?

Das wars wohl doch nicht. Dann werde ich zu meinem Workaround greifen.

Danke für Deine Antwort !

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.