Forum: Mikrocontroller und Digitale Elektronik zufalls-pwm erzeugen ATMEGA88


von vianney (Gast)


Lesenswert?

Hallo, an alle
ich hoffe ihr könnte mir helfen, ich habe als Aufgabe die erzeugung von 
PWM mit Hilfe von ATMEGA88 mit AVR zufälligeweise zu kreigen, bzw. die 
Pulsbreite oder das Tastverhältnis sollte zufällig erscheinen, aber nach 
einer gewiessen Zeit  klappt es nicht mehr. Ich habe ganz normal 
zufällige Zahlen erzeugt und die an meine OCRA gegeben. ich schicke 
anbei das programmcode damit ihr auch eine gute Vorstellung der Sachen 
habt.
danke schön im voraus



#include <avr\io.h>
#include <avr\interrupt.h>                        #include 
"lcd_lib_de.h"
#include <util\delay.h>
#include <stdbool.h>
#include <stdlib.h>
#define  RAND_MAX 0x7FFF

void Init_Timer_0(void);
void Init_Timer_1(void);
void Displayanzeigen(void);
void mainDisplay(void);
void initDisplay(void);
void ZufallsZahlgenerieren(void);
int Zufallszahl;
int Zahl,Zahl_0,Zahl_1;

int main (void)

  //Hauptschleife

{
    DDRB |= (1 << PB2);
    Init_Timer_0();

    DDRB |= (1 << PB1);
    Init_Timer_1();
    while(1)
    {
    }
    return 0;
}

void Init_Timer_0(void)
{

    TCCR1A |= (0<<COM1B0) | (1<<COM1B1);
   TCCR1B |= (1<<CS10)|(1<<WGM13);
   for(Zahl_0=100;Zahl_0>44;Zahl_0=Zahl_0+1)
   {
       int Zahl_0;
      if(Zahl_0<44)
      { Zahl_0 = (min + ((float) rand() / RAND_MAX * (max - min +1)));
}
  OCR1B = Zahl_0 ;
}
      ICR1 = 181;

}



void Init_Timer_1(void)
{
  TCCR1A |= (1<<COM1A0)|(1<<COM1A1) ;
  TCCR1B |= (1<<WGM13)|(1<<CS10);
   for(Zahl_1=200; Zahl_1>144;Zahl_1=Zahl_1+1)
   {
       int Zahl_1;
   if(Zahl_1<144)
      { Zahl_1 = (min + ((float) rand() / RAND_MAX * (max - min +1)));
}
  OCR1A = Zahl_1;
}
  ICR1 = 181;
}

von Karl H. (kbuchegg)


Lesenswert?

vianney schrieb:
> Hallo, an alle
> ich hoffe ihr könnte mir helfen, ich habe als Aufgabe die erzeugung von
> PWM mit Hilfe von ATMEGA88 mit AVR zufälligeweise zu kreigen, bzw. die
> Pulsbreite oder das Tastverhältnis sollte zufällig erscheinen, aber nach
> einer gewiessen Zeit  klappt es nicht mehr.

Wundert mich nicht besonders


> int main (void)
>
>   //Hauptschleife
>
> {
>     DDRB |= (1 << PB2);
>     Init_Timer_0();
>
>     DDRB |= (1 << PB1);
>     Init_Timer_1();
>     while(1)
>     {
>     }
>     return 0;
> }

Ich hätte jetzt eigentlich erwartet, dass die 'zufällige Umstellung der 
PWM' in der Hauptschleife erfolgen wird. Denn genau da findet sich der 
Prozessor ja nach der Initialisierungsphase wieder.

