A/D-Routine im Atmega128

OP #1606392
Servus,

ich verwende alle 8 A/D-Kanäle vom Atmega128. Bisher sieht meine 
A/D-Routine wie folgt aus:
1
ISR(ADC_vect) 
2
{ 
3
   static UINT8 adc_channel;
4
   static UINT16 m[8]; 
5
   
6
   m[adc_channel] = (3 * m[adc_channel] + ADC) >> 2;  // Low Pass Filter 
7
   adc_result[adc_channel] = (m[adc_channel] - 512) * 64;  // convert to INT16
8
   adc_channel++; 
9
   if (adc_channel == 8) 
10
       adc_channel = 0; 
11
   ADMUX = (ADMUX & 0xE0) | adc_channel; 
12
 
13
   ADCSRA |= (1 << ADSC);   // start next conversion 
14
}
D.h. A/D-Wandlung mit A/D-Interrupt direkt nacheinander aufrufen. Es 
gibt einen Nachteil, dass man die Abtastrate nicht feststellen kann. 
Frage, kann man stattdessen einen 1ms-Timer wie folgt einsetzen:
1
void 1ms_TimerInterrupt(void)
2
{
3
  ADCSRA |= (1 << ADSC);   // start next conversion
4
}
5

6
ISR(ADC_vect) 
7
{ 
8
   static UINT8 adc_channel;
9
   static UINT16 m[8]; 
10
   
11
   m[adc_channel] = (3 * m[adc_channel] + ADC) >> 2;  // Low Pass Filter 
12
   adc_result[adc_channel] = (m[adc_channel] - 512) * 64;  // convert to INT16
13
   adc_channel++; 
14
   if (adc_channel == 8) 
15
       adc_channel = 0; 
16
   ADMUX = (ADMUX & 0xE0) | adc_channel;  
17
}
D.h. die Abtastrate ist nun 1000Hz/8 = 125Hz.

Welche Methode ist üblicher?

Gruss
Senmeis
Persönliche Seite #1606420
Die Methode mit Timer ist IMHO eleganter und wenn man einen Timer dafür 
frei hat oder einen mitbenutzen kann....

Aber was anderes: Nach der Kanalumschaltung legt dein Quelltext ja 
direkt mit der Messung los und verwendet keine üblicherweise empfohlene 
Dummyreadouts. Sind deine Messungen trotzdem genau?
#1606478
Stefan B. schrieb:

> Aber was anderes: Nach der Kanalumschaltung legt dein Quelltext ja
> direkt mit der Messung los und verwendet keine üblicherweise empfohlene
> Dummyreadouts.

Das ist doch nur ein (anscheinend nicht tot zu kriegender) Mythos(*).
Dummyreads sind nötig nach dem Umschalten der Referenz, nicht dem Kanal 
(außer im Differential-Mode).

(*) Oder war das vielleicht mal bei den Uralt-AVRs nötig?
Gast #1607608
>Vielen Dank. Die Voraussetzung für die Methode mit Timer ist jedoch,
>dass die Bearbeitungsdauer der A/D-Wandlung kürzer als 1ms sein muss.
>Ich denke, dies wird immer erfüllt.
1
void 1ms_TimerInterrupt(void)
2

3
ISR(ADC_vect)

Ich würde den ADC-Int weglassen und das ADC-Ergebnis einfach im nächsten 
1ms-Int abholen, vor dem Start der nächsten Wandlung.
#1608785
Matthias Lipinsky schrieb:
>>Vielen Dank. Die Voraussetzung für die Methode mit Timer ist jedoch,
>>dass die Bearbeitungsdauer der A/D-Wandlung kürzer als 1ms sein muss.
>>Ich denke, dies wird immer erfüllt.
>
>
1
> void 1ms_TimerInterrupt(void)
2
> 
3
> ISR(ADC_vect)
4
>
>
> Ich würde den ADC-Int weglassen und das ADC-Ergebnis einfach im nächsten
> 1ms-Int abholen, vor dem Start der nächsten Wandlung.

Im Gegenteil. Den ADC durch den Timer triggern lassen und optional, 
falls der Timer Interrupt nicht verwendet wird (den benötigt man 
eigentlich nicht) in der darauffolgenden ADC ISR das Interrupt-Flag des 
Timer zurücksetzen. Das ergibt die genauesten Abtastintervalle die auf 
einem AVR möglich sind, da nicht einmal mehr die zufällige Interrupt 
Latency Time des Timer Interrupts eine Rolle spielt.

Ausschnitt einer ADC Initilisierung (für einen ATMega32)
1
...
2
  // ADC Trigger Source = Timer0 Compare Match
3
  SFIOR |= (1 << ADTS1) | (1 << ADTS0);
4

5
  ADCSRA = ADC_DIVISOR |      // Pick the fastest sample frequency (smallest divisor) we can use 
6
     _BV(ADEN)|      // ADC an
7
     _BV(ADSC)|      // Beginne mit der Konvertierung
8
     _BV(ADIE)|      // ADC-Interrupt an
9
     _BV(ADATE);     // Auto trigger on
10
  TIFR =  _BV(OCF0); // Reset OCF0 - Flag
11
...

Und der zugehörigen ADC-ISR
1
...
2
ISR(ADC_vect)
3
{
4
  int16_t adc = ADCW;      // ADC einlesen
5

6
  TIFR =  _BV(OCF0);      // Reset OCF0 - Flag
7
...
8
}
9
...

Antwort schreiben

Eine eigene Frage? Dieser Thread ist über 16 Jahre alt. Stell sie in einem eigenen Thread – dort lesen mehr Leute mit, und sie wird öfter und schneller beantwortet.

Neuen Thread starten

Eine Lösung, Ergänzung oder Rückmeldung zu diesem Thread? Dann antworte hier.

Formatierung
  • [c]C-Code[/c]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] – Link zu einem Artikel
  • Verweis auf einen anderen Beitrag: Rechtsklick auf dessen Beitrags-ID (#8078628), „Adresse kopieren“, in den Text einfügen

Mehr zur Formatierung

Längeren Sourcecode als Anhang, nicht in den Text. JPG nur für Fotos und Scans; Zeichnungen und Screenshots als PNG oder GIF. Siehe Bildformate.

Schon registriert? Anmelden

Wird nicht angezeigt. Wir schicken dir einen Link; sobald du damit bestätigst, erscheint dein Beitrag.

Mit dem Abschicken legst du einen kostenlosen Account an und erkennst die Nutzungsbedingungen und die Datenschutzerklärung an.