PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : 16bit PFM mit Timer1



bieber
12.01.2010, 15:34
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

rossir
12.01.2010, 21:24
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:

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();
}

bieber
14.01.2010, 20:28
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:





$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

rossir
14.01.2010, 23:42
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.)

Mitch64
27.01.2010, 20:26
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.