> void Init_Timer_0(void)
> {
>
>     TCCR1A |= (0<<COM1B0) | (1<<COM1B1);
>    TCCR1B |= (1<<CS10)|(1<<WGM13);
>    for(Zahl_0=100;Zahl_0>44;Zahl_0=Zahl_0+1)

Wie soll das gehen.
Zahl0 beginnt mit 100
Bei jedem Schleifendurchlauf kommt 1 dazu
Und die Schleife soll solange laufen, solange gilt  Zahl_0 > 44

Ich denke, dass ist nicht wirklich das was du dir vorstellst.
Zahl_0 wird solange erhöht, bis sie überlauft. Denn dann ist es erst der 
Fall, dass Zahl_0 nicht mehr größer als 44 ist.

Aber auf jeden Fall hätte ich diesen Teil ganz sicher nicht in einer 
Init-Fuunktion erwartet, der eigentlich nur die Aufgabe hat, die 
Grundbedingungen der PWM zu konfiguerieren.


Selbiges für Init_Timer_1

Denn: Irgendwann sind die Init Funktionen durch. Und was passiert dann? 
Dann geht das Hauptprogramm in main() in die Hauptschleife über und 
vorbei ist es mit deiner 'zufälligen PWM'

von R. M. (rmax)


Lesenswert?

Du deklarierst Zahl_0 und Zahl_1 jeweils innerhalb der For-Schleife 
erneut. Dadurch hast Du innerhalb der Schleife eine andere Variable als 
außerhalb. Außerdem enden die beiden For-Schleifen, sobald die 
Zählervariablen überlaufen und damit kleiner als 44 bzw 144 werden. Weil 
Du sie nicht neu startest, bleibt spätestens dann die Ausgabe stehen.

Was willst Du mit den Zahlen 100, 44, 200 und 144 denn überhaupt 
erreichen?

von vianney (Gast)


Lesenswert?

hallo,
vielen dank für ihr hilfe, ich hab verstanden und glaub jetzt klappt es 
sauber. so sieht das ganz aus

#include <avr\io.h>
#include <avr\interrupt.h>
#include "lcd_lib_de.h"
#include <util\delay.h>
#include <stdbool.h>
#include <stdlib.h>
#define  RAND_MAX 0x7FFF

void Init_Timer_0(void);
void Init_Timer_1(void);
void Displayanzeigen(void);
void mainDisplay(void);
void initDisplay(void);
void Zufallszahl_0(void);
void Zufallszahl_1(void);
int  Zahl_0,Zahl_1;




int main (void)

  //Hauptschleife


{

    DDRB |= (1 << PB2);
    Init_Timer_0();
    Zufallszahl_0();

    DDRB |= (1 << PB1);
    Init_Timer_1();
    Zufallszahl_1();

    while(1)
    {

    }
    return 0;
}


void Init_Timer_0(void)

{
    TCCR1A |= (0<<COM1B0) | (1<<COM1B1);

   TCCR1B |= (1<<CS10)|(1<<WGM13);
       OCR1B = 55 ;
       ICR1 = 181;

}

void Init_Timer_1(void)
{

  TCCR1A |= (1<<COM1A0)|(1<<COM1A1) ;

  TCCR1B |= (1<<WGM13)|(1<<CS10);
  OCR1A =125 ;
  ICR1 = 181;

}
void Zufallszahl_0(void)

{

    int Zahl_0;

   for(Zahl_0=1;Zahl_0>1;Zahl_0=Zahl_0+1)
   {
      if(Zahl_0>1)

      { Zahl_0 = (min + ((float) rand() / RAND_MAX * (max - min +1)));
}
}
}

void Zufallszahl_1(void)

{
     int Zahl_1;

   for(Zahl_1=1; Zahl_1>1;Zahl_1=Zahl_1+1)
   {
   if(Zahl_1>1)

      { Zahl_1 = (min + ((float) rand() / RAND_MAX * (max - min +1)));
}
}

}

nochmals danke

von R. M. (rmax)


Lesenswert?

Wie hast Du getestet, daß es klappt?

Ich behaupte Mal, es klappt nach wie vor nicht, denn Du berechnest zwar 
Zufallszahlen, verwendest die aber nicht, um die PWM-Ausgabe zu 
modulieren, also kommt dort eine konstante Frequenz mit einem konstanten 
Tastverhältnis heraus. Außerdem werden auch hier die Schleifen, die die 
Zufallszahlen berechnen, nach einer gewissen Zeit aufhören. So wie Dein 
Programm momentan aussieht, sind die Funktionen Zufallszahl_0() und 
Zufallszahl_1() Warteschleifen mit einer pseudozufälligen Dauer.

Um Dir über die offensichtlich vorhandenen Verständnisprobleme 
hinweghelfen zu können, ohne gleich die fertige Lösung zu präsentieren 
(Du willst/sollst ja durch die Aufgabe etwas lernen), wäre es hilfreich, 
wenn Du das Programm mal mit Kommentaren versiehst, die sagen, was Du 
Dir beim Schreiben der einzelnen Anweisungen gedacht hast.

Ein Mißverständnis zeigt schon der einzige bisher vorhandene Kommentar. 
Bei der Funktion main() handelt es sich nicht um eine Hauptschleife (die 
automatisch wiederholt wird), sondern um das Hauptprogramm, das nur 
einmal durchlaufen wird. Willst Du eine Hauptschleife haben, mußt Du die 
explizit hinschreiben. Mit "while(1) { }" hast Du das zwar getan, aber 
die Schleife tut nichts.

von vianney (Gast)


Lesenswert?

du hast ya recht, ich kriege signale, die tastverhältnise änder sich 
zwar (man hat das gefühl sie sind zufällig erzeugt) aber es geht 
irgenwie nicht. klar das ich wass lernen will und sogar soll, nd hab das 
gefühl verständnisse probleme bei der aufgabe zu haben. ok ich hab ein 
paar kommentare dazu gebastel. so sieht das aus



#include <avr\io.h>                                // Header Datei für 
Inputs/Outputs
#include <avr\interrupt.h>                         // Header Datei für 
Interrupts
#include "lcd_lib_de.h"
#include <util\delay.h>
#include <stdbool.h>                          // Bibliothek fuer 
Bit-Variable
#include <stdlib.h>


#define  RAND_MAX 0x7FFF




void Init_Timer_0(void);
void Init_Timer_1(void);
void Displayanzeigen(void);
void mainDisplay(void);
void initDisplay(void);
void Zufallszahl_0(void);
void Zufallszahl_1(void);
int  Zahl_0,Zahl_1;




unsigned int min = 0 ;
unsigned int max  =10 ;



int main (void)

  //Hauptsprogramm


{



    DDRB |= (1 << PB2);   //PortB2 als   outpout deklarieren (Ausgang 
AIN0)
    Init_Timer_0();       // Aufrufen des  Unterprogramms Init_Timer_0, 
um das Signal am PORTB2 zu generieren

  Zufallszahl_0();            // Aufrufen des Unterprogramms 
Zufallszahl_0


    DDRB |= (1 << PB1);     //PortB1 als Outpout deklarieren (Ausgang 
OC1A)
    Init_Timer_1();         // Aufrufen des Unterprogramms Init_Timer_1, 
um das Signal am PORTB1 zu generieren

  Zufallszahl_1();          // Aufrufen des Unterprogramms Zufallszal_1
  Displayanzeigen();



    while(1)
    {

    }
    return 0;
}


void Init_Timer_0(void)              //Unterprogramm:Timer für Outpout 
PB2

