avr ersterer schritt
  ANALOG
 
Analoge Ein- und Ausgabe

Analoge Eingangswerte werden in der Regel über den AVR Analog-Digital-Converter (AD-Wandler, ADC) eingelesen, der in vielen Typen verfügbar ist (typisch 10bit Auflösung). Durch diesen werden analoge Signale (Spannungen) in digitale Zahlenwerte gewandelt. Bei AVRs, die über keinen internen AD-Wandler verfügen (z. B. ATmega162), kann durch externe Beschaltung (R/C-Netzwerk und "Zeitmessung") die Funktion des AD-Wandlers "emuliert" werden.

Es existieren keine AVRs mit eingebautem Digital-Analog-Konverter (DAC). Diese Funktion muss durch externe Komponenten nachgebildet werden (z. B. PWM und "Glättung").

Unabhängig davon besteht natürlich immer die Möglichkeit, spezielle Bausteine zur Analog-Digital- bzw. Digital-Analog-Wandlung zu nutzen und diese über eine digitale Schnittstelle (z.b. SPI oder I2C) mit einem AVR anzusteuern.

[Bearbeiten] AC (Analog Comparator)

Der Comparator vergleicht 2 Spannungen an den Pins AIN0 und AIN1 und gibt einen Status aus welche der beiden Spannungen größer ist. AIN0 Dient dabei als Referenzspannung (Sollwert) und AIN1 als Vergleichsspannung (Istwert). Als Referenzspannung kann auch alternativ eine interne Referenzspannung ausgewählt werden.

Liegt die Vergleichsspannung (IST) unter der der Referenzspannung (SOLL) gibt der Comperator eine logische 1 aus. Ist die Vergleichsspannung hingegen größer als die Referenzspannung wird eine logische 0 ausgegeben.

Der Comparator arbeitet völlig autark bzw. parallel zum Prozessor. Für mobile Anwendungen empfiehlt es sich ihn abzuschalten sofern er nicht benötigt wird, da er ansonsten Strom benötigt. Der Comparator kann Interruptgesteuert abgefragt werden oder im Pollingbetrieb.

Das Steuer- bzw. Statusregister ist wie folgt aufgebaut:

ACSR - Analog Comparator Status Register
Bit 7 6 5 4 3 2 1 0
Name ACD ACBG ACO ACI ACIE ACIC ACIS1 ACIS0
R/W R/W R/W R R/W R/W R/W R/W R/W
Initialwert 0 0 n/a 0 0 0 0 0
Bit 7 ACD
Analog Comparator Disable: 0 = Comparator ein, 1 = Comparator aus. Wird dieses Bit geändert kann ein Interrupt ausgelöst werden. Soll dies vermieden werden muß das Bit 3 ACIE ggf. abgeschaltet werden.
Bit 6 ACBG
Analog Comparator Bandgap Select: Ermöglicht das umschalten zwischen interner und externer Referenzspannung. 1 = interne (~1,3 Volt), 0 = externe Referenzspannung (an Pin AIN0)
Bit 5 ACO
Analog Comparator Output: Hier wird das Ergebnis des Vergleichs angezeigt. Es liegt typischerweise nach 1-2 Taktzyklen vor.
IST < SOLL → 1
IST > SOLL → 0
Bit 4 ACI
Analog Comparator Interrupt Flag: Dieses Bit wird von der Hardware gesetzt wenn ein Interruptereignis das in Bit 0 und 1 definiert ist eintritt. Dieses Bit löst noch keinen Interrupt aus! Die Interruptroutine wird nur dann ausgeführt wenn das Bit 3 ACIE gesetzt ist und global Interrupts erlaubt sind (I-Bit in SREG=1). Das Bit 4 ACI wird wieder gelöscht wenn die Interruptroutine ausgeführt wurde oder wenn manuell das Bit auf 1 gesetzt wird. Das Bit kann für Abfragen genutzt werden, steuert oder konfiguriert aber nicht den Comparator.
Bit 3 ACIE
Analog Comparator Interrupt Enable: Ist das Bit auf 1 gesetzt wird immer ein Interrupt ausgelöst wenn das Ereignis das in Bit 1 und 0 definiert ist eintritt.
Bit 2 ACIC
Analog Comparator Input Capture Enable: Wird das Bit gesetzt wird der Comparatorausgang intern mit dem Counter 1 verbunden. Es könnten damit z.b. die Anzahl der Vergleiche im Counter1 gezählt werden. Um den Comparator an den Timer1 Input Capture Interrupt zu verbinden muß im Timerregister das TICIE1 Bit auf 1 gesetzt werden. Der Trigger wird immer dann ausgelöst wenn das in Bit 1 und 0 definierte Ereignis eintritt.
Bit 1,0 ACIS1,ACIS0
Analog Comparator Interrupt select: Hier wird definiert welche Ereignisse einen Interrupt auslösen sollen:
  • 00 = Interrupt auslösen bei jedem Flankenwechsel
  • 10 = Interrupt auslösen bei fallender Flanke
  • 11 = Interrupt auslösen bei steigender Flanke

