Pfad:
Home =>
AVR-DE =>
Anwendungen =>
Zufall tn13 > Zufallszahlen anzeigen
This page in english:
 |
AVR-Anwendungen
Zufallszahlen mit ATtiny13
Anwendung und Software für Zufallszahlen in Assembler |
Zufallszahlen mit ATtiny13
Natürlich ist das reine Simulieren nicht so arg prickelnd, es muss auch
etwas Farbe in die Würfelei. Hier werden auf einer RGB-LED Zahlen zwischen
0 und 255*255*255 = 16.711.680 verschiedene Farben angezeigt. Das Ein- und
Ausschalten der drei LEDs erfolgt mit drei Pulsweiten-Generatoren, die in einem
ATtiny13(A) werkeln.
2.1 Hardware
Die RGB-LEDs sind an den Portausgängen PB0 (rot), PB1 (grün) und PB2
(blau) angeschlossen. Der Strom durch die LEDs wird von drei Widerständen
kontrolliert, deren Größe an die unterschiedlichen Durchlassspannungen
der LEDs angepasst sind. Sie sind für einen Strom von ca. 20 mA pro
LED ausgelegt.
Die eingezeichneten Widerstandswerte erwiesen sich bei einer zweiten Liefercharge
RGB-LEDs als zu klein. Sie mussten auf 100 Ω, 47 Ω und
56 Ω vergrössert werden, um bei ca. 20 mA zu landen. Am
Besten vorher ausprobieren: Die Spannungen an den Portausgängen dabei
entweder
- mit zwei Schottkydioden nachbilden, oder
- die Spannung auf 4,6 V einstellen, oder
- die Spannung aus drei AA- oder AAA-Batterien beziehen.
Wer keine RGB-LEDs mit gemeinsamer Anode, sondern welche mit gemeinsamer
Kathode verwenden will, kann das ganz leicht ändern:
- Die Kathode mit GND verbinden statt mit VCC, und
- die drei Bits PB0, PB1 und PB2 im PORT-Register zu Beginn des Programms
auf Eins setzen.
Zur Einstellung der Geschwindigkeit, mit der die nächste Farbe angezeigt
wird, ist am Eingang ADC3 ein Poti von 10 kΩ angeschlossen. Der
Vorwiderstand von 33 kΩ setzt die Einstellspannung von 5 V auf
1,1 V herab, da der AD-Wandler per Software auf die intern erzeugte
Referenzspannung eingestellt ist.
An den Eingang ADC2 kann ein Rauschgenerator angeschlossen werden. Dieser sollte
maximal 1 Vpp Rauschspannung liefern. Der Eingang sollte, wenn
kein Rauschgenerator angeschlossen ist, auf GND (Null Volt) gezogen werden.
Die Schaltung hat noch einen ISP6-Stecker, mit dem der ATtiny13 programmiert
werden kann und aus dem auch die 5V-Versorgung bezogen werden kann.
So sieht die Schaltung mit der RGB-LED, dem ATtiny13 und dem Rauschgenerator
(siehe Rauschgenerator) auf dem Steckbrett
aus.
Zwei kurze Videos,
mit schneller Einstellung hier
und mit langsamer Einstellung hier.
Falls der Browser die Videos nicht direkt abspielt, die Videos herunterladen und mit dem
Lieblings-Videoabspieler des Betriebssystems öffnen.
2.2 Programm des ATtiny13
Dies hier beschreibt, wie das Programm funktioniert. Wer es einfach nur downloaden
möchte, findet es in Assemblerformat hier,
im Browser angezeigt gibt es das hier.
2.2.1 Einstellungen im Programm
Um möglichst viele Anwendungsfälle abzudecken, ist das Programm sehr
vielfältig einstellbar. Dazu müssen im Kopf der Assemblerdatei ein
paar Zeilen geändert werden. Mit den drei Schaltern swCalcOnly,
swNoiseOnly und swMixed lässt sich die Zufallsquelle
auswählen, nur eine der drei Möglichkeiten darf mit 1 eingeschaltet
sein. swMixed erzeugt 15 Zufallszahlen per Rechnung und setzt dann die
beiden Seeds aus dem externen Rauschgenerator.
In der Sektion Adjustable Const weiter unten im Quellcode kann man noch
ein paar Hardware-Einstellungen vornehmen. So bestimmt cLedLong die
Verzögerungszeit bis zur nächsten Zufallszahl. PwmFreq stellt
die Frequenz des PWM-Generators für die LED-Anzeige ein. Die Untergrenze
sind 19 Hz, die Obergrenze 146 Hz.
2.2.2 Pulsweitensteuerung
Um die Pulsweitensignale für die LEDs zu erzeugen, arbeitet der Timer TC0
im CTC-Modus: nach 64 Takten des ATtiny13 (bei der Default-Taktfrequenz
von 1,2 MHz) setzt der Zähler zurück auf Null und unterbricht mit
dem Compare-A-Interrupt die Programmausführung. Das ist alle 64 / 1,2 =
53,3 µs der Fall. Mit jedem dieser Unterbrechungen wird geprüft,
ob der Rot-Wert in rRed, der Grün-Wert in rGreen und der
Blau-Wert in rBlue erreicht ist: die entsprechenden Bits werden dann
ausgeschaltet, die LED leuchtet nur so viele Zyklenschritte lang, wie es der
Vergleichswert angibt. Nach 256 Schritten = 256 * 53,3 µs =
13,65 ms, beginnt der PWM-Zyklus wieder von vorne, was eine Wiederholfrequenz
von 73,24 Hz ergibt.
Damit das Schalten der LEDs immer zum gleichen Zeitpunkt erfolgt, egal wie lange
Vergleiche und Neustart benötigen, wird der Zustand der LEDs in einem
Arbeitsregister rWork immer zu Beginn der CTC-ISR ausgegeben. In diesem
Register erfolgt auch das Löschen der Farbbits, wenn Gleichheit mit rPwm
erreicht ist.
In der Interrupt-Service-Routine des Interrupts zählt ein Register rPwm
nach oben, von 0 bis 255. Ist rPwm nicht Null, erfolgt der Vergleich von
rPwm mit den zufallsgenerierten Vergleichswerten von rot in rRed,
von grün in rGreen und vo blau in rlue. Ist der Vergleichswert
erreicht, wird das entsprechende Bit im Register rWork rot, grün bzw.
blau ausgeschaltet.
Ist beim Erhöhen von rPwm dieser auf Null übergelaufen, beginnt
ein neuer PWM-Zyklus. Ein 16-Bit-Zähler in rCntH:rCntL = R25:R24 wird
abwärts gezählt. Der Startwert dieses Zählers gibt an, mit welcher
Geschwindigkeit eine neue Farbe eingestellt wird. Er wird durch Multiplikation
des Potentiometerwertes mit einer Konstanten ermittelt. Solange dieser Zähler
nicht Null ist, wird ein weiterer PWM-Zyklus gestartet, indem das Arbeitsregister
rWork mit dem Startregister rStart überschrieben wird.
Ist der 16-Bit-Zähler Null geworden, entscheidet die Voreinstellung, ob neue
Zufallszahlen nur aus der berechneten Reihe verwendet werden (Option
swCalcOnly) oder ob ausschließlich die vom externen Rauschgenerator
erzeugten Zahlen genommen werden (Option swNoiseOnly) oder ob beides
gemischt wird. Beide Programmteile laufen auf die gleiche Routine zu: die Bildung
von rStart. Im Register rStart werden die drei Farbbits auf Eins
gesetzt, wenn der Farbwert größer als Null ist. Ist das nicht der Fall,
wird die LED zu Beginn des PWM-Zyklusses gar nicht erst eingeschaltet (da sie sonst
niemals auch wieder ausgeschaltet werden würde, denn rPwm = 0 wird beim
Farbvergleich gar nicht geprüft.
Nach Erstellung von rStart wird das Arbeitsregister rWork mit dem
Inhalt von rStart überschrieben, was auch bei jedem Neustart des
PWM-Zyklusses so passiert. Nach Wiederherstellen von SREG ist die ISR mit RETI
zu Ende. Die eigentliche Ausgabe von rWork an die LED-Pins erfolgt zu
Beginn des nachfolgenden CTC-Interrupts.
Da jede Einzelstufe des PWM-Zyklusses nach 64 / 1,2 MHz = 53,33 µs
erfolgt und 256 dieser Stufen aufeinander folgen, dauert ein ganzer PWM-Zyklus
13,65 ms. Das entspricht einer Wiederholfrequenz von 73,24 Hz und ist
schnell genug für das menschliche Auge.
Es ist daher auch sicherzustellen, dass keine der ISR-Verzweigungen länger
als 64 Takte dauert. Wie an den Taktzyklen im Fließdiagramm zu erkennen,
ist dies auch nicht der Fall.
2.2.3 Zufallszahlen
Sind alle Ausgabezyklen durchlaufen und rCntH:rCntL wird Null, dann werden
nach dem in Kapitel 1 beschriebenen
Algorithmus (oder auch nach dem in Kapitel 3
beschriebenen Rauschgenerator) drei neue Zufallszahlen generiert und letztlich in
die Register rRed, rGreen und rBlue geschrieben. Da die
Entscheidung, ob berechnete oder mit dem Rauschgenerator erzeugte Zufallszahlen
angezeigt werden, schon beim Assemblieren erfolgt, benötigt diese Entscheidung
keinen Prozessortakt.
2.2.4 ADC-Wandlung und -auswertung
Der AD-Wandler muss zwei Signale messen:
- die Einstellung des Geschwindigkeitspotenziometers, und
- eintreffende Signale am Rauschgenerator-Eingang.
Er wird dazu beim Init der Hardware einmalig gestartet. Dazu wird die MUX auf
ADC3 eingestellt und die interne Referenzspannung von 1,1 V eingeschaltet.
Die Einstellung auf 1,1 V stellt sicher, dass auch schwache Rauschsignale
zu einer Aussteuerung des ADC führen. Verwendet man einen Sinusgenerator,
wie er in Kapitel 4 beschrieben ist,
muss man entweder
- die Amplitude mit einem Spannungsteiler auf 1,1 V herabteilen, oder
- die 5 V als Referenzspannung einstellen, wozu die Konstante
cNoiseHigh in den Adjustable Const auf Eins gesetzt wird.
Allerdings muss dann auch der Vorwiderstand vor dem Poti entfallen oder die
LED-Zeit ist zu verfünffachen.
Die weitere AD-Wandlung erfolgt interruptgesteuert. Immer, wenn ein Messwert
vorliegt, wird dazu die Flagge bAdc gesetzt. Die dazugehörende ISR
ist daher sehr kurz und stört die PWM-Ausgabe nicht. Die Auswertung der
Flagge erfolgt nämlich außerhalb der ISR.
Welcher der beiden AD-Werte vorliegt, geht aus dem Zustand des MUX-Portregisters
hervor, das zu Beginn gelesen wird.
2.2.5 Die Geschwindigkeitseinstellung
Wurde das Potenziometer gemessen, dann wird der 10-Bit-ADC-Wert invertiert
(höhere Spannungen = schnellere Ausgabe = kürzere PWM-Zyklen-Zählung).
Die Invertierung erfolgt, indem der AD-Wandler-Wert von 0x0400 abgezogen wird.
Um unabhängig von dem eingestellten Timing (clock, CTC-Teiler, etc.) zu
werden, wird der invertierte Wert dann mit einer Konstanten multipliziert. Die
Konstante cMultiplier gibt an, mit welchem Wert der invertierte AD-Wert
zu multiplizieren ist, um bei einem invertierten AD-Wandler-Wert von 1023
(linker Anschlag des Potis, ADC = 0) die Anzahl an PWM-Wiederhol-Zyklen so
einzustellen, dass die in der Einstellkonstanten cLedLong vorgegebene
Zeit erreicht wird.
.equ cLedLong = 100 ; Longest delay in tens of ms
Die Multiplikationskonstante cMultiplier
.equ cMultiplier = (((cLedLong*clock/(cCtcCmpA+1))+512)/1024)/100
ergibt sich bei einer Sekunde zu 18 (1023 * 18 = 18.414, bei 10 Sekunden
zu 183 und bei 100 Sekunden zu 1.831. Diese Konstante enthält den
Faktor 256, so dass nach dem Multiplizieren das unterste Byte gestrichen
werden muss.
Die Multiplikation des invertierten AD-Wertes (10 Bits) mit diesem Wert
(maximal 16 Bits) erfordert ziemlich viele Register. Der invertierte AD-Wert
wird in die vier Register R3:R2:R1:R0 geschrieben (die oberen beiden Register
sind zu Beginn der Multiplikation Null). In das Registerpaar XH:XL kommt zu
Beginn der 16-Bit-Multiplikatorwert.
Die Register ZH:ZL:YH:YL nehmen das 32-Bit-Ergebnis auf. Die obersten acht
Bit in ZH müssen dabei Null sein. Sind sie das nicht, wird das Ergebnis
auf 0xFFFF eingestellt. Die untersten 8 Bits in YL werden zum Aufrunden des
Ergebnisses in ZL:YH verwendet. Damit das Ergebnis nicht Null werden kann,
wird noch eine Eins addiert.
Die Multiplikation von 1024 mit 18 liefert 18.432, geteilt durch 256 ergibt
72 und 72 PWM-Zyklen zu je 13,65 ms dauert 0,983 Sekunden. Maximal
können auf diese Weise 65.535 * 0,01365 = 894 Sekunden =
14,9 Minuten eingestellt werden.
2.2.6 Zufallszahlen vom Rauschgenerator
War die MUX auf der ADC2-Position und ist das Ergebnis weder Null noch
Vollausschlag, dann wird das unterste Bit des AD-Wandlers in die Carry-Flagge
geschoben und von rechts her in die Register rRnd3:rRnd2:rRnd1
eingerollt. Da der AD-Wandler mit einem Vorteiler von 128 arbeitet, für die
Wandlung 14 Takte benötigt und zwei Kanäle im Wechsel gemessen werden,
liegt alle 128 * 14 * 2 / 1.200.000 = 3 ms ein neues Bit vor. Alle 24 Bits
eines Sets benötigen 72 ms. Das ist auch bei schnellem Wechsel der
Zahlen ausreichend schnell, zumal der Inhalt bei unvollständigem Linksrotieren
aller 24 Bits ja ohnehin schon genug Zufall ist.
Ist die Option swMixed gewählt, wird noch zusätzlich geprüft,
ob der Zähler rRndC auf Null ist. Dieser wird bei jeder Neuberechnung
einer Zufallszahl in der PWM-Interrupt-Routine abwärts gezählt. Hat er
Null erreicht, werden die beiden Zufallszahlen aus dem Rauschgenerator als neue
Basiszahlen genommen. Der Zähler wird dann auf 15 (Einstellung mit
cRndCount) gesetzt. Die 15 wurde deshalb gewählt, weil die
Zykluslänge von beliebigen Startkombinationen immer länger als 25 ist
(siehe Kapitel 1).
Bei Beendigung beider Zweige wird der AD-Wandler mit dem jeweils anderen Kanal neu
gestartet.
Der Schlafanteil des Programms liegt bei bei allen hier dargestellten
Default-Einstellungen bei ca. 65%, bedingt durch die häufigen
PWM-Schritt-Unterbrechungen. Erhöhung der PWM-Frequenz senkt den Schlafanteil
stark ab, was bei Batteriebetrieb eine wichtige Rolle spielt. Allerdings ist der
Stromanteil der RGB-LED ohnehin viel h&aouml;her (max. 60 mA), sodass der
Prozessorstrom nicht so arg viel beiträgt (max. 2 mA).
Lob, Tadel, Fehlermeldungen, Genöle und Geschimpfe oder Spam bitte über
das Kommentarformular an mich.
©2020 by http://www.avr-asm-tutorial.net