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


von Benjamin Munske (Gast)


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!

von Jörg Wunsch (Gast)


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.

von Uwe Nagel (Gast)


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

von Jörg Wunsch (Gast)


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.

von Uwe Nagel (Gast)


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

von Jörg Wunsch (Gast)


Lesenswert?

Ach, dass das zwei Timer waren, hatte ich bereits verdrängt.

von Benjamin Munske (Gast)


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?

von Peter Dannegger (Gast)


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

von Benjamin Munske (Gast)


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?

von Peter Dannegger (Gast)


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

von Benjamin Munske (Gast)


Lesenswert?

Das betrifft doch aber nur Timer1 - was hat das mit Timer0 zu tun?

von Peter Dannegger (Gast)


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

von Benjamin Munske (Gast)


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?

von Peter Dannegger (Gast)


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

von Benjamin Munske (Gast)


Lesenswert?

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

von Benjamin Munske (Gast)


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?

von Volkmar (Gast)


Lesenswert?

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

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

Volkmar

von Benjamin Munske (Gast)


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?

von thkais (Gast)


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.

von Benjamin Munske (Gast)


Angehängte Dateien:

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?

von Benjamin Munske (Gast)


Angehängte Dateien:

Lesenswert?

Signal an den Ausgängen des L298

von Benjamin Munske (Gast)


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!*

von Volkmar (Gast)


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

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.