{
     //Initialisierung Timer 0
 TCCR1A |= (0<<COM1B0) | (1<<COM1B1); //Phase and Frequency correct 
PWM_Mode
//COM1B0=0,COM1B1=1 clear OC1B on compare match when up-counting,
 // set OC1B on compare match when down-counting


   // Prescaler and Waveform Generation Mode

   TCCR1B |= (1<<CS10)|(1<<WGM13);               //Systemtakt without 
Prescaler, WGM13=1: control the counting sequence of the counter

     //Outpout compare Register B belegen, zuständig fürs Tasverhältnis

       OCR1B = 55;

      //Input captur register

       ICR1 = 181;                                  //used as TOP value


}



void Init_Timer_1(void)              //Unterprogramm:Timer für Outpout 
PB1


{

  //Initialisierung Timer 1

  // Clear Timer on Compare (CTC)

  TCCR1A |= (1<<COM1A0)|(1<<COM1A1) ; //Phase and Frequency correct 
PWM_Mode //COM1A0,COM1A1=1 Set OC1A on compare match when up-counting,
         // clear OC1A on compare match when down-counting

 // Prescaler and Waveform Generation Mode

  TCCR1B |= (1<<WGM13)|(1<<CS10);  //Systemtakt without Prescaler, 
WGM13=1: control the counting sequence of the counter

//Outpout compare Register A belegen, zuständig fürs Tasverhältnis

  OCR1A =125 ;

 //Input captur register

  ICR1 = 181;                                     //used as TOP value



}
void Zufallszahl_0(void)  //Zufallzahlgenerieren

{

    int Zahl_0;   //Zahl_0 initializiert

   for(Zahl_0=1;Zahl_0>1;Zahl_0=Zahl_0+1)
   {

      if(Zahl_0>1)

      { Zahl_0 = (min + ((float) rand() / RAND_MAX * (max - min +1))); 
//Berechnunug der zufälligen Zahlen zahl_0

}
}
}

void Zufallszahl_1(void)  //Zufallzahlgenerieren


{
     int Zahl_1; //Zahl_1 initializiert

   for(Zahl_1=1; Zahl_1>1;Zahl_1=Zahl_1+1)
   {

   if(Zahl_1>1)

      { Zahl_1 = (min + ((float) rand() / RAND_MAX * (max - min +1))); 
//Berechnung der zufälligen Zahlen Zahl_1
}
}

}

// Unterprogramm: Display

// Initialisierung Display-Anzeige 
============================================

void Displayanzeigen()        // Start der Funktion
{

    DDRC = 0x0F;
    DDRD = 0xFF;
  PORTC = 0x0F;

    lcd_init();

    lcd_gotoxy(0,0);             // Cursor auf 1. Zeile, 1. Zeichen
  lcd_putstr("     Projekt"); // Ausgabe Festtext: 16 Zeichen

  lcd_gotoxy(1,0);             // Cursor auf 2. Zeile, 1. Zeichen
  lcd_putstr(" Rechtecksignale erzeugen");  // Ausgabe Festtext: 16 
Zeichen

  _delay_ms(20000);      // Wartezeit nach Initialisierung

  lcd_gotoxy(0,0);             // Cursor auf 1. Zeile, 1. Zeichen
  lcd_putstr(" signal1:51,2Khz "); // Ausgabe Festtext: 16 Zeichen

  lcd_gotoxy(1,0);             // Cursor auf 2. Zeile, 1. Zeichen
  lcd_putstr(" signal2:51,2Khz  ");  // Ausgabe Festtext: 16 Zeichen


     _delay_ms(20000);



    lcd_gotoxy(0,0);             // Cursor auf 1. Zeile, 1. Zeichen
  lcd_putstr(" Vianney Ayemle "); // Ausgabe Festtext: 16 Zeichen

  lcd_gotoxy(1,0);             // Cursor auf 2. Zeile, 1. Zeichen
  lcd_putstr(" danke schoen ");  // Ausgabe Festtext: 16 Zeichen



}

von Karl H. (kbuchegg)


Lesenswert?

vianney schrieb:

> gefühl verständnisse probleme bei der aufgabe zu haben. ok ich hab ein
> paar kommentare dazu gebastel. so sieht das aus

Du musst endlich begreifen, dass hier


>     while(1)
>     {
>
>     }

die Stelle ist, die Hauptschleife, innerhalb der sich die eigentliche 
Arbeit deines Programmes abspielen muss. Das ist die Stelle an der deine 
PWM Änderungen erfolgen müssen. Diese Endlos-Schleife ist das 
Arbeitspferd des Programmes. Nicht das Vorgeplänkel davor, nicht 
irgendwelche Teile danch (die nie abgearbeitet werden würden). Innerhalb 
dieser Schleife spiel sich alles ab (sofern es sich nicht in Interrupt 
Service Routinen abspielt)

Der grundlegende Aufbau eines Programms ist immer
1
...
2
int main()
3
{
4
   ....
5
   Initialisierungsteil:
6
7
   hier werden Ports auf Ein/Ausgang gestellt
8
   hier werden zb Geräte konfiguriert
9
   hier werden Timer auf ihre Arbeitsbedingungen eingestellt
10
11
12
   while( 1 ) {
13
14
     ... und hier ist die Hauptschleife
15
     hier findet die eigentliche Arbeit des
16
     Programmes statt
17
     hier sitzt die Programmlogik, die zb
18
     aus irgendwelchen Eingangswerten irgendwelche
19
     Ausgangswerte errechnet und an den Ports
20
     einstellt. zb auch indem eine PWM auf einen
21
     anderen Wert eingestellt wird
22
23
  }
24
25
  return 0;
26
}


Solange du das nicht begriffen hast, ist alles andere sinnlos.

von R. M. (rmax)


Lesenswert?

vianney schrieb:

> du hast ya recht, ich kriege signale, die tastverhältnise änder sich
> zwar (man hat das gefühl sie sind zufällig erzeugt) aber es geht
> irgenwie nicht.

