Hallo, ich habe ein Problem: und zwar habe ich eine Frequenz über den Timer1 generiert. diese möchte ich jedoch nicht unbegrenzt ausgeben lassen, sondern nach einer bestimmten Zeit beenden, so dass am Ausgang 0V anliegen. Ich wollte mit einer for-schleife einfach hochzählen und dann nach einer bestimmten Zeit stoppen. Wie jedoch stoppe ich diesen timer bzw. gibt es eine andere Möglichkeit um die Frequenzausgabe zu beenden? Danke schon mal :)
Dankeschön, ich habs ausprobiert und in einer for- schleife geschrieben. nur hört er nicht vollständig auf, sondern fängt dann iwann wieder an:( verstehs ehrlichgesagt nicht, weil ich ja TR1=0 setze und dadurch der timer ja gestoppt wird. warum startet er dann trotzdem wieder? habs einmal versucht in die main zu schreiben und einmal in die funktion für den timer aber beides funktioniert nicht.
Dann startet Dein Programm an irgend einer Stelle den Timer neu, vielleicht in der ISR? Ohne die genauere Kenntnis Deines Programmes ist Hilfe schwer.
Nachtrag: TR1 ist Teil des SFR TCON. Vielleicht setzt eine Bitoperation TR1 in TCON immer wieder neu.
hmm, iwie funktioniert das wirklich nicht. glaube habe insgesamt ein Problem mit dem Verständnis für die Timer /interrupts. Habe mal den Quelltext angefügt. Mit TR0=0; bzw. TR1=0; erreiche ich absolut keine Wirkung. Wäre wirklich nett, wenn mir jemand auf die Sprünge helfen könnte. Verzweifel gerade ein wenig. Dankeschön :)
>glaube habe insgesamt ein Problem mit dem Verständnis für die Timer
Stimmt
Um eine saubere Frequenz auszugeben, kommst Du um eine ISR für den Timer
nicht drum rum. Mit Deinem Progamm dürfte das nichts werden.
Also: Timer-ISR programmieren, die zyklisch entsprechend der geforderten
Frequenz aufgerufen wird. Darin kannst Du dann ein Port-Pin toggeln.
so z.B. für f=11.0592MHz:
1 | // Testprogramm TIMER
|
2 | // Beispiel: LED blinkt im o.5s Takt
|
3 | |
4 | #include "reg51.h" // Register des 8051MCs |
5 | #define LED P0_7
|
6 | |
7 | // Timer 0 - Zeitbasis
|
8 | // Timer0: Reload Wert für T0 T=1/(fosz/12)*(65536-(TH0*256+TL0))
|
9 | // RELOAD (16bit) = -(0.01 * FREQ_OSC / 12 - 65536);
|
10 | // RELOAD-Wert für 10ms = 0xDC00 (56320) bei FOSZ 11.059200 MHz
|
11 | #define TH0Reload 0xDC
|
12 | #define TL0Reload 0x00
|
13 | |
14 | static unsigned char int_delay = 0; |
15 | |
16 | // ********************************************************************
|
17 | // Timer 0 Interrupt
|
18 | // Routine wird alle 10ms aufgerufen
|
19 | // ********************************************************************
|
20 | void TIMER0ISR (void) interrupt 1 { |
21 | TH0 = TH0Reload; // Update MSB |
22 | TL0 = TL0Reload; // Update LSB |
23 | int_delay++; |
24 | if (int_delay == 50) { |
25 | // LED blinkt im Sekundentakt (500ms an, 500ms aus)
|
26 | // nur Bsp., anpassen!
|
27 | LED = !LED; |
28 | int_delay = 0; |
29 | }
|
30 | }
|
31 | |
32 | // ********************************************************************
|
33 | // Grund-Initialisierung
|
34 | // ********************************************************************
|
35 | void init (void) { |
36 | // Timer 0 initialisieren
|
37 | TMOD = 0x01; // 0000 0001B Timer 0: Mode 1 (16-Bit Zähler) |
38 | TH0 = TH0Reload; // Reloadwert Timer 0 |
39 | TL0 = TL0Reload; |
40 | TR0 = 1; // Timer 0 starten |
41 | // Interruptsystem
|
42 | ET0 = 1; // Timer 0, Interruptfreigabe |
43 | EA = 1; // generelle Interruptfreigabe |
44 | }
|
45 | |
46 | // ********************************************************************
|
47 | // Hauptprogramm
|
48 | // ********************************************************************
|
49 | void main (void) { |
50 | init(); |
51 | while(1); |
52 | }
|
hey, das hat top funktioniert:) bekomm jetzt ein schönes rechtecksignal, sieht wesentlich besser aus als bei mir. jetzt steh ich aber noch immer vor dem problem, dass ich den timer irgendwie stoppen möchte: hab das Programm wie unten abgeändert. Dachte dass ich zu Anfang nun über eine Zählschleife die Dauer des Zählers beschränken kann (was ja später durch einen weiteren Zähler verbessert werden könnte). Jedoch stoppt mein Timer absolut nicht. Wie du siehst, bin ich noch nicht wirklich in dem Thema drin :(. void initzaehler (void) { // Timer 0 initialisieren TMOD = 0x01; // 0000 0001B Timer 0: Mode 1 (16-Bit Zähler) TH0 = TH0Reload; // Reloadwert Timer 0 TL0 = TL0Reload; TR0 = 1; // Timer 0 starten // Interruptsystem ET0 = 1; // Timer 0, Interruptfreigabe EA = 1; // generelle Interruptfreigabe } // ******************************************************************** void init0 (void) { TMOD = 0x01; // 0000 0001B Timer 0: Mode 1 (16-Bit Zähler) TH0 = 0; // Reloadwert Timer 0 TL0 = 0; TR0 = 0; // Timer 0 stoppen // Interruptsystem ET0 = 0; // Timer 0, Interruptsperren EA = 0; } // ******************************************************************** // Hauptprogramm // ******************************************************************** void main (void) { init(); for(i=1; i<5;i++) { initzaehler(); while(1); } init0(); }
Durch das while(1); kommst Du nie wieder aus der Schleife raus und die init0(); wird nie aufgreufen! TR0 = 0; würde auch schon reichen, den Timer anzuhalten. Das i<5 wird auch bei richtiger Funktion nur sehr kurz die Frequenz ausgeben! Den Timer brauchst Du auch nur einmal am Anfang zu initialisieren.
hab das jetzt so ergänzt: mit einer wait funktion von 5ms (habs auch mit einer höheren Zahl versucht) aber der Timer stoppt einf nicht. iwo ist wohl noch ein denkfehler vorhanden void wait5ms(void) { TMOD = 0x11; TR0=0; //Timer stoppen TH0 = 0xE8; // TH0 wird auf 15 gesetzt, so dass zusammen mit TL0 die Zahl 0x159F /5000 entsteht, welche die 0,5ms ausmacht. TL0 = 0x8E; TR0 = 1; while (TF0 == 0); //zählt so lange, bis TF0 == 0 TF0 = 0; } // ******************************************************************** void pwm(void) { TR0=0; for (i=0; i<2000; i++) wait5ms(); TR0=1; for (i=2000; i<100; i++) wait5ms(); } // ******************************************************************** // Hauptprogramm // ******************************************************************** void main (void) { init(); initzaehler(); pwm(); }
Das ist jetzt aber was ganz anderes. Du sprachst im ersten Beitrag von einer Frequenzausgabe und nun von einer PWM. Dafür ist eine andere Herangehensweise erforderlich, da bei konstanter Frequenz nun das Tastverhältnis geändert werden muss. Der XC886 (noch nicht damit gearbeiet) hat nach querlesen des Datasheets eine spezielle Capture/Compare-Unit dafür. Du solltest diese benutzen. Mit Standard-Timer geht es auch bedingt zu machen, ist aber aufwendiger. Es wird damit nur eine geringe PWM-Grundfrequenz zu realisieren sein. Was willst Du eigentlich machen?
muss das denn unbedingt mit pwm gemacht werden. hab den obigen namen einf. nur mal so gewählt muss aber nicht heißen, dass es damit gemacht weren sollte. ich möchte mit dem Programm vier Schrittmotoren ansteuern und somit brauche ich für jeden Schrittmotor unter anderem eine andere FReqeuenz. Da der Schrittmotor nach einer bestimmten Strecke anhalten soll, muss ja die Frequenz stoppen. Müsste ja eigentl auch mit dem von dir genannten Timer gehen, den man dann einfach nach einer Bestimmten Zeit (wait-Timer) stoppen würde. oder sehe ich das falsch?
Wenn Du 4 Schrittmotoren direkt selber steuern willst, werden so wie Du es vor hast sicher die Timer knapp. Lass besser einen Timer mit konstanter Wiederholrate (ms-Bereich) frei laufen (ohne ihn jemals wieder anzuhalten!) und programmiere darin dann das entsprechende Timing für jeden Motor. Ist nicht besonderes kompliziert. Einfacher wird es beim Einsatz entprechender Schrittmotortreiber als Hardware. Du solltest Dir zunächst grundlegende Kenntnisse der 8051er Familie aneignen. Dazu gibt es jede Menge guter Literatur. Die XC8.. Serie ist für den Einstieg nicht unbedingt geeignet. Besser sind überschaubare MC, z.B. Atmel AT89C51ED2 oder AT89S8253.
habe bisher immer mit xc8... gearbeitet, deswegen will ich mich da auch nicht großartig umlernen. mein problem an sich ist einfach, dass meine Frequenz nicht stoppen will auch mit TR0=0 nicht. hättest du da nicht evtl ein beispielprogramm wie das funktioniert, damit ich überhaupt mal sehe wie ich eine Frequenz ausgebe und diese nach einer bestimmten zeit null ist. weil mit dem oben von dir genannten tip, welcher nicht schlecht ist muss ja trotzdem der ms timer iwann gestoppt werden bzw in den ms timer etwas hineingeschrieben werden. iwie ist mir das einfach nicht ganz klar. Danke dir, tine
eigentl dachte ich ich könnte einfach nur sagen: TR0=1 bzw. TR0=0 und damit meinen timer ein bzw ausschalten. aber angenommen ich schreibe mein programm so: TR0=1; wait(); // dann warte ich ein weilchen TR0=0; na ja dann passiert niente... oder wenn ichs so schreib, dann geht halt meine frequenz "an" aber nie mehr wieder aus :( for(i=0; i<100; i++) {TR0=1;} warte(); for(i=100; i>100; i++) { LED=0; TR0=0; warte(); }
vergiss das TRx Bit mal ganz, bleibt immer 1 und wird nicht mehr verändert.
1 | // ********************************************************************
|
2 | // Timer 0 Interrupt
|
3 | // Routine wird alle xxms aufgerufen
|
4 | // ********************************************************************
|
5 | void TIMER0ISR (void) interrupt 1 { |
6 | TH0 = TH0Reload; // Update MSB |
7 | TL0 = TL0Reload; // Update LSB |
8 | // Motor 1
|
9 | if (motor1) { |
10 | // hier alles tun was Motor 1 betrifft
|
11 | }
|
12 | // Motor 2
|
13 | if (motor2) { |
14 | // hier alles tun was Motor 2 betrifft
|
15 | }
|
16 | usw. |
17 | }
|
Im Hauptprogramm setzt Du nur motorX auf 1 ode 0 und damit steuerst Du die einzelnen Motoren. In den jeweiligen IF-Zweig kommen die Funktionen für die Schrittmotorsteuerung. Die ISR läuft dann immer.
oki, damit hat sich mein Problem aber noch immer nicht gelöst. Zum einen stoppt die Frequenz nicht, egal was ich für Befehle eingebe. Zum anderen kann ich nach deinem oben genannten Programm die beiden Motoren nicht ablaufen lassen. Ich muss ja beide gleichzeitig auf 1 setzen jedoch läuft immer nur einer der beiden und zwar motor2 ab.
Dein Programm faellt durch die main loop durch. Das ergibt undefiniertes Verhalten.
fetchy schrieb:
> und was kann ich dagegen machen?
// ********************************************************************
// Hauptprogramm
// ********************************************************************
void main (void) {
init();
initzaehler();
pwm();
}
Was soll denn deiner meinung nach passieren, wenn die pwm() funktion
zurueckkommt? Wie gehts dann weiter?
so wie es jetzt geschrieben ist geht es unendlich weiter. wollte ja eigentl nur, dass die Frequenz dann iwann beendet wird, aber die "warte" zeiten wurden einfach übergangen. und wenn ich danach schreibe TR0=0; ändert das an der Situation absolut nichts. Habs schon versucht mit dem Beispiel von Matthias aber das ist iwie auch nicht das wahre weil Motor1 und motor2 nicht gleichzeitig laufen können und nicht einfahc mit motor1=1; motor1=0 angesprochen werden können. Ich kapiers einfach nicht :(
1 | void main (void) { |
2 | init(); |
3 | initzaehler(); |
4 | |
5 | while(1) { |
6 | pwm(); |
7 | }
|
8 | |
9 | |
10 | }
|
oki jetzt bekomm ich dadurch eine frequenz. so weit war ich schon. mein Ziel ist eine Frequenz zu erhalten die dann aber nach einer bestimmten Zeit komplett aufhört und die Ausgangsspannung einfach konstant 0 ist. Dachte das geht in dem ich den Zähler einfach stoppe und die den jeweiligen Port auf 0 setze, aber wohl offensichtlich nicht, weil die main funktion immer wieder abgelaufen wird?
abgesehen davon hätte ich noch eine weitere frage: wie kann ich zwei unterschiedlich frequenzen gleichzeitig ausgeben? weil bei mir überlagern die sich dann und die frequenz wird nur über einen Port ausgegeben.
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.