ADC Rutine vom GCC-Tutorial

#798379
Lesenswert?

Hallo,

es geht um diese Methode vom GCC-Tutorial:
1
uint16_t ReadChannel(uint8_t mux)
2
{
3
  uint8_t i;
4
  uint16_t result;
5
 
6
  ADCSRA = (1<<ADEN) | (1<<ADPS2) | (1<<ADPS1);    // Frequenzvorteiler 
7
                               // setzen auf 8 (1) und ADC aktivieren (1)
8
 
9
  ADMUX = mux;                      // Kanal waehlen
10
  ADMUX |= (1<<REFS0); // AVCC als Referenz
11
 
12
  /* nach Aktivieren des ADC wird ein "Dummy-Readout" empfohlen, man liest
13
     also einen Wert und verwirft diesen, um den ADC "warmlaufen zu lassen" */
14
  ADCSRA |= (1<<ADSC);              // eine ADC-Wandlung 
15
  while ( ADCSRA & (1<<ADSC) ) {
16
     ;     // auf Abschluss der Konvertierung warten 
17
  }
18
  result = ADCW;  // ADCW muss einmal gelesen werden,
19
                  // sonst wird Ergebnis der nächsten Wandlung
20
                  // nicht übernommen.
21
 
22
  /* Eigentliche Messung - Mittelwert aus 4 aufeinanderfolgenden Wandlungen */
23
  result = 0; 
24
  for( i=0; i<4; i++ )
25
  {
26
    ADCSRA |= (1<<ADSC);            // eine Wandlung "single conversion"
27
    while ( ADCSRA & (1<<ADSC) ) {
28
      ;   // auf Abschluss der Konvertierung warten
29
    }
30
    result += ADCW;        // Wandlungsergebnisse aufaddieren
31
  }
32
  ADCSRA &= ~(1<<ADEN);             // ADC deaktivieren (2)
33
 
34
  result /= 4;                     // Summe durch vier teilen = arithm. Mittelwert
35
 
36
  return result;
37
}

Es wir in der Methode der ADC immer komplett neu initialisiert, bei 
jeder Messung.
Ist das sinvoll? wird das nicht lagsam? Ich messe jede 10ms einen Wert 
... ist es nicht besser wenn man den ADC in der main Einstellt und dann 
in der  ReadChannel Methode den ADC nur ein und ausmacht?
#798405
Lesenswert?

@ Richard B. (rbrose)

>es geht um diese Methode vom GCC-Tutorial:

Das ist eine einfache Funktion. Wie sind hier bei C, nicht C++.

>Es wir in der Methode der ADC immer komplett neu initialisiert, bei
>jeder Messung.

Ja.

>Ist das sinvoll?

Nein.

> wird das nicht lagsam?

Ja.

> Ich messe jede 10ms einen Wert
>... ist es nicht besser wenn man den ADC in der main Einstellt und dann
>in der  ReadChannel Methode den ADC nur ein und ausmacht?

Ja.

MfG
Falk
#798501
Lesenswert?

Ok, ich benutze den AtMEga168 und habe ADC so eingestellt:
1
  //init ADC
2
  ADCSRA |= (1<<ADEN) | (1<<ADSC) | (1<<ADPS2) | (1<<ADPS1);    // Frequenzvorteiler 
3
                               // setzen auf 64 (1) und ADC aktivieren (1)   //Free Running Mode     
4
    ADMUX |= (1<<REFS0) | (1<<ADLAR); // AVCC als Referenz //ADC0

Aber wenn ich mit
1
  char buffer[7];
2
  itoa(ADCH, buffer,10);
3
  uart_puts(buffer);

ADCH jede Sekunde ausgeben ist die Variable immer 255 groß, egal welcher 
Wert an PC0 anliegt.

Was ist falsch? Habe ich etwas übersehen? Mit ADSC sollte es jetzt im 
Free Running Mode permanent messen oder?
#798524
Lesenswert?

MMhh der ADC scheint zu funktionieren ... weil wenn ich die Taste Drücke 
und dann der AVR anmachen, dann zeigt er mir ein anderen Wert an .. aber 
alle folgende sind gleich. Das heißt der Free Running Mode klappt nicht 
... Ich dachte er Updated das ADCH automatisch.