Du setzt die OCR-Werte jeweils genau einmal, insofern springt die 
Ausgabe allenfalls zwischen zwei Tastverhältnissen hin und her.

> int main (void)

Wie schon gesagt, durchläuft das Hauptprogramm die Init- und 
Zufalls-Funktionen genau einmal und hängt dann in der Endlosschleife, 
die nichts mehr tut. Die PWM-Ausgabe läuft natürlich die ganze Zeit, 
aber ihr Tastverhältnis wird nie geändert.

>  //Initialisierung Timer 0
>  //Phase and Frequency correct

Wurde genau dieser Modus des Timers vom Aufgabensteller gefordert?

Falls nicht würde ich Dir für den Anfang den "Fast PWM" Modus empfehlen, 
weil ich den etwas leichter verständlich finde. Außerdem würde ich als 
ersten Schritt nur das Tastverhältnis zufällig ändern und erst wenn das 
läuft die Frequenz in Angriff nehmen. Eine feste Frequenz hat den 
Vorteil, daß Du das sich verändernde Tastverhältnis leichter am 
Oszilloskop (sofern vorhanden) kontrollieren kannst. Bis es 
funktioniert, würde ich auch erstmal nur einen Timer verwenden, dann 
wird der Code kompakter und Du mußt beim Experimentieren nicht immer 
gleich zwei Stellen ändern.

> void Zufallszahl_0(void)  //Zufallzahlgenerieren
> {
>     int Zahl_0;   //Zahl_0 initializiert
>    for(Zahl_0=1;Zahl_0>1;Zahl_0=Zahl_0+1)
>    {
>       if(Zahl_0>1)
>
>       { Zahl_0 = (min + ((float) rand() / RAND_MAX * (max - min +1)));
> //Berechnunug der zufälligen Zahlen zahl_0
> }
> }
> }

Bitte erläutere noch genauer, was Du mit dieser Funktion erreichen 
willst.

Du definierst eine Zählervariable, veränderst die aber dann innerhalb 
der Schleife. Das ist zwar nicht verboten aber eher unüblich, und wenn 
man es so macht, sollte man genau wissen, was man tut, wovon ich hier 
eher nicht den Eindruck habe. ;)

Das Hauptproblem ist aber, daß Du zwar eine Menge Zufallszahlen 
berechnest, die aber nicht verwendest, um die PWM zu modulieren. Du mußt 
die Werte, wie in der ersten Version Deines Programmes in das 
entsprechende OCR-Register schreiben, damit sie die PWM beeinflussen.

Karl Heinz hat natürlich auch recht, aber zu dem Punkt wollte ich erst 
im nächsten Schritt kommen.

von Rolf Magnus (Gast)


Lesenswert?

>    for(Zahl_0=1;Zahl_0>1;Zahl_0=Zahl_0+1)
>    {
>       if(Zahl_0>1)
>
>       { Zahl_0 = (min + ((float) rand() / RAND_MAX * (max - min +1)));
> //Berechnunug der zufälligen Zahlen zahl_0
> }
> }

Diese Schleife ist schon äußerst kreativ. ;-)
Du machst eine Schleife, die bei einem Zählerwert von 1 anfängt, so 
lange läuft, wie der Wert größer 1 ist (sprich - gar nicht, weil der 
Anfangswert schon nicht größer als 1 ist) und dann in jedem 
Schleifendurchlauf den Zähler inkrementiert, so daß er immer noch 
frühestens beim Überlauf des Zählers kleiner als 1 werden könnte, wenn 
die Schleife überhaupt angelaufen wäre. Um das Chaos noch komplett zu 
machen, ersetzt du innerhalb der Schleife den gerade frisch 
inkrementierten Zählwert durch einen komplett neuen Zufallswert, aber 
nur, wenn er vorher größer als 1 war.
Irgendwie hab ich keine Ahnung, was die Idee hinter dieser Schleife ist.

von Karl H. (kbuchegg)


Lesenswert?

Rolf Magnus schrieb:

> Diese Schleife ist schon äußerst kreativ. ;-)

In dem Programm stimmt vieles nicht zusammen.
Ich sehe 2 Möglichkeiten
* entweder da wurde aus mehreren Quellen zusammenkopiert was das
  Zeug hält (ohne verstanden zu haben, wie das alles zusammenspielt)
* Jemand anderer hat den Grundaufsatz gemacht und er versucht das
  jetzt mit 0-Wissen abzuändern

Auf jeden Fall passt da vieles nicht zusammen. Da werden elementarste 
Fehler gemacht und auf der anderen Seite sind die Teile, in denen man am 
ehesten Fehler vermuten würde auf wundersame Weise gar nicht so schlecht 
abgehandelt.

zb.
  (min + ((float) rand() / RAND_MAX * (max - min +1)));
OK. Der Umweg über float ist nicht so toll, das hätte man auch anders 
lösen können, aber grundsätzlich ist die Erzeugung einer Zufallszahl gar 
nicht mal schlecht. Auch mit dem Hintergrund, dass so etwas die meisten 
Neulinge vor unüberwindbare Schwierigkeiten stellt.

(Aber Hauptsache am LCD steht ein schöner Begrüßungstext und der Name 
des Autors :-)

von vianney (Gast)


Lesenswert?

