Forum: Mikrocontroller und Digitale Elektronik Problem mit Zufallscode


von Jackson02 (Gast)


Lesenswert?

Guten Abend zusammen!

Ich hätte hier meiner Meinung nach eine "schöne" und einfache Idee einen 
fast einwandfreien Zufallsgenerator für eigentlich jede Anwendung. Die 
Idee dazu ist eigentlich recht gut.
Nur leider gibts einen Hacken - Da ich noch nicht so lange in der 
µC-Branche bin, kann es sein, dass sich ein Fehler (wahrscheinlich mit 
dem Interrupt) eingeschlichten hat.
- Controller ist zu Testzwecken nur ein Attiny13 (Soll später über 
Matrixdisplay eine Zahl ausgegeben werden mit einem Atmega8 oder 
Attiny2313)
- Der Interrupt-Pin ist der PB0 (Pin5)
- Ausgänge sind (wie man sieht) PB2 (Pin7) und PB1 (Pin6)

Die Idee ist, einen Zufälligen "RND"-Wert durch ständiges Wiederholen 
dauernd zu ändern und in die Variable A zu schreiben. Durch den 
Interrupt soll dann der in A gespeicherte Wert verarbeitet und 
ausgegeben werden.

Hier nun einmal der Code:
(Ich habe hier bewusst Rnd(50) statt die normalerweise benötigten Rnd(2) 
für meine 2 Zustände bzw. Ausgänge genommen, da sich so mehrere Ausgänge 
oder die "Wahrscheinlichkeit" leicht ändern lässt)
1
$regfile = "attiny13.dat"
2
$crystal = 1200000
3
$hwstack = 22
4
5
Config Pinb.0 = Input
6
Config Portb.1 = Output
7
Config Portb.2 = Output
8
Pinb.0 = 1
9
10
On Int0 On_int0
11
Config Int0 = Falling
12
Enable Int0
13
Enable Interrupts
14
15
Dim A As Word
16
A = 0
17
18
Do
19
A = Rnd(50)
20
Waitms 10
21
End
22
Loop
23
24
On_int0:
25
If A < 25 Then
26
Portb.1 = 0
27
Portb.2 = 1
28
Else
29
Portb.1 = 1
30
Portb.2 = 0
31
End If
32
Wait 1
33
Portb.1 = 0
34
Portb.2 = 0
35
Return

Ich hoffe, dass mir jemand weiterhilft :)

Mit den besten Grüßen

Manuel

von Karl H. (kbuchegg)


Lesenswert?

Mit Zufallszahlen muss man vorsichtig sein.
So manche vermeintlich clevere Idee dazu ist ein Schuss in den Ofen.

Deine gehört dazu.
Wenn die Laufzeiten der einzelnen Programmteile ein ganzzahliges 
Vielfaches zueinander haben, kann es sein, dass einzelne Zahlen deines 
Wertebereiches niemals erzeugt werden. Oder aber noch schlimmer: 
Einzelne Zahlen werden durch das Verhältnis der Laufzeiten zueinander 
extrem bevorzugt.

Daher ist es am besten:
Benötigt man eine Zufallszahl, dann ruft man die RND auf. Und ansonsten 
lässt man das Zeugs in Ruhe. Die Formel die hinter RND steckt, ist so 
ausgeklügelt worden, dass sich automatisch die gewünschte Verteilung der 
Zufallszahlen ergibt (meistens eine Gleichverteilung). Greift man da an, 
macht man die Dinge nie besser sondern maximal bleibt die Charakteristik 
der Zahlen erhalten. Meistens verschlimmert man aber die Situation und 
die generierten Zahlen weisen alles andere als eine vernünftige 
Zufallsverteilung auf.

Viele Zufallszahlengeneratoren kann man seeden. Das heist man gibt ihnen 
den ersten Wert vor, von dem an dann der Generator die weiteren Zahlen 
bestimmt. Dieses seeden kann man zb durch Zeitmessung bis zum ersten 
Tastendruck machen. Aber danach ist man mit der Devise: Hände weg vom 
Generator besser bedient.

In deinem konkreten Beispiel könntest du zb eine Steuerung einbauen, 
dass dein ständiges RND generieren abgebrochen wird, sobald der erste 
externe Interrupt kommt. Ab dann verwendet die Interrupt Routine nur 
noch RND um jeweils die nächste Zahl zu erzeugen, die laufende 
Generierung in der Hauptschleife sollte dann besser aufhören.
Damit hast du erreicht was du erreichen wolltest: Die Startbedingungen 
für die erzeugten Zufallszahlen hängen von der Zeitdauer bis zum ersten 
Interrupt ab und danach hast du eine saubere Zufallszahhlenverteilung, 
wie sie RND implementiert hat.

