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; }
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'
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?
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
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.
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 }
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.
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.
> 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.
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 :-)
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
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.
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.
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
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.
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
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.
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.
ok dank ich probiere erstmal mit einem kanal und versuch noch besser das prinzip des prn zu verstehen danke
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.
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
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?
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
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.
ya hab ich schonkappiert deswegen hab ich mal was anderes versucht zu probieren. brauchst du nicht es zu wiederholen, das hab ich kapiert danke
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).
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üß
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.
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.