mikrocontroller.net

Forum: Compiler & IDEs 16-Bit Timer im Comparemode funktioniert nicht


Autor: Benjamin Munske (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Leute,

ich habe eine Software PWM programmiert, allerdings hält Timer1 seine
Zeit nicht ein.
Hier erst einmal ein Ausschnitt aus der Software:

void init_timer(void)
{
  TCCR0 |= (1<<CS01);          // CLK/8 8-Bit Timer
  TCCR1B |= (1<<CS11)|(1<<CTC1);    // CLK/8 16-Bit Timer
    TCNT0 = 0;                          // Reset Timer0
  TCNT1H = 0;
  TCNT1L = 0;
  OCR1AH = 0;
  OCR1AL = 125;            // Compare-Wert für 16-bit Timer festlegen (1 
=
0,8µs)
    TIMSK |= (1<<TOIE0);
  sei();                // Enable Interupts
  return;
}

SIGNAL(SIG_OVERFLOW0)          // Timer0 = 255
{
  PORTD |= (1<<Enable);        // Schaltet den Enable-Pin ein
  OCR1AH = 0;
  OCR1AL = 125;            // Compare-Wert für 16-bit Timer festlegen (1 
=
0,8µs)
  TIMSK |= (1<<OCIE1A);        // Aktiviert den Compare-Interrupt
  return;
}

SIGNAL(SIG_OUTPUT_COMPARE1A)      // Timer1 = Wert
{
  PORTD &= ~(1<<Enable);        // Schaltet den Enable-Pin ab
  TIMSK &= ~(1<<OCIE1A);        // Deaktiviert den Compare-Interrupt
  TCNT1H = 0;
  TCNT1L = 0;
  return;
}

Zur Erklärung: Ich benutze einen AT90S2313, der mit 10Mhz getaktet ist.
Bei beiden Timern benutze ich einen Vorteiler von 8, so dass Timer0
immer nach 204µs einen Overflow erzeugt und somit in SIG_OVERFLOW0
springt - Timer0 stellt also die Trägerfrequenz von ca. 4900Hz für die
PWM. Dies funktioniert soweit auch (mit dem Oszilloskop geprüft).
Jetzt sollte immer wenn ein Overflow erreicht ist Timer1 für eine
bestimmte Zeit (je nach Pulsweite) einen Portpin einschalten. In meinem
Fall sollten es ca. 100µs sein, so dass ich quasi ein relativ
gleichmäßiges Rechtecksignal bekomme. Die 100µs habe ich mir so
errechnet: 10Mhz / 8 (Vorteiler) = 1250000, d.h. er zählt eben so oft
in einer Sekunde. In 100µs zählt er also von 0 bis 125. So habe ich
dann OCR1AL = 125; auch eingestellt (s.o.).
Mein Oszilloskop sagt mir allerdings, dass der Portpin nur ca. 4,5µs
angeschaltet ist. Woran kann das liegen - habe ich etwas übersehen oder
missverstanden?
Ich hoffe, dass mir jemand helfen kann, da ich schon einmal das gleiche
Problem hatte und damals auch zu keiner Lösung gekommen bin!

Vielen Dank!