R-max ya ich muss mit dem phase nd frequency correct mode arbeiten, weil 
ich einen uc arbeite, der einen quarz von 18,432mhz hat, und ich brauche 
ein signal mit einer frequenz von 51khz. Durch berechnung hab ich 
festgestellt dass ich mit deisem mode arbeiten sollte. ich bin grad 
dabei das programm abgesehen ihre erklärungen zu schreiben, das hilft 
mir viel und hoff es wird klappen. das einzig ist, dass ich net genau 
weiss wie ich mien pwm in der hauptschleife while() einstellen kann, 
weil meine timer sind schon fertige "module" und ich glaube (wenn ich 
das funktionsprinzip des timers verstanden habe)das ich nur diese 
tastverhältnise zufällig haben könnte nur durch veränderung bzw 
einstellung mein OCR. aber wie kann ich es in der hauptschleife 
umstellen ohne das gesamte timer-modul bearbeiten zu haben.
ich hoff du verstehst was ich meine
dank

von Karl H. (kbuchegg)


Lesenswert?

vianney schrieb:

> einstellung mein OCR. aber wie kann ich es in der hauptschleife
> umstellen ohne das gesamte timer-modul bearbeiten zu haben.
> ich hoff du verstehst was ich meine

um es kurz zu machen, sonst hampelst du da noch 2 Wochen damit rum
1
....
2
3
int main()
4
{
5
  ....
6
7
8
  while( 1 ) {
9
10
    ....
11
12
    OCR1A = ..... Berechnung
13
    OCR1B = ..... Berechnung
14
  }
15
}

Wahrscheinlich muss da noch eine Verzögerung rein, damit die OCR Werte 
nicht im Nanosekundentakt von einem Wert zu einem anderen umgestellt 
werden.

von R. M. (rmax)


Lesenswert?

vianney schrieb:

> ich muss mit dem phase nd frequency correct mode arbeiten, weil
> ich einen uc arbeite, der einen quarz von 18,432mhz hat, und
> ich brauche ein signal mit einer frequenz von 51khz.

Ah, ich hatte Deinen ersten Post falsch verstanden und dachte, die 
Frequenz soll auch variabel sein. Trotzdem würde ich Dir für den Anfang 
den Einfacheren Modus empfehlen, da ist ja auch erstmal nicht die genaue 
Frequenz wichtig, sondern daß es überhaupt funktioniert. Anschließend 
kannst Du es dann immer noch auf den anderen Modus umbauen, falls es 
nötig ist. Übrigens kannst Du auch im Fast-PWM-Modus den TOP-Wert 
beliebig einstellen, von daher müßten die 51kHz damit auch zu erreichen 
sein.

> aber wie kann ich es in der hauptschleife
> umstellen ohne das gesamte timer-modul bearbeiten zu haben.

Die Timer sind Teil der Hardware des Controllers.
Darauf kann man von beliebigen Stellen im Code zugreifen.

von vianney (Gast)


Lesenswert?

HALLO,
ertsmal danke für die hilfe, ich glaub ich verstehe dann jetzt besser.
ich habe aber noch eine frage, ich weiss net ob ich noch was falsch 
mache aber ich kriege zwar ein signal aber nach betsimmter zeit hört das 
ganze auf. ich weiss net ob das liegt daran dass, das ich den befehl um 
zufallszahl zu berechnen falsch gebe, oder ws anders vertshe ichnet. im 
databuch dass man einfach den befehl rand() schreibt, und es wird 
berechnet, oder mit float kann man das auch berechnen, aber irgendwie 
komm ich net dran. könnt ihr mir noch helfen bitte?
GRÜß nd dank

von R. M. (rmax)


Lesenswert?

Ohne die aktuelle Version Deines Programms gesehen zu haben, kann ich 
nur Vermutungen anstellen. Ich nehme an, Du hast immer noch ein 
unbedachtes Abbruchkriterium in einer der Schleifen. An der 
rand()-Funktion selbst wird es sicher nicht liegen, denn die kommt ja 
aus der Standardbibliothek und ist entsprechend getestet.

von vianney (Gast)


Lesenswert?

ok ich schick dann das code



int main (void)

  //Hauptsprogramm


{



    DDRB |= (1 << PB2);
    Init_Timer_0();



    DDRB |= (1 << PB1);
    Init_Timer_1();
    Displayanzeigen();



    while(1)
    {


    OCR1B = Berechnungswert_0;
  OCR1A = Berechnungswert_1;

    }
    return 0;
}


void Init_Timer_0(void)

{
     //Initialisierung Timer 0
    TCCR1A |= (0<<COM1B0) | (1<<COM1B1);


   // Prescaler and Waveform Generation Mode

   TCCR1B |= (1<<CS10)|(1<<WGM13);

     //Outpout compare Register B belegen, zuständig fürs Tasverhältnis

     Zufallszahl_0();

      //Input captur register

       ICR1 = 181;                                  //used as TOP value


}



void Init_Timer_1(void) 
//Unterprogramm:Timer für Outpout PB1


{

  //Initialisierung Timer 1

  // Clear Timer on Compare (CTC)

  TCCR1A |= (1<<COM1A0)|(1<<COM1A1) ;

 // Prescaler and Waveform Generation Mode

  TCCR1B |= (1<<WGM13)|(1<<CS10);

//Outpout compare Register A belegen, zuständig fürs Tasverhältnis

  Zufallszahl_1();

 //Input captur register

  ICR1 = 181;                                     //used as TOP value



}



void Zufallszahl_0(void)  //Zufallzahlgenerieren

{



     int Zahl_0; //Zahl_0 initializiert

   Zahl_0=0;

   Zahl_0 = (min + ((float) rand() / RAND_MAX * (max - min +1)));

   while (Zahl_0>50)

   {
    Zahl_0 = Berechnungswert_0;


}


}

void Zufallszahl_1(void)  //Zufallzahlgenerieren


{
     int Zahl_1; //Zahl_1 initializiert
   Zahl_1=0;

    Zahl_1 = (min + ((float) rand() / RAND_MAX * (max - min +1)));
   while (Zahl_1>80)
   {

    Zahl_1= Berechnungsswert_1;

}


}


