Forum: Mikrocontroller und Digitale Elektronik AVR Zufalsgenerator


von Michelle Erne (Gast)


Lesenswert?

Hallo,

ich möchte für mein Schulprojekt einen Zufallsgenerator in c Schreiben.
Da ich nicht wirklich Lösungen für mein Projekt finde frage ich einfach 
mal hier ^^

also ich brauche nur eine zufallszahl von 0-5, ich habe schon RAND_MAX 
und RANDOM_MAX in der h-file geändert (Bringt das was?) also auf 0x05.

ich bräuchte eine einfache und gut erklärte Version damit ich die 
einzelnen Schritte nachverfolgen kann und eventuell anpassen kann.

hier wäre mein C-Code aber es funktioniert leider nicht ganz wie ich 
will.
Ich habe hier mit einem AT-tiny85 gearbeitet.

Und es wäre schön und praktisch wenn mir jemand helfen kann und die If 
Funktionen so bleiben könnten(Brauch ich für später)

C-Code
1
# define F_CPU 1000000UL
2
#include <avr/io.h>
3
#include <stdint.h>
4
#include <util/delay.h>
5
6
#include "Zufall.h"
7
8
9
int main(void)
10
{
11
DDRB= 0XFF; //|= 1<<PB2 | 1<<PB3 | 1<<PB4 | 1<<PB0 | 1<<PB1 | 1<<PB5;
12
13
  
14
  
15
   while(0)
16
   
17
   {
18
      int x= random();
19
     
20
     if (x==0x00)
21
     {
22
       PORTB |= 1<<PB0;
23
       _delay_ms(500);
24
       //PORTB &=~ (1<<PB0);
25
      }
26
   
27
      else if (x==0x01)
28
     {
29
       PORTB |= 1<<PB1;
30
       _delay_ms(500);
31
       PORTB &=~ (1<<PB1);
32
     }
33
   
34
    else if (x==0x02)
35
       {
36
       PORTB |= 1<<PB2;
37
       _delay_ms(500);
38
       PORTB&=~(1<<PB2);
39
     }
40
   
41
     else if (x==0x03)
42
      {
43
        PORTB |= 1<<PB3;
44
        _delay_ms(500);
45
       PORTB &= ~(1<<PB3);
46
     }
47
  
48
     else if (x==0x04)
49
      {
50
        PORTB |= 1<<PB4;
51
        _delay_ms(500);
52
        PORTB &= ~(1<<PB4);
53
      }
54
    else if (x==0x05)
55
     {
56
       PORTB |= 1<<PB4;
57
       _delay_ms(500);
58
       PORTB &= ~(1<<PB4);
59
     }
60
   }
61
}

: Bearbeitet durch Moderator
von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Michelle Erne schrieb:
> mein C-Code aber es funktioniert leider nicht ganz wie ich will.
Was funktioniert nicht? Was erwartest du und was passiert stattdessen?

> also ich brauche nur eine zufallszahl von 0-5, ich habe schon RAND_MAX
> und RANDOM_MAX in der h-file geändert (Bringt das was?) also auf 0x05.
Warum rechnest du da mit Hex-Zahlen? 5 ist doch sowieso das selbe wie 
0x05...

BTW:
Bitte in Zukunft so:
1
[c]
2
  C-Code
3
[/c]

: Bearbeitet durch Moderator
von Karl M. (Gast)


Lesenswert?

Einene "Zufallsgenerator" kann man nicht programmieren, da ja die 
Zustände zufällig sein sollen.

Was bleibt ist ein pseudo Zufallsgenerator, der Beim selben Startwert 
auch die gleichen Zustände annimmt.

http://www.kuno-kohn.de/crypto/crypto/prngs.htm

Als Startwert könnte man eine ADC-Wandung eines unbeschaltenten 
ADC-Eingangs verwenden.

von Ralf G. (ralg)


Lesenswert?


von Karl H. (kbuchegg)


Lesenswert?

Michelle Erne schrieb:

> also ich brauche nur eine zufallszahl von 0-5, ich habe schon RAND_MAX
> und RANDOM_MAX in der h-file geändert (Bringt das was?) also auf 0x05.

