Pfad: Home => AVR-Übersicht => PWM-ADC
ADC8 Tutorial für das Erlernen der Assemblersprache von
AVR-Einchip-Prozessoren AT90Sxxxx
von ATMEL anhand geeigneter praktischer Beispiele.
Einfacher 8-Bit-Analog-Digital-Wandler mit PWM auf dem STK board

Aufgabe

Mit Hilfe der Analogeingänge AIN0 und AIN1 läßt sich ohne größeren zusätzlichen Aufwand an Hardware ein einfacher Analog-Digital-Wandler erstellen. Der Analogvergleicher wird dabei benutzt, um eine mit dem Timer/Counter 1 (TC1) erzeugte Vergleichsspannung mit der Eingangsspannung zu vergleichen und diese so lange nachzujustieren, bis das Ergebnis auf 8 Bit genau feststeht. TC1 arbeitet dabei als Pulsweitenmodulator (PWM), das Tastverhältnis bestimmt die Ausgangsspannung.
Das Ergebnis der Wandlung wird auf den LEDs des STK500-Boards ausgegeben.

Erforderliche Hardware

Hardware of the 8-bit-ADC Das Bild links zeigt die gesamte Testhardware zum Anschluss an das STK500-Board. Die Portanschlüsse sind von oben gezeichnet.
Die Messspannung von 0,00 bis 5,00 Volt wird mit dem 10k-Poti aus der Betriebsspannung des Boards erzeugt und mit einem Kondensator gefiltert. Sie wird an den Eingang des Analogkomparators AIN0 (entspricht beim AT90S8515 dem Port PB2) gelegt.
Die Vergleichsspannung wird aus dem PWM-Ausgang OC1A (entspricht beim AT90S8515 dem Port PD5) erzeugt und über drei RC-Filter mit 10k/100n an den analogen Vergleichseingang AIN1 (entspricht beim AT90S8515 dem Port PB3) geführt. Das ist schon alles.

ADC8-Connections Noch ein paar Hinweise zum Testaufbau am STK500. Das RC-Filter und das Teststpannungspoti passen auf ein kleines Lochplatinchen. Der Anschluss an das Board kann mit den beim STK500 mitgelieferten zweipoligen Anschlusskabeln vorgenommen werden, wenn man entsprechende Pfostenstecker auf der Lochplatine vorsieht. Nicht vergessen, dass die LEDs in dieser Schaltung leider an Port C angeschlossen werden müssen, weil Port B für die Analogeingänge gebraucht wird. Deshalb ist auch die Schaltung und die Software für das STK200 nicht geeignet (feste Verdrahtung der LEDs an Port B). Nach Abschluss der Arbeiten nicht vergessen, die LEDs über das Parallelkabel wieder an Port B anzuschließen, wo sie standardmäßig hingehören.
An den Anfang dieser Seite

Funktionsweise

Erzeugung der Vergleichsspannung mit Pulsweitenmodulation

Ein Pulsweitenmodulator erzeugt ein Rechtecksignal mit einer festgelegten Pulsweite. Der Modulator erzeugt ein 1-Signal für eine bestimmte Zeit lang, der Rest der Zeit ist der Ausgang auf Null. Filtert man diese Rechteckspannung, dann kann man über die Pulsweite eine Analogspannung erzeugen. Stellt man ein Impuls-/Pausen- Verhältnis von 50% ein, dann ergibt sich am Ausgang des Filters die halbe Betriebsspannung, entsprechend bei 25% ein Viertel, etc.
Simulation Die Lade- und Entladeverhältnisse an den RC-Filtern zeigt vereinfacht die Grafik. Die Rechteckspannung U(PWM) bildet sich noch deutlich auf der Spannung am Kondensator C1 ab. Die Glättung am Kondensator C2 ist sehr deutlich zu erkennen. Allerdings ist das Nachlaufen zu Beginn des Einschwingvorganges auch deutlich zu erkennen. Noch deutlicher ist dieses Nachlaufen am Kondensator C3 zu sehen.
Weil sich auch im eingeschwungenen Zustand noch Lade- und Entladevorgänge auf das Ausgangssignal auswirken, muss das Filter so dimensioniert sein, dass diese Restwelligkeit niedriger ist als das Auflösungsvermögen des AD-Wandlers. Bei 8 Bit Auflösung und 5,0 Volt Betriebsspannung muss die Restwelligkeit deutlich unter 5/256 = 19,5 mV liegen. Vergrößerung der Widerstände und Kondensatoren des RC-Filters oder das Hinzufügen weiterer RC-Glieder bewirkt eine Verminderung der Restwelligkeit.
Allerdings wird dadurch die Zeit, die der PWM-Modulator bis zum Einstellen der Analogspannung benötigt, ebenfalls länger. Daher ist ein PWM-basierter ADC nicht sehr schnell (im vorliegenden Fall maximal etwa 5 Messungen pro Sekunde). In der Praxis wird man einen Kompromiss zwischen Einschwingzeit und Restwelligkeit schließen. Die Einschwingzeit wird durch die Anzahl PWM-Zyklen gewählt, die der AVR abwartet, bevor er den Analogvergleich am Port abliest. Sie ist daher durch Software einstellbar. Im vorliegenden Fall wurden dafür 128 Zyklen gewählt, was für eine stabile Einschwingzeit bei der vorliegenden Dimensionierung völlig ausreicht. Ohne Softwareänderung sind bis zu 65536 Zyklen möglich.
Für die Dimensionierung des RC wurde ein kleines Pascal-Programm entwickelt, das die Vorgänge beim PWM simuliert und die Ermittlung der Restwelligkeit und Einschwingzeit ermöglicht. Es läuft auf der Kommandozeile. Der Quellcode avr_pwm1.pas kann auf jedem gängigen Pascal-Compiler zu einem lauffähigen Programm kompiliert werden.
Die Frequenz, mit der der PWM arbeitet, ergibt sich bei 8-Bit-Auflösung zu