dank

von R. M. (rmax)


Lesenswert?

Du rufst die Zufallszahl-Funktionen nirgends auf, wo sollen also Deine 
Zufallswerte herkommen?

In Deinen Variablen herrscht noch ein ziemlicher Wirrwarr. Laß Dir die 
Logik der Zufallszahl-Funktionen nochmal durch den Kopf gehen und fürhe 
Dir dabei insbesondere die Rolle der Berechnungswert-Variablen vor 
Augen.

Schau' Dir auch nochmal das Gerippe an, das Karl Heinz zuletzt gepostet 
hatte und vergleiche es mit Deinem Code.


Und bitte reduziere Deinen Code (besonders für den Fall, daß Du ihn 
nochmal posten mußt) erstmal auf einen PWM-Kanal, um die Sache 
einigermaßen übersichtlich zu halten. Wenn der eine Kanal dann läuft, 
ist es nur noch eine Frage von Minuten, das Programm um den zweiten 
Kanal zu erweitern.

von Karl H. (kbuchegg)


Lesenswert?

1
    while(1)
2
    {
3
4
5
    OCR1B = Berechnungswert_0;
6
  OCR1A = Berechnungswert_1;
7
8
    }

Ein AVR ist doch kein Excel.
Variablen ändern nicht magisch ihren Wert!
1
void Zufallszahl_0(void)  //Zufallzahlgenerieren
2
3
{
4
5
6
7
     int Zahl_0; //Zahl_0 initializiert
8
9
   Zahl_0=0;
10
11
   Zahl_0 = (min + ((float) rand() / RAND_MAX * (max - min +1)));
12
13
   while (Zahl_0>50)
14
15
   {
16
    Zahl_0 = Berechnungswert_0;
17
18
19
}
Was soll das den sein?
Du rechnest so schön eine Zufallszahl aus. Und dann verwirfst du sie 
wieder, indem du sie mit Berechnungswert_0 überschreibst? Und das ganze 
dann auch noch so lange, so lange Zahl_0 größer als 50 ist.

Wie R.Max schon schrieb. Konzentrier dich erst mal nur auf 1 Kanal. Und 
dann formatiere deinen Code! In diesem Kraut und Rüben Haufen kann man 
ja gar keine Fehler sehen. Schon gar nicht, wenn man erst am Lern-Anfang 
steht.

Und dann spiele erst mal selber Computer.
Nimm dir einen Bleistift (oder den Finger) und gehe Anweisung für 
Anweisung durch. Was passiert, welcher Wert wird errechnet etc. Wenn ein 
Wert errechnet wird, dann schreib ihn dir auf einem Zettel nieder und 
lies ihn von dort wieder ab, wenn dein Programmtext danach verlangt. 
Aber tu nur das, was im Programmtext steht. Nicht mehr und nicht 
weniger! Die Hardwaresachen kannst du fürs erste einmal als richtig 
annehmen. Und für die Zufallszahl kannst du auch einen gültigen Wert 
erfinden. Aber tu um Himmels Willen nur das, ws im Programmtext steht. 
Denn genau das macht auch der µC. Er führt nur das aus, was du 
niedergeschrieben hast und nicht das was du denkst, das an dieser Stelle 
passieren sollte.

Normalerweise würde man sagen, dass dieses Beispiel mindestens 3 
Schuhnummern zu groß für dich ist. Da fehlt es hinten und vorne am 
elementaren Verständnis, dass in einem Programm die Reihenfolge der 
Operationen eine Rolle spielt und nichts irgendwie magisch von selbst 
passiert. Wenn du mit Funktionen durcheinanderkommst und nicht mehr 
weißt, was wo passiert, dann schreibe das Ganze ohne Funktionen. Bei der 
Beispielgröße geht das noch ohne Probleme.

von vianney (Gast)


Lesenswert?

ok dank ich probiere erstmal mit einem kanal und versuch noch besser das 
prinzip des prn zu verstehen
danke

von Karl H. (kbuchegg)


Lesenswert?

Und hör um Himmels Willen damit auf, deinen Code mit Unmengen an 
Leerzeilen zu spicken. Das bringt keine Übersicht! Wohl aber das 
Gegenteil!
Leerzeilen nur dann, wenn ein logisch zusammengehörender Block zu Ende 
ist. Aber nicht nach jeder einzelnen Zeile.

von vianney (Gast)


Lesenswert?

hallo,
erstmal morgen und dank für ihre hilfe
ich glaube endlich(zu mindest hof ich mal), hier ist das code
int main (void)

  //Hauptprogramm
{
    DDRB |= (1 << PB2);
    Init_Timer_0();
    while(1)
    {
     int Zahl;
   Zahl = rand();
     if (Zahl>80)
  {
    OCR1B = Zahl;
  }
}
    return Zahl;
}
void Init_Timer_0(void)
{
    TCCR1A |= (0<<COM1B0) | (1<<COM1B1);
    TCCR1B |= (1<<CS10)|(1<<WGM13);
    ICR1 = 181;
}

ich wollte dann wiessen ob ich die werte die ich zu meiner ocr1a geben 
will, begrenzen, bzw das sie zb zwischen 100 und 150 sein sollten. wie 
kann ich das, wenn das überhaupt geht
danke

von Karl H. (kbuchegg)


Lesenswert?

vianney schrieb:
> hallo,
> erstmal morgen und dank für ihre hilfe
> ich glaube endlich(zu mindest hof ich mal), hier ist das code

Jetzt bist du auf dem richtigen Weg.


> ich wollte dann wiessen ob ich die werte die ich zu meiner ocr1a geben
> will, begrenzen, bzw das sie zb zwischen 100 und 150 sein sollten.

Jetzt bin ich aber enttäuscht.
In deinem Urprogramm hattest du

    (min + ((float) rand() / RAND_MAX * (max - min +1)))

Fragen dazu:
  Welche Bedeutung hat wohl   RAND_MAX
  Welche Bedeutung hat wohl   min
  Welche Bedeutung hat wohl   max

  Was macht daher die Berechnung als Ganzes?

Einfach abgeschrieben ohne zu verstehen oder darüber nachzudenken was da 
eigentlich passiert?

> wie kann ich das, wenn das überhaupt geht

Wie würdest DU (als Person) das denn machen?
Angenommen du hast irgendwelche Zahlen
    23, 35, 48, 109, 87, ....

Du weißt: die kleinste Zahl die vorkommen kann ist 0. Die größte 
vorkommende Zahl ist 127.

Du brauchst jetzt nicht die Zahlen von oben, sondern welche im Bereich 
200 bis 270. Wie würdest du (mit dem Wissen, welche Zahlen in der 
Zahlenreihe vorkommen können) die Zahlenreihe von oben so umrechnen, 
dass sie in den gewünschten Bereich verschoben/gestaucht/gedehnt wird?

von vianney (Gast)


Lesenswert?

hi karl,
den satz hatte ich vom internet, aber das war für c-programmierung, und 
ich dachte es wäre auch vlt gelten bei assembler, deswegen wollte ich 
damit probieren, danach hab ich von avr-libc alle befehlensätze die man 
in avr benutzt gefunden, und drin stand dass man um zufallszahlen 
generieren zu können den befehl rand() benutzen sollte.
kann man auch (min + ((float) rand() / RAND_MAX * (max - min +1)))

benutzen? um auch bestimmte zufallszahlen zu generieren?
vianney

von Karl H. (kbuchegg)


Lesenswert?

vianney schrieb:
> hi karl,
> den satz hatte ich vom internet, aber das war für c-programmierung, und
> ich dachte es wäre auch vlt gelten bei assembler, deswegen wollte ich
> damit probieren, danach hab ich von avr-libc alle befehlensätze die man
> in avr benutzt gefunden, und drin stand dass man um zufallszahlen
> generieren zu können den befehl rand() benutzen sollte.
> kann man auch (min + ((float) rand() / RAND_MAX * (max - min +1)))
>
> benutzen? um auch bestimmte zufallszahlen zu generieren?

Ich würde vorschlagen, du hörst damit auf, einfach irgendwelche Teile 
zusammenzukopieren sondern beginnst damit, darüber nachzudenken, was die 
Einzelteile die du irgendwo findest, eigentlich machen.


> dass man um zufallszahlen
> generieren zu können den befehl rand() benutzen sollte.

Hier

   (min + ((float) rand() / RAND_MAX * (max - min +1)))
                   ******

wird rand() benutzt!

Nur wird das Ergebnis von rand(), welches gewisse Eigenschaften besitzt, 
umgerechnet und besitzt dann andere Eigenschaften. Zumindest lesen 
solltest du das Geklaute schon!

Wie gesagt: Hör auf, stumpfsinnig irgendwelche Teile zusammenzukopieren. 
So wirst du nie anfangen zu programmieren. Sich in fremden Code Dinge 
abschauen ist ok. Aber man muss analysieren, was man sich da eigentlich 
abschaut und wie das Geklaute eigentlich funktioniert.

von vianney (Gast)


Lesenswert?

ya hab ich schonkappiert deswegen hab ich mal was anderes versucht zu 
probieren. brauchst du nicht es zu wiederholen, das hab ich kapiert
danke

von Karl H. (kbuchegg)


Lesenswert?

Na hoffentlich. So recht glaube ich noch nicht daran :-)

