www.mikrocontroller.net

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


Autor: fetchy (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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 :)

Autor: Matthias (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
TR1 = 0;

Autor: fetchy (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Matthias (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Matthias (Gast)
Datum:

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

Autor: fetchy (Gast)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht 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 :)

Autor: Matthias (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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:
// Testprogramm TIMER
// Beispiel: LED blinkt im o.5s Takt

#include "reg51.h"   // Register des 8051MCs
#define LED P0_7

// Timer 0 - Zeitbasis
// Timer0: Reload Wert für T0 T=1/(fosz/12)*(65536-(TH0*256+TL0))
// RELOAD (16bit) = -(0.01 * FREQ_OSC / 12 - 65536);
// RELOAD-Wert für 10ms = 0xDC00 (56320) bei FOSZ 11.059200 MHz
#define TH0Reload 0xDC
#define TL0Reload 0x00

static unsigned char int_delay = 0;

// ********************************************************************
// Timer 0 Interrupt
// Routine wird alle 10ms aufgerufen
// ********************************************************************
void TIMER0ISR (void) interrupt 1 {
  TH0  = TH0Reload; // Update MSB
  TL0  = TL0Reload; // Update LSB
  int_delay++;
  if (int_delay == 50) {
    // LED blinkt im Sekundentakt (500ms an, 500ms aus)
    // nur Bsp., anpassen!
    LED = !LED;
    int_delay = 0;
  }
}

// ********************************************************************
// Grund-Initialisierung
// ********************************************************************
void init (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
}

// ********************************************************************
// Hauptprogramm
// ********************************************************************
void main (void) {
  init();
  while(1);
}

Autor: fetchy (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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();
}

Autor: Matthias (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: fetchy (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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();


}

Autor: Matthias (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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?

Autor: fetchy (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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?

Autor: Matthias (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: fetchy (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: fetchy (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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();
      }

Autor: Matthias (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
vergiss das TRx Bit mal ganz, bleibt immer 1 und wird nicht mehr 
verändert.
// ********************************************************************
// Timer 0 Interrupt
// Routine wird alle xxms aufgerufen
// ********************************************************************
void TIMER0ISR (void) interrupt 1 {
  TH0  = TH0Reload; // Update MSB
  TL0  = TL0Reload; // Update LSB
  // Motor 1
  if (motor1) {
    // hier alles tun was Motor 1 betrifft 
   }
  // Motor 2
  if (motor2) {
    // hier alles tun was Motor 2 betrifft 
   }
  usw.
 }

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.

Autor: fetchy (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Robert Weber (rweber)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Dein Programm faellt durch die main loop durch. Das ergibt undefiniertes 
Verhalten.

Autor: fetchy (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
und was kann ich dagegen machen?

Autor: Robert Weber (rweber)
Datum:

Bewertung
0 lesenswert
nicht 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?

Autor: fetchy (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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 :(

Autor: Robert Weber (rweber)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
void main (void) {
    init();
    initzaehler();

    while(1) {
        pwm();
    }


}

Autor: fetchy (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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?

Autor: fetchy (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.