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?
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
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
intmain()
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.
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.
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.
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.
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