Werden diese Bit geändert kann ein Interrupt ausgelöst werden. Soll dies vermieden werden muß das Bit 3 gelöscht werden.

[Bearbeiten] ADC (Analog Digital Converter)

Der Analog-Digital-Konverter (ADC) wandelt analoge Signale in digitale Werte um, welche vom Controller interpretiert werden können. Einige AVR-Typen haben bereits einen mehrkanaligen Analog-Digital-Konverter eingebaut. Die Genauigkeit, mit welcher ein analoges Signal aufgelöst werden kann, wird durch die Auflösung des ADC in Anzahl Bits angegeben, man hört bzw. liest jeweils von 8-Bit-ADC oder 10-Bit-ADC oder noch höher. ADCs die in AVRs enthalten sind haben zur Zeit eine maximale Auflösung von 10-Bit.

Ein ADC mit 8 Bit Auflösung kann somit das analoge Signal mit einer Genauigkeit von 1/256 des Maximalwertes darstellen. Wenn wir nun mal annehmen, wir hätten eine Spannung zwischen 0 und 5 Volt und eine Auflösung von 3 Bit, dann könnten die Werte 0V, 0.625V, 1.25, 1.875V, 2.5V, 3.125V, 3.75, 4.375, 5V daherkommen, siehe dazu folgende Tabelle:

Eingangsspannung am ADC [V] Entsprechender Messwert
0–0.625 0
0.625–1.25 1
1.25–1.875 2
1.875–2.5 3
2.5–3.125 4
3.125–3.75 5
3.75–4.375 6
4.375–5 7

Die Angaben sind natürlich nur ungefähr. Je höher nun die Auflösung des Analog-Digital-Konverters ist, also je mehr Bits er hat, um so genauer kann der Wert erfasst werden.

[Bearbeiten] Der interne ADC im AVR

Wenn es einmal etwas genauer sein soll, dann müssen wir auf einen AVR mit eingebautem Analog-Digital-Wandler (ADC) zurückgreifen, die über mehrere Kanäle verfügen. Kanäle heißt in diesem Zusammenhang, dass zwar bis zu zehn analoge Eingänge am AVR verfügbar sind, aber nur ein "echter" Analog-Digital-Wandler zur Verfügung steht, vor der eigentlichen Messung ist also einzustellen, welcher Kanal ("Pin") mit dem Wandler verbunden und gemessen wird.

Die Umwandlung innerhalb des AVR basiert auf der schrittweisen Näherung. Beim AVR müssen die Pins AGND und AVCC beschaltet werden. Für genaue Messungen sollte AVCC über ein L-C Netzwerk mit VCC verbunden werden, um Spannungsspitzen und -einbrüche vom Analog-Digital-Wandler fernzuhalten. Im Datenblatt findet sich dazu eine Schaltung, die 10uH und 100nF vorsieht.

Das Ergebnis der Analog-Digital-Wandlung wird auf eine Referenzspannung bezogen. Aktuelle AVRs bieten 3 Möglichkeiten zur Wahl dieser Spannung:

  • Eine externe Referenzspannung von maximal Vcc am Anschlusspin AREF. Die minimale (externe) Referenzspannung darf jedoch nicht beliebig niedrig sein, vgl. dazu das (aktuellste) Datenblatt des verwendeten Controllers.
  • Verfügt der AVR über eine interne Referenzspannung, kann diese genutzt werden. Alle aktuellen AVRs mit internem AD-Wandler sollten damit ausgestattet sein (vgl. Datenblatt: 2,56V oder 1,1V je nach Typ). Das Datenblatt gibt auch über die Genauigkeit dieser Spannung Auskunft.
  • Es kann die Spannung AVcc als Referenzspannung herangezogen werden