Nein, das bringt nix.
RANDOM_MAX ist die Information für dich, welches die größte Zahl ist, 
die vom Zufallszahlengenerator kommen wird.

Die Zahl zu ändern bringt genausowenig, wie in einer Übersicht zu 
behaupten, ein bestimmtes Buch hätte nich 236 Seiten sondern nur 20. 
Behaupten kannst du es natürlich, aber deswegen wird sich die Anzahl der 
Seiten nicht ändern.

> ich bräuchte eine einfache und gut erklärte Version damit ich die
> einzelnen Schritte nachverfolgen kann und eventuell anpassen kann.

Die gibt es im Web zu hauf.
Dreh und Angelpunkt ist praktisch immer, dass man mit Zahlen auch 
rechnen kann. Was du also brauchst ist eine Rechenvorschrift, wie du dir 
aus dem Ergebnis von random(), welches in einem bestimmten Bereich 
liegt, neue Zahlen errechnen kannst, die in dem von dir gewünschten 
Bereich liegen.

Du kennst doch die Modulo-Funktion (in C ist das die Operation %). Das 
Ergebnis einer Modulo-Operation (das ist nichts anderes als der Rest bei 
einer ganzzahligen Division) liegt immer in welchem Bereich?

Das ist nicht unbedingt die beste Lösung, aber es ist eine einfache 
Lösung, die so schlechte Ergebnisse auch wieder nicht bringt, solange 
nur RAND_MAX (oder bei dir eben RANDOM_MAX) nur gross genug ist.

: Bearbeitet durch User
von Pandur S. (jetztnicht)


Lesenswert?

Nimm ein LFSR (google) und kein Float oder so.
Auch keine delays.
EIN LFSR ist deterministisch, und waehlbar in der Periode. Die Periode 
kann sehr lang sein, ohne viel code.

: Bearbeitet durch User
von Karl H. (kbuchegg)


Lesenswert?

Leute

Ich bin mir recht sicher, dass das Problem des TO nicht in einer nicht 
optimal gleichverteilten Verteilung liegt oder sonstigen technischen 
Finessen.

Das Problem liegt, wie meistens bei der Verwendung von rand() ganz 
einfach darin, dass man erhaltene Zahlen als Gott-gegeben hinnimmt und 
sich nicht traut damit ganz einfach ein wenig rumzurechnen.
Man kann einem rand() nicht vorgeben, in welchem Zahlenbereich die 
Ergebnisse liegen sollen. Aber man kann den (bekannten) Zahlenbereich, 
bzw. die von rand() erhaltenen Zahlen so umrechnen, dass sie im 
gewünschten Zahlenbereich zu liegen kommen. Für viele Neulinge besteht 
das Hauptproblem darin, dass sie erkennen müssen, das sie sich etwas 
einfallen lassen müssen um mit dem Gegebenen das Gewünschte zu 
erreichen. Und das verunsichert sie. Das sind sie nicht mehr gewohnt, 
bzw. das haben sie noch nie gemacht, dass sie auch mal selbst eine 
mathematische Formel 'erfinden' müssen. Bisher haben sie immer alles von 
ihrem Lehrer aufs Auge gedrückt bekommen.
Die Ergebnisse vom rand() sind, wenn auch nicht ideal, für 99% aller 
Neulings-Projekte gut genug.

: Bearbeitet durch User
von Rudolph R. (rudolph)


Lesenswert?

Da fällt mir der hier ein:
http://dilbert.com/strip/2001-10-25

:-)

Interessant ist ja auch, wofür die Zufallszahl gebraucht wird.
Die einfachen elektronischen Würfel zählen nur sehr schnell und man hält 
die zufällig auf einer Zahl an.

von chris (Gast)


Lesenswert?

Ich bin mir relativ sicher, dass das Problem hieran liegt:

Michelle Erne schrieb:
> while(0)

von Karl H. (kbuchegg)


Lesenswert?

chris schrieb:
> Ich bin mir relativ sicher, dass das Problem hieran liegt:
>
> Michelle Erne schrieb:
>> while(0)

Autsch.
Den hab ich nicht gesehen.

Guter Fang

von foo (Gast)


Lesenswert?

