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!
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.
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
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.
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...
Ach, dass das zwei Timer waren, hatte ich bereits verdrängt.
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?
"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
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?
"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
Das betrifft doch aber nur Timer1 - was hat das mit Timer0 zu tun?
"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
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?
"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
Das schon, aber doch nur am OC1-Pin und der wiederum hat in meiner Schaltung leider schon eine andere Aufgabe zu erledigen.
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?
> Ich vermute mal, dass Pulsbreite und Strom nicht linear abhängig
sind,
oder?
Das hängt ganz von Deiner Last ab...
Volkmar
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?
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.
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?
*Edit: Die Bilder sind leider vertauscht. PWM2 ist das Signal an den Eingängen des L298 und PWM1 das an den Ausgängen - sorry!*
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.