Bei Nutzung von AVcc oder der internen Referenz wird empfohlen, einen Kondensator zwischen dem AREF-Pin und GND anzuordnen. Die Festlegung, welche Spannungsreferenz genutzt wird, erfolgt z. B. beim ATmega16 mit den Bits REFS1/REFS0 im ADMUX-Register. Die zu messende Spannung muss im Bereich zwischen AGND und AREF (egal ob intern oder extern) liegen.

Der ADC kann in zwei verschiedenen Betriebsarten verwendet werden:

Einfache Wandlung (Single Conversion) 
In dieser Betriebsart wird der Wandler bei Bedarf vom Programm angestoßen für jeweils eine Messung.
Frei laufend (Free Running) 
In dieser Betriebsart erfasst der Wandler permanent die anliegende Spannung und schreibt diese in das ADC Data Register.

[Bearbeiten] Die Register des ADC

Der ADC verfügt über eigene Register. Im Folgenden die Registerbeschreibung eines ATMega16, welcher über 8 ADC-Kanäle verfügt. Die Register unterscheiden sich jedoch nicht erheblich von denen anderer AVRs (vgl. Datenblatt).

ADCSRA    ADC Control and Status Register A.

In diesem Register stellen wir ein, wie wir den ADC verwenden möchten.
Das Register ist wie folgt aufgebaut:

Bit 7 6 5 4 3 2 1 0
Name ADEN ADSC ADFR ADIF ADIE ADPS2 ADPS1 ADPS0
R/W R/W R/W R/W R/W R/W R/W R/W R/W
Initialwert 0 0 0 0 0 0 0 0

ADEN (ADC Enable)

Dieses Bit muss gesetzt werden, um den ADC überhaupt zu aktivieren. Wenn das Bit nicht gesetzt ist, können die Pins wie normale I/O-Pins verwendet werden.

ADSC (ADC Start Conversion)

Mit diesem Bit wird ein Messvorgang gestartet. In der frei laufenden Betriebsart muss das Bit gesetzt werden, um die kontinuierliche Messung zu aktivieren.
Wenn das Bit nach dem Setzen des ADEN-Bits zum ersten Mal gesetzt wird, führt der Controller zuerst eine zusätzliche Wandlung und erst dann die eigentliche Wandlung aus. Diese zusätzliche Wandlung wird zu Initialisierungszwecken durchgeführt.
Das Bit bleibt nun so lange auf 1, bis die Umwandlung abgeschlossen ist, im Initialisierungsfall entsprechend bis die zweite Umwandlung erfolgt ist und geht danach auf 0.

ADFR (ADC Free Run select)

Mit diesem Bit wird die Betriebsart eingestellt.
Ist das Bit auf 1 gesetzt arbeitet der ADC im Freerunning Modus. Dabei wird das Datenregister permanent aktualisiert. Ist das Bit hingegen auf 0 gesetzt macht der ADC nur eine Single Conversion.


ADIF (ADC Interrupt Flag)

Dieses Bit wird vom ADC gesetzt, sobald eine Umwandlung erfolgt ist und das ADC Data Register aktualisiert wurde. Das Bit wird bei lesendem Zugriff auf ADC(L,H) automatisch (d.h. durch die Hardware) gelöscht.
Wenn das ADIE Bit sowie das I-Bit im AVR Statusregister gesetzt ist, wird der ADC Interrupt ausgelöst und die Interrupt-Behandlungsroutine aufgerufen.
Das Bit wird automatisch gelöscht, wenn die Interrupt-Behandlungsroutine aufgerufen wird. Es kann jedoch auch gelöscht werden, indem eine logische 1 in das Register geschrieben wird.

ADIE (ADC Interrupt Enable)

Wenn dieses Bit gesetzt ist und ebenso das I-Bit im Statusregister SREG, dann wird der ADC-Interrupt aktiviert.

ADPS2...ADPS0 (ADC Prescaler Select Bits)

Diese Bits bestimmen den Teilungsfaktor zwischen der Taktfrequenz und dem Eingangstakt des ADC.
Der ADC benötigt einen eigenen Takt, welchen er sich selber aus der CPU-Taktfreqenz erzeugt. Der ADC-Takt sollte zwischen 50 und 200kHz sein.
Der Vorteiler muss also so eingestellt werden, dass die CPU-Taktfrequenz dividiert durch den Teilungsfaktor einen Wert zwischen 50-200kHz ergibt.
Bei einer CPU-Taktfrequenz von 4MHz beispielsweise rechnen wir

                begin{matrix}
                TF_{min}=frac{CLK}{200,mathrm{kHz}}=frac{4000000}{200000}=mathbf{20}
                TF_{max}=frac{CLK}{50,mathrm{kHz}}=frac{4000000}{50000}=mathbf{80}
                end{matrix}