f (PWM) = Taktfrequenz / 510 (9 Bit: 1022, 10 Bit: 2046)


Bei einer Taktfrequenz von 3,685 MHz auf dem STK500 Board ergeben sich krumme 7.225,5 Hz PWM-Frequenz oder 138,4 Mikrosekunden pro PWM-Zyklus. Bei 128 Zyklen pro Bit ergeben sich Umwandlungszeiten von 142 Millisekunden pro Messung oder 7 Messungen pro Sekunde. Nicht sehr schnell, aber immer noch schneller als das menschliche Auge.

Referenzspannung dieser Schaltung ist die Betriebsspannung des Prozessors. Diese kann eventuell mit dem Studio im STK500 verstellt werden. Die Genauigkeit des PWM-Signals ist im untersten Bereich (0,00 bis 0,10 V), aber mehr noch im oberen Spannungsbereich nicht sehr genau, weil die MOS-Ausgangstreiber nicht ganz bis an die obere Betriebsspannung herankommen. Das bedingt im mittleren Bereich zwar auch schon Ungenauigkeiten, wirkt sich aber in diesen Extrembereichen in Nichtlinearität aus. Es hat deshalb auch keinen großen Sinn, 9 oder 10 Bits Auflösung anzustreben. Wer es genauer haben möchte, greift zu einem Prozessor mit eingebauten AD-Wandlern.

An den Anfang dieser Seite

Methode der sukzessiven Approximation

Zum Messen der Eingangsspannung könnte man schrittweise die Pulsweite erhöhen und jeweils prüfen, ob die Spannung am Vergleichseingang schon größer ist als die Eingangsspannung. Das erfordert bei 8 Bit Genauigkeit aber schon 255 Einzelschritte, bei 10 Bit Genauigkeit stolze 1023 Schritte.
Als Wandelmethode wird deshalb die sukzessive Approximation verwendet. Im ersten Schritt wird die Vergleichsspannung auf die halbe Betriebsspannung eingestellt und festgestellt, ob die Messspannung darüber oder darunter liegt. Liegt sie darunter, wird die Vergleichsspannung im nächsten Schritt auf ein Viertel eingestellt, liegt sie darüber, dann auf dreiviertel. Diese Schritte setzt man so lange fort, bis man die Messspannung mit der nötigen Genauigkeit festgestellt hat. Bei 8 Bit Genauigkeit sind demnach acht Schritte, bei 10 Bit zehn Schritte nötig. Das ist um den Faktor 30 (8 Bit) bzw. 100 schneller als die Methode mit der schrittweisen Erhöhung der Vergleichsspannung.
Das Verfahren lässt sich leicht per Software umsetzen. Die ersten fünf Schritte sind für eine 8-Bit-Wandlung in der Tabelle angegeben. Angegeben ist die Vergleichsspannung beim n-ten Schritt und die korrespondierende binäre Ausgabe an den 8-Bit-PWM. Ist die Vergleichsspannung größer als die Messspannung, geht es beim oberen Kasten weiter. Umgekehrt beim unteren Kasten.
1
1000.0000
2
0100.0000
3
0010.0000
4
0001.0000
5
0000.1000
U=2,5V
1000.0000
U=1,25V
0100.0000
U=0,625V
0010.0000
U=0,3125V
0001.0000
U=0,15625V
0000.1000
U=0,46875V
0001.1000
U=0,9375V
0011.0000
U=0,78125V
0010.1000
U=1,09375V
0011.1000
U=1,875V
0110.0000
U=1,5625V
0101.0000
U=1,40625V
0100.1000
U=1,71875V
0101.1000
U=2,1875V
0111.0000
U=2,03125V
0110.1000
U=2,34375V
0111.1000
U=3,75V
1100.0000
U=3,125V
1010.0000
U=2,8125V
1001.0000
U=2,65625V
1000.1000
U=2,96875V
1001.1000
U=3,4375V
1011.0000
U=3,28125V
1010.1000
U=3,59375V
1011.1000
U=4,375V
1110.0000
U=4,0625V
1101.0000
U=3,90625V
1100.1000
U=4,21875V
1101.1000
U=4,6875V
1111.0000
U=4,53125V
1110.1000
U=4,84375V
1111.1000
Das Muster ist leicht erkennbar: Zu Beginn jedes Schrittes ist das entsprechende Bit auf 1 zu setzen. Ist das zuviel an Spannung, wird es beim nächsten Schritt wieder auf Null gesetzt. Ideal einfach zu programmieren!

