Hallo alle zusammen,
ich muß mich mal an Euch wenden, da ich im Moment nicht so richtig
weiterkomme:
Ich möchte eine Schleife in Assembler programmieren für den ATMega8, die
Zufallszahlen ausgibt. Als Zufallszahlen werden hier an einem Port
einfach Kombinationen von Low und High ausgegeben, mit denen man dann
die Würfelpunkte durch LED's darstellt.
Das Problem ist, ich bekomme einfach zu viele gleiche Werte
hintereinander.
Das ganze läuft im Moment so ab:
Durch Betätigung eines Tasters läuft eine Schleife an. Der Zählerstand
wird dabei immer beim Start vom Wert 6 aus vermindert bis 0. Diese 0
wird abgefragt und wenn ja, wird der Zählerstand wieder auf 6 gebracht
usw.
Die Schleife läuft solange, bis der Taster wieder losgelassen wird.
Vor Abfrage des Tasters wird natürlich der Ausgabewert (momentaner Wert
der Schleife) in ein Register geladen. Das alles funktioniert ja auch.
Nun sollte man meinen, mit einer Taktfrequenz von 4 MHz wird die
Schleife immer irgendwo zufällig verlassen. Das scheint aber nicht so.
Woran könnte denn das liegen?
In einem Buch von G. Schmitt war die Konzeption so, daß die Schleife
immer läuft, und ich mit dem Tastendruck dann irgendwo abbreche.
In meiner Konstruktion ist es ja so, daß ich mit dem Tastendruck erst
die Schleife anlaufen lasse, gewöhnlich eine Zeit da auf dem Taster
bleibe und dann mit dem loslassen des Tasters den Wert erhalte.
Wie seht Ihr das?
Ja, die Taste muss unbedingt entprellt werden, sonst stoppt die
Schleife von Dir unbemerkt schon nach z. B. 1 ms (Zeitpunkt des ersten
Prellers) und Deine Zufallszahlen sind Murks.
Ansonsten hier mal ein paar "echte" Zufallszahlen von 1 bis 6. Wenn Du
die studierst, wirst Du feststellen, dass das zwei- oder dreimalige
Aufeinanderfolgen desselben Werts durcaus nicht so selten vorkommt, wie
man vielleicht vermuten würde. Vielleicht hilft Dir das, den Output
Deines Programms besser beurteilen zu können (ist er am Ende doch
korrekt?)
451466531525614326266421664161546646615132532534465441252221
552466662315233363352453151635334525126613511365521652422314
324642256522521164614636244452445252254323425665225352462241
144241216155423263223546563411454435226244423221442246642141
163411261356351244136563254521245514366342425412534654435442
111123631342616221524146511525622544315641654144662256133353
323456144646526166546634635163363631361661264531356542255152
261165555321364544222323631324331246265221221156131131655223
634566336352641454563513551521655425166612655265635221251131
122535234425523121411664336556546441562125266321126465311652
311413124655355243222261564253124644465151455236532162423263
235156621255135415363461324134452446254142253261321361544654
311431451241141355633635662641131426525131216142636122266655
366464313652233165545453216646465144611126425524611236452623
414123353426511514336514465211153311216432442462244241414412
144666526421365156554245432462153353514455632662126226526316
Ich hab eine Tüte mit Konfetti (gut, dass gerade Fasching iss) in sechs
verschiedenen Farben genommen, mit Schwung in die Luft geworfen (bis
hierhin wars noch einfach), die Fitzelchen anschließend mit verbundenen
Augen auf dem Boden in eine Reihe gelegt (stöhn), und dann in den
Rechner getippt: rot = 1, gelb = 2... (ächz)
Zufrieden? ;-)
Und trotzdem hab ich noch "echte" in Anführungszeichen gesetzt... lach
Uups, noch was vergessen:
1. Ein oder mehrere Byte's der Zufallszahl mit 6 malnehmen.
Vom Ergebnis nur das obere Byte behalten.
INC Oberes_Byte und wir haben eine Zufallszahl von 1 bis 6
2. Das Zufallszahlenprogramm liefert natürlich immer die selbe
Zahlenfolge, die aber (2^32) - 1 lang ist. Jemand mit sehr gutem
Gedächnis könnte die Zahlenfolge auswendig lernen und beim Würfeln
schummeln.
Deshalb den Würfel so bauen, das der Zufallszahlengenerator frei läuft
und manuell durch Tastendruck gestoppt werden muss.
>1. Ein oder mehrere Byte's der Zufallszahl mit 6 malnehmen.>Vom Ergebnis nur das obere Byte behalten.>INC Oberes_Byte und wir haben eine Zufallszahl von 1 bis 6
Eben so sollte man es lieber nicht machen. Jemand, der Deinen Würfel
einem Härtetest unterziehen würde (10000 Runs über Nacht sind kein
Problem, wenn man den Taster mit einem PC-gesteuerten Relais
überbrückt), würde nämlich feststellen, dass er gezinkt ist. Denn die
Würfelzahlen 3 und 6 erscheinen mit der Wahrscheinlichkeit 1/256 weniger
oft als die 1, 2, 4 und 5 (bei Auswertung eines Zufallszahlen-Bytes).
Den Grund dafür kannst Du Dir selbst überlegen. Was würdest Du auf den
Vorwurf, dass der Output Deines Würfelsimulators nicht gleichverteilt
ist, antworten?
>2. Das Zufallszahlenprogramm liefert natürlich immer die selbe>Zahlenfolge, die aber (2^32) - 1 lang ist. Jemand mit sehr gutem>Gedächnis könnte die Zahlenfolge auswendig lernen und beim Würfeln>schummeln.
So ist es.
>Deshalb den Würfel so bauen, das der Zufallszahlengenerator frei läuft>und manuell durch Tastendruck gestoppt werden muss.
lach... na klar... fragt sich nur, warum es dann nicht auch eine simple
Schleife 1, 2, 3, 4, 5, 6, 1, 2, 3, 4, 5, 6, 1, 2, 3... genauso tut, wie
von cody realisiert? Damit läßt sich die Gleichverteilung auch sehr
leicht erreichen.
>>Deshalb den Würfel so bauen, das der Zufallszahlengenerator frei läuft>>und manuell durch Tastendruck gestoppt werden muss.>> lach... na klar... fragt sich nur, warum es dann nicht auch eine simple> Schleife 1, 2, 3, 4, 5, 6, 1, 2, 3, 4, 5, 6, 1, 2, 3... genauso tut, wie> von cody realisiert? Damit läßt sich die Gleichverteilung auch sehr> leicht erreichen.
Klar ist eine Pseudozufallszahlengeneration (theoretisch) sicherer, aber
mal ehrlich: Angenommen der Zufallszahlengenerator läuft mit 1MHz, dann
müsste man auf die Mikrosekunde genau drücken, damit man gewollt eine
bestimme Zahl herbei führt. Für nen lockeren Spieleabend dürfte das
reichen, meine ich.
Klar, für eine Spielhalle müsste man einiges an Vorschriften und
Sicherheitsrichtilinien beachten wie starke Pseudozufallsgeneration,
Schutz gegen erneutes Drücken, etc.
Gruß
Christian
PS.: Ich hätte die aufgabe spontan mit einem NE555er und nem Zähler
gelöst...
Obwohl es ja schon fast billiger ist nen Tiny zu benutzen statt den
ganzen BCD->7-Segment Encodern ^^
@cody
Mit mehr Informationen bräuchte ich meine Kristallkugel nicht zu
bemühen. Welche Zahl kommt denn häufiger? War es die 6? Wie groß war die
Stichprobe?
Da du bei 0 wieder zurück auf 6 gehst, verbringt der µC vergleichsweise
viel Zeit bei der Abarbeitung dieser Bedingung. Die Wahrscheinlichkeit
des Abbruchs vor (und damit bei) einer 6 ist also deutlich höher als bei
den anderen Zahlen. Du müsstest die Schleife so programmieren, dass
diese Zeit für alle Zahlen gleich ist (oder einen Hardware-Timer
bemühen)
Wenn du den "Würfel" dort weiter laufen lässt wo er das letzte mal
angehalten hat macht sogar das Prellen des Tasters nichts mahr aus.
Detlev T.'s gedanke ist auch sehr gut und muss auch beachtet werden.
>Angenommen der Zufallszahlengenerator läuft mit 1MHz, dann>müsste man auf die Mikrosekunde genau drücken, damit man gewollt eine>bestimme Zahl herbei führt.
Richtig, das gezielte Erwirken einer bestimmten Zahl ist durch das
rasend schnelle Durchlaufen der Schleife ausgeschlossen. Damit ist aber
noch nicht die Gleichverteilung der Zahlen 1 bis 6 garantiert. Um
diese zu erreichen, muss man sogar höllisch aufpassen - sonst bekommt
man einen Würfel, bei dem manche Zahlen öfter erscheinen als andere.
Man könnte z. B. auf die Idee kommen, statt nach dem Schema "1...6,
1...6, 1..." ein Register einfach "0...255, 0...255, 0..." zählen zu
lassen, und nach dem Loslassen der Taste seinen Wert modulo 6 zu nehmen
(plus Addition von 1). Das Ergebnis? Die 1, 2, 3 und 4 würden etwas
häufiger auftreten als die 5 und 6!
>Da du bei 0 wieder zurück auf 6 gehst, verbringt der µC vergleichsweise>viel Zeit bei der Abarbeitung dieser Bedingung. Die Wahrscheinlichkeit>des Abbruchs vor (und damit bei) einer 6 ist also deutlich höher als bei>den anderen Zahlen. Du müsstest die Schleife so programmieren, dass>diese Zeit für alle Zahlen gleich ist (oder einen Hardware-Timer>bemühen)
Exakt. Dem muss unbedingt Rechnung getragen werden. Übrigens sollte
man den Ausbruch aus der Schleife auch blos nicht mit Interrupts (z. B.
Taste an INT0 mit Flankenerkennung) realisieren. Da die Abarbeitung der
Instruktionen unterschiedlich lange dauert (z. B. 'inc' 1 Taktzyklus,
'rjmp' aber 2), ein Sprung zum Interruptvektor jedoch nur nach
vollständig ausgeführtem Befehl erfolgt, kann man sich auch damit wieder
eine Ungleichverteilung der Zahlen einhandeln.
>Da die Abarbeitung der>Instruktionen unterschiedlich lange dauert (z. B. 'inc' 1 Taktzyklus,>'rjmp' aber 2), ein Sprung zum Interruptvektor jedoch nur nach>vollständig ausgeführtem Befehl erfolgt, kann man sich auch damit wieder>eine Ungleichverteilung der Zahlen einhandeln.
Kapier ich nicht wirklich, gib mal ein Beispiel.
>Kapier ich nicht wirklich, gib mal ein Beispiel.
Stell Dir vor, jemand realisiert den Würfel wie folgt.
(1) Damit die Durchlauffrequenz so hoch wie möglich ist, wird Timer1
ohne Prescaler im CTC-Modus verwendet. Mit passendem Compare-Match-Wert
zählt er nach dem Start 0, 1, 2, ..., 5, 0, 1, 2, ... 5, 0, 1, 2... mit
voller Taktfrequenz (8 MHz) durch.
(2) Nach Drücken des Tasters wird Timer1 auf Null gesetzt, um einen
definierten Startzustand zu gewährleisten. Danach tritt das Programm in
die angegebene Endlosschleife ein:
1
clr temp
2
out TCNT1H, temp
3
out TCNT1L, temp
4
5
Loop:
6
nop
7
nop
8
nop
9
nop
10
rjmp Loop
(3) Die Würfel-Start-Stop-Taste hängt am externen Interrupt INT0. Der
Interrupt ist so konfiguriert, dass er bei einer
Taste-losgelassen-Flanke getriggert wird. Im Interrupthandler wird der
Zählerstand von Timer1 ausgelesen: TCNT1L + 1 ist der Würfelwert.
Fertig.
Was ist dazu zu sagen? Man könnte glauben, das müsse einen äußerst guten
Würfel ergeben. Die Wahrheit ist, dass er völlig unbrauchbar wäre, weil
eine der Zahlen 1 bis 6 niemals erscheinen würde.
Hätte man in der Loop-Schleife statt der 'nop's irgendwelchen Code
stehen, der z. B. die LEDs während die Taste gedrückt ist blinken läßt,
wäre der Effekt nicht so drastisch, aber die Zahlen wären wahrscheinlich
auch nicht völlig gleichverteilt.
>Nen Würfel hab ich vor kurzem auch mal programmiert.>Nicht sehr schöner code, funzt aber.
Der Code in der Schleife ist nicht laufzeitkompensiert. Er wird etwas
mehr Zeit brauchen, wenn i = 7 ist, denn nur für i = 7 wird die
Anweisung i = 1 ausgeführt. Die zugehörige Würfelzahl wird entsprechend
etwas häufiger auftreten als die anderen. Wenn Du Deinen PC über ein
geeignetes Interface ein paar tausend mal würfeln und ein Histogramm
erstellen ließest, würde Dir der längere Balken sofort auffallen.