mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik Zufallsfunktion weigert sich, ihren Dienst zu leisten.


Autor: Pia (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hey Jungs,

ich habe ein Problem  mit folgendem Code:
#define F_CPU 4800000L
#include <avr/io.h>
#include <util/delay.h>
#include <stdlib.h>

int zufall(int min, int max) {
  return min + (rand() % max);
}

void main() {
  DDRB = 0xFF;
  PORTB = 0xFF;
  srand(1);
  
  while(1) {
    // Zwischen einer und drei Sekunde warten, ...
    int i = zufall(100, 200);
    for(; i > 0; i--) {
      _delay_ms(10);
    }
    
    // ..., dann PORTB togglen.
    PORTB ^= 0xFF;
  }
}

Wenn ich i eine beliebige Konstante zuweise, funktioniert das alles. Mit 
meiner kleine "Zufallsfunktion" allerdings nicht. Die scheint irgendwie 
immer 0 zurückzugeben.
Ich brauche keine wirklich zufälligen Zahlen. Deshalb reicht es mir, 
wenn jedesmal die gleiche Reihenfolge kommt => daher srand(1). Sollte 
doch eigentlich gehen, oder nicht?

Hoffe, Mann/man kann mir helfen :)
Pia

: Gesperrt durch Moderator
Autor: Lothar Miller (lkmiller) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Die scheint irgendwie immer 0 zurückzugeben.
Wie kommst du darauf?
Was passiert, wenn du sowas machst:
int zufall(int min, int max) {
  return min + 100;
}



Richtiger wäre:
int zufall(int min, int max) {
  return min + (rand() % (max-min));
}
Dann gehen die Werte von min bis max

