oberallgeier
15.03.2016, 13:53
Bitte um Hilfe.
Stand:
Der Timer2 generiert mir den Heartbeat - einen 20 kHz-Interrupt bzw. 50µs, mit dem alle 20 000 Interrupts, also sekündlich, die Heartbeat-LED getoggelt wird. Dieser Timer (nicht jedes Mal Timer2) dient mir auch anderswo, z.B. bei Drehzahlen, für Zeitmessungen. Die Nutzung ist problemlos.
Zum Auslesen eines Servopulses ist eine Genauigkeit von 50µs ungenügend, die Auflösung der Pulse, 1ms bis 2ms beträgt ja grad mal 200 bis 400 Schritte. Daher wurde eine Zeiterfassung direkt mit dem 16bittigen Timer1 geplant.
Plan:
Es wird der Timer1 zum Messen der Pulszeit benutzt. Initialisierung auf normal operation, TOP 0xFFFF, clk/1 = kein Prescaling.
Die Pulse werden von einem PCINT0 am PIN PB5 eingelesen. Die entsprechend geschaltete LED zeigt mit Dimmgrad optisch die eingelesenen Servopulse eines potentiometergesteuerten Servotesters - funktioniert.
Die Zeit vom Pulsstart bis zum Pulsende, PB5=hig bis PB5=low wird in der ISR von PCINT0 ausgelesen: bei Pulsanfang <=> PB5=high, wird OCR1A auf Null gesetzt, bei Pulsende <=> PB5=low, wird der Stand von OCR1A in eine Variablen tPULS (volatile int16/int16_t/ tPULS;x) übernommen. Die Variable tPULS ist aus Kompatibilitätsgründen signed integer.
Zur Funktionskontrolle wird der Wert tPULS alle Sekunden über UART ausgegeben. Die betreffenden Codezeilen sind hier :
// ================================================== =========================== =
// === Initialisierung v Timer1 mega328/20 MHz zur Messung Impulsdauer Servo
// Dokumentation ATmega328P_8271I_10/2014.pdf, siehe Seitenangaben
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void TC1TMR_init(void) // Init Tmr/Cntr 1, 8-Bit auf 20 kHz = 50 µs
{ //
TCCR1B |= (1<<CS10); // No Prescaler Clock <- CPU DOC 134
//TCCR1B |= (1<<WGM12); // WGM00:13=0=> normal operation, TOP 0xFFFF 132
TIMSK1 &= ~(1<<OCIE1A); // Tmr/Cntr2 CompareA interrupt disabled
TIMSK1 &= ~(1<<OCIE1B); // Tmr/Cntr2 CompareB interrupt disabled
//
} // Ende void TC1TMR_init(void)
// ================================================== =========================== =
// ================================================== =========================== =
ISR(PCINT0_vect) // PCINT0 triggert bei ANY edge => bei PB5=high
{ // Start der Messung, bei PB5=low Wert übernehmen
// - - - - - - - - - - - - - - - -
if ( (IsBitSet ( PINB, 5))) // WENN der ServoPULS beginnt, dann OCR1A nullen
{ //
OCR1A = 0; // Timer zurücksetzen
SetBit ( PBLED, LBb ); // blLED an, PORTB, blLED auf PB2
} // weiter mit if ( (IsBitSet ( PORTB, 5))
else //
{ //
tPULS = OCR1A; // Übernimm den Wert
ClrBit ( PBLED, LBb ); // blLED aus, PORTB, blLED auf PB2
} // Ende if/else ( (IsBitSet ( PINB, 5)))
//
} // Ende ISR(PCINT0_vect)
// ================================================== =========================== =
// ================================================== =========================== =
// . . . .
s16 wOCR1A; // Wert von OCR1A zum Ausgeben, 16 Bit
// . . . .
while ( 1 ) //
{ //
wms ( 1000); //
cli(); wOCR1A = tPULS; sei(); // Wert des Servopulses auslesen
uputs0 ("\r\tOCR1A ist aktuell "); uputs0i ( wOCR1A );
} // Ende while ( 1 )
// ================================================== =========================== =
Aktuell:
Der Stand von OCR1A/tPULS wird stets mit "0" ausgegeben, da funktioniert also keine Zeitmessung. Die LED zeigt durch die ISR(PCINT0_vect) die Potentiometerbewegung des Servotesters korrekt an (fade-in bzw. fade-out). Der Wert tPULS ist aus Kompatibilitätsgründen signed integer; ein Überlauf >32767 würde ja trotzdem per UART angezeigt
Problem:
Irgendwo steckt ein Programmierfehler, ich sehe den nicht. Oder stimmt die Timernutzung so nicht ?
Danke im Voraus für die Hilfe
Stand:
Der Timer2 generiert mir den Heartbeat - einen 20 kHz-Interrupt bzw. 50µs, mit dem alle 20 000 Interrupts, also sekündlich, die Heartbeat-LED getoggelt wird. Dieser Timer (nicht jedes Mal Timer2) dient mir auch anderswo, z.B. bei Drehzahlen, für Zeitmessungen. Die Nutzung ist problemlos.
Zum Auslesen eines Servopulses ist eine Genauigkeit von 50µs ungenügend, die Auflösung der Pulse, 1ms bis 2ms beträgt ja grad mal 200 bis 400 Schritte. Daher wurde eine Zeiterfassung direkt mit dem 16bittigen Timer1 geplant.
Plan:
Es wird der Timer1 zum Messen der Pulszeit benutzt. Initialisierung auf normal operation, TOP 0xFFFF, clk/1 = kein Prescaling.
Die Pulse werden von einem PCINT0 am PIN PB5 eingelesen. Die entsprechend geschaltete LED zeigt mit Dimmgrad optisch die eingelesenen Servopulse eines potentiometergesteuerten Servotesters - funktioniert.
Die Zeit vom Pulsstart bis zum Pulsende, PB5=hig bis PB5=low wird in der ISR von PCINT0 ausgelesen: bei Pulsanfang <=> PB5=high, wird OCR1A auf Null gesetzt, bei Pulsende <=> PB5=low, wird der Stand von OCR1A in eine Variablen tPULS (volatile int16/int16_t/ tPULS;x) übernommen. Die Variable tPULS ist aus Kompatibilitätsgründen signed integer.
Zur Funktionskontrolle wird der Wert tPULS alle Sekunden über UART ausgegeben. Die betreffenden Codezeilen sind hier :
// ================================================== =========================== =
// === Initialisierung v Timer1 mega328/20 MHz zur Messung Impulsdauer Servo
// Dokumentation ATmega328P_8271I_10/2014.pdf, siehe Seitenangaben
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void TC1TMR_init(void) // Init Tmr/Cntr 1, 8-Bit auf 20 kHz = 50 µs
{ //
TCCR1B |= (1<<CS10); // No Prescaler Clock <- CPU DOC 134
//TCCR1B |= (1<<WGM12); // WGM00:13=0=> normal operation, TOP 0xFFFF 132
TIMSK1 &= ~(1<<OCIE1A); // Tmr/Cntr2 CompareA interrupt disabled
TIMSK1 &= ~(1<<OCIE1B); // Tmr/Cntr2 CompareB interrupt disabled
//
} // Ende void TC1TMR_init(void)
// ================================================== =========================== =
// ================================================== =========================== =
ISR(PCINT0_vect) // PCINT0 triggert bei ANY edge => bei PB5=high
{ // Start der Messung, bei PB5=low Wert übernehmen
// - - - - - - - - - - - - - - - -
if ( (IsBitSet ( PINB, 5))) // WENN der ServoPULS beginnt, dann OCR1A nullen
{ //
OCR1A = 0; // Timer zurücksetzen
SetBit ( PBLED, LBb ); // blLED an, PORTB, blLED auf PB2
} // weiter mit if ( (IsBitSet ( PORTB, 5))
else //
{ //
tPULS = OCR1A; // Übernimm den Wert
ClrBit ( PBLED, LBb ); // blLED aus, PORTB, blLED auf PB2
} // Ende if/else ( (IsBitSet ( PINB, 5)))
//
} // Ende ISR(PCINT0_vect)
// ================================================== =========================== =
// ================================================== =========================== =
// . . . .
s16 wOCR1A; // Wert von OCR1A zum Ausgeben, 16 Bit
// . . . .
while ( 1 ) //
{ //
wms ( 1000); //
cli(); wOCR1A = tPULS; sei(); // Wert des Servopulses auslesen
uputs0 ("\r\tOCR1A ist aktuell "); uputs0i ( wOCR1A );
} // Ende while ( 1 )
// ================================================== =========================== =
Aktuell:
Der Stand von OCR1A/tPULS wird stets mit "0" ausgegeben, da funktioniert also keine Zeitmessung. Die LED zeigt durch die ISR(PCINT0_vect) die Potentiometerbewegung des Servotesters korrekt an (fade-in bzw. fade-out). Der Wert tPULS ist aus Kompatibilitätsgründen signed integer; ein Überlauf >32767 würde ja trotzdem per UART angezeigt
Problem:
Irgendwo steckt ein Programmierfehler, ich sehe den nicht. Oder stimmt die Timernutzung so nicht ?
Danke im Voraus für die Hilfe