Forum: Mikrocontroller und Digitale Elektronik C8051F020DK SiLab Zufallsgenerator


von batty m. (battyman)


Lesenswert?

Tachchens,

ich habe mich wegen dem Zufallsgenerator schon ein wenig belesen und 
nach guten Lösungen gesucht.
Die eigentliche "rand"-Anwendung gibt ja keine beliebigen Zufallszahlen 
aus, da der Startwert ja immer derselbe ist und somit immer der selbe 
Ablauf generiert wird.
Nun habe ich gelesen dass man dieses mit einer "Clock"-Anwendung besser 
machen kann. Problem dabei ist jedoch, dass mir mein Compiler sagt, er 
kann mit "#include <timer.h>" überhaupt nichts anfangen, da er es wohl 
nicht kennt.
-> Gebe ich bloß den falschen "include"-Befehl ein oder muss ich eine 
für mich nicht bekannte Generier-Funktion wählen???

Mit der Systemfrequenz kann ich die Zufälle ja auch nicht wirklich 
zufällig generieren, da der Chip ja auch immer wieder an der selben 
Stelle, beim Einschalten, anfängt zu zählen und somit ein Interrupt auch 
an dem selben Stellenwert auslöst.

Vielen Dank für eure Hilfestellung

von Norbert M. (Gast)


Lesenswert?

Marcel M. schrieb:
> ich habe mich wegen dem Zufallsgenerator schon ein wenig belesen und
> nach guten Lösungen gesucht.

Und, was ist rausgekommen? Würde mich interessieren, wenn's was anderes 
ist als ein rückgekoppeltes Shift-register :-p

> Die eigentliche "rand"-Anwendung gibt ja keine beliebigen Zufallszahlen
> aus, da der Startwert ja immer derselbe ist und somit immer der selbe
> Ablauf generiert wird.

Deswegen wechselt man auch hin und wieder den Seed, Salt, oder wie der 
Initialisierungswert bei Deiner rand-Funktion eben heisst.

> Nun habe ich gelesen dass man dieses mit einer "Clock"-Anwendung besser
> machen kann.

Sagt mir nix.

> Problem dabei ist jedoch, dass mir mein Compiler sagt, er
> kann mit "#include <timer.h>" überhaupt nichts anfangen, da er es wohl
> nicht kennt.

Gibt's überhaupt eine timer.h in deinem Entwicklungssystem? Und wenn ja, 
wird auch die richtige Library dazugelinkt? Sind die Time-Funktionen 
nicht aus der libC? Und wenn ja, gibt's überhaupt eine komplette libC 
für Deinen Chip (unwahrscheinlich)? Falls ja, ist diese vollständig?

> -> Gebe ich bloß den falschen "include"-Befehl ein oder muss ich eine
> für mich nicht bekannte Generier-Funktion wählen???

Die Header-Datei selbst ist ja nur eine Deklaration von Funktionen für 
den Compiler. Die Funktionalität selbst steckt in der entsprechenden 
Library.
Wenn die entsprechende Header-Datei existiert, dann muß auch die 
entsprechende Library dazugelinkt werden. Wie Du das Deiner 
Entwicklungsumgebung mitteilst, sollte in der Doku stehen.

Einfach auf Verdacht #include <schiessmichtod> in den Source 
reinzuschreiben und zu hoffen daß eine schießmichtod-Bibliothek 
existiert geht meistens nicht gut.

> Mit der Systemfrequenz kann ich die Zufälle ja auch nicht wirklich
> zufällig generieren, da der Chip ja auch immer wieder an der selben
> Stelle, beim Einschalten, anfängt zu zählen und somit ein Interrupt auch
> an dem selben Stellenwert auslöst.

Wie zufällig muss es denn sein? Und wie oft wird der Zufall benötigt?
Wenn es sicher sein muß, dann böte sich eventuell ein externes 
Kryptomodul (gibt's teilweise als Sim-Karte) an.

> Vielen Dank für eure Hilfestellung

Viel Erfolg mit Deinem Projekt,
N.

von batty m. (battyman)


Lesenswert?

Hey Danke für die Antwort.

Dachte bisher, das die "time"-Library eine Standard C-Library ist und 
ich diese damit einbinden kann. Dem ist wohl nicht so, der er damit ja 
nichts anfangen kann.

ich habe "seed" als Initialisierung verwendet, jedoch bleibt es einfach 
immer der selbe Algorhythmus.
So hatte ich es gemacht:
1
int rand(void);
2
void srand(unsigned int seed);
3
unsigned char t2 = 1;
4
5
t2 = rand()%22+2;

ich habe 22 Case's die zufällig angesprochen werden sollen. Derzeitig 
ist es eben so, dass es jedesmal der selbe Startwert, t2 = 1 und dmait 
Case 1, ist wenn ich den µC Strom gebe. Dadurch liegt eben immer die 
selbe Laufroutine vor.

Was mir dabei so auffällt, darf ich denn t2 überhaupt einen Startwert 
geben?

Danke :-)

von Norbert M. (Gast)


Lesenswert?

Marcel M. schrieb:
> So hatte ich es gemacht:
1
 void srand(unsigned int seed);
2
unsigned char t2 = 1;
3
t2 = rand()%22+2;

Hmm, bleibt nur noch die Frage, woher Dein Samen kommt. ;-p
Mach doch einfach Folgendes:
1
 t2 = srand(rand()) %22 + 2 ;

> Was mir dabei so auffällt, darf ich denn t2 überhaupt einen Startwert
> geben?

Dürfen schon, aber was bringt's, wenn er in der nächsten Zeile sowiso 
die 1 mit dem Rückgabewert von rand() überschreibt. Eine einfache 
Deklaration ohne Wertzuweisung täte es da meiner persönlichen Meinung 
nach auch.

> Danke :-)

Schönen Rest-Dienstag noch und viel Erfolg,
NOR-Jäger

von Andreas H. (ahz)


Lesenswert?

Marcel M. schrieb:
> Problem dabei ist jedoch, dass mir mein Compiler sagt, er
> kann mit "#include <timer.h>" überhaupt nichts anfangen, da er es wohl
> nicht kennt.

Heisst die nicht time.h ?

> ich habe "seed" als Initialisierung verwendet, jedoch bleibt es einfach
> immer der selbe Algorhythmus.
>
> So hatte ich es gemacht:
> int rand(void);
> void srand(unsigned int seed);
>
> unsigned char t2 = 1;
>
> t2 = rand()%22+2;

Und WO machst Du da den seed() call ? Du deklarierst die Funktion nur, 
führst sie aber nie aus. Oder übersehe ich da was ?

Anyway, so kannst Du keine zufälligen Werte erzeugen (aber das hast Du 
auch schon gemerkt ;-)

Eine übliche Methode ist, sich erst mal eine ECHTE Zufallszahl zu 
erzeugen.
Damit initialisierst Du Deinen Zufallszahlengenerator mit der seed() 
Funktion.

Dann liefert Dir auch rand() am Anfang unterschiedliche Werte. Aber 
bitte dran denken, dass das ein Kongruenzgenerator ist, die 
Zufallszahlen sind nicht echt. Insbesondere ist die Folge der 
Zufallszahlen periodisch.

Bleibt noch die Frage, woher Du eine ECHTE Zufallszahl bekommst. Der 
Trick ist hier, Teile des uPs zu missbrauchen, die nicht wirklich 
deterministisch sind (ok, das ist bissl abstract, sry).

Eine Möglichkeit ist der Temperatursensor, den der Chip (lt. kurzem 
Blick ins DS hat). Eine Andere ist einer der ADCs (bevorzugt der 12Bit).

Mal als Beispiel mit ADC:
Ob der ADC für etwas Anderes benutzt wird ist meist egal. Man nutzt aus, 
dass das LSB eines ADCs eigentlich immer "wackelt".

Lies den ADC 16 mal aus. Bei jedem Auslesen nimmst Du jetzt nur das LSB 
und schiebst es in eine Variable. Nach 16 Durchläufen stehen dann also 
die 16LSBs drin. Und da bei fast allen ADC das LSB "wackelt" hast Du 
jetzt eine "relativ" echte Zufallszahl.
Mit dem Temperatursensor geht eigentlich genau so (must Du mal 
probieren).

Wenn Dir das immer noch zu "gleichmässig" ist (z.B. lange '0' oder '1' 
Folgen im 16Bit Integer, dann Hash den Integer. Das wirbelt die Bits 
nochmal durcheinander.

Das hat bei mir schon bei >zwei Impelmentierungen gut funktioniert 
(allerdings andere uPs). Sollte bei dem SiLabs aber auch funktionieren. 
Probiers mal ;-)

Grüße
Andreas

von batty m. (battyman)


Lesenswert?

Norbert M. schrieb:

> Hmm, bleibt nur noch die Frage, woher Dein Samen kommt. ;-p
> Mach doch einfach Folgendes:
>
1
 t2 = srand(rand()) %22 + 2 ;
>
Das frisst mein Compiler so leider eben auch nicht.
1
#include <c8051f020.h>
2
#include <stdlib.h>
3
4
int rand(void);
5
void srand(unsigned int Seed);
6
unsigned char t2;
7
8
void main (void)
9
{
10
  Timer3_Init (SYSCLK / 12 / 10)
11
  EA = 1;
12
  while (1)
13
  {
14
  }
15
}
16
17
void Timer3_ISR (void) interrupt 14
18
// t2 = Case-Nummer 1-22
19
{
20
   t2 = srand(rand()) % 22+2; //-> illegal type conversion from/to void
21
   if (t2<23)
22
   {
23
      switch (t2)
24
      {
25
      }
26
   }
27
}

Ich habe es auch probiert "srand(Seed)" erst aunzusprechen und danach 
"t2=rand()" auszuüben, dort hängt das Programm jedoch immer in dem 
selben Case fest und wiederholt es
1
...
2
{
3
   srand();            // oder srand(Seed); // oder srand(5);
4
   t2 = rand()% 22+2;
5
   ...
6
}

Ist es ein Problem weil ich es nicht in der Main-Routine ausführe? 
Dürfte doch eigentlich nicht, oder?

> Schönen Rest-Dienstag noch und viel Erfolg,
> NOR-Jäger



Andreas H. schrieb:
>Heisst die nicht time.h ?

jo, habe ich auch so verwenden wollen, kennt er jedoch nicht - LEIDER
Das hier war ein Schreibfehler, der nur hier war, nicht im eigentlichen 
Programm, sorry.

>Wenn Dir das immer noch zu "gleichmässig" ist (z.B. lange '0' oder '1'
>Folgen im 16Bit Integer, dann Hash den Integer. Das wirbelt die Bits
>nochmal durcheinander.

Also ich habe die 22 Case's die ich einfach per Zufall ausüben möchte. 
Was ich eigentlich erstmal nur will ist, dass der Startwert der 
Rand-Anwendung ein anderer ist, damit das Programm bei jedem Einschalten 
anders anfängt. Somit ist der Ablauf ja auch immer etwas anders. Das 
sich dann die Routine wiederholt ist mir, bei 22-Werten, persönlich erst 
einmal egal. Das kann ich dann bei Gegebenheit wieder weiter entwickeln, 
sodass es wirklich Zufälle sind, dazu muss ich aber weiter in die 
Materie einstagen (was noch kommen wird).
Das Erste wäre für mich an dieser Stelle aber von Wichtigkeit.

THX

von Andreas H. (ahz)


Lesenswert?

Marcel M. schrieb:
> Ist es ein Problem weil ich es nicht in der Main-Routine ausführe?
> Dürfte doch eigentlich nicht, oder?

Nein. Das Problem ist, das Du den Zufallszahlengenerator immer mit dem 
gleichen Startwert initialisierst. srand(startwert) initialisiert den 
Generator, rand() liefert Dir die nächste Pseudozufallszahl.

Die Zufallszahl ist aber deterministisch, d.h. sie hängt nur von den 
bisher erzeugten Zufallszahlen (und dem seed, den Du mit srand() 
angegeben hast) ab.

Solange Du immer mit dem gleichen seed initialisierst wird sich da 
nichts ändern.

Versuch mal Dir das hier klarzumachen: 
http://de.wikipedia.org/wiki/Linearer_Kongruenzgenerator

Grüße
Andreas

von batty m. (battyman)


Lesenswert?

Vielen Dank für eure Hilfestellungen!

I-wie schein ich trotzdem zu dusslig für die korrekte Eingabe zu sein. 
Ärgert mich jetzt richtig.

von Andreas H. (ahz)


Lesenswert?

Marcel M. schrieb:
> I-wie schein ich trotzdem zu dusslig für die korrekte Eingabe zu sein.
Nö. Wenn überhaupt ist Dir noch nicht wirklich klar, was Du machen 
willst.

Solange Du aber noch ernsthaft mit Syntaxfehlern kämpfst, hast Du eine 
ganz andere (durchÜbung beseitigbare) Baustelle.

> Ärgert mich jetzt richtig.
Glaub ich, ist normal. Bringt Dich aber nicht weiter ;-)
Einfach weiter probieren.

Grüße
Andreas

von batty m. (battyman)


Lesenswert?

Guten Morgen,

nachdem ich das mit dem srand() nicht mal ansatzweise hin bekommen habe, 
habe ich mir nun die Haare ruasgerupft. Ich habe i-wie das Gefühl, dass 
mein Rechner den Befehl nicht mal kennt.

Jetzt habe ich das erstmal wie folgt gemacht - aber das nicht LÖSEN 
ko*** mich echt an.
1
 t2 = rand()%22;

denn das funktionierte auch nicht, da ich nun auch noch zu dusslig bin 
eine for-Schleife zu bauen:
1
int rand(void);
2
unsigned char i;
3
unsigned char t2;
4
5
Timer3_ISR
6
{
7
  for (i=0; i>22; i++)
8
  {
9
     t2 = rand()%22;
10
  }
11
}

es will wirklich nicht in meinem Kopf, warum das mit
1
 void srand (unsigned int seed);
nicht klappt. Wenn ich "srand" dann später nutzen will, kommt 
"redefinition" oder "undefined" - je nach dem was ich probiert habe.

Dann habe ich es wieder etwas anders versucht:
1
void srand (seed);
2
unsigned int (seed);
Damit habe ich zwar "undefined" unterbunden, jedoch laufen immer wieder 
nur 2 bestimmte Case's ab. Ick komm einfach nicht weiter.

Der Wiki-Algorhythmus ansich ist --- halbwegs :-) --- verständlich. 
Jedoch bekomm ich diese Transferleistung nicht auf die Reihe.

THX für die Hilfe

von Andreas H. (ahz)


Lesenswert?

Marcel M. schrieb:
> Jedoch bekomm ich diese Transferleistung nicht auf die Reihe.

Mal aus der hohlen Hand, ohne Compiler, beim Frühstück, basierend auf 
Deinem Code:

#include <c8051f020.h>
#include <stdlib.h>

int rand(void);
void srand(unsigned int Seed);
unsigned char t2;

void main (void)
{
  Timer3_Init (SYSCLK  12  10)

  // Initialisierung rnd-generator. Hier muss statt 8643
  // ein "echter" Zufallswert hin
  srand(8643);

  EA = 1;

  while (1)
  {
  }
}

void Timer3_ISR (void) interrupt 14
// t2 = Case-Nummer 1-22
{
   t2 = rand()) % 22+2; // neue Zufallszahl generieren
   if (t2<23)
   {
      switch (t2)
      {
      }
   }
}

Eine "PC (Linux) verträgliche" Version, die (bei flüchtigewm Test) 
klappt:
#include <stdio.h>

unsigned char t2;

void Timer3_ISR (void) //interrupt 14
// t2 = Case-Nummer 1-22
{
    t2 = rand() % 22+2; // neue Zufallszahl generieren
    if (t2<23)
    {
        printf( "--> %d\n", t2);
    }
}

void main (void)
{
//  Timer3_Init (SYSCLK  12  10)

        // Initialisierung rnd-generator. Hier muss statt 8643
        // ein "echter" Zufallswert hin
        srand(8643);

//  EA = 1;

    while (1)
    {
        Timer3_ISR();
    }
}

Hilft Dir das weiter ?

Grüße
Andreas

von batty m. (battyman)


Lesenswert?

Hey Danke,

du hast damit aber "srand" doch in die "main (void)" gesetzt. Wenn ich 
dich beim letzem Mal richtig verstanden habe wird diese "echte 
Zufallszahl dann durch das Analoge Rauschen realisiert. Richtig?

von Andreas H. (ahz)


Lesenswert?

Marcel M. schrieb:
> du hast damit aber "srand" doch in die "main (void)" gesetzt.

Ja, da gehört sie ja auch hin. Bzw. in die Initialisierungsroutine 
Deines Programms. Mit dieser Routine setzt Du ja nur den Startwert des 
Randomgenerators.

>Wenn ich
> dich beim letzem Mal richtig verstanden habe wird diese "echte
> Zufallszahl dann durch das Analoge Rauschen realisiert. Richtig?

Nein.

Deine "Zufallszahlen" sind keine Zufallszahlen, sondern eine normale, 
kausale Folge. Also 100% Deterministisch.

Um das Ganze etwas "zufälliger" zu bekommen, kannst Du aber einen 
Startwert dieser Folge festlegen, der im Idealfall eine komplett andere 
Folge erzeugt.

Dieser Startwert (seed genannt) wird durch den Aufruf von srand() an den 
Generator übergeben. Im meinem Beispiel war das 8643.

Nimmst Du immer den gleichen Startwert, dann liefern alle Aufrufe von 
rand() auch immer wieder die gleiche Zufallszahlenfolge.

Um das zu verhindern, musst Du also den seed "zufällig" erzeugen. Das 
kann zu diesem Zeitpunt aber noch nicht durch rand() gemacht werden, da 
rand() ja immer noch auf seinem "Defaultwert" steht, der natürlich auch 
konstant ist.

Darum brauchst Du hier eine "echte" Zufallszahl. Und die erzeugst Du Dir 
z.B. so, wie ich das im Beitrag #3181981 (mein Post weiter oben im 
Thread) beschrieben habe.

Eine evtl. einfachere Methode wäre übrigens, den aktuellen State des 
Zufallsgenerators permanent zu speichern. So wird das z.B. bei Linux 
gemacht (siehst Du als Meldung beim runterfahren).

Bei uPs ist das etwas schwieriger, weil Du nicht weisst, wann der 
Benutzer den Strom wegnimmt, bzw. wann ein Reset kommt.
Hier ist eine (ungeschickte) Lösung, den State regelmäßig ins EEPROM zu 
sichern und beim Neustart in Main wieder zu restaurieren.
Allerdings wird Deine Folge dann endgültig periodisch (alle 
Kongruenzgeneratoren erzeugen ja eine periodische Folge)

Am besten alle 30000 Aufrufe von rand() mal kurz die oben beschriebenen 
"echte" Zufallszahl neu generieren und mit srand() an den Generator 
übergeben. Dann solltest Du nicht mehr ganz "vorhersehbar sein" ;-)

Grüße
Andreas

von batty m. (battyman)


Lesenswert?

Jo dank dir! :-)

Ich mach mich nächste Woche wieder bei und probiere das, von dir 
motivierte, Thema weiter zu vertiefen und umzusetzen.

von batty m. (battyman)


Lesenswert?

Tach mal wieder ;-)

wie schon geschrieben wollte ich mich mal wieder mit dem 
Zufallsgenerator quälen und weiter in die Programmierung von µC 
einsteigen.

Den Tipp den auf dem Board befindlichen Temp-Sensor für die 
Rand-Start-Initialisierung zu nutzen, versuche ih nun seit 3 Tagen. Hab 
mich versucht durchs Datenblatt des C8051*** zu kämpfen und haben des 
Weiteren auf meiner CD ein Sample-TempSensor gefunden. Leider ist der 
als Assembler geschrieben und das raff ick nun leider noch weniger. Wie 
kann ich denn das benötigte aus dem Programm herausfiltern und in meines 
transferieren??

Wenn jmd. den Code dazu gerne sehen möchte, den kann ich bei belieben 
auch reinstellen.
eine Erklärung was ich denn aber eigentlich im Einzelnen tun muss währe 
mir auch sehr gelegen. Möcht das Themengebiet ja verstehen und den 
Umgang damit vertiefen, also warum man was wie macht.

Für weitere Hilfe-Stellung dank ich abermals :-)

von batty m. (battyman)


Lesenswert?

??? Hilfe ???

von Andreas H. (ahz)


Lesenswert?

Marcel M. schrieb:
> Hab
> mich versucht durchs Datenblatt des C8051*** zu kämpfen und haben des
> Weiteren auf meiner CD ein Sample-TempSensor gefunden. Leider ist der
> als Assembler geschrieben und das raff ick nun leider noch weniger. Wie
> kann ich denn das benötigte aus dem Programm herausfiltern und in meines
> transferieren??

Da kann ich Dir leider auch nicht mehr weiterhelfen. Meinen letzten 8051 
hatte ich vor >20Jahren auf dem Tisch.

Du wirst dann wohl mal die Nase in 8051 Asm reinstecken müssen. Das kann 
aber sowieso nicht schaden.

Das Beispiel könntest Du aber evtl. auch mal posten. Ist die Anstuerung 
des T-Sensors denn nicht irgendwo dokumentiert ? Normalerweise steht 
sowas doch im Datenblatt ?

Grüße
Andreas

von batty m. (battyman)


Lesenswert?

Mhh, ja das mit dem Temp-Sensor ist leider nur in ASM geschrieben und 
beschrieben. Ich muss ja erstmal mit einem halbwegs klar kommen. ;-)

von Andreas H. (ahz)


Lesenswert?

Marcel M. schrieb:
> Ich muss ja erstmal mit einem halbwegs klar kommen. ;-)

Das ist nicht so schwierig. Schau Dir z.B. mal an, was Dein C-Compiler 
aus dem C-Code macht. Da lernt man relativ schnell, wie es geht.
Ein Blick ins DS kann dabei auch helfen ;-)

Grüße
Andreas

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.