Autor: Walter (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Lothar Miller schrieb:
> Dann gehen die Werte von min bis max

bzw. von min bis max-1

Autor: Pia (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Achja,
int zufall(int min, int max) {
  return min + (rand() % (max-min));
}
meinte ich auch. Hatte nur rumprobiert und das rausgenommen. Und 
vergessen, es wieder einzufügen.

Das da scheinbar immer 0 zurückgegeben wird, erkenne ich daran, dass die 
an PB3 angeschlossene LED nicht - oder schneller als meine Äuglein es 
wahrnehmen können, blinkt.

Bei
int zufall(int min, int max) {
  return min + 100;
}
 blinkt die LED ganz gleichmäßig. Das Problem muss also irgendwo bei dem 
"(rand() % (max-min))" liegen.

Autor: Erdnuckel (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich weiß keine Lösung für dein Problem, kann aber zwei Sachen dazu 
sagen:

1.
Wenn man dein Programm mit dem gcc kompiliert und zufall() ein paarmal 
aufruft, kommen "Zufallszahlen" bei raus, also die Funktion gibt nicht 
immer nur 0 zurück.

2.
Der Vorschlag von Lothar Miller war nicht richtig, da du der Funktion ja 
Werte 100 und 200 übergibst, aber bis zu 300 erhalten willst, wie ich 
das verstehe, also war deine alte Zufallsfunktion richtig.

Ich weiß nicht was das macht: PORTB ^= 0xFF; Das ist aber richtig, ja?

Autor: anfänger (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
wird rand wirklich einen integer zurückgeben??
ich erinnere mich an ein rand , was immer float geliefert hat - beim 
runden
bleibt dann nix ...

nur so eine vermutung

Autor: Erdnuckel (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
anfänger schrieb:
> wird rand wirklich einen integer zurückgeben??
> ich erinnere mich an ein rand , was immer float geliefert hat - beim
> runden
> bleibt dann nix ...

Das war bei Java so^^

Autor: Lothar Miller (lkmiller) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Der Vorschlag von Lothar Miller war nicht richtig, ...
> also war deine alte Zufallsfunktion richtig.
Schon schön, aber dann wären ja die Namen der Übergabewerte extremst 
unintiutiv gewählt. Das mit dem max-1 war mir klar. Richtig müsste die 
Funktion also heissen:
int zufall(int min, int max) {
  return min + (rand() % (max+1-min));
}

> Ich weiß nicht was das macht: PORTB ^= 0xFF; Das ist aber richtig, ja?
Ja, das invertiert einfach alle Bits vom Port B

Autor: Volker Schulz (volkerschulz)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hab den Code aus dem allerersten Post mal eben auf einen ATMEGA8 (auf 
einem STK500) gebracht und es funktioniert alles einwandfrei...


Volker

Autor: Pia (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Habe das ganze soeben mal auf einen ATmega48 draufgeschubst. Da gibt's 
aber genau das gleiche Problem - am Code kanns also eigentlich nicht 
liegen, weil der Mega48 dem Atmega8 ja recht ähnlich ist und es auf dem 
läuft.

Komplieren tu ich das mit
avr-gcc -Os -o main.hex main.c
, auf den uc schubs ich's mit
avrdude -c avrispv2 -p m48 -P usb -U flash:w:main.hex

Programmer ist ein AVRISP MKII.




> hey pia,
> wie wärs mit nem bild und ner telefonnummer ??
> lach!
Bist du aber auch der einzige, der lacht. Lustig war das nämlich nicht 
...

Autor: Pia (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Und ob zufall() nun werte von 100 bis 200, von 100 bis 201 oder von 100 
bis 299 liefert, ist für den Anfang eigentlich egal. Bei all diesen 
Werten müsste man eigentlich ein gut sichtbares, unregelmäßiges Blinken 
sehen :S

Autor: Volker Schulz (volkerschulz)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Build started 18.2.2010 at 22:23:45

avr-gcc  -mmcu=atmega8 -Wall -gdwarf-2 -Os -std=gnu99 -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums -MD -MP -MT RandomTest.o -MF dep/RandomTest.o.d  -c  ../RandomTest.c

../RandomTest.c:10: warning: return type of 'main' is not 'int'

avr-gcc -mmcu=atmega8 -Wl,-Map=RandomTest.map RandomTest.o     -o RandomTest.elf

avr-objcopy -O ihex -R .eeprom -R .fuse -R .lock -R .signature  RandomTest.elf RandomTest.hex

avr-objcopy -j .eeprom --set-section-flags=.eeprom="alloc,load" --change-section-lma .eeprom=0 --no-change-warnings -O ihex RandomTest.elf RandomTest.eep || exit 0

avr-objdump -h -S RandomTest.elf > RandomTest.lss

So kompiliert das AVR-Studio... ;)


Volker

Autor: jl (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Versuch doch mal alles etwas lesbarer zu schreiben :-), dann kannst du 
auch versuchen schrittweise einzugrenzen.


> int zufall(int min, int max) {
    int result;

    result = rand();
    result %= max;
    result += min;

    return(result);

>   return min + (rand() % max);
> }


> void main() {
>   DDRB = 0xFF;
>   PORTB = 0xFF;
>   srand(1);
>
>   while(1) {
>     // Zwischen einer und drei Sekunde warten, ...
>     int i = zufall(100, 200);
      ??? -> wird die initialisierung in jeder while loop aufgerufen 
oder nur einmal ???
      ??? -> deklaration am beginn der Funktion und nicht mittendrin
             (auch wenn es möglicherweise funktioniert)

      i = zufall(100,200);



>     for(; i > 0; i--) {
>       _delay_ms(10);
>     }
>
>     // ..., dann PORTB togglen.
>     PORTB ^= 0xFF;
>   }
> }

Autor: Pia (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hatte in der Tat nichts mit dem Code zu tun. Wenn man das ganze vom gcc 
als .elf-Datei kompiliert und anschließend mit avr-objcopy ins Intel 
Hex-Format umwandelt und dann draufstubst, geht es.

Jemand eine passende Erklärung parat? :D

Autor: Christian H. (netzwanze) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Du hast immer den gleichen falschen und alten Code eingespielt.
Eine Codeänderung brachte daher nie etwas.

Kannst Du mal Dein Makefile und die Ausgaben beim Compilieren schicken?
Das vereinfacht die Erklärung.

Autor: Volker Schulz (volkerschulz)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
jl schrieb:
> ??? -> wird die initialisierung in jeder while loop aufgerufen
> oder nur einmal ???
> [...]
> ??? -> deklaration am beginn der Funktion und nicht mittendrin
> (auch wenn es möglicherweise funktioniert)

Das Deklarieren von Variablen "mittendrin" funktioniert nicht nur 
"moeglicherweise" sondern ist seit bestimmt 10 Jahren C-Standard. 
Mehrfaches Deklarieren einer Variablen gilt es jedoch in der Tat zu 
vermeiden.


Christian H. schrieb:
> Du hast immer den gleichen falschen und alten Code eingespielt.
> Eine Codeänderung brachte daher nie etwas.

Ich kann Deinen Gedankengang nicht so ganz nachvollziehen. Alleine schon 
weil
Pia schrieb:
> Wenn ich i eine beliebige Konstante zuweise, funktioniert das alles.


Volker

P.S.:
srand(1);
ist ueberfluessig. Schadet aber auch nicht. ;)

Autor: Pia (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ein Makefile habe ich nicht. Habe avr-gcc und avrdude "per Hand" 
aufgerufen:
> avr-gcc -Os -o main.hex main.c
> avrdude -c avrispv2 -p m48 -P usb -U flash:w:main.hex

Die Konsolenausgaben kann ich dir schicken, sobald ich zuhause bin.
Da war aber weder ein Fehler, noch eine Warnung oder sonstwas. Alles 
erfolgreich.

Autor: Pia (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>  avr-gcc -Os -mmcu=atmega48 -o main.hex main.c
Keine Ausgabe.

>  avrdude -c avrispv2 -p m48 -P usb -U flash:w:main.hex

avrdude: AVR device initialized and ready to accept instructions

Reading | ################################################## | 100% 
0.01s

avrdude: Device signature = 0x1e9205
avrdude: NOTE: FLASH memory has been specified, an erase cycle will be 
performed
         To disable this feature, specify the -D option.
avrdude: erasing chip
avrdude: reading input file "main.hex"
avrdude: input file main.hex auto detected as raw binary
avrdude: writing flash (4096 bytes):

Writing | ################################################## | 100% 
2.18s

avrdude: 4096 bytes of flash written
avrdude: verifying flash memory against main.hex:
avrdude: load data flash data from input file main.hex:
avrdude: input file main.hex auto detected as raw binary
avrdude: input file main.hex contains 4096 bytes
avrdude: reading on-chip flash data:

Reading | ################################################## | 100% 
1.96s

avrdude: verifying ...
avrdude: 4096 bytes of flash verified

avrdude: safemode: Fuses OK

avrdude done.  Thank you.



Nichts ungewöhnliches, oder?

Autor: Stefan B. (stefan) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Also funktioniert jetzt alles oder gibt es noch Probleme?

Pia schrieb:
>>> Hatte in der Tat nichts mit dem Code zu tun. Wenn man das ganze vom gcc
>>> als .elf-Datei kompiliert und anschließend mit avr-objcopy ins Intel
>>> Hex-Format umwandelt und dann draufstubst, geht es.

Das ist der von Hand-und-zu-Fuß-Weg. Automatisieren kann man das in 
einem Makefile.

> avr-gcc -Os -mmcu=atmega48 -o main.hex main.c
> avrdude -c avrispv2 -p m48 -P usb -U flash:w:main.hex

IMHO fehlt da die Umwandlung der Binärausgabe in das Intel-Hex-Format 
mit dem Tool avr-objcopy.

Avrdude mosert das auch an:
> avrdude: input file main.hex auto detected as raw binary

Ich habe bisher d.h. bis eben :) noch nie gelesen, dass man diesen 
Schritt mit avr-objcopy überspringen kann indem man per -o Option die 
Hexdatei erzeugt.

In der GCC Doku 
(http://gcc.gnu.org/onlinedocs/gcc-4.3.2//gcc/index.html) taucht hex als 
Ausgabeformat auch nicht auf:
-o file     
    Place output in file file. This applies regardless to whatever 
sort of output is being produced, whether it be an executable file, 
an object file, an assembler file or preprocessed C code.

Es ist die Frage, was avr-gcc jetzt erzeugt hat... irgendein "raw 
binary". Ist das ein "executable file" oder "an object file". D.h. wurde 
die Library mit der rand()-Funktion zum Objektcode aus dem Quelltext 
dazugelinkt oder nicht?

Auf RN (http://www.rn-wissen.de/index.php/Avr-gcc/Interna) gibt es eine 
schöne Übersicht, wie aus Quelltext ein FLASHROM-Inhalt wird.

Dort steht ein Hinweis zu einer bestimmten Option, um aus avr-gcc heraus 
die Hexdatei direkt zu erzeugen. Diese Option -Wl,--oformat=ihex sehe 
ich bei deiner Kommandozeile nicht. Sie kann aber in deine avr-gcc 
Version einkompiliert sein.

Um das zu kontrollieren und ob avr-gcc den Linker aufgerufen hat oder 
nicht, könntest du -v in die avr-gcc Kommandozeile aufnehmen.
-v
    Print (on standard error output) the commands executed to run 
the stages of compilation. Also print the version number of the 
compiler driver program and of the preprocessor and the compiler 
proper.

Autor: yousra (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
ich habe ein problem damit das mein msn sich weigert etwas einzufügen 
wenn ich etwas anders kopiere weiss jemand was man da mahccen kann ?

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Man kann
* eine Frage so formulieren, bzw. vor dem Absenden noch einmal
  korrekturlesen.
  Dabei darauf auchten: Jemand der nicht mit mir vor dem Bildschirm
  sitzt, kann der mein Problem zweifelsfrei nachvollziehen?
* einen eigenen Thread für sein Problem aufmachen und nícht einfach
  irgendeinen anderen für eine Frage zweckentfremden

Versuchs noch einmal

Dieser Beitrag ist gesperrt und kann nicht beantwortet werden.