Fehler im Programm zum Erzeugen von Zufallszahlen

Hallo,
leider musste ich feststellen, dass ich die randomSeed und random-Funktion auf meinem Attiny85 nicht verwenden kann, weshalb ich auf das speicherintensivere srand und rand von C zurückgreifen musste (randomSeed und random verbrauchen (zu meiner Verwunderung) gut 1 KB weniger bei der Kompilierung als die Verwendung von srand und rand :frowning: )
Aber jetzt mal zum eigentlichen Problem. Der Code ist folgender :
(Der Serial Monitor wird hier nur verwendet, um die erzeugten Zahlen einzusehen. Wird später entfernt.)

int Wert[20];  //Erzeuge ein Integer-Array, bestehend aus 20 Feldern

void setup() {
  Serial.begin(9600);  //Zum Testen Zufallszahlen im Serial Monitor ausgeben
  pinMode(A5, INPUT);
}

void Init_Random()
{
  //Warte auf Tastendruck
  while (analogRead(A5) < 700)
      delayMicroseconds(1);
  Serial.println(millis(), DEC);
  srand(millis());  //Zufallszahlengenerator initialisieren
}

void loop() {
  Init_Random();   //Initialisiere Zufallszahlengenerator

  //Befülle das Array mit Zufallszahlen im Bereich von 1 bis 3
  for (int i=0; i<20; i++)
    Wert[i] = (rand() % 3 + 1);  //Hier befindet sich das Problem.....
  
  //Ausgabe der Zufallszahlen im Serial Monitor
  for (int i=0; i<20; i++)
    Serial.println(Wert[i], DEC);
}

Der Fehler liegt darin, dass anscheinend nur 2 Zufallszahlen erzeugt werden, anstatt 20. Habe die rand-Funktion mal durch die Random-Funktion der Arduino Library ersetzt und da funktioniert es, wodurch der Fehler bei der rand-Funktion liegen muss.

Könnt ihr mir helfen ?

Vielen Dank und Grüße,
UnoRookie

Zu den Bibliotheken kann ich nur sagen, daß der Speicherbedarf größtenteils von den benutzten Rechenfunktionen abhängt. Bei den Arduinos muß ja schon die Integer-Division (und Modulo) durch ein Unterprogramm erledigt werden. Ggf. sind das schon mehrere Funktionen, für Operanden mit 1, 2 und 4 Bytes. Kommt dann noch Fließkomma-Arithmetik hinzu, wird Speicher auch für diese Funktionen benötigt (+ - * /). Die gute Nachricht: alle diese Funktionen liegen nur einmal im Speicher, egal wie oft sie benutzt werden.

Es könnte auch helfen, die Variablen für die Random-Werte als long zu deklarieren, wie im Beispiel zu random() angegeben. Und auf Modulo zu verzichten, das hat random() schon eingebaut.

Dein Programm enthält IMO zwei grundsätzliche Fehler:

Die Initialisierung des Random-Generators sollte nur einmal (in setup) ausgeführt werden, sonst bekommst Du ggf. mehrmals die gleiche Belegung des Arrays.

Die Verwendung von delay() bzw. delayMicroseconds() kann die seirelle Ausgabe beeinträchtigen. Möglicherweise gilt das auch für analogRead(). Benutze eine der vielen Funktionen zur Abfrage eines Buttons, die ohne Delays auskommen, oder benutze Serial.flush(), um die komplette Ausgabe in jedem Durchlauf zu erhalten.

Und auf Modulo zu verzichten, das hat random() schon eingebaut.

Das weiß ich. Da ich aber beim Attiny85 nur folgende Befehle

The following Arduino commands should be supported:

  • pinMode()
  • digitalWrite()
  • digitalRead()
  • analogRead()
  • analogWrite()
  • shiftOut()
  • pulseIn()
  • millis()
  • micros()
  • delay()
  • delayMicroseconds()

verwenden kann, muss ich auf auf Standard-C ausweichen. Würd ja liebend gern die randomSeed und random - Funktion verwenden, wenn se unterstützt würden...

Die Initialisierung des Random-Generators sollte nur einmal (in setup) ausgeführt werden, sonst bekommst Du ggf. mehrmals die gleiche Belegung des Arrays.

Das ist mir klar. Hab se nur versehentlich in die loop-Funktion gepackt :frowning:

Die Verwendung von delay() bzw. delayMicroseconds() kann die seirelle Ausgabe beeinträchtigen. Möglicherweise gilt das auch für analogRead(). Benutze eine der vielen Funktionen zur Abfrage eines Buttons, die ohne Delays auskommen, oder benutze Serial.flush(), um die komplette Ausgabe in jedem Durchlauf zu erhalten.

Aber ich hatte bisher nie Probleme bei der Verwendung von analogRead() in Verbindung mit Serial.println.

Ist es evtl. einfacher und unkomplizierter, einfach einen unbelegten Analog-Pin zu verwenden und 20 Werte davon zu lesen ?

