mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik Zufallszeit bestimmen - solange Taster gedrückt? (MSP430, in C)


Autor: Olliver (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi,
ich möchte eine Zufallszeit zwischen 1000 und 5000 Millisekunden 
bestimmen.

Nach einiger Recherche bin ich mittlerweile bei dem Lösungsansatz 
"Erzeugung einer Zufallszahl mittels Tasten" angelangt. Soweit ich das 
richtig verstanden habe, ist die Lösung am "einfachsten".

So würde ich bei meinem Programm die Zufallszahl erzeugen, indem ich die 
Dauer des Tastendrucks auswerte bzw. so eine Zufallszahl erzeugt wird.
Ist dieser Ansatz gut/okay?

Doch wie realisiere ich die Generierung?

Mein Ansatz:

int zufallszahl=0; //init

int main( void )
{
  WDTCTL = WDTPW + WDTHOLD;
  P3IE = 0x27               // Interrupt enable
  __enable_interrupt();     // Interrupt aktivieren
  __low_power_mode_3();     // LPM3 => 0,8 uA

  return 0;
}


#pragma vector=PORT3_VECTOR
__interrupt void P3_ISR(void)
{
 while (P3IFG)
  {
    zufallszahl++;
    if (zufallszahl==5000) zufallszahl=1000;
}


Aber irgendwie klappt das leider nicht :( Die Zufallszahl bleibt immer 
gleich. Kann mir jemand helfen? Evtl. auch generelle 
Verbesserungsvorschläge?

Vielen Dank schonmal,

vg Olli

Autor: Uwe ... (uwegw)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich kenn die Syntax für den MSP nicht, aber P3IFG hört sich irgendwie 
nach Interruptflag an. Du müsstest stattdessen das Bit pollen, das dir 
angibt ob die Taste gedrückt ist oder nicht.

Und üblicherweise gewinnt man mit dieser Methode erst mal nur eine 
Zufallszahl (die aber noch nicht sehr gut normalverteilt ist) und nimmt 
sie dann als seed für die rand()-Funktion. Die liefert dann bessere 
Zufallszahlen.

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

Bewertung
0 lesenswert
nicht lesenswert
Wird der Interrupt aufgerufen
a) wenn eine Taste gedrückt wird    oder
b) solange eine Taste gedrückt ist

Wharscheinlich macht dein µC ersteres, du willst aber letzteres.

Tasten wertet man eigentlich nicht mittels Interrupt aus. Also einfach 
den Portpin abfragen und wenn der sich im Zustand 'gedrückt' befindet 
(entweder 0 oder 1, je nach deiner Hardware) dann den Zufallszahlen 
Zähler erhöhen so wie du das gemacht hast.

Autor: Stefan B. (stefan) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Entprellung des Tasters beachten, sonst ist deine Zufallszahl die 
Prellzeit :)

Manche Compiler optimieren dir den die Anweisungen im while-Block 
radikal weg, weil zufallszahl nicht volatile gekennzeichnet ist.

Die P3_ISR könnte IMHO in einer Endlosschleife stecken bleiben oder 
wirkunslos sein, jenachdem wann dein µC das P3IFG löscht. 
Endlosschleife, wenn es beim Verlassen der ISR gelöscht wird; 
wirkungslos wenn es beim Eintritt in die ISR gelöscht wird.

Hat deine C-Library keine rand() Funktion? Als Seed (=> srand()) 
könntest du die Zeit bis zum ersten Tastendruck (oder sonst eine 
Pseudozufallseingabe) nehmen, und dann rand() eine Zufallszahl 
generieren lassen.

Autor: viel wissen, aber keine Ahnung haben (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
nach mein Wissen gitb es in C ein Befehl der Random heißt.

Vielleicht diesen benutzen, dann sind die Zahlen auch mehr zufällig, als 
hoch gezählt wie in folgender Funktion deines Programms:
__interrupt void P3_ISR(void)
{
 while (P3IFG)
  {
    zufallszahl++; // *1
    if (zufallszahl==5000) zufallszahl=1000; // *2
}


zu 1: plus eins, so lange while die Bedingung nicht erfüllt.
zu 2: wenn die Zahl gleich 5000 ist setz sie auf 1000 runter

PS... da fehlt eine } ... kann so ja nicht funktionieren ;-)

Weiter kann ich dein Code nicht auseinander pflücken, da mit der µC 
fremd ist