Somit kann hier der Teilungsfaktor 32 oder 64 verwendet werden. Im Interesse der schnelleren Wandlungszeit werden wir hier den Faktor 32 einstellen.
ADPS2 ADPS1 ADPS0 Teilungsfaktor
0 0 0 2
0 0 1 2
0 1 0 4
0 1 1 8
1 0 0 16
1 0 1 32
1 1 0 64
1 1 1 128
ADCL

ADCH

ADC Data Register

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) 
ADMUX   ADC Multiplexer Select Register

Mit diesem Register wird der zu messende Kanal ausgewählt. Beim 90S8535 kann jeder Pin von Port A als ADC-Eingang verwendet werden (=8 Kanäle).
Das Register ist wie folgt aufgebaut:

Bit 7 6 5 4 3 2 1 0
Name REFS1 REFS0 ADLAR MUX4 MUX3 MUX2 MUX1 MUX0
R/W R/W R/W R/W R/W R/W R/W R/W R/W
Initialwert 0 0 0 0 0 0 0 0

REFS1...REFS0 (ReferenceSelection Bits)

Mit diesen Bits kann die Referenzspannung eingestellt werden. Bei der Umstellung sind Wartezeiten zu beachten, bis die ADC-Hardware einsatzfähig ist (Datenblatt und [1]):
REFS1 REFS0 Referenzspanung
0 0 Externes AREF
0 1 AVCC als Referenz
1 0 Reserviert
1 1 Interne 2,56 Volt


ADLAR (ADC Left Adjust Result)

Das ADLAR Bit verändert das Aussehen des Ergebnisses der AD-Wandlung. Bei einer logischen 1 wird das Ergebnis linksbündig ausgegeben, bei einer 0 rechtsbündig. Eine Änderung in diesem Bit beeinflusst das Ergebnis sofort, ganz egal ob bereits eine Wandlung läuft.


MUX4...MUX0

Mit diesen 5 Bits wird der zu messende Kanal bestimmt. Wenn man einen einfachen 1-kanaligen ADC verwendet wird einfach die entsprechende Pinnummer des Ports in die Bits 0...2 eingeschrieben.
Wenn das Register beschrieben wird, während dem eine Umwandlung läuft, so wird zuerst die aktuelle Umwandlung auf dem bisherigen Kanal beendet. Dies ist vor allem beim frei laufenden Betrieb zu berücksichtigen.
Eine Empfehlung ist deswegen diese, dass der frei laufende Betrieb nur bei einem einzelnen zu verwendenden Analogeingang verwendet werden sollte, wenn man sich Probleme bei der Umschalterei ersparen will.

[Bearbeiten] Nutzung des ADC

Um den ADC zu aktivieren, müssen wir das ADEN-Bit im ADCSR-Register setzen. Im gleichen Schritt legen wir auch die Betriebsart fest.

