AVR Embedded Tutorial - Random/de
│ Deutsch (de) │ English (en) │
Zufallsgenerator
Vorwort
Ein Zufallsgenerator ist auf einem AVR gar nicht so einfach. Ein Random(...) aus der Unit System geht leider nicht. Dieses Tutorial zeigt, wie man wenigstens einen Würfel auf einem AVR programmieren kann.
Der Bereich der Zufallszahl muss von Anfang an bekannt sein, bei einem klassischen Würfel ist dies 6.
Für die Kommunikation über UART siehe hier:
Für einfache Zufallszahlen eignen sich folgende beschriebenen Methoden. Voraussetzung ist, das die Abfrage der Zufallszahlen in unregelmässigen Abständen kommt. Das ist zB. auch bei einem Tastendruck der über GPIO abgefragt wird der Fall.
Diese Voraussetzung kann man gut beim ersten Beispiel erkennen, wen man im Terminalprogramm eine Taste gedrückt hält, da kann man eine Regelmässigkeit gut erkennen.
Wen man einen float als Zufallszahl will, dann wird es schon sehr kompliziert. Dafür habe ich (noch) keine Lösung gefunden.
Ein einfacher Würfel
var
Random: byte; // Gibt die Zufallszahl zurück.
procedure Timer0_Interrupt; public Name 'TIMER0_OVF_ISR'; interrupt;
const
RandomCount = 6; // Anzahl Würfelaugen
begin
Inc(Random);
if Random >= RandomCount then begin
Random := 0;
end;
end;
var
s: ShortString;
begin
// Timer 0
TCCR0A := %00; // Normaler Timer
TCCR0B := %001; // Clock = CPU
TIMSK0 := (1 shl TOIE0); // Enable Timer0 Interrupt.
// UART
UARTInit; // UART inizialisieren.
// Interrupts einschalten.
asm sei end;
// Hauptschleife
repeat
UARTReadChar; // Simuliert einen Tastendruck.
Str(Random + 1: 4, s); // Die Zufallszahl abholen.
UARTSendString(s); // Zufallszahl ausgeben.
until 1 = 2;
end.
Mehrere Würfel
Schlechte Lösung
Man könnte auf den Gedanken kommen und bei mehreren Würfel folgendes zu machen:
Str(Random + 1: 4, s); // Die Zufallszahl abholen.
UARTSendString(s); // Zufallszahl ausgeben.
Str(Random + 1: 4, s); // Ist abhängig vom ersten Wurf.
...
Nur bekommt man das Problem, das die Reihenfolge der Würfe voraussehbar ist. Daher ist dies unbrauchbar !
Ideale Lösung
Aus diesem Grund habe ich folgenden Code, da kommt es unvorhersehbar.
Einziges Manko, es ist etwas komplizierter, dafür ist jede Zufallszahl unabhängig von den anderen. Bei diesem Beispiel sind es 15 Würfel. Der Timer musste noch etwas langsamer gestellt werden, als bei dem Beispiel mit nur einem Würfel.
Der Trick ist, es werden nicht alle Würfel bei jedem Timeraufruf inkrementiert. Der zweite Würfel nur bei jedem zweiten Aufruf, der Dritte nur beim dritten Aufruf, etc.
// Globale Variablen.
const
anzWuerfel = 15;
var
Random: array[0..anzWuerfel - 1] of byte;
procedure Timer0_Interrupt; public Name 'TIMER0_OVF_ISR'; interrupt;
// Lokale Variablen.
const
RandomCount = 6; // Anzahl Würfelaugen
var
i: integer;
rnd: array [0..anzWuerfel - 1] of byte;
begin
for i := 0 to anzWuerfel - 1 do begin
Inc(rnd[i]);
if rnd[i] > i then begin
rnd[i] := 0;
Inc(Random[i]);
if Random[i] >= RandomCount then begin
Random[i] := 0;
end;
end;
end;
end;
var
s: ShortString;
i: integer;
begin
// Timer 0
TCCR0A := %00; // Normaler Timer
TCCR0B := %011; // Clock = CPU / 16.
TIMSK0 := (1 shl TOIE0); // Enable Timer0 Interrupt.
// UART
UARTInit;
// Interrupts einschalten.
asm SEI end;
// Hauptschleife
repeat
UARTReadChar;
for i := 0 to anzWuerfel - 1 do begin
Str(Random[i] + 1: 4, s); // Jeder Würfel hat eine eigene Zufallszahl.
UARTSendString(s);
end;
UARTSendString(#13#10);
until 1 = 2;
end.
Siehe auch
- Übersichtseite AVR Embedded Tutorial
Autor: Mathias