Forum: Mikrocontroller und Digitale Elektronik Timerproblem bei PWM nach Tutorial „SOFT-PWM“ ( Atmega8)


von Oger (Gast)


Angehängte Dateien:

Lesenswert?

Hallo,

ich beschäftige mich gerade mit der PWM-Problematik für ein LED-Projekt. 
Ich benutze auf dem Board von Pollin einen Atmega8, der extern mit 16MHz 
getaktet wird. Der µC macht auch soweit erstmal das, was er soll. 
Programmierung mit AVRISPMKII funktioniert, die UART gibt mir das 
Gewünschte auf dem Terminal aus, die Interrupts und die Timer 
funktionieren. Soweit so gut.

Für die PWM-Geschichte versuche ich, den erste Codevariante aus dem TUT 
zu verwenden:

http://www.mikrocontroller.net/articles/Soft-PWM

Ich möchte mit 100Hz und 255 Schritten arbeiten. Ich lasse also meinen 
Timer bis 627 zählen, das sind bei 16MHz 25,5kHz. Wenn ich jetzt mit 
dieser Frequenz jeweils bis 255 zähle, dann sind das ca. 100Hz.
Ich habe das nach bestem Wissen und Gewissen programmiert, aber ich muss 
einen ganz hohlen Denkfehler gemacht haben, denn die LED wird nicht etwa 
dunkler, sondern sie blinkt nur mit ca. 2Hz. Die UART sagt, dass der 
PWM-Zähler brav immer von 0 bis 255 zählt und auch an der entsprechenden 
Stelle die LED abschaltet. Also z.B. bei 150, wenn der Sollwert bei 150 
steht. Aber irgendwie geht das viel zu langsam.
Ich weiß echt nicht, was ich noch machen könnte. Ich habe das TCCR1B 
auseinandergenommen, überall die Frequenzen geprüft und bin mit meinem 
Latein erstmal am Ende. Es wäre schön, wenn mal jemand über meinen 
Quellcode drüber schauen könnte.
Danke!

Olaf

von Oliver J. (skriptkiddy)


Lesenswert?

Der Atmega 8 hat 2 CTC-Modi. Der, den du verwendest (WGM=1100), lässt 
den Timer bis ICR1 laufen und nicht wie du annimmst bis OCR1A.

Gruß Skriptkiddy

von Oger-Berserker (Gast)


Lesenswert?

Hallo Oger hier dein Quelltext:

//************* Timer *********************
  TCCR1B=0;
  TCCR1B |=(1<<CS10); // ohne 1024 Prescaler
  TCCR1B &=~(1<<CS11);
  TCCR1B &=~(1<<CS12);
  TCCR1A=0;
  TCCR1A &=~(1<<WGM10); // CTC Modus
  TCCR1A &=~(1<<WGM11);
  TCCR1B |=(1<<WGM12);
  TCCR1B |=(1<<WGM13);
  OCR1AH =0x02; // Vergleichswert:3D09=15625=16000000/1024 =1s  0273 ist 
für PWM 627Takte für 100Hz mal 255 zählen
  OCR1AL =0x73;

  TIMSK |=(1<<OCIE1A); //Interrupt an

  //*****************************************

  //*************** Interrupt ***************

  MCUCR |= (1<<ISC01); // steigende Flanke für INT0
  MCUCR |= (1<<ISC00);
  MCUCR |= (1<<ISC11); // steigende Flanke für INT1
  MCUCR |= (1<<ISC10);

  GICR |=(1<<INT1);  // INT0 und INT1 aktivieren
  GICR |=(1<<INT0);

Fass deine Einstellungen zu jeweils 8-Bit zusammen. Also die Register in 
einem Rutsch programmieren. OCR1A ist ein 16Bit-Reg kannst also auch 
OCR1A = 0x0273; schreiben.

von Oger (Gast)


Lesenswert?

Hallo,

danke für die Antworten!

@Skriptkiddy:

Ich habe jetzt das WGM auf 0100 geändert, damit laut Datenblatt jetzt 
das OCR1A für CTC benutzt wird. Leider macht der Timer das gleiche, wie 
vorher?!

Was mich am meisten wundert ist, dass ich mit den vorherigen 
Einstellungen problemlos die 1s Zeitbasis für eine Uhr realisiert 
bekommen habe. Dort habe ich nur noch den 1024 Prescaler dringehabt und 
dann bis 15625 gezählt. Das hat wunderbar funkioniert...

@Oger-Berserker:

Danke für den Hinweis. Ich habe das so auseinandergezogen, damit ich 
besser nachschauen kann, was die einzelnen Bits bedeuten.

von Oger-Berserker (Gast)


Lesenswert?

Also da deine UART-Verbindung funktioniert schätze ich mal das deine 
Fuses korrekt eingestellt sind. Wenn nicht kannst du dort ja nochmal 
genau nachschauen.

von Oger (Gast)


Lesenswert?

@Oger-Berserker:

Ja, die Fuses sind in Ordnung. Extern-Crystal/Resonator, High-f... Ich 
werde morgen mal sehen, ob ich an ein Oszi rankomme, evtl. bringt mich 
das weiter.

von Oger (Gast)


Lesenswert?

Tjoa, mittelfristig komme ich nicht ins Labor, also keine Oszimessung. 
Hat noch jemand eine Idee, was das Problem bei meinem Code sein könnte?

von Helfer (Gast)


Lesenswert?

Oger, ich würde das Programm zuerst mal vereinfachen.

1) Weg mit den anderen Interrupts (INT0, INT1)

2) ISR für den COMPA-Interrupt entschlacken.

Die UART-Ausgabe inkl. itoa() haben dort nichts zu suchen. Die 
Debugausgabe von pwm_cnt ist wertlos. Wenn du COMPA-Interrupts 
verlierst, weil dein Debuggerötel zu lange dauert, wird zwar pwm_cnt 
sauber hochgezählt aber die PWM funktioniert nicht mit der 
beabsichtigten Frequenz.

Pi*Daumen:

Aufruf des COMPA-IRQ mit 25,5kHz, d.h. alle 0,04 ms.
Reine Debugausgabe von 2 bis 8 Zeichen bei 9600 Baud: 2 bis 8 ms!
=> Statt 25.5 kHz hast du effektiv nur noch 0,5 kHz bis 0,125 kHz

von Oger (Gast)


Lesenswert?

@Helfer:

Ich glaub' es nicht, die UART-Geschichte in der ISR des COMPA war das 
ganze Problem! Jetzt funktioniert alles wunderbar. Also daran hätte ich 
nie gedacht, dass die Umwandlung für uart_puts und dann natürlich die 
megalangsame Ausgabe selber mir meinen PWM-Takt verderben... Die UART 
war immer mein Standard-Debugger und weil ich kaum mal etwas wirklich 
schnelles gemacht habe, ist es mir nie aufgefallen, was da an Takten 
"verloren geht".

Herzlichen Dank für deine Hilfe!

Oger

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.