Stell dir vor, du hast einen Freund. Dieser Freund ruft dir irgendwelche 
Zahlen im Bereich 0 bis (inklusive)9 zu:

4, 1, 8, 7, 0, 3, 9, ...

zu jeder einzelnen Zahl zählst du im Kopf 15 dazu und schreibst die Zahl 
nieder:

19, 16, 23, 22, 15, 18, 24, ....

Was ist passiert? Aus den (zufälligen) Zahlen 0 bis 9 hast du 
(zufällige) Zahlen im Bereich 15 bis 24 gemacht. Einfach nur, in dem du 
den Bereich 'verschoben' hast und deinen Minimalwert 15 dazu addiert 
hast.

Das ist aber nicht die einzige Operation, die du mit den Zahlen machen 
kannst. Du kannst zb jede einzelne der dir zugerufenen Zahlen vorher mit 
2.5 multiplizieren, ehe du sie niederschriebst. Aus den dir zugerufenen 
Zahlen

4, 1, 8, 7, 0, 3, 9, ...

wird dann

10, 2.5, 20, 17.5, 0, 7.5, 22.5, ....

Was ist jetzt passiert? Die von dir niedergeschriebenen Zahlen bewegen 
sich jetzt plötzlich im Bereich 0 bis 22.5

Und natürlich kannst du auch beides kombinieren: Zuerst mal 2.5 und dann 
noch 15 dazu.  Aus

4, 1, 8, 7, 0, 3, 9, ...

wird so

29, 18.5, 43, 39.5, 15, 25.5, 46.5, ....

Deine jetzt niedergeschriebenen Zahlen bewegen sich im Bereich 15 bis 
46.5