Software

Die Software ist in HTML-Form als adc8.html und als ASM-Quellcode-Datei adc8.asm zugänglich.

Das Programm besteht aus sehr langen Wartezeiträmen, die der PWM braucht, bis sich die erzeugte Spannung stabilisiert hat. Das ist ideal für den Einsatz von Interrupts, da wir sonst komplizierte und vom Timing her ausgeklügelte Verzögerungsschleifen programmieren müssten. Weil der TC1 sowieso mit nichts anderem befasst ist als mit dem Hoch- und Runterzählen des PWM, kann er das gesamte Timing der Messung mit übernehmen. Der Prozessor selbst ruht die meiste Zeit im Schlafmodus und wird alle 142 Mikrosekunden durch den PWM-Interrupt aufgeweckt. Nach der Feststellung, dass die Fertig- Flagge nicht gesetzt ist, kann er weiter ruhen. Ist er fertig, muss das Ergebnis auf den Port und die Flagge wieder gelöscht werden.

An den Anfang dieser Seite

Hauptprogramm

Das Hauptprogramm durchläuft folgende Schritte:
  1. Der Stapel wird eingerichtet. Das ist nötig, weil das Programm über Interrupts des Timers gesteuert abläuft. Interrupts brauchen immer den Stapel, um die Rücksprungadresse dort ablegen zu können. Der Stapel wird auf dem obersten internen SRAM angelegt.
  2. Der Zyklenzähler wird gesetzt. Er bestimmt, nach wievielen Zyklen des PWM der Vergleich zwischen der erzeugten PWM-Analogspannung mit dem analogen Eingangssignal erfolgt. Im Beispiel sind das 128 Zyklen. Es ist durch Ändern der Konstanten CycLen0 einstellbar (z.B. um zu erreichen, dass jede Sekunde eine Messung beginnt).
  3. Der Bitzähler rBlc wird zu Beginn auf 0x80 gesetzt. Das entspricht der halben Betriebsspannung als Vergleichsspannung. Das Messergebnis in rTmp wird zu Beginn ebenfalls auf diesen Wert gesetzt.
  4. Die Portausgänge von Port C zum Treiben der Leuchtdioden werden als Ausgänge geschaltet.
  5. Das Portbit PD5 von Port D ist als Ausgang einzustellen, damit das PWM-Ausgangssignal außen am Portpin ausgegeben werden kann.
  6. Der Schlafmodus Idle muss eingestellt werden, damit die CPU auf die SLEEP-Instruction reagiert und beim Interrupt des TC1 wieder korrekt aufwacht.
  7. Timer/Counter 1 wird als 8-bit-PWM eingestellt und bezieht seinen Zähltakt direkt aus dem CPU-Takt (möglichst große PWM-Frequenz).
  8. Die PWM-Pulsweite wird auf 50% (0x0080) eingestellt.
  9. Im Timer Int Mask Register wird der Overflow-Interrupt ermöglicht, damit TC1 nach jedem PWM-Zyklus einen Interrupt auslöst.
  10. Die Annahme von Interruptanforderungen durch die CPU wird ermöglicht.
Ab jetzt beginnt die Schleife, die nach jedem Aufwecken durch TC1 durchlaufen wird. Nachdem der Interrupt bearbeitet ist, wird die Ready-Flagge befragt, ob der ADC-Vorgang schon durchlaufen und der gemessene Wert gültig ist. Ist das der Fall, wird die Flagge wieder gelöscht, der gemessene Wert bitweise invertiert und an die Leuchtdioden ausgegeben. Dann versinkt die CPU wieder in den Schlaf, bis ein neuer Messvorgang beendet ist und die Flagge nach dem Wecken gesetzt ist.