Autor: Olliver (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

vielen Dank schonmal für eure Antworten.
Mit rand könnte man das auch lösen - stimmt. Danke für den Tipp. Aber 
trotzdem würd ich gern wissen wie man es mit dem Taster lösen könnte 
bzw. wo mein Fehler liegt. Leider wird so keine Zufallszahl erzeugt. 
Weiß jemand vielleicht wo der Fehler liegt?



int zufallszahl=1000;

int main( void )
{
  WDTCTL = WDTPW + WDTHOLD;
  P1DIR = 0xFF; // P1.0-P1.7 als Output
  P3IES = 0x27;             // BIT0, BIT1,BIT2,BIT5 Alle 4 Taster;
  P3IE = 0x27;              // Interrupt enable für die 4 Taster
  P1OUT = 0x0F; // LED 1-4 ON FF=Aus(!!!)
  __enable_interrupt();     // Interrupt aktivieren
  __low_power_mode_3();     // LPM3 => 0,8 uA
  return 0;
}


#pragma vector=PORT3_VECTOR
__interrupt void P3_ISR(void)
{
  P1OUT = 0xFF; // LED 1-4 on -> Daran sieht man das Interrupthandler 
aufgerufen wird.

  while (P3SEL)   //P3SEL müsste laut UserGuide richtig sein
  {
    zufallszahl++;
    if (zufallszahl==5000) zufallszahl=1000;
  }
  int i= zufallszahl;
}

i müsste einen zufälligen Wert enthalten, dem ist leider nicht so :(

Vielen Dank im Voraus,

vg Olli

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

Bewertung
0 lesenswert
nicht lesenswert
Olliver schrieb:

> trotzdem würd ich gern wissen wie man es mit dem Taster lösen könnte
> bzw. wo mein Fehler liegt.

Dazu müsste man erst mal wissen, worauf der Interrupt reagiert. Auf die 
Flanke oder auf den Pegel.
Da hier mehr die AVR-Spezialisten unterwegs sind, musst du das 
mitteilen.

> Weiß jemand vielleicht wo der Fehler liegt?

Die Vermutungen wurden ja schon geäussert.


> int main( void )
> {
>   WDTCTL = WDTPW + WDTHOLD;
>   P1DIR = 0xFF; // P1.0-P1.7 als Output
>   P3IES = 0x27;             // BIT0, BIT1,BIT2,BIT5 Alle 4 Taster;
>   P3IE = 0x27;              // Interrupt enable für die 4 Taster
>   P1OUT = 0x0F; // LED 1-4 ON FF=Aus(!!!)
>   __enable_interrupt();     // Interrupt aktivieren
>   __low_power_mode_3();     // LPM3 => 0,8 uA
>   return 0;
> }

Keine Endlosschleife?
Was macht dein µC, wenn er aus main() rausfällt?

> #pragma vector=PORT3_VECTOR
> __interrupt void P3_ISR(void)

Wann wird dieser Interrupt aufgerufen:
wenn sich der Pegel ändert oder solange der Pin einen bestimmten Pegel 
hat?

Autor: Olli (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

danke für die Hilfe.

>Keine Endlosschleife?
>Was macht dein µC, wenn er aus main() rausfällt?

Achso, also gehört immer eine Endlosschleife wie while(1) {} oder for 
(;;) in die Mainfunktion? Aber was sollen die Schleifen enthalten? 
Sorry, bin noch ziemlich neu auf dem Gebiet - wie man sicher bemerkt ;)



> #pragma vector=PORT3_VECTOR
> __interrupt void P3_ISR(void)

>Wann wird dieser Interrupt aufgerufen:
>wenn sich der Pegel ändert oder solange der Pin einen bestimmten Pegel
>hat?

Der Interrupt reagiert auf die Flanke

Vg Olli

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

Bewertung
0 lesenswert
nicht lesenswert
Olli schrieb:

>>Keine Endlosschleife?
>>Was macht dein µC, wenn er aus main() rausfällt?
>
> Achso, also gehört immer eine Endlosschleife wie while(1) {} oder for
> (;;) in die Mainfunktion? Aber was sollen die Schleifen enthalten?
> Sorry, bin noch ziemlich neu auf dem Gebiet - wie man sicher bemerkt ;)

Üblich ist zb, dass die Runtime Library nach der Rückkehr aus main den 
Prozessor anhält. Was soll er auch sonst vernünftiges tun? Das Progrmm 
ist ja offiziell zu ende.

>> #pragma vector=PORT3_VECTOR
>> __interrupt void P3_ISR(void)
>
>>Wann wird dieser Interrupt aufgerufen:
>>wenn sich der Pegel ändert oder solange der Pin einen bestimmten Pegel
>>hat?
>
> Der Interrupt reagiert auf die Flanke

Na ja. Was erwartest du dann?
Du drückst die Taste einmal, der Interrupt wird aufgerufen, zählt einmal 
hoch (wenn überhaupt, denn das Programm ist ja offiziell schon zu ende, 
so schnell kannst du nicht drücken nachdem das Programm gestartet 
wurde). D.h. dein Haochzählen findet genau einmal statt. Und das wars 
dann.

Vorschlag: Vergiss die Idee mit dem Interrupt. Braucht kein Mensch.
Dein Programm startet und wartet darauf, dass die Taste gedrückt wird. 
Während die Taste gedrückt ist, erfolgt das Hochzählen und wenn die 
Taste losgelassen wird hast du dein Ergebnis.

Wie man einen ganz bestimmten Portpin abfrägt ob er 0 oder 1 ist, ist 
ein Wissen, das du sowieso brauchst.

Autor: Olli (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>Dein Programm startet und wartet darauf, dass die Taste gedrückt wird.

Genau das wollte ich ja mit dem Interrupt lösen. Also würdest du 
alternativ vorschlagen in der main:
while(1)
{ if (Taste gedrückt) ... }


>Während die Taste gedrückt ist, erfolgt das Hochzählen und wenn die Taste 
>losgelassen wird hast du dein Ergebnis.

Genau das wollte ich ja auch mit der Whileschleife erzielen.

  while (P3SEL)
  {
    zufallszahl++;
    if (zufallszahl==5000) zufallszahl=1000;
  }


Okay, dann liegt der Fehler anscheinend an der Bedingung in der 
Whileschleife (P3SEL) und vielleicht an der nicht vorhandenen 
Endlosschleife im Mainprogramm...

Vielen Dank für die Hilfe,

vg Olli

Autor: Florian (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Die einfachste Möglichkeit echte Zufallszahlen zu erzeugen, ist es, 
die Rauschspannung an einem offen in der Luft baumelnden A/D Wandler Pin 
zu messen. Wenn Dein MC also einen A/D Wandler integriert hat...

Autor: Dennis (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Olli: Also dein erster Ansatz mit dem LPM ist besser als von anderen 
hier vorgeschlagen mit einer Endlosschleife. Der MSP430 ist ein 
"Ultra-Low-Power" Mikrocontroller, da versucht man alles mit Interrupts 
abzuarbeiten, und in main() entweder dauerhaft im LPM zu sein (dann 
brauchst du eigentlich auch keine while-schleife, wenn deine interrupts 
nicht den aktiv-modus für main aktivieren)
ansonsten wohl eher sowas in main:

while(1)
{
  while (EventFlag1 > 0 || EventFlag2 > 0)
  {
    if(EventFlag1 > 0)
       do_something();
    if(EventFlag2 > 0)
       do_something_else();
  }
  __bic_SR_register(LPM0_bits + GIE);
  __no_operation();
}

Ich denke es wird in etwa ersichtlich was gemeint ist:
Dann machst du interrupts welche dir diverse globale Event Flags setzen 
können, die dann in main abgearbeitet werden können. Ansonsten, während 
nichts passiert, ist dein System im low-power modus....
Die interrupts können dann durch __bis_SR_register_on_exit(LPM4_bits); 
das Status-Register, welches auf dem Stack liegt, manipulieren. Wenn die 
interrupt service routine dann zu Ende ist, läuft die main-schleife nach 
dem __bic_SR_register(LPM0_bits + GIE) weiter und steckt nicht im 
low-power-modus fest.

Aber zurück zu deinem eigentlichen Taster-Problem:

Eine andere Möglichkeit wäre einfach einen Timer laufen zu lassen... 
Dann machst du einen Taster-Interrupt, und liest dann dort den 
Timer-Wert aus - fertig.
Pollen ist doch unschön, und Low-Power ist das dann auch nicht...

Andererseits, wenn du wirklich die Zeit des Tastendrucks aufnehmen 
willst (da hast du dann aber wahrscheinlich eher eine Gauss-Verteilung 
um einen bestimmten Wert, und kein so richtiges "random"):

Also interrupts sind durch Flanken bestimmt, Auszug aus dem User Guide:
"If any PxIFGx flag becomes set during a Px interrupt
service routine, or is set after the RETI instruction of a Px interrupt 
service routine is executed, the set
PxIFGx flag generates another interrupt. This ensures that each 
transition is acknowledged."

D.h. du kannst einfach die ISR wie folgt machen (in etwa):

Port-ISR:

static int level = 0;
if (level = 0) {
Timer-Modul starten, einfach von 0 ab laufen lassen
}
else
{
Timer-Modul stoppen und Wert notieren, dieser Wert ist dein Random-Wert
}
return...

Das wars! Völlig ohne while-Schleife in main, und völlig ohne unnötigen 
Stromverbrauch...

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.