Das sind alles einfach nur Umrechnungen von einem Zahlenbereich in einen 
anderen Zahlenbereich. Die Kunst besteht jetzt darin, die Umrechnung zu 
finden, die gezielt in einem bestimmten Zahlenbereich umrechnet. Dazu 
ist es am einfachsten, wenn man sich die Zahlen zunächst in den Bereich 
0 bis 1 abbildet. Und genau dazu benötigt man die Kentniss der höchsten 
vorkommenden Zahl, die dir dein Freund zuruft. Bei deinem Freund ist das 
die 9. In C übernimmt RAND_MAX diese Rolle. Dividierst du jede Zahl 
deines Freundes durch RAND_MAX (=9), dann wird aus

4, 1, 8, 7, 0, 3, 9, ...

die Zahlen

0.44444, 0.11111, 0.88888, 0.77777, 0, 0.33333, 1.0, ....

und aus diesen Zahlen sollte es nicht weiter schwer sein, Zahlen zu 
generieren, die sich zb zwischen 200 und 245 bewegen. Der Bereich 
zwischen 200 und 245 umfasst 46 Zahlen (245 - 200 + 1). Also 
multipliziert man die auf 0..1 normierten Zahlen mit 46. Dadurch erhält 
man Zahlen von 0 bis 45 (no, na). Dazu dann noch 200 dazugezählt, und 
die Zahlen deines Freundes finden sich im gewünschten Bereich wieder.

Aus den Zahlen deines Freundes mit der Eigenschaft 'bewegen sich im 
Bereich 0 bis 9' sind neue Zahlen geworden, die jetzt die Eigenschaft 
haben 'bewegen sich im Bereich 200 bis 245'

Und jetzt vergleich das alles mal mit

     (min + ((float) rand() / RAND_MAX * (max - min +1)))

dort findest du genau diese Umrechnung wieder :-)

rand() liefert eine Zahl von 0 bis RAND_MAX
die wird durch RAND_MAX dividiert um sie in den Bereich 0 bis 1 zu 
bringen. Dann wird mit (max-min+1) multipliziert, also der 
Bereichsbreite in die man das Ergebnis haben will und zum Schluss wird 
noch min dazuaddiert.

DAS ist analysieren, wie ein bestimmter Code-Fetzen funktioniert. Du 
musst erklären können, warum genau diese Umrechnung gemacht wird und, 
wenn man bestimmte Zahlen für min und max einsetzt, was sich daraus 
ergibt. Welches ist die Idee dahinter? Wie kommt man darauf? etc.

Nicht einfach nur fragen
> kann man auch (min + ((float) rand() / RAND_MAX * (max - min +1)))
> benutzen? um auch bestimmte zufallszahlen zu generieren?
sondern sich mit Papier und Bleistift hinsetzen und einfach mal ein paar 
Zahlen durchrechnen, so wie ich das oben gemacht habe (mit der Annahme, 
dass sich die originalen Zufallszahlen im Bereich 0 bis 9 bewegen, damit 
man nicht so viele verschiedene Zahlen zu untersuchen hat).

von vianney (Gast)


Lesenswert?

ich kann nur danke schön sagen
vianney

von vianney (Gast)


Lesenswert?

hallo,
hat endlich geklappt danke
und es ist eigentlich (bei meiner aufgabe)egal ob ich den befehl rand() 
alleine oder (min + ((float) rand() / RAND_MAX * (max - min +1))); 
benutze, ich bekomme eigentlich was ich brauch
danke für ihre hilfe
grüß

von R. M. (rmax)


Lesenswert?

rand() ohne die Umrechnung mag so aussehen als ob es funktioniert, ist 
aber eigentlich nicht korrekt, denn dabei werden die oberen 7Bit der 
15-bittigen Zufallszahl einfach abgeschnitten und vom Rest läßt Du die 
Werte einfach unter den Tisch fallen, die außerhalb Deines gewünschten 
Intervalls liegen.

Das kann die Gleichverteilung Deiner Zufallszahlen verschlechtern und es 
beeinträchtigt das Zeitverhalten Deines Programms, denn wenn 
nacheinander viele Werte kommen, die außerhalb Deines Intervalls liegen, 
dann dauert es länger, bevor der PWM-Wert wieder geändert wird.

Die Umrechnung braucht zwar länger als das abschneiden der Bits, aber 
sie dauert jedes Mal gleich lang, so daß Du ein definiertes Verhalten 
hast, was beim "Warten auf einen brauchbaren Wert" nicht der Fall ist.

Übrigens solltest Du Deine Hauptschleife auf jeden Fall noch mit dem 
Timer synchronisieren, denn es sollte nur einmal pro Zählerdurchlauf ein 
neuer PWM-Wert berechnet werden, sonst leidet wiederum die 
Gleichverteilung der Werte.

Das kannst Du z.B. dadurch erreichen, daß Du in der Hauptschleife nach 
der Berechnung der Zahl so lange den Timer ausliest, bis der aktuelle 
Wert kleiner ist als der beim letzten Durchlauf und erst dann den neuen 
Wert ins OCR schreibst.

Eleganter wäre natürlich, den Timer beim Überlauf einen Interrupt 
auslösen zu lassen und den neuen Wert in der Interrupt-Routine zu 
setzen.

von vianney (Gast)


Lesenswert?

da hast du recht, die zahlen sind zwar zufällig erzeugt, aber nach einer 
bestimmten zeit wiederholen sie sich und der rest bleibt genau nicht 
benutzt.
ich hätte eine andere frage die wäre, kann man die pulsbreite beliebig 
bzw zufällig ändern ohne das zewitsintervall zwischen 2 pick zu ändern?
meine idee wäre z.b ob man diese zeitsintervall umstellen kann, so dass 
es immer in einem bestimmten bereich sich bewegt, d.h das könnte z.b 
zwischen 10 und 30 sich bewegen?
wenn ya wie dann?
danke

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.