Hallo,
ich würde gerne exakt alle 5 Millisekunden auf einem Pin ein Signal
ausgeben, welches etwa 100 Mikrosekunden breit ist. Zu diesem Zweck
eignet sich theoretisch sehr gut der Timer1 im Fast-PWM mode. Laut
Datasheet kann ich dafür z.B. für den Timer1 den mode 15 nehmen. Habe
alles so gemacht wie im Datasheet beschrieben, doch es funktioniert
einfach nicht. Benutze ich die Simulation im AVR-Studio, so geschieht so
einiges was keinen Sinn macht, nur nicht die Funktionalität von mode 15.
In der Simulation sehe ich deutlich dass der Mode 15 eingestellt ist,
aber der TCNT1 zählt auch gerne mal wieder runter wie es im dual-slope
üblich ist was aber nicht möglich sein sollte im mode 15.
Compare-Matches werden generell ignoriert. Im folgenden der komplette
Quelltext in C. Wo liegt der Fehler? Bin für Hilfe aus dem Forum sehr
dankbar, da ich an diesem Punkt keine Lösung weiss. Beste Grüße,
Olivier
#include <avr/io.h>
int main()
{
//COM1A1: Clear OC1A (PB1) on Compare-Match, set OC1A (PB1) at BOTTOM
//WGM11, WGM10: Mode 15, FAST-PWM, OCR1A defines TOP
TCCR1A |= (1<<COM1A1) | (1<<WGM11) | (1<<WGM10);
//WGM13, WGM12: Mode 15
//CS11: Prescaler to 8
TCCR1B |= (1<<WGM13) | (1<<WGM12) | (1<<CS11);
OCR1A = 200; //Defines TOP
ICR1 = 50; //Compare-Match
TCNT1 = 0; //Counter-Reset
DDRB |= (1<<PB1); //Enable OC1A for PWM-Output
for(;;);
return 0;
}
...OCR1A = 200; //Defines TOP
ICR1 = 50; //Compare-Match
TCNT1 = 0; //Counter-Reset
DDRB |= (1<<PB1); //Enable OC1A for PWM-Output....
Das passt nicht:
ICR1 = 50; Compare Match ?????????????
Das glaube ich nicht! EIn Compare Match wird immer mit OCR1A/B
generiert...
OCR1A = 200; //Defines TOP ????????
Der TOP-Wert ist meineswissen eher OCR1B oder ICP..
Musst du nochmal im Datenblatt lesen...
@ Matthias (Gast):
Doch, die Register stimmen, der Mode 15 ist wohl so gedacht, falls man
das (gepufferte) OCR1n Register im Betrieb öfter verändern muss -- hier
wäre mode 14 (ICR1 als TOP) wahrscheinlich angebrachter.
Der Duty-Cycle stimmt auf jeden Fall nicht (50/200 = 25% an) weil
0.0001s/0.005s = 2% verlangt ist.
@OP:
Dass der Simulator merkwürdiges anzeigt, wenn du C-Code durchsteppst,
ist dir hoffentlich klar: man kann kaum vorhersagen wie lange ein C
Statement dauert und so entsteht der Eindruck vom Rückwärtslaufenden
Timer (Wie bei drehenden Rädern, v.A. auf Video). Bei Hardware-einheiten
ist dem Simulator nicht so recht zu trauen, also "in echt" ausprobieren!
hth. Jörg
"16-bit Timer/Counters on all devices have several problems with PWM,
prescaler and output compare. Output compare registers are not buffered
properly."
(Zitat AVRStudio-Hilfe, Simulator, Known Issues)
Zum Simulator:
Im Simulator läßt sich kein Fast-PWM-Mode einstellen, wohl aber z.B. der
Mode 1, 2, 3 und auch mindestens ein CTC-Mode (Mode12).
Fast-PWM auf ATmega88:
Der Mode 15 (Datasheet P.132) funktioniert auf meinem ATmega88 nicht,
wohl aber der Mode 14. So bleiben zwar die Doublebuffereigenschaften des
Registers OCR1A ungenutzt, beim Verändern von ICR1 ist daher Vorsicht
geboten so dass ICR1 immer >= TCNT1 ist.
Im folgenden der Quelltext, alle 5 Millisekunden wird ein 100
Mikrosekunden breiter Puls ausgegeben, sofern der Controller mit 16 MHz
getaktet wird:
--------------------------------------------------------------------
#include <avr/io.h>
int main()
{
TCCR1A |= (1<<WGM11); //Mode 14, Fast-PWM
TCCR1B |= (1<<WGM13) | (1<<WGM12); //Mode 14, Fast-PWM
OCR1A = 200; //100 Mikrosekunden Puls
ICR1 = 10000; //Periodendauer 5 Millisekunden *1)
TCCR1A |= (1<<COM1A1); //HIGH at BOTTOM, LOW at
Compare-Match
TCNT1 = 0; //Timer Reset
TCCR1B |= (1<<PB1); //Timer starten mit Prescaler = 8
DDRB |= (1<<PB1); //PWM-Output OC1A bzw. PB1
freischalten
for(;;);
return 0;
}
--------------------------------------------------------------------
*1)
ICR1 kann nur im Fast-PWM-Mode beschrieben werden, deswegen muß zuerst
der Fast-PWM-Mode in den Registern TCCR1A und TCCR1B eingestellt werden.
Gruß Olivier
Sorry, kleine Korrektur ist noch fällig:
Zyklus von 5 Millisekunden: ICR1 = 9999;
(0 bis 9999 => 10000 Counts)
Puls von 100 Mikrosekunden: OCR1A = 199;
(OC1A wird bei TCNT=BOTTOM=0000 gesetzt und
bei TCNT=200 wieder gelöscht, also im nächsten
Count nach dem Compare-Match)
Also auf einem M8 funktioniert Mode 15.
TCCR1A = 1<<COM1B1 ^ 1<<WGM11 ^ 1<<WGM10 ;
TCCR1B = 1<<WGM13 ^ 1<<WGM12 ^ 1<<CS10;
OCR1A=65535; //TOP
OCR1B=32767; //50%
Aber Achtung, echte 0% kriegt man nicht hin. Gut erkennbar bei kleinem
TOP und nem Oszi.
Bsp. (s. Bild):
OCR1A=3; //TOP
OCR1B=0; //0%?