Vielen Dank,
UnoRookie

Ist es evtl. einfacher und unkomplizierter, einfach einen unbelegten Analog-Pin zu verwenden und 20 Werte davon zu lesen ?

Der Zeitpunkt eines Tastendrucks in ms ist schon ein ziemlich guter Random Seed Wert.

Unbenutzte Eingänge per analogRead liefern die möglichen Ergebnisse (0 .. 1023) nicht wirklich gleichverteilt. Sind also theoretisch nicht so gut.

Aber in der Praxis (wofür denn ?) auch durchaus brauchbar als Startwert, wenn man nichts zufälligeres hat.
Wenn schon mehrere analogRead:
Für einen gleichverteilt zufälligen int32_t Wert z.B. 8 mal analogRead und die Ergebnisse um 4 Bit verschoben miteinander xor-vermischt ...

Hauptsache, man macht es nur beim Start und lässt die generierte Zufallsfolge laufen.

Da ich aber beim Attiny85 nur folgende Befehle ... verwenden kann, muss ich auf auf Standard-C ausweichen. Würd ja liebend gern die randomSeed und random - Funktion verwenden, wenn se unterstützt würden...

Erstaunlicher Weise, liegt das alles im Quellcode vor.
Es sind also nur deine inneren Widerstände welche es verhindern, dass du dir den gewünschten Code aus dem Arduino default Core klaust.

Erstaunlicher Weise, liegt das alles im Quellcode vor.

Ja, das dachte ich mir schon. Hatte auch schon nach “Arduino Befehle implementation”, “Arduino Befehl random implementation” und “Arduino Befehle kopieren” gegoogelt, in den Arduino FAQs und der Arduino Reference Library gesucht aber nix gefunden. Könnt ihr mir sagen, wo man die Implementation der Arduino-Befehle findet ?

Könnt ihr mir sagen, wo man die Implementation der Arduino-Befehle findet ?

Auf meinem Rechner finde ich die Random Funktionen in:
E:\Programme\Arduino\hardware\arduino\avr\cores\arduino\WMath.cpp

E:\Programme\Arduino\hardware\arduino\avr\cores\arduino\WMath.cpp

Super, vielen Dank. Werd gleich nachschauen.

Desweiteren funktioniert mein Code doch. Hab am Ende einfach ein Delay(60000) eingefügt und dann wurden schon 20 Zufallszahlen ausgegeben. Lag also wahrscheinlich doch am Serial Monitor => Du hattest recht, DrDiettrich

Vielen Dank für alles !!

michael_x:
Für einen gleichverteilt zufälligen int32_t Wert z.B. 8 mal analogRead und die Ergebnisse um 4 Bit verschoben miteinander xor-vermischt …

Meinst Du so was?

void seedRandom(uint8_t analogPort) {
uint32_t wert = analogRead(analogPort);
  for(uint8_t i = 0; i < 7; i++) {
    wert = wert << 4;
    wert ^= analogRead(analogPort);     
  }
  Serial.print("Wert: "); Serial.println(wert,HEX);
  randomSeed(wert);
}

void setup() {
  Serial.begin(115200);
  Serial.println("Start");
  seedRandom(A0);
}

void loop() {
  
}

Gruß Tommy

Tommy56:
Meinst Du so was?

ja z.B. so (nur 8 statt 7). Und das hat den kleinen Nachteil, dass das Ergebnis von analogRead nicht gleichverteilt zufällig ist. Selbst wenn der Eingang offen floatet. Aber man will ja nur einen von möglichst vielen und nicht vorhersehbaren Anfangswerten.

Und das hat den kleinen Nachteil, dass das Ergebnis von analogRead nicht gleichverteilt zufällig ist. Selbst wenn der Eingang offen floatet.

Ja, allerdings. Wobei ich meine Zufallszahlen eh nur für ein Spiel brauch, wie so eine Art Würfel. Da ist es mir relativ egal, ob eine Zahl mehrmals hintereinander auftaucht. Klar, für Verschlüsselungsalgorithmen ist so ne Möglichkeit ungeeignet

Und das hat den kleinen Nachteil, dass das Ergebnis von analogRead nicht gleichverteilt zufällig ist. Selbst wenn der Eingang offen floatet. Aber man will ja nur einen von möglichst vielen und nicht vorhersehbaren Anfangswerten.

Besser mehrfach lesen.
Auch gerne mit leicht überhöhtem ADC Takt.
Und nur das niederwertigste Bit verwenden
So oft lesen, bis man genug Bits beisammen hat.

Als Random Ersatz:
Kann auch gerne im Hintergrund gemacht werden, damit die Zahlen SOFORT zur Verfügung stehen.

Was bei Spielen auch gut geht ist den Zeitpunkt des ersten Tastendrucks als Seed zu nehmen. Das ist glaube ich auch der Grund weshalb heute noch manche Spiele erwarten dass man eine Taste drückt um zu Starten