Interruptsteuerung

Zentrales Herzstück des AD-Wandlers ist der Pulsweitenmodulator mit dem Timer/Counter TC1. Immer wenn TC1 einen PWM-Zyklus vollendet hat, wird der Overflow-Interrupt ausgelöst, der Programmzähler auf den Stapel abgelegt und der Programmablauf zur Interruptroutine verzweigt. Diese Interruptroutine übernimmt selbstständig die gesamte PWM-ADC-Steuerung und teilt dem Hauptprogramm über eine Flagge mit, wann die Umwandlung beendet und das Ergebnis gültig ist. Sie startet nach Ende einer Messung automatisch wieder von vorne. Durch Einstellung der PWM-Zyklusanzahl zu Beginn einer Messung und der Anzahl PWM-Zyklen für die Messung der Einzelbits ergibt sich die Wiederholzeit für die Messungen.
TC1-Overflow-Int-Algorithm Im linken Bild ist der Algorithmus für die gesamte Steuerung des AD-Wandlers abgebildet.
Es beginnt damit, dass der Inhalt des Statusregisters gesichert wird. Vor der Rückkehr vom Interrupt wird dessen Originalinhalt wieder hergestellt.
Im nächsten Schritt wird der Zähler für die PWM-Zyklen um Eins erniedrigt und festgestellt, ob schon genügend PWM-Zyklen durchlaufen sind, dass sich die vom PWM erzeugte und vom RC-Filter geglättete Vergleichsspannung am Analog-Eingang AIN1 stabilisiert hat. Ist der Zykluszähler noch nicht Null, werden weitere Zyklen abgewartet und der Interrupt ist vorerst beendet.
Ist die vorgegebene Anzahl PWM-Zyklen durchlaufen, wird zunächst der PWM-Zykluszähler auf seinen Voreinstellungswert gesetzt. Dann wird der Analog-Komparator-Ausgang abgefragt, ob die Vergleichsspannung an AIN1 größer oder kleiner als die zu messende Spannung am Eingang AIN0 ist. War die Vergleichsspannung zu hoch, wird das zuletzt gesetzte Bit wieder auf Null gesetzt. Wenn nicht, bleibt es auf Eins.
Nun wird der Bitzähler mit dem aktiven Bit um eine Stelle nach rechts geschoben. Dabei wird von links eine Null in Bit 7 des Bitzählers hineingeschoben, nach rechts rutscht Bit 0 des Bitzählers in das Carry-Flag des Statusregisters. Rollt dabei eine Null heraus, dann sind wir noch nicht fertig und müssen uns weiter sukzessiv approximieren.
Rollt bei dem Vorgang eine Eins aus dem Bitzähler heraus, dann sind wir fertig. Das Ergebnis im Temporärregister wird in das Ergebnisregister kopiert, die Fertig-Flagge im Flaggenregister gesetzt, der PWM-Zyklenzähler auf den längeren Anfangswert für den Neuanfang gesetzt, das Temporärregister entleert und der Bitzähler auf 0x80 gesetzt (acht Näherungsschritte).
Schließlich wird das aktive Bit im Bitzähler auf das Temporärregister übertragen (aktives Bit wird auf Eins gesetzt) und das Zwischenergebnis dem PWM mitgeteilt, der damit die Vergleichsspannung am Analogeingang AIN1 füttert.
Am Ende wird nur noch das Statusregister wieder in den Originalzustand versetzt und vom Interrupt zurückgekehrt.
Die gesamte Interruptroutine ist mit maximal 25 Taktzyklen oder etwa 6 Mikrosekunden (bei 4 MHz) sehr kurz. Auch wenn noch andere Tasks laufen, dürfte dies immer zu verkraften sein.

änderungen und Ergänzungen

Für Experimente mit 9- oder 10-Bit-Auflösung müssen die Register rRes, rTmp und rBlc als Zwei-Byte-Worte ausgeführt werden. Bei der Ausgabe über die LEDs muss entschieden werden, welche Bits dargestellt oder nicht dargestellt werden sollen.
Soll das Ergebnis auf einer LCD-Anzeige angezeigt oder über die serielle Schnittstelle des Prozessors an einen Computer in dezimaler Form ausgegeben werden, können die Festkomma-Umrechnungsroutinen in der Rechenabteilung des Anfängerkurses hinzugebaut werden.

An den Anfang dieser Seite

©2003 by http://www.avr-asm-tutorial.net