von Manuel B. (jackson02)


Lesenswert?

Was bedeutet das nun im Bezug auf meinen Code?

Achja, ich vergaß zu erwähnen. Das Problem ist, dass sie bei einem 
Drücken des Interrupt-Tasters nichts tut. Also die Ausgänge werden nicht 
gesetzt und führen ständig 0-Signal.

Grüßle

von Grübler (Gast)


Lesenswert?

@Manuel B.
>Was bedeutet das nun im Bezug auf meinen Code?

Wenn ich K.H.B. richtig verstanden habe,
ist dein Code für den A... ;-)


>Achja, ich vergaß zu....... führen ständig 0-Signal.

Siehe oben

von spess53 (Gast)


Lesenswert?

Hi

Nur mal so: Wolltest du mit

>Pinb.0 = 1

den Pull-Up einschalten? Wenn ja sollte es wohl besser

Portb.0 = 1 heissen.

MfG Spess

von Manuel B. (jackson02)


Lesenswert?

Also nach K.H.B. soll ich ja "nur" den RND verwenden wenns nicht anders 
geht. In diesem Fall ruf ich ihn ja schließlich auch nur auf, weil ich 
eben seine Funktion brauche - die Zeit mit der 1ms soll ja ledeglich den 
RND-Wert alle paar Millisekunden verändern.
Ich bezweifle nicht, dass das nicht passiert.
Jedoch fällt mir kein Fehler an dem Code auf, welchen ich aber gerne 
Wissen würde. Schließlich lernt man ja aus seinen Fehlern ;)


Grüßle

von Manuel B. (jackson02)


Lesenswert?

Ahh..
@spess53

Danke.. fiel mir gar nicht auf.

Ich stells gleich mal um.
Danke nochmals.

Allerdings besteht das Problemchen nun leider immer noch :(

Grüßle

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Karl heinz Buchegger schrieb:
> So manche vermeintlich clevere Idee dazu ist ein Schuss in den Ofen.

Man kann eigentlich generell sagen: echte Zufallszahlen (also
solche, die selbst dann nicht vorhersagbar sind, wenn man den Code
kennt, der sie erzeugt) lassen sich nur durch physikalische
Effekte erzeugen, die bedingt durch ihre Physik eine garantiert
zufällige Verteilung haben.

von GerK (Gast)


Lesenswert?

Hallo!

Dreh mal "End und Loop" um.

MfG
GerK

von MaWin (Gast)


Lesenswert?

> Die Idee ist, einen Zufälligen "RND"-Wert durch ständiges Wiederholen
> dauernd zu ändern und in die Variable A zu schreiben. Durch den
> Interrupt soll dann der in A gespeicherte Wert verarbeitet und
> ausgegeben werden.

Der Interrupt ist also ein Tastendruck,
und gezählt wird so schnell, daß der Zähler dauernd komplett rumzählt,
wie lang die Zeit zwischen dem vorherigen und diesem Tastendruck ist, 
wobei nur die niederwertigen Stellen benutzt werden.

Das Verfahren ist alt, uralt,
bei ausreichend schnellem Zähler reicht es gar, die Länge des 
Tastendrucks (in Millisekunden, wobei nur der Mikrosekundenanteil als 
Zufallszahl gilt) abzustoppen.

von Peter D. (peda)


Lesenswert?

Ob das geht, dazu müßte man erstmal wissen, wie die rnd()-Funktion 
implementiert ist.
Wenn sie z.B. nicht immer exakt gleiche Berechnungszeit benötigt, ist 
das Ergebnis nicht mehr zufällig.
Wenn sie einen Timer benutzt, auch nicht.

Warum nimmst Du ein Word (16Bit) für ne Variable, die nur max 50 sein 
kann?
Und wenn sie >255 werden könnte, hast Du eh noch das Atomicity-Problem.


Peter

von Jackson02 (Gast)


Lesenswert?

Guten Abend,
Werde eure Ratschläge mal befolgen und so den Code morgen Vormittag mal 
umbauen.
Ich hoffe dass dann keine Leichtsinnsfehler mehr drinnen sind und ich 
das Programm zuverlässig gestalten kann.
Werde den Code natürlich dann mal posten.

Die besten Grüße

Manuel

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.