-
16bit PFM mit Timer1
Guten Tag,
dieses Forum hat mir als Neuling schon viele Fragen beantwortet, doch zu
meiner jetzigen Frage habe ich keine passende Antwort gefunden.
Allgemein möchte ich mit einem Atmega8 eine PFM (Pulsfrequenzmodulation)
umsetzen.
Um dies zu realisieren würde ich Timer1 im 16bit Fast PWM Mode
verwenden.
Dieser soll von 0 bis zu einem variabel einstellbaren Wert hochzählen.
Von 0 bis zu einem fest eingestellten Wert soll der Ausgang OCR1A high
sein und dann bis zu meinem TOP Wert low sein. Somit kann ich die
Periodendauer ändern und die high Zeit bleibt konstant. Im Datenblatt
findet man ein Beispiel auf Seite 88, Fig. 38 bei Period 5 und 6.
Laut Datenblatt (Tab. 39) kann man die PWM mit WGM13:0 = 15 einstellen.
Nun kann ich mit dem OCR1A Register den TOP Wert einstellen. Der Timer
zählt auch brav von 0 bis zu diesem Wert und springt wieder auf 0.
Aber wo kann ich meinen Compare Wert einstellen, bei dem das OCnX Signal
von 1 auf 0 springt? Oder hat jemand eine komplett andere Idee für eine
"hardware" PFM?
Hier mal mein erster Testcode. In diesem fehlt noch eine Zeile, in der
ich den Compare Wert an ein Register übergebe.
$regfile = "m8def.dat"
$crystal = 3686400
$baud = 9600
Ddrb.1 = 1
Tccr1a = &B10000011
Tccr1b = &B00011101
Do
If Ucsra.rxc = 1 Then
Ocr1ah = UDR
Ocr1al = &B11111111
End If
Loop
Vielen Dank für eure Hilfe!!
Gruss Lars
-
Hallo,
ich sehe da auch ein Problem. Es wird nichts anderes übrig bleiben als
OCR1A für die Periodendauer (TOP) zu nehmen
OCR1B als Compare Register zu nehmen und dann
OC1B als Output Pin (nicht OC1A) zu nehmen.
Oder Du nimmst bzw. wagst(!) WGM13:0 = 14 und stellst TOP mittels ICR1 ein. Ist ein Wagnis da ICRn kein double buffering hat.
Ich habe es da mit meiner PWM einfacher weil ich ICR1 nur einmal auf die von mir gewünschte Periodendauer einstellen muss. Und dann für die Pulsweiten mit OCR1A und OCR1B arbeiten kann:
Code:
const unsigned long fosc=F_CPU/8; // Arduino 16 MHz -> 8-Prescaler -> 2 MHz damit ~32.7ms Periodendauer bei 65535
const unsigned int UpperLimit= (unsigned int) (fosc*0.0025);
const unsigned int LowerLimit= (unsigned int) (fosc*0.0005);
const unsigned int Middle= (unsigned int) (fosc*0.0015);
const unsigned int Period= (unsigned int) (fosc*0.020);
void initServos(void) {
cli();
DDRB = (1<<DDB1)|(1<<DDB2);
// Init Timer1 for ICP and FastPWM Mode 14
ICR1=Period;
// fast PWM mode 14
TCCR1A = (1<<COM1A1) | (1<<COM1B1) | (1<<WGM11) | (0<<WGM10); // non-inverting OC-Mode
TCCR1B = (1<<CS11) | (1<<WGM13) | (1<<WGM12); // 8-Prescaler
OCR1A = Middle;
OCR1B = Middle;
sei();
}
-
Hallo,
vielen Dank für die schnelle, helfende Antwort.
Habe das mal ausprobiert und nach etwas hin und her auch hinbekommen. Viel leichter als gedacht.
Habe dazu noch eine kleine Frage.
Wie wird festgelegt, welches der beiden OC1x Register für TOP bzw. Compare verwendet wird? Habe es bis jetzt nicht im Datenblatt gefunden....
Timer1=0 OC1B = 1
Timer1 =OCR1B OC1B =0 (Timer läuft weiter)
Timer1=OCR1A OC1B=1
usw...
Hier mal mein "Beispiel" Code dazu:
Code:
$regfile = "m8def.dat"
$crystal = 3686400
$baud = 9600
Dim Pwm As Word At &H60
Dim Pwm_lo As Byte At &H60 Overlay
Dim Pwm_hi As Byte At &H61 Overlay
Ddrb.2 = 1
Tccr1a = &B10100011
Tccr1b = &B00011001
Ocr1bh = &B00000000
Ocr1bl = &B11111111
Ocr1ah = &B11111111
Ocr1al = &B11111111
Main:
'pwm Wert z.B. über RS232
Ocr1ah = Pwm_hi
Ocr1al = Pwm_lo
Goto Main
Vielen Dank für die Hilfe
Gruß Lars
-
Ich denke mal, dass wird nicht festgelegt sondern ist verdrahtet.
D.h.
OCR1A ist immer das compare register für OC1A und
OCR1B ist immer das compare register für OC1B.
Zusätzlich darf man OCR1A als TOP für OC1A und OC1B festlegen. Wie das in Deinem Fall auf OC1B wirkt ist jetzt klar. Wie das auf OC1A wirkt muss man gesondert nachlesen. (Ich glaube OC1A toggelt dann einfach zwischen 0 und 1 bei erreichen von TOP=OCR1A.)
-
Hallo,
das geht, ich habs selbst mal ausprobiert.
Schau mal im Datenblatt unter Timer 1 / Modes of Operations.
Dirt steht, welche registerbits gesetzt werden müssen, um ICR1 als Top-Wert zu konfigurieren um OCR1A und OCR1B als PWM-Register zu verwenden.
In deinem Fall must du Mode 8, 10 oder 14 verwenden.