Forum: Mikrocontroller und Digitale Elektronik Verständnissfrage bei ADC


von Max (Gast)


Lesenswert?

Hallo Leute,

ich setze mich im Moment mit ADC auseinander, zum größten Teil verstehe 
ich es, ich hätte jedoch trotzdem paar Fragen.

Dieses Außenrum verstehe ich nicht.
Das ist dieses Beispiel aus dem Tutorial:

uint16_t ReadChannel(uint8_t mux)
{
  uint8_t i;
  uint16_t result;

  ADCSRA = (1<<ADEN) | (1<<ADPS1) | (1<<ADPS0);    // Frequenzvorteiler
                               // setzen auf 8 (1) und ADC aktivieren 
(1)

  ADMUX = mux;                      // Kanal waehlen
  ADMUX |= (1<<REFS1) | (1<<REFS0); // interne Referenzspannung nutzen

  /* nach Aktivieren des ADC wird ein "Dummy-Readout" empfohlen, man 
liest
     also einen Wert und verwirft diesen, um den ADC "warmlaufen zu 
lassen" */
  ADCSRA |= (1<<ADSC);              // eine ADC-Wandlung
  while ( ADCSRA & (1<<ADSC) ) {
     ;     // auf Abschluss der Konvertierung warten
  }
  result = ADCW;  // ADCW muss einmal gelesen werden,
                  // sonst wird Ergebnis der nächsten Wandlung
                  // nicht übernommen.

  /* Eigentliche Messung - Mittelwert aus 4 aufeinanderfolgenden 
Wandlungen */
  result = 0;
  for( i=0; i<4; 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 (2)

  result /= 4;                     // Summe durch vier teilen = arithm. 
Mittelwert

  return result;
}

...

/* Beispielaufrufe: */

void foo(void)
{
  uint16_t adcval;

  adcval = ReadChannel(0); /* MUX-Bits auf 0b0000 -> Channel 0 */
  ...
  adcval = ReadChannel(2); /* MUX-Bits auf 0b0010 -> Channel 2 */
  ...
}

Wenn ich es richtig verstanden habe, ist es wie eine Funktion aufgebaut,
mit der Variable "mux" wird der analoge Pin übergeben, an dem gemessen 
werden soll, und in die Variable "ReadChannel" das Ergebniss der Messung 
an
das eigentliche Programm.
Ich bin mir aber gar nicht sicher weil ich so eine Schreibweise noch 
nicht gesehen habe "uint16_t ReadChannel(uint8_t mux)"
Was haben die Klammern zusagen??
Muss ich "mux" eine Nummer zuweisen? (Welcher Pin)und in welcher 
Schreibweise 2 oder 0b00000010.

Ich Verwende ein ATmega 32, habe ich es richtig verstanden dass man die 
Taktung von 0-16 MHz einstellen kann? Ich weis nicht wie der jetzt 
getaktet wird, wo finde ich es? dann muss ich doch auch den 
Frequenzvorteiler im ADCSRA verändern.
Mit dem Quellcode von Oben funktioniert es noch nicht.

Ich hoffe die Fragen sind nicht all zu doof und dass ihr einem Anfänger 
helfen könnt. (Wäre sehr nett)

von yalu (Gast)


Lesenswert?

> Wenn ich es richtig verstanden habe, ist es wie eine Funktion
> aufgebaut,

Nicht nur wie, das ist eine Funktion.

> mit der Variable "mux" wird der analoge Pin übergeben, an dem
> gemessen werden soll,

Richtig.

> und in die Variable "ReadChannel" das Ergebniss der Messung

ReadChannel ist der Name der Funktion, die als Funktionswert das
Ergebnis der Messung liefert.

> uint16_t ReadChannel(uint8_t mux)
                                ^ Name des Arguments
                         ^ Typ des Arguments (8-Bit-Zahl ohne
                           Vorzeichen)
               ^ Name der Funktion
     ^ Typ des Funktionswerts (16-Bit-Zahl ohne Vorzeichen)

> Was haben die Klammern zusagen??

Die Klammern umschließen einfach die Liste der Funktionsargumente.

> Muss ich "mux" eine Nummer zuweisen? (Welcher Pin)und in welcher

Der Aufruf der Funktion sieht bspw. so aus:
1
   ergebnis = ReadChannel(3);
Diese Anweisung führt eine Messung am Pin ADC3 durch.

Führ dir doch mal ein C-Tutorial zu Gemüte, dann werden dir viele
dieser Dinge klar werden.

> Ich Verwende ein ATmega 32, habe ich es richtig verstanden dass man
> die Taktung von 0-16 MHz einstellen kann?

Es gibt verschiedene Möglichkeiten, den ATmega32 zu takten: Meist wird
der interne RC-Oszillator oder der interne Quarzoszillator mit
externem Quarz verwendet. Weitere Möglichkeiten stehen im Datenblatt
unter "System Clock and Clock Options". Je nach verwendetem Oszillator
stehen unterschiedliche Frequenzen zur Verfügung. Parametriert wird
das Ganze über sogenannte Fuses (AVR Fuses).

Die Fuses können auch ausgelesen werden, um festzustellen, was gerade
eingestellt ist. Ein fabrikneuer ATmega32 ist so eingestellt, dass er
durch den internen RC-Oszillator mit 1 MHz getaktet wird.

von Max (Gast)


Lesenswert?

Super, DANKE SEHR

ich glaube jetzt komme ich langsam dahinter, das ist eine Funktion der 
ein Wert übergeben wird, die aber auch ein Wert zurück liefert.

Wie kann ich die Fuses auslesen??

Aber da es ein neuer Atmega 32 ist, gehe ich davon aus dass der mit 1MHz 
getaktet wird.

Mit dem Wert habe ich mir den Teilungsfaktor von 5 bis 20 ausgerechnet 
und
im ADC den Wert von 16 eingestellt.

Leider funtioniert es immer noch nicht, es leuchtet warum auch immer die 
2 LED (PORTC1), aber sonst pasiert nichts.

Könnte mir einer bei der Fehlersuche helfen??

Das ist mein Quellcode
Die Funktion "warte_ms" hat nichts zu sagen

#include <avr\io.h>
#include <inttypes.h>
#include <stdint.h>



// Funktionen
void warte_ms(unsigned int Verzoegern);
uint16_t ReadChannel(uint8_t mux);




int main(void)

{

DDRC =  0b11111111; // Ausgänge am PORTC
PORTC = 0b11111111; // LEDs Aus
uint16_t adcval;


adcval = ReadChannel(1); /* MUX-Bits auf 0b0001 -> Channel 1 */

if (adcval > 0)
{
PORTC= 0b00000000;   // LEDs EIN
}
  return 0;

}



 //____________________Funktion 
ADC_______________________________________
uint16_t ReadChannel(uint8_t mux)
{
  uint8_t i;
  uint16_t result;

  ADCSRA = (1<<ADEN) | (1<<ADPS2);    // Frequenzvorteiler
                               // setzen auf 16 (1) und ADC aktivieren 
(1)

  ADMUX = mux;                      // Kanal waehlen
  ADMUX |= (1<<REFS1) | (1<<REFS0); // interne Referenzspannung nutzen

  /* nach Aktivieren des ADC wird ein "Dummy-Readout" empfohlen, man 
liest
     also einen Wert und verwirft diesen, um den ADC "warmlaufen zu 
lassen" */
  ADCSRA |= (1<<ADSC);              // eine ADC-Wandlung
  while ( ADCSRA & (1<<ADSC) )
  {
     ;     // auf Abschluss der Konvertierung warten
  }
  result = ADCW;  // ADCW muss einmal gelesen werden,
                  // sonst wird Ergebnis der nächsten Wandlung
                  // nicht übernommen.

  /* Eigentliche Messung - Mittelwert aus 4 aufeinanderfolgenden 
Wandlungen */
  result = 0;
  for( i=0; i<4; 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 (2)

  result /= 4;                     // Summe durch vier teilen = arithm. 
Mittelwert

  return result;
}





//__________Funktion___Wartezeit_in_ms______________

void warte_ms(unsigned int Zeitwert)  //Lade Funktion "warte_ms" mit dem 
Wert Zeitwert

{
 while(Zeitwert!=0)            //Solange laufen bis Zeitwert Null ist
  {
   unsigned int j;            //Variable "j"
   for(j=0;j<2000; j++) {asm("nop");} //Anfangswert=0 laufen bis 1000 
mit jedem Durchlauf um 1 erhöhen
   Zeitwert--;                //Wenn bei 1000 angekommen den Zeitwert um 
1 reduzieren
  }
}

von Karl H. (kbuchegg)


Lesenswert?

Max wrote:

> ich glaube jetzt komme ich langsam dahinter, das ist eine Funktion der
> ein Wert übergeben wird, die aber auch ein Wert zurück liefert.

Genau. Ist so wie

  x = sin( 25 );

sin ist eine Funktion namens Sinus. Sie bekommt einen Wert übergeben,
macht irgendetwas damitund liefert wieder einen Wert.

> Wie kann ich die Fuses auslesen??

Dein Brennprogramm hat irgendwo einen Menüpunkt dafür. Welches
Programm verwendest du?

> Aber da es ein neuer Atmega 32 ist, gehe ich davon aus dass der mit 1MHz
> getaktet wird.

Korrekt.

>
> Mit dem Wert habe ich mir den Teilungsfaktor von 5 bis 20 ausgerechnet
> und
> im ADC den Wert von 16 eingestellt.
>
> Leider funtioniert es immer noch nicht, es leuchtet warum auch immer die
> 2 LED (PORTC1), aber sonst pasiert nichts.

Nimm einen anderen Port. Auf PORTC liegen Sonderfunktionen, die
Defaultmaessig aktiviert sind. Die kann man mit einer Fuse (JTAGEN)
abschalten aber dazu musst du erst mal die Fuses lesen und schreiben
können :-)

von Max (Gast)


Lesenswert?

Ich verwende WinAVR

Ich habe es jetzt mit PORTD und B probiert, es fuktioniert nicht.
Wobei am B der Programeierstecker liegt.

Hier ist was faul, ich habe jetzt genau andersrum probiert

also so

int main(void)

{

DDRD =  0b11111111; // Ausgänge am PORTC
PORTD = 0b00000000; // LEDs EIN
uint16_t adcval;


adcval = ReadChannel(2); /* MUX-Bits auf 0b0000 -> Channel 0 */

if (adcval > 0)
{
PORTD = 0b11111111;   // LEDs AUS
}
  return 0;

}

Jetzt sollen die LEDs sofort angehen und wenn gemessen wurde und Wert >0 
ist, wieder ausschalten.

Die gehen aber nicht mal an.

von Max (Gast)


Lesenswert?

So, die LEDs sind jetzt an (PORTD), der Analoge Wert kommt auch am PINA1 
an, die Messung geht aber nicht.

von Max (Gast)


Lesenswert?

Jepii
Es funktioniert

Danke euch für die Hilfe

Gruß
Max

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.