Hi manhunt,
Zitat von
manhunt
... vermutlich den Atmega168 ... Phase correct Mode ...
ja, das ist eine hübsche Möglichkeit - allerdings habe ich den Vorteil des Verfahrens bei meinen Anwendungen noch nicht überzeugend gefunden. Ich steuere von einem mega168 in diesem Modus (m)eine irLED:
Code:
/* ============================================================================== */
/* == PWM-Routinen zur IRLED-ansteuerung auf OC1A/PB1 ======================= */
void TC1PWM_init(void) //Init Timer/Counter 1, PWM-Signal
{ // PWM aktivieren
TCCR1A |= (1<<COM1A1); //Clear/set OC1A on Compare Match doc S132
// also Port PB3, vgl. auch PWM-routine unten
TCCR1B |= (1<<CS10); // cs10 <=> clk/1 => no prescaling doc S 134
TCCR1B |= (1<<WGM13); // PWM, Phase+Frequency correct doc S 134
ICR1 = 278; // =>PWM-Frequenz 20MHz/(2*278) => 36,0kHz/27,8µs
/* Interrupts deaktivieren. Siehe Registerbelegung :
mega168 Bit7 6 5 4 3 2 1 0
TIMSK1 – – ICIE1 – – OCIE1B OCIE1A TOIE1
im m168 ? ? ? ? ? ? ? ? */
//
TIMSK1 &= ~(1<<OCIE1A); // Tmr/Cntr1 Oput CompA/B Mtch intrrpt disab
TIMSK1 &= ~(1<<OCIE1B); // Tmr/Cntr1 Oput CompA/B Mtch intrrpt disab
TIMSK1 &= ~(1<<TOIE1); // Tmr/Cntr1 Overflow interrupt disabled
}
/* ============================================================================== */
void setSRV1(uint16_t speed1) //Relative Pulslänge auf OC1A/PB1
{OCR1A = speed1;} // z.B. für SFH5110
/* ============================================================================== */
Diesen Modus gibt es (natürlich) auch bei anderen Controllern. Auf einem tiny2313 hatte ich mir damit eine SEHR feinfühlig arbeitende PWM für einen Servo gemacht:
Code:
// =================================================================================
// ======= Die untere Routine modifiziert für Servotester tiny2313 ==============
// =================================================================================
// === Routinen zur Interrupterzeugung auf OC1A/PB1 ============================
void TC1TMR_init(void) //Init Timer/Counter 1, PWM-Signal
{ // PWM aktivieren
TCCR1B |= (1<<WGM13); // ??? doc S???
TCCR1B |= (1<<CS11); // cs10 <=> clk/8 doc S111
ICR1 = 25000;
OCR1A = 1000;
TIMSK |= (1<<OCIE1A); // Tmr/Cntr1 Oput CompA Mtch intrrpt enabld
TIMSK |= (1<<OCIE1B); // Tmr/Cntr1 Oput CompB Mtch intrrpt enabld
}
// =================================================================================
// === Nicht unterbrechbare ISR für TIMER1_COMPA_vect ===========================
// == Aufgaben: ISRoutine für den ca. 20 ms-Servozyklus
ISR(TIMER1_COMPA_vect) //
{
PORTB ^= (1<<PB1); // Port toggeln
}
// =================================================================================
Der Bereich des Servosignals geht dabei von
Code:
// for(loopSrv=500; loopSrv<3750; loopSrv++) // Servoloop laufen lassen
. . . .
OCR1A = loopSrv;
. . . .
und überstreicht damit etwas mehr als den zulässigen Bereich, in dem meine Servos arbeiten (können). Das Register ICR1 dient dazu, die Phasendauer der PWM auf ungefähr 20ms zu dimensionieren (Controllerquarz mit 20 MHz) und mit dem OCR1A wird die Rampe bemessen. Soweit die Hardwarefunktion. Um die Rampe dann wirklich korrekt zu bekommen, muss in der ISR der Ausgang getoggelt werden - ist ein bisschen tricky, läuft aber eben extrem feinfühlig. So feinfühlig braucht das aber wohl niemand, ich hatte das als Servotester gemacht.
Lesezeichen