Michelle Erne schrieb:
>      else if (x==0x04)
>       {
>         PORTB |= 1<<PB4;
>         _delay_ms(500);
>         PORTB &= ~(1<<PB4);
>       }
>     else if (x==0x05)
>      {
>        PORTB |= 1<<PB4;
>        _delay_ms(500);
>        PORTB &= ~(1<<PB4);
>      }
>    }
> }

Hier sollte beim letzten doch sicherlich PB5 und nicht auch PB4 stehen, 
oder?

Ansonsten könnte man die hundert Zeilen auch deutlich einfacher 
schreiben mit:
1
PORTB |= (1 << x);
2
_delay_ms(500);
3
PORTB &= ~(1 << x);

Copy&Paste-Programmierung riecht und führt auch nur zu Fehlern wie dem 
da oben.

von Dussel (Gast)


Lesenswert?

Rudolph R. schrieb:
> Da fällt mir der hier ein:
> http://dilbert.com/strip/2001-10-25

Das angefragte Problem wurde doch schon ewig effizient gelöst.
http://www.xkcd.com/221/

Beim AVR fällt mir spontan das Bitwackeln des ADC ein. Wenn man es 
einigermaßen geschickt macht, sollte man da sehr zufällige Zahlen 
bekommen.

von Michelle Erne (Gast)


Lesenswert?

das habe ich so gemacht weil er sonst Fehlermeldungen bring, und das hat 
mein Lehrer auch bemängelter, aber so wie ich einsehen musste..

der Zufallgenerator ist für eine uslesbox die ich selber machen möchte 
und zuerst mal möchte ich die einzelnen Schritte erlernen bevor ich 
weiter mache.

aber ich möchte euch nochmal darum bitten mir falls ihr das könnt mir 
einen c-code zu schreiben da ich so am besten nachvollziehen kann wie es 
gemacht wird! nur mit trockender Theorie kann ich nicht wirklich viel 
anfangen. wahrscheinlich wird jetzt alle auch mich losgehen aber vl gibt 
es ja welche die mir weiter helfen können!

Oder zumindest ein Beispiel wie man rand() oder random richtig anwendet.
und noch danke an die dir mir geantwortet haben hat mir doch etwas 
geholfen:
)

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

Michelle Erne schrieb:
> der Zufallgenerator ist für eine uslesbox die ich selber machen möchte

Was ist denn das?

Michelle Erne schrieb:
> Oder zumindest ein Beispiel wie man rand() oder random richtig anwendet.

Lies dir dazu mal die Dokumentation von 'stdlib.h' in der avr-libc 
durch. Der zufällige Startwert, von dem die Teilnehmer hier reden, wird 
dort als 'seed' bezeichnet und soll dafür sorgen, das der Generator 
nicht immer die gleiche Sequenz an Zufallszahlen erzeugt. Hier mal ein 
ungetestetes Snippet:
1
#include <stdlib.h>
2
#include <avr/io.h>
3
int16_t myRandom;
4
uint16_t seed;
5
DDRB = 0xFF  // all outputs
6
seed = ADCRead(noisyChannel);  // irgendein Wert, der immer anders ist
7
srand(seed); // Seed setzen
8
while (1) {
9
  myRandom = rand();    
10
  PortB = (myRandom & 0xFF) >> 8;
11
  _delay_ms(20);
12
 }
ADC Init usw. sind hier nicht bei, musst du selber schreiben.

: Bearbeitet durch User
von Pandur S. (jetztnicht)


Lesenswert?

>Die Ergebnisse vom rand() sind, wenn auch nicht ideal, für 99% aller
Neulings-Projekte gut genug.

IMO, benoetigt Rand() floating point. Was ein LFSR das nicht tut.

von Michelle Erne (Gast)


Angehängte Dateien:

Lesenswert?

gut es leuft jezt ich danke euch ^^

von Karl H. (kbuchegg)


Lesenswert?

Jetzt Nicht schrieb:
>>Die Ergebnisse vom rand() sind, wenn auch nicht ideal, für 99% aller
> Neulings-Projekte gut genug.
>
> IMO, benoetigt Rand() floating point.

Deine Opionion ist falsch.

von Christian K. (the_kirsch)