Autor: Jörg Wunsch (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Klingt so, als würde er beim Erreichen des compare match einen
(soft) reset auslösen.  Der häufigste Fehler hier wäre ein
Schreibfehler im Namen des Vektors, aber der stimmt bei dir.  Da
bliebe mir nur noch rätselratenderweise zu vermuten, dass du dem
Linker nicht die korrekte -mmuc=at90s2313 Option mit auf die
Reise gegeben hast.

Autor: Uwe Nagel (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
solltest du in deinem SIG_OVERFLOW nicht lieber den Timer1 Wert auf 0
setzen, statt das Compare-Register neu zu laden? Der Timer steht doch
irgendwo beim Timer0-Interrupt. Das Compare-Register wird in init_timer
schon gesetzt und dürfte sich nie verändern.
Zusätzlich würde ich empfehlen 16-Bi Zugriffe zu verwenden also TCNT1
und OCR1A zu schreiben, dann bringt man die Reihenfolge der Zugriffe
nicht durcheinander.

Uwe

Autor: Jörg Wunsch (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Das Timer-Register willst du beim Overflow nicht wirklich vermasseln.
Das ist kurz davor nämlich gerade 0 gewesen (eventuell auch im Moment
immer noch), sonst hättest du diesen Interrupt nicht bekommen.

Aber in der Tat, das Setzen des Overflow-Werts ist unnütz.  Eigentlich
ist auch das Ein- und Ausschalten des Overflow-Interrupts unnütz
(sofern es wirklich in jeder Periode passieren soll).

Was ich schlicht nicht verstehe ist, warum beim compare match der
Timer auf 0 zurückfallen soll.  Warum tickert der hier nicht einfach
weiter bis zum nächsten Overflow?

Das hatte ich mir nur beim letzten Kommentar geklemmt, weil das mit
dem eigentlichen Problem nichts zu tun hat.

Autor: Uwe Nagel (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Der Overflow kam doch von Timer 0, die PWM Zeit macht Timer 1. Also
müsste man doch beim Overflow den Timer 1 nullen, damit er jetzt
loszählt und nach 125 Takten ein Compare-Interrupt autritt.
Ich glaube ja auch, dass man das alles nur mit Timer 1 machen kann,
weiss aber gerade nicht, ob der 90s2313 das schon konnte...

Autor: Jörg Wunsch (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ach, dass das zwei Timer waren, hatte ich bereits verdrängt.

Autor: Benjamin Munske (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

ich habe eure Tipps angewendet, doch leider keinen Erfolg erzielt. Hier
ist noch einmal der aktuelle Quellcodeausschnitt:

void init_timer(void)
{
  TCCR0 |= (1<<CS01);          // CLK/8 8-Bit Timer
  TCCR1B |= (1<<CS11)|(1<<CTC1);    // CLK/8 16-Bit Timer
    TCNT0 = 0;                          // Reset Timer0
  TCNT1 = 0;
  OCR1A = 125;            // Compare-Wert für 16-bit Timer festlegen (1 
=
0,8µs)
    TIMSK |= (1<<TOIE0);
  sei();                // Enable Interupts
  return;
}

SIGNAL(SIG_OVERFLOW0)          // Timer0 = 255
{
  PORTD |= (1<<Enable);        // Schaltet den Enable-Pin ein
  TCNT1 = 0;              // Timerregister resetten
  TIMSK |= (1<<OCIE1A);        // Aktiviert den Compare-Interrupt
  return;
}

SIGNAL(SIG_OUTPUT_COMPARE1A)      // Timer1 = Wert
{
  PORTD &= ~(1<<Enable);        // Schaltet den Enable-Pin ab
  TIMSK &= ~(1<<OCIE1A);        // Deaktiviert den Compare-Interrupt
  return;
}

Der Linker ist richtig eingestellt, das habe ich auch geprüft.
Zwischenzeitlich habe ich nur den Timer1 laufen lassen, um zu prüfen,
ob der richtig läuft: Alleine funktionierte er natürlich - war ja klar
lol. Aber wenn beide Timer zusammen laufen, dann sind die Zeiten von
Timer1 scheinbar zu kurz. Woran kann das bloß liegen?

Autor: Peter Dannegger (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
"Aber wenn beide Timer zusammen laufen, dann sind die Zeiten von
Timer1 scheinbar zu kurz."


Das ist korrekt.
T1 zählt ja immer nur bis 125, d.h. wenn T0 256 erreicht, ist das
Compare schon längst passiert und der Interrupt wird ausgeführt, sobald
Du ihn freigibst.


Peter

Autor: Benjamin Munske (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
ach so, das wusste ich als C-Anfänger noch nicht! Wie kann ich das
umgehen? Dann müsste man das ganze doch eigentlich auch mit einem Timer
machen können, d.h. nach einem Mal bis 255 zählen einfach den
Compare-Interrupt einschalten und dann fängt Timer0 ja wieder von vorne
an, so dass er bei 125 das Compare-Signal auslöst, oder?

Autor: Peter Dannegger (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
"das wusste ich als C-Anfänger noch nicht"

Das hat überhaupt nichts mit C zu tun, sondern mit dem Lesen des
Datenblatts:

• Bit 3 - CTC1: Clear Timer/Counter1 on Compare Match
When the CTC1 control bit is set (one), the Timer/Counter1 is reset to
$0000 in the clock cycle after a compareA match. If
the CTC1 control bit is cleared, Timer/Counter1 continues counting and
is unaffected by a compare match.


Peter

Autor: Benjamin Munske (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Das betrifft doch aber nur Timer1 - was hat das mit Timer0 zu tun?

Autor: Peter Dannegger (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
"Das betrifft doch aber nur Timer1 - was hat das mit Timer0 zu tun?"


???

Du benutzt doch beide.

Während T0 bis 255 zählt, hat T1 mindestens zweimal bis 125 gezählt.

Das Compare-Flag ist also gesetzt und warten nur darauf, bis Du endlich
den Interrupt freigibst.

Der SIG_OUTPUT_COMPARE1A wird also direkt nach Ende des SIG_OVERFLOW0
ausgeführt.


Peter

Autor: Benjamin Munske (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ach so, dann habe ich dich das letzte Mal falsch verstanden. Das würde
also bedeuten, dass ich das Compare-Flag löschen müsste, oder? Geht das
überhaupt oder hast du eine andere Lösung?

Autor: Peter Dannegger (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
"dass ich das Compare-Flag löschen müsste"


Entweder das oder einfach durchlaufen lassen (CTC1 = 0).


Du weißt aber schon, daß T1 auch mehrere Hardware-PWM-Modi hat ?


Peter

Autor: Benjamin Munske (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Das schon, aber doch nur am OC1-Pin und der wiederum hat in meiner
Schaltung leider schon eine andere Aufgabe zu erledigen.

Autor: Benjamin Munske (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
So, die PWM funktioniert dank Peter Danneggers Tipp wunderbar. Jetzt hat
der PWM-Anfänger allerdings dazu noch ein paar Fragen:

Wie kann ich bei einer Stromkontrolle durch PWM ausrechnen, bei welcher
Pulsweite ein bestimmter Strom fließt?

Ich vermute mal, dass Pulsbreite und Strom nicht linear abhängig sind,
oder?

Autor: Volkmar (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Ich vermute mal, dass Pulsbreite und Strom nicht linear abhängig
sind,
oder?

Das hängt ganz von Deiner Last ab...

Volkmar

Autor: Benjamin Munske (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich habe einen Motor über eine H-Brücke an der Schaltung angeschlossen -
kennst du die Möglichkeit, wie man dort den Strom in Abhängigkeit von
der Pulsweite berechnet?

Autor: thkais (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Das kannste knicken, denn der Strom ist auch abhängig von der Last am
Motor. Du kannst bestenfalls die Effektivspannung in etwa ausrechnen.
Um den Strom bestimmen zu können, müßtest Du ihn messen.

Autor: Benjamin Munske (Gast)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Leute,

ich habe jetzt mal ein PWM laufen mit der Frequenz von ca. 500Hz und
einer Pulsweite von 100µs. (s. Anlage) An den Ausgängen des L298 ist
allerdings ein Signal zu messen, welches ich in meinem nächsten Posting
als Bild zeigen werde. Mein Schrittmotor gibt auch nur ein müdes Pfeifen
von sich und bewegt sich nicht.

Hat jemand eine Idee, warum aus der Treiberstufe so ein komisches
Signal herauskommt?

Autor: Benjamin Munske (Gast)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Signal an den Ausgängen des L298

Autor: Benjamin Munske (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
*Edit: Die Bilder sind leider vertauscht. PWM2 ist das Signal an den
Eingängen des L298 und PWM1 das an den Ausgängen - sorry!*

Autor: Volkmar (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Kann es sein, daß das PWM1 (die Ausgänge) auf dem Oszi nicht ordentlich
getriggert ist? Kannst Du mal versuchen, daß Eingangssignal als Trigger
zu nehmen?

Die fallende Flanke (soweit man die noch als Flanke bezeichnen kann),
sollte von der Nicht-Linearität Deines Motors kommen.

Bezüglich Schrittmotoren habe ich zuwenig Ahnung, bei einem normalen
Motor würde ich sagen, daß der Anlaufstrom zu groß ist, und der Motor
mit der kurzen Impulsbreite nicht anläuft.

Volkmar

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.