Beim ATTiny26 muss man das ADFR Bit aktivieren ... aber der AtMega168 
hat es nicht. Das wird im Register ADCSRB gemacht. Sehe ich das Richtig? 
Aber om Register ADCSRB ist Free Running Mode default ausgewählt, also 
brauche ich da nichts ändern.

Was ist falsch?
#798571
Lesenswert?

@ Richard B. (rbrose)

>ADCH jede Sekunde ausgeben ist die Variable immer 255 groß, egal welcher
>Wert an PC0 anliegt.

Lies das Tutorial. GENAU!

>Was ist falsch? Habe ich etwas übersehen?

Ja. Du musst ADCW lesen, das ist der ADC als 16 Bit Wert. Denn der 
Zugriff auf ADCL ADCH muss VOLLSTÄNDIG in der RICHIGEN Reihenfolge 
erfolgen. Sonst liest du nämlich immer das gleiche.

> Mit ADSC sollte es jetzt im Free Running Mode permanent messen oder?

Ja.

MFG
Falk
#798665
Lesenswert?

@ Richard B. (rbrose)

>Wieso muss ich ADCW lesen?

Warum liest du nicht des Tutorial GENAU! Dann würdes du DAS hier finden.

"
Wenn eine Umwandlung abgeschlossen ist, befindet sich der gemessene Wert 
in diesen beiden Registern. Von ADCH werden nur die beiden 
niederwertigsten Bits verwendet. Es müssen immer beide Register 
ausgelesen werden, und zwar immer in der Reihenfolge: ADCL, ADCH. Der 
effektive Messwert ergibt sich dann zu:

x = ADCL;       // mit uint16_t x
x += (ADCH<<8); // in zwei Zeilen (LSB/MSB-Reihenfolge und
                // C-Operatorpriorität sichergestellt)

oder

x = ADCW; // je nach AVR auch x = ADC (siehe avr/ioxxx.h)
"

MfG
Falk
#798705
Lesenswert?

@Falk
Du hast dich geirrt, ich muss nicht ADCL vor ADCH auslesen wenn ADLAR 
gesetzt ist.

Habe jetzt in die Schaltung einen ATMega8 getan ... und da klappt es 
problemlos mit 8bit und 10bit.

Ich glaube der AtMega168 hat ein Bug. Finde irgendwie auch nicht viel 
über den 168 im Free  Running mode.
Gast #798810
Lesenswert?

Ist das :
1
//init ADC
2
  ADCSRA |= (1<<ADEN) | (1<<ADSC) | (1<<ADPS2) | (1<<ADPS1);    // Frequenzvorteiler 
3
                               // setzen auf 64 (1) und ADC aktivieren (1)   //Free Running Mode     
4
    ADMUX |= (1<<REFS0) | (1<<ADLAR); // AVCC als Referenz //ADC0
wirklich der Code den du benutzt?
Ich würde es ja eher so versuchen:
1
ADMUX  = (1<<REFS0) | (1<<ADLAR); //erst initialiseren, DANN starten
2
ADCSRA = (1<<ADEN) | (1<<ADSC) | (1<<ADATE) | (1<<ADPS2) | (1<<ADPS1);
3
    //                           ^^^^^^^^^^
4
    //                           free-running mode...
Oder z.B. im ADC-Interrupt die nächste Wandlung starten, WENN du mehrere 
Kanäle wandeln willst.
Außerdem kannst du dir mal das Register ADCSR*B* bei den AtmegaX8 
anschauen..

hth. Jörg
#798982
Lesenswert?

@Andreas?
Bin ich blind? Oder habe ich ein anderes Datenblatt?

Table 23-5. ADC Auto Trigger Source Selections
ADTS2 ADTS1 ADTS0 Trigger Source
0 0 0 Free Running mode
0 0 1 Analog Comparator
0 1 0 External Interrupt Request 0
0 1 1 Timer/Counter0 Compare Match A
1 0 0 Timer/Counter0 Overflow
1 0 1 Timer/Counter1 Compare Match B
1 1 0 Timer/Counter1 Overflow
1 1 1 Timer/Counter1 Capture Event


0 0 1 wäre der Analog Comparator.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren