Forum: Mikrocontroller und Digitale Elektronik Zufallszahlen & Watch-Window (AVR-Studio)


von Andreas Brunner (Gast)


Lesenswert?

Hallo zusammen!

Folgende Situation bei mir...hab ein STK500 mit Tiny13, funktioniert 
alles prima bisher. Hier gleich eine kleine Frage am Rande: Hab 
folgendes Programm:
1
#include <avr/io.h> 
2
#include <stdint.h>
3
#include <avr/delay.h> 
4
#include <stdlib.h>
5
 
6
inline uint8_t debounce(volatile uint8_t *port, uint8_t pin) //Tasterentprellung
7
{
8
    if ( ! (*port & (1 << pin)) )
9
    {
10
        /* Pin wurde auf Masse gezogen, 100ms warten   */
11
        _delay_ms(50);  // max. 262.1 ms / F_CPU in MHz
12
        _delay_ms(50); 
13
        if ( *port & (1 << pin) )
14
        {
15
            /* Anwender Zeit zum Loslassen des Tasters geben */
16
            _delay_ms(50);
17
            _delay_ms(50); 
18
            return 1;
19
        }
20
    }
21
    return 0;
22
}
23
24
unsigned short get_seed() //Startwert für rand() erzeugen
25
{
26
   unsigned short seed = 0;
27
   unsigned short *p = (unsigned short*) (RAMEND+1);
28
   extern unsigned short __heap_start;
29
    
30
   while (p >= &__heap_start + 1)
31
      seed ^= * (--p);
32
    
33
   return seed;
34
}
35
36
37
int main (void)
38
{            
39
  DDRB = 0b001111; //PB4 als Eingang, PB0-3 als Ausgang
40
41
  PORTB &= ~ ((1<<PB2) | (1<<PB3)); // PB2 und 3 einschalten
42
  PORTB |= (1<<PB0) | (1<<PB4); // PB0 ausschalten, PB4 internen Pull-up deaktivieren
43
44
  uint16_t zufall;
45
  
46
  while(1)
47
  {
48
    if (debounce(&PINB, PB4))   
49
    {
50
      PORTB = PINB ^ (1<<PB1) ^ (1<<PB0);
51
      srand(get_seed());
52
      zufall = rand();  
53
    }
54
  }                       
55
  return 0;                 
56
}
Hab mit diesem Programm schon 63% des Programmspeichers vom ATtiny13 
verbraucht, hätte echt nicht gedacht, dass der so schnell voll wird. Und 
dazu meine Frage: wirken sich die inkludierten Header-Files auf die 
Größe des Programms aus oder werden nur die benötigten Funktionen am µC 
gespeichert? Das würde ja irgendwie erklären warum dieses Miniprogramm 
schon so viel Platz benötigt...

Aber jetzt zur richtigen Frage. Will letztlich mit diesem µC einen 
Würfel ansteueren. Hab mich über die Erzeugung von Zufallszahlen schon 
ausreichend informiert und mich letztendlich für die Variante mit dem 
SRAM entschieden, da sie für diese Anwendung vollkommen ausreicht. Wie 
kann ich jetzt
1) den Zufallszahlenbreich auf 1-6 eingrenzen und
2) wenn ich im Watch-Window im AVR-Studio die Variable "zufall" ansehen 
will, steht bei Value immer nur "Location not valid". Was ist hier 
falsch?

Zu 1) Wäre das eine Möglichkeit?
1
int zufallszahl ()
2
{
3
  int x;
4
5
  while( (x = rand()) >= RAND_MAX - (RAND_MAX % 6) )
6
    ; 
7
  return x % 6;
8
}

Danke schon mal,
Lg Andi

von Tobias (Gast)


Lesenswert?

Von Zufallszahlenerzeugung hab ich keine Ahnung, aber was die größe des 
Codes angeht, hast du die Codeoptimierung aktiviert?

von Andreas Brunner (Gast)


Lesenswert?

Optimierung ist auf "-Os" eingestellt.

von Stefan H. (stefanhennig)


Lesenswert?

Zu 1): Nach langem Nachdenken bin ich zur Überzeugung gekommen, dass 
dieser Code wahrscheinlich sehr schlau ist. Ich hätte nie daran gedacht, 
dass es nicht gleich viele Zufallszahlen kongruent zu 0,1,2,3,4,5 gibt, 
wenn RAND_MAX kein Vielfaches von 6 ist. Aber wenn der 
Zufallszahlengenerator so gut ist, wie die halt normalerweise so sind, 
dann ist dass auch nur Zuckerguss auf einem Sandkuchen. Allerdings gibst 
Du einen int zurück, wo ein uint16 erwartet wird und ein uint8 reichen 
würde. Das ist unordentlich.

Zu 2): Das kann ich beantworten: Die Variable wurde wegoptimiert, weil 
sie nur beschrieben und nie gelesen wurde.

Aber warum verwendest Du überhaupt rand() aus der stdlib? Hast Du 
Zugriff auf die Numerical Recipes? Da gibt's doch sicherlich einen 
10-Zeiler, der gut genug ist für einen Würfel. Ich nehme mal an, dass 
sich dann auch Dein Speicherverbrauch besser in den Griff bekommen 
lässt.

von Karl H. (kbuchegg)


Lesenswert?

Und solltest du bei rand() bleiben dann zieh den Aufruf der srand vor 
die while Schleife.

Zufallszahlengeneratoren funktionieren nur dann vernünftig, wenn man sie 
in Ruhe arbeiten lässt. Den ersten Seed gibt man vor (ev. in irgendeiner 
Form von einer Benutzeraktion abhängig) und dann lässt man den Seed 
tunlichst in Ruhe! Nur so kann der Generator seine Normalverteilung 
(oder was er sonst für eine Verteilung hat) aufbauen.

von Andreas Brunner (Gast)


Lesenswert?

Also sollte "zufall" als uint8_t und nicht als uint16_t definiert sein, 
um es sauber zu machen?

Naja, aus den Numerical Recipes werd ich nicht schlau, aber diese 
Variante des Zufallsgenerators ist eh schon recht kurz. Wie könnte ich 
den am einfachsten diese Zufallszahl einfach an Port B mit 4 Leds 
(einfach in BCD Code) ausgeben?

von Andreas Brunner (Gast)


Lesenswert?

Das hatte ich ganz vergessen dass das srand() aus der Schleife raus 
gehört. Ich hab jetzt einfach mal ganz plump PORTB = zufall; 
geschrieben, so sehe ich in der Simulation, dass sich bei jedem 
Tastendruck dann an Port B etwas ändert, also dass sollte dann schon mal 
funktionieren. Jetzt fehlt nur noch die Eingrenzung auf 1 bis 6.

von Karl H. (kbuchegg)


Lesenswert?

Andreas Brunner schrieb:
> Das hatte ich ganz vergessen dass das srand() aus der Schleife raus
> gehört. Ich hab jetzt einfach mal ganz plump PORTB = zufall;
> geschrieben, so sehe ich in der Simulation, dass sich bei jedem
> Tastendruck dann an Port B etwas ändert, also dass sollte dann schon mal
> funktionieren. Jetzt fehlt nur noch die Eingrenzung auf 1 bis 6.

Deine Funktion zufallszahl() macht das schon.
Die macht das sogar sehr gut.

von Andreas Brunner (Gast)


Lesenswert?

Scheint zu funktionieren. Mein Problem ist jetzt wie gesagt die Ausgabe 
über die vier Leds...

von Karl H. (kbuchegg)


Lesenswert?

Andreas Brunner schrieb:
> Scheint zu funktionieren. Mein Problem ist jetzt wie gesagt die Ausgabe
> über die vier Leds...

Versteh ich nicht.
Das ist doch der leichteste Teil der Übung.
Einfach an den Port rausgeben, so wie du das schon gemacht hast.

   PORTB = zufall | ( 1 << PB4 );  // damit der Pullup nicht flöten geht

von Andreas Brunner (Gast)


Lesenswert?

Achso, na dann scheint es doch eh irgendwie zu stimmen ^^ Aber auch eben 
nur irgendwie, denn die Leds sind wenn ich mich richtig entsinne 
active-Low, also hab ich mal geschaut, welche Werte da mit den Leds zu 
Tage kommen, und habe festgestellt, dass 6 nicht vorkommt. Es war nur 
0-5 zu sehen...hab ich doch glatt das "+1" bei der Berechnung vergessen. 
Jetzt scheint der Generator fertig zu sein!

Alles weitere wird hoffentlich kein Problem mehr...und braucht auch 
hoffentlich nicht mehr zu viel Speicherplatz ^^

Danke für die Hilfe,
Lg Andi

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.