Forum: Compiler & IDEs ADC Rutine vom GCC-Tutorial


von Richard B. (rbrose)


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?

von Falk B. (falk)


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

von Rolf Magnus (Gast)


Lesenswert?

>>es geht um diese Methode vom GCC-Tutorial:
>
> Das ist eine einfache Funktion. Wie sind hier bei C, nicht C++.

Und C++ ist nicht Java.

von Richard B. (rbrose)


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?

von Richard B. (rbrose)


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?

von Falk B. (falk)


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

von Richard B. (rbrose)


Lesenswert?

@Falk

Wieso muss ich ADCW lesen? Ich habe doch ADLAR aktiviert.
Und Peter Dannegger liesst im seinem Beispiel auch nur ADCH aus:

http://www.mikrocontroller.net/attachment/highlight/21646

Lese jetzt ADCW aus ... ist aber nicht viel besser ... jetzt bekomme ich 
-64^^

von Falk B. (falk)


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

von Richard B. (rbrose)


Lesenswert?

Wieso widerspricht ihr euch hier im Forum??


Beitrag "ADC des ATMEGA168"
>Autor: Andreas Kaiser (a-k)
>Datum: 01.03.2008 16:28
>
>ADLAR setzen und nur ADCH verwenden.
>

Dennach kann ich nur ADCH lesen ....

Aber das ich nicht der Fehler ... man musste ADATE aktivieren.
Aber irgendwie will er trotzdem nicht richtig funktinieren.
Ich glaube es liegt am AtMega168 ...

von Richard B. (rbrose)


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.

von Jörg X. (Gast)


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

von Richard B. (rbrose)


Lesenswert?

@Jörg
was meintest du in dem anderen Thread mit

>> ADCSRB = (0<<ADTS2) | (0<<ADTS1) | (1<<ADTS0);   // Free running mode.
>Das stimmt nicht...

von Andreas K. (a-k)


Lesenswert?

Mit diesem Pattern triggert der ADC auf den AC.

von Richard B. (rbrose)


Lesenswert?

DANKE DIR JÖRG!! Es lag an der reihenfolge ;-)
Erst ADMUX und dann ADCSRA.
Jetzt funktioniert es.

von Richard B. (rbrose)


Lesenswert?

ADCSRB = (0<<ADTS2) | (0<<ADTS1) | (1<<ADTS0);   // Free running mode.

Es stimmt so ... 0 0 0 ist für Free running mode. Steht im Datenblatt 
von dem AtMega168.

von Andreas K. (a-k)


Lesenswert?

Da steht aber nicht 0 0 0, da steht 0 0 1.

von Richard B. (rbrose)


Lesenswert?

Aber wieso wird dann im dem AVR Tutorial erst ADCSRA beschaltet und dann 
ADMUX ?
Man sollte es mal überarbeiten. Ist ja ein sehr schlechtes Beispiel. 
Nicht allgemein gültig!

von Richard B. (rbrose)


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.

von Andreas K. (a-k)


Lesenswert?

Putz die Brille, wisch dir die Augen und lass mal jemand aus deiner 
Umgebung drauf gucken. Vielleicht siehst du dann, dass da (1<<ADTS0) 
steht, nicht etwa (0<<ADTS0).

von Richard B. (rbrose)


Lesenswert?

Alles klar ;-) Im Code ist es falsch .. nicht im Datenblatt. Ich merke 
es jetzt, sitze schon zu lange vor dem PC :-) Sehe den Wald vor lauter 
Bäume nicht.

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.