Forum: Mikrocontroller und Digitale Elektronik xc886 in C; timer stoppen


von fetchy (Gast)


Lesenswert?

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 :)

von Matthias (Gast)


Lesenswert?

TR1 = 0;

von fetchy (Gast)


Lesenswert?

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.

von Matthias (Gast)


Lesenswert?

Dann startet Dein Programm an irgend einer Stelle den Timer neu, 
vielleicht in der ISR? Ohne die genauere Kenntnis Deines Programmes ist 
Hilfe schwer.

von Matthias (Gast)


Lesenswert?

Nachtrag:
TR1 ist Teil des SFR TCON. Vielleicht setzt eine Bitoperation TR1 in 
TCON immer wieder neu.

von fetchy (Gast)


Angehängte Dateien:

Lesenswert?

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 :)

von Matthias (Gast)


Lesenswert?

>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
}

von fetchy (Gast)


Lesenswert?

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();
}

von Matthias (Gast)


Lesenswert?

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.

von fetchy (Gast)


Lesenswert?

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();


}

von Matthias (Gast)


Lesenswert?

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?

von fetchy (Gast)


Lesenswert?

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?

von Matthias (Gast)


Lesenswert?

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.

von fetchy (Gast)


Lesenswert?

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

von fetchy (Gast)


Lesenswert?

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();
      }

von Matthias (Gast)


Lesenswert?

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.

von fetchy (Gast)


Lesenswert?

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.

von Robert W. (rweber)


Lesenswert?

Dein Programm faellt durch die main loop durch. Das ergibt undefiniertes 
Verhalten.

von fetchy (Gast)


Lesenswert?

und was kann ich dagegen machen?

von Robert W. (rweber)


Lesenswert?

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?

von fetchy (Gast)


Lesenswert?

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 :(

von Robert W. (rweber)


Lesenswert?

1
void main (void) {
2
    init();
3
    initzaehler();
4
5
    while(1) {
6
        pwm();
7
    }
8
9
10
}

von fetchy (Gast)


Lesenswert?

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?

von fetchy (Gast)


Lesenswert?

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
Noch kein Account? Hier anmelden.