Lesenswert?

Die Funktion rand() gibt dir einen 16 Bit (Pseudo)-Zufallswert zurück, 
aber immer die gleichen in der selben Rheinfolge.

Um das zu ändern muss die Funktion seed() einmalig mit einem 16-Bit 
zufallswert gefüttert werden.

Also hast du ein Henne-Ei Problem. Du willst Zufallszahlen, brauchst 
aber einmalig eine (echte) Zufallszahl, damit dir rand() eine aus 2^16 
möglichen Zahlenreihen Pseudozufallszahlen ausspuckt.

Eine Möglichkeit ist an einem ADC-Kanal zu messen (am besten 16 Mal und 
immer nur das niederwertigste Bit verwenden).

Eine andere Möglichkeit ist den nicht initialisierten Arbeitsspeicher zu 
verwenden, der nach einem Power-Down-Reset ziemlich zufällig sein 
sollte.
1
uint16_t get_seed( ) {
2
  uint16_t seed = 0;
3
  uint16_t* p = ( uint16_t* ) ( RAMEND + 1 );
4
  extern uint16_t __heap_start; // This Variable is defined elsewhere
5
  while ( p >= &__heap_start + 1 ) {
6
    seed ^= *(--p);
7
  }
8
  return seed;
9
}
Nach einem Watchdog-Reset behält der Arbeitsspeicher seine alten Werte, 
daher funktioniert diese Methode dann nicht mehr 100tig.

rand() gibt dir einen 16-Bit Zufallswert zurück, will man mehr ruft man 
die Funktion mehrmals auf:
1
uint32_t x = (rand() << 16) | rand();

Du willst jetzt aber weniger, ist es ein vielfaches von 2, einfach die 
variable nach rechts shiften.

Willst du jetzt eine Zahl zwischen 1 und 5 ist der einfachste weg eine 
Modulu-Rechnung
1
uint8_t x = rand() % 5 + 1;
Das + 1 weil sonst Zahlen zwischen 0 und 4 raus kommen.

Die Modulu-Rechnung ist nicht das beste, da die Zahlen dann nicht 
gleichverteilt sind.
Bei deiner 5 hast du aber Glück, da 2^16 - 1 = 65535 und diese Zahl ist 
Ganzzahlig durch 5 Teilbar. Also dann doch gleichverteilt.

: Bearbeitet durch User
von Karl H. (kbuchegg)


Lesenswert?

> Eine andere Möglichkeit ist den nicht initialisierten Arbeitsspeicher zu
> verwenden, der nach einem Power-Down-Reset ziemlich zufällig sein
> sollte.

Noch eine andere Möglichkeit ist es, eine Benutzereingabe zu benutzen. 
Gerade bei einer Useless Box würde es sich anbieten, die 'Zeit' bis zur 
ersten Schalterbetätigung als Seed Wert zu nehmen.

Eine andere Variante ist es, auf rand() bzw seed() komplett zu 
verzichten und den µC einfach in der Zeit in der es nichts zu tun gibt, 
eine Variable laufend von 0 bis 5 durchzuzählen. Wieder: die 
Schalterbetätigung durch den Benutzer ist das Signal den aktuellen 
Zählerwert als Zufallszahl zu nehmen.

: Bearbeitet durch User
von Malte S. (maltest)


Lesenswert?

Matthias Sch. schrieb:
>   PortB = (myRandom & 0xFF) >> 8;

Q: was steht jetzt in PortB? (bzw. PORTB?)

von Route_66 H. (route_66)


Lesenswert?

Malte S. schrieb:
> Q: was steht jetzt in PortB? (bzw. PORTB?)

alles NULL?

von Malte S. (maltest)


Lesenswert?

Und ich denke nicht, dass Matthias das beabsichtigt hatte.

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

Malte S. schrieb:
> Und ich denke nicht, dass Matthias das beabsichtigt hatte.

Ich sach' doch noch:

Matthias Sch. schrieb:
> Hier mal ein
> ungetestetes Snippet:

Aber man kann ja einfach das >>8 weglassen:
1
  PORTB = (myRandom & 0xFF);
Es ging ja auch eher um rand(), als um die Bitshifterei.

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.