Ein kleines Beispiel für den "single conversion"-Mode bei einem ATmega169 und Nutzung der internen Referenzspannung (beim '169 1,1V bei anderen AVRs auch 2,56V). D.h. das Eingangssignal darf diese Spannung nicht überschreiten, gegebenenfalls muss es mit einem Spannungsteiler verringert werden. Das Ergebnis der Routine ist der ADC-Wert, also 0 für 0-Volt und 1023 für V_ref-Volt.

In der praktischen Anwendung wird man zum Programmstart den ADC erst einmal grundlegend konfigurieren und dann auf verschiedenen Kanälen messen. Diese beiden Dinge sollte man meist trennen, denn das Einschalten des ADC und vor allem der Referenzspannung dauert ein paar Dutzend Mikrosekunden. Ausserdem ist das erste Ergebnis nach dem Einschalten ungültig und muss verworfen werden.

/* ADC initialisieren */
void ADC_Init(void) {
 
  uint16_t result;
 
  ADMUX = (1<<REFS1) | (1<<REFS0);      // interne Referenzspannung nutzen
  ADCSRA = (1<<ADPS1) | (1<<ADPS0);     // Frequenzvorteiler
  ADCSRA |= (1<<ADEN);                  // ADC aktivieren
 
  /* 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
  /* ADCW muss einmal gelesen werden, sonst wird Ergebnis der nächsten
     Wandlung nicht übernommen. */
  result = ADCW;
}
 
/* ADC Einzelmessung */
uint16_t ADC_Read( uint8_t channel )
{
  // Kanal waehlen, ohne andere Bits zu beeinflußen
  ADMUX = (ADMUX & ~(0x1F)) | (channel & 0x1F);
  ADCSRA |= (1<<ADSC);            // eine Wandlung "single conversion"
  while (ADCSRA & (1<<ADSC) )     // auf Abschluss der Konvertierung warten
    ;
  return ADCW;                    // ADC auslesen und zurückgeben
}
 
/* ADC Mehrfachmessung mit Mittelwertbbildung */
uint16_t ADC_Read_Avg( uint8_t channel, uint8_t average )
{
  uint32_t result = 0;
 
  for (uint8_t i = 0; i < average; ++i )
    result += ADC_Read( channel );
 
  return (uint16_t)( result / average );
}
 
...
 
/* Beispielaufrufe: */
 
void foo(void)
{
  uint16_t adcval;
  ADC_Init();
 
  adcval = ADC_Read(0);  // Kanal 0
  adcval = ADC_Read_Avg(2, 4);  // Kanal 2, Mittelwert aus 4 Messungen
}

Im Beispiel läuft der ADC ständig. Wenn man diesen Strom sparen will, z.B. bei Verwendung des Sleep Modes, muss man den ADC nach jeder Messung abschalten und vor der nächsten Messung wieder einschalten, wobei auch dann wieder eine kleine Pause und Anfangswandlung nötig sind.

Analog-Digital-Wandlung ohne internen ADC

[Bearbeiten] Messen eines Widerstandes

 

Analoge Werte lassen sich ohne Analog-Digital-Wandler auch indirekt ermitteln. Im Folgenden wird die Messung des an einem Potentiometer eingestellten Widerstands anhand der Ladekurve eines Kondensators erläutert. Bei dieser Methode wird nur ein Portpin benötigt, ein Analog-Digital-Wandler oder Analog-Comparator ist nicht erforderlich. Es wird dazu ein Kondensator und der Widerstand (das Potentiometer) in Reihe zwischen Vorsorgungsspannung und Masse/GND geschaltet (sogen. RC-Netzwerk). Zusätzlich wird eine Verbindung der Leitung zwischen Kondensator und Potentiometer zu einem Portpin des Controllers hergestellt. Die folgende Abbildung verdeutlicht die erforderliche Schaltung.

Wird der Portpin des Controllers auf Ausgang konfiguriert (im Beispiel DDRD |= (1<<PD2)) und dieser Ausgang auf Logisch 1 ("High", PORTD |= (1<<PD2)) geschaltet, liegt an beiden "Platten" des Kondensators das gleiche Potential VCC an und der Kondensator somit entladen. (Klingt komisch, mit Vcc entladen, ist aber so, da an beiden Seiten des Kondensators das gleiche Potential anliegt und somit eine Potentialdifferenz von 0V besteht => Kondensator ist entladen).

Nach einer gewissen Zeit ist der Kondensator entladen und der Portpin wird als Eingang konfiguriert (DDRD &= ~(1<<PD2); PORTD &= ~(1<<PD2)), wodurch dieser hochohmig wird. Der Status des Eingangspin (in PIND) ist Logisch 1 (High). Der Kondensator lädt sich jetzt über das Poti auf, dabei steigt der Spannungsabfall über dem Kondensator und derjenige über dem Poti sinkt. Fällt nun der Spannungsabfall über dem Poti unter die Thresholdspannung des Eingangspins (2/5 Vcc, also ca. 2V), wird das Eingangssignal als LOW erkannt (Bit in PIND wird 0). Die Zeitspanne zwischen der Umschaltung von Entladung auf Aufladung und dem Wechsel des Eingangssignals von High auf Low ist ein Maß für den am Potentiometer eingestellten Widerstand. Zur Zeitmessung kann einer der im Controller vorhandenen Timer genutzt werden. Der 220 Ohm Widerstand dient dem Schutz des Controllers. Es würde sonst bei Maximaleinstellung des Potentionmeters (hier 0 Ohm) ein zu hoher Strom fließen, der die Ausgangsstufe des Controllers zerstört.

Mit einem weiteren Eingangspin und ein wenig Software können wir auch eine Kalibrierung realisieren, um den Messwert in einen vernünftigen Bereich (z.B: 0...100 % oder so) umzurechnen.


 


 

 
  Heute waren schon 1 Besucher (20 Hits) hier!  
 
Diese Webseite wurde kostenlos mit Homepage-Baukasten.de erstellt. Willst du auch eine eigene Webseite?
Gratis anmelden