root2
10.04.2007, 12:33
Nachdem dies mein erster Post hier ist ein herzliches "Hallo Forum" an alle.
Nun gleich zu meinem Problem:
Ich möchte mit einem atmega48 (@ 8MHz) per Timer1 eine PWM am Ausgang PortB.1 erzeugen, die eine LED in der Helligkeit steuert (in meinem Fall ein zyklisches An- und Abschwellen).
Die PWM hat folgende Kenngrößen: f=80Hz, Duty Cycle variabel von 0..100%
Der Duty Cycle der PWM wird dabei durch einen zweiten Timer alle 10ms neu gesetzt (der Wert wird aus einem uchar array gelesen und dann auf das passende Maß umgerechnet). Nachdem das Array einmal durchlaufen ist, wird eine Zeit lang gewartet (der Ausgang soll während der Wartezeit auf 0 sein).
Die PWM funktioniert auch schon recht gut. In der Wartezeit ist der Pegel am Ausgang auch konstant 0. Nur habe ich während des Array Durchlaufs - selbst wenn das ganze Array mit 0x00 (0% Duty Cycle) gefüllt ist - das Problem, dass im Oszi immernoch in unregelmäßigen Abständen sehr schmale Peaks zu erkennen sind und der Ausgang nicht konstant abgeschaltet bleibt.
Nachtrag: Ich habe gerade am Oszi bemerkt, auch bei 100% Duty Cycle ist die Einschaltzeit nicht konstant auf 1, sondern fällt in unregelmäßigen Abständen immer mal wieder auf 0 ab. Das stört mich nicht so arg, aber der Wert bei 0% Duty Cycle sollte wirklich dauernd auf 0 sein.
Hier ein (etwas vereinfachter) Auszug aus dem Code (ich verwende IAR Embedded Workbench als IDE/Compiler):
void UpdateDutyCycle(void)
{
if(bArrayFinished < 0x01) // we're not at the end of the array, so update the duty cycle
{
OCR1A = ucDutyCycleArray[ucDutyIndex] * 39 / 10; // duty cycle of PWM for LED calculated via uchar array
ICR1 = 0x0188; // TOP value: 0x0188 = 125us period @ prescaler 256 and 8MHz
TCCR1A = (1<<COM1A1 | 1<<WGM11); // Clear OC1A on match, set OC1A on BOTTOM / fast PWM, ICR1 used for TOP
TCCR1B = (1<<WGM13 | 1<<WGM12 | 1<<CS12); // fast PWM, ICR1 used for TOP / timer prescaler 256
PRR = (1<<PRTW1)|(1<<PRTIM0)|(1<<PRUSART0); // Turn Timer1 on as we need it running here
}
else // we're at the end of the array, now wait some time
{
SET_LED_OFF(); // Reset LED periodically via #DEFINE to ensure it stays turned off during wait time
TCCR1B = (1<<WGM13 | 1<<WGM12 | 0<<CS12 | 0<<CS11 | 0<<CS10); // Turn off Timer1
/* wait routine goes here... */
}
}
Mache ich hier einen Denkfehler, was die Benutzung von ICR1 und OCRA1 angeht?
Danke schon jetzt für euere Hilfe.
Bernd
Nun gleich zu meinem Problem:
Ich möchte mit einem atmega48 (@ 8MHz) per Timer1 eine PWM am Ausgang PortB.1 erzeugen, die eine LED in der Helligkeit steuert (in meinem Fall ein zyklisches An- und Abschwellen).
Die PWM hat folgende Kenngrößen: f=80Hz, Duty Cycle variabel von 0..100%
Der Duty Cycle der PWM wird dabei durch einen zweiten Timer alle 10ms neu gesetzt (der Wert wird aus einem uchar array gelesen und dann auf das passende Maß umgerechnet). Nachdem das Array einmal durchlaufen ist, wird eine Zeit lang gewartet (der Ausgang soll während der Wartezeit auf 0 sein).
Die PWM funktioniert auch schon recht gut. In der Wartezeit ist der Pegel am Ausgang auch konstant 0. Nur habe ich während des Array Durchlaufs - selbst wenn das ganze Array mit 0x00 (0% Duty Cycle) gefüllt ist - das Problem, dass im Oszi immernoch in unregelmäßigen Abständen sehr schmale Peaks zu erkennen sind und der Ausgang nicht konstant abgeschaltet bleibt.
Nachtrag: Ich habe gerade am Oszi bemerkt, auch bei 100% Duty Cycle ist die Einschaltzeit nicht konstant auf 1, sondern fällt in unregelmäßigen Abständen immer mal wieder auf 0 ab. Das stört mich nicht so arg, aber der Wert bei 0% Duty Cycle sollte wirklich dauernd auf 0 sein.
Hier ein (etwas vereinfachter) Auszug aus dem Code (ich verwende IAR Embedded Workbench als IDE/Compiler):
void UpdateDutyCycle(void)
{
if(bArrayFinished < 0x01) // we're not at the end of the array, so update the duty cycle
{
OCR1A = ucDutyCycleArray[ucDutyIndex] * 39 / 10; // duty cycle of PWM for LED calculated via uchar array
ICR1 = 0x0188; // TOP value: 0x0188 = 125us period @ prescaler 256 and 8MHz
TCCR1A = (1<<COM1A1 | 1<<WGM11); // Clear OC1A on match, set OC1A on BOTTOM / fast PWM, ICR1 used for TOP
TCCR1B = (1<<WGM13 | 1<<WGM12 | 1<<CS12); // fast PWM, ICR1 used for TOP / timer prescaler 256
PRR = (1<<PRTW1)|(1<<PRTIM0)|(1<<PRUSART0); // Turn Timer1 on as we need it running here
}
else // we're at the end of the array, now wait some time
{
SET_LED_OFF(); // Reset LED periodically via #DEFINE to ensure it stays turned off during wait time
TCCR1B = (1<<WGM13 | 1<<WGM12 | 0<<CS12 | 0<<CS11 | 0<<CS10); // Turn off Timer1
/* wait routine goes here... */
}
}
Mache ich hier einen Denkfehler, was die Benutzung von ICR1 und OCRA1 angeht?
Danke schon jetzt für euere Hilfe.
Bernd