oberallgeier
02.04.2009, 11:50
Hallo alle
bitte helft mir bei (m)einem Timerproblem.
Aktueller Stand: meinen Pacer (Schrittsignal für Trainingszwecke/Laufen) schreibe ich neu, diesmal in C statt Assembler. Der Assemblerpacer läuft gut. Der C-pacer funktioniert im Prinzip so, wie ich das will.
Aufgabe: Es werden in einer Minute eine bestimmte Anzahl "Blinkies" (BpM) mit einer Leuchtdiode erzeugt als Vorgabe für Doppelschritte. Dazu läuft mein Lieblingstimer im 50µs-Takt - will sagen, die ISR wird alle 50 µs aufgerufen. Zur Messung der ungefähren ISR-Dauer (Pushs und Pops werden ja nicht erfasst) wird zu Beginn der ISR eine separate LED an- und am Ende der ISR ausgeschaltet.
Aktuelle Beschaltung des Controllers:
// Pins/Ports als Ein- (0) oder Ausgänge (1) konfigurieren, Pull Ups (1) aktivieren
// A = Ausgang, E = Eingang ohne , EU = Eingang MIT PullUp
DDRB = 0b11111111; // Aus- + Eingänge definieren
PORTB = 0b00000000; // und Port/Pull Ups (1) aktivieren
//DDRC = 0b--------; // Von Port C existiert nur /RESET
//PORTC = 0b--------; //
//
DDRD = 0b01111110; // PD7 existiert beim t2313 nicht
PORTD = 0b00000001; // Pull Ups aktivieren
/* Dadurch Initialisierung der Anschlüsse für Pacer60+ : - - - - - - - - - - - - -
/RESET, dW, PC6 1 A 20 VCC
RxD, PD0 2 EU A 19 PB7, USCK, SCL
TxD, PD1___3 A A 18___PB6, MISO
XTAL1, PA1 4 A A 17 PB5, MOSI
XTAL2, PA0___5 A A 16___PB4
(Test-) gLED1, PD2 6 A A 15 PB3 Test-LED zum Messen der ISR-Dauer
PD3___7 A 14___PB2
PD4 8 A A 13 PB1, rLED - das Minuten-Signal
PD5 9 A A 12 PB0, gLED - die Blinkie-Leuchte
GND__10 A 11___PD6
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
Timerinitialisierung und ISR Code:
/* ================================================== ============================ */
/* === Initialisierung fuer Timer0 tiny2313 ==================================== */
void TC0TMR_init(void) // Init Tmr/Cntr 2, 8-Bit auf 20 kHz = 50 µs
{
TCCR0A |= (1<<WGM01); // Timer im CTC-Mode, Top=OCR2A doc S 79
TCCR0B |= (1<<CS01); // Prescaler 1/8 / Clock <- CPU doc S 81
OCR0A = 124; // Preset 124 für 50µs bei 20Mhz
TIMSK |= (1<<OCIE0A); // Tmr/Cntr2 CompareA interrupt enabled
}
/* ================================================== ============================ */
/* ================================================== ============================ */
/* === Nicht unterbrechbare ISR für timer0 ===================================== */
/* Routine zählt hoch im Takt 20 kHz = 50 µs.
Der Zählerwert wird von den ISR weiter ausgewertet ...... */
ISR(TIMER0_COMPA_vect) // Vektor 7
{
PORTB |= (1<<PB3); // Zeitmessung ISR: LED auf Port PB3 einschalten
// Messzeit am 02apr09 1036: 1,5 µs
// !!! Zyklusdauer 25 µs !!!
if (Izeit_1 < 20000) //Interrupt-Timer = 20 000 ... (1 sec blink on/off)
{
Izeit_1 ++; // war: alle drei Sekunden wird 60000 erreicht
} // und Izeit_1 bleibt in der uint16-Grenze
else
{
PORTD ^= (1<<PD2); // LED auf Port PD2 toggeln
Izeit_1 = 0; // ansonsten: Rückstellen auf Null
icntdwn = icntdwn + 1; // Countdownzähler hoch(!!)zählen
if (icntdwn > 32400) // Countdownzähler geht maximal 9 Std.
icntdwn = 1;
}
if (Iblink < Ibzykl) // Blinkzyklus noch nicht zu Ende?
{
Iblink ++; // Counter für Blinkzyklus hochzählen
}
else // Blinkzyklus ist abgelaufen
{
Iblink = 1; // Counter für Blinkzyklus zurücksetzen
PORTB |= (1<<PB0); // bLED auf Port PB0 ein
}
if (Iblink == Iblitz) // Leuchtdauer des Blinkies
{
PORTB &= ~(1<<PB0); // bLED auf Port PB0 aus
}
PORTB &= ~(1<<PB3); // Zeitmessung ISR: LED auf Port PB3 ausschalten
}
/* ================================================== ============================ */
Im main läuft derzeit folgende Dummy-Schleife:
// ###>>> Erste pacerversion in C #####################>>>>>>>>
cli(); // Verbiete Interrupts während der folgenden
// ##### Dateninitialisierung ===================
Ibanz = 82; // Anzahl der blinkies pro Minute
Ibzykl = (20000 / Ibanz); // Berechne Blinkiezyklus
Ibzykl = Ibzykl * 60; // in 50µs-Zeitscheiben
Iblitz = 1000;
// Im Blinkiezyklus wird geblinkt
// Ibanz Anzahl der Blinkies pro Minute
// Ibzykl Blinkie-Abstand in 50µs-Einheiten
// Iblink der Counter für Blinkieabstand
// Iblitz Dauer des Blinkens in 50µs-Einheiten
sei(); // Abschluss der Initialisierung, erlaube Interrupts
while (1)
{
if (Izeit_1 <= 10)
PORTB |= (1<<PB1); // bLED auf Port PB1 an
if (Izeit_1 >= 10000)
PORTB &= ~(1<<PB1); // bLED auf Port PB1 aus
}
// ########### Ende des pacers #####################<<<<<<<<
Ergebnisse:
1) Die übliche Kontroll-LED auf PD2 toggelt wie bisher immer im 1-sec-Takt: 1 sec an - 1 sec aus.
2) Die Blinkies werden je nach Vorgabe der BpM korrekt erzeugt.
3) Die ungefähre ISR-Dauer wird mit 1,5 µs von der LED (Oszilloskop) bestätigt.
4) Die LED auf PB3 zur Messung der ISR-Dauer wird alle 25 µs eingeschaltet (5 µs/DIV, ziemlich genau 5 DIV).
5) Alle Variablen sind int16_t bis auf Izeit_1, die ist traditionell uint16_t.
Punkt 4 ist mir völlig schleierhaft. Die ISR sollte doch "nur" alle 50 µs laufen - da bekäme ich bei 5 µs/DIV auf meinem 10-DIV-Bildschirm gerade einen vollen Zyklus mit - es sind aber momentan 2.
Danke im Voraus
bitte helft mir bei (m)einem Timerproblem.
Aktueller Stand: meinen Pacer (Schrittsignal für Trainingszwecke/Laufen) schreibe ich neu, diesmal in C statt Assembler. Der Assemblerpacer läuft gut. Der C-pacer funktioniert im Prinzip so, wie ich das will.
Aufgabe: Es werden in einer Minute eine bestimmte Anzahl "Blinkies" (BpM) mit einer Leuchtdiode erzeugt als Vorgabe für Doppelschritte. Dazu läuft mein Lieblingstimer im 50µs-Takt - will sagen, die ISR wird alle 50 µs aufgerufen. Zur Messung der ungefähren ISR-Dauer (Pushs und Pops werden ja nicht erfasst) wird zu Beginn der ISR eine separate LED an- und am Ende der ISR ausgeschaltet.
Aktuelle Beschaltung des Controllers:
// Pins/Ports als Ein- (0) oder Ausgänge (1) konfigurieren, Pull Ups (1) aktivieren
// A = Ausgang, E = Eingang ohne , EU = Eingang MIT PullUp
DDRB = 0b11111111; // Aus- + Eingänge definieren
PORTB = 0b00000000; // und Port/Pull Ups (1) aktivieren
//DDRC = 0b--------; // Von Port C existiert nur /RESET
//PORTC = 0b--------; //
//
DDRD = 0b01111110; // PD7 existiert beim t2313 nicht
PORTD = 0b00000001; // Pull Ups aktivieren
/* Dadurch Initialisierung der Anschlüsse für Pacer60+ : - - - - - - - - - - - - -
/RESET, dW, PC6 1 A 20 VCC
RxD, PD0 2 EU A 19 PB7, USCK, SCL
TxD, PD1___3 A A 18___PB6, MISO
XTAL1, PA1 4 A A 17 PB5, MOSI
XTAL2, PA0___5 A A 16___PB4
(Test-) gLED1, PD2 6 A A 15 PB3 Test-LED zum Messen der ISR-Dauer
PD3___7 A 14___PB2
PD4 8 A A 13 PB1, rLED - das Minuten-Signal
PD5 9 A A 12 PB0, gLED - die Blinkie-Leuchte
GND__10 A 11___PD6
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
Timerinitialisierung und ISR Code:
/* ================================================== ============================ */
/* === Initialisierung fuer Timer0 tiny2313 ==================================== */
void TC0TMR_init(void) // Init Tmr/Cntr 2, 8-Bit auf 20 kHz = 50 µs
{
TCCR0A |= (1<<WGM01); // Timer im CTC-Mode, Top=OCR2A doc S 79
TCCR0B |= (1<<CS01); // Prescaler 1/8 / Clock <- CPU doc S 81
OCR0A = 124; // Preset 124 für 50µs bei 20Mhz
TIMSK |= (1<<OCIE0A); // Tmr/Cntr2 CompareA interrupt enabled
}
/* ================================================== ============================ */
/* ================================================== ============================ */
/* === Nicht unterbrechbare ISR für timer0 ===================================== */
/* Routine zählt hoch im Takt 20 kHz = 50 µs.
Der Zählerwert wird von den ISR weiter ausgewertet ...... */
ISR(TIMER0_COMPA_vect) // Vektor 7
{
PORTB |= (1<<PB3); // Zeitmessung ISR: LED auf Port PB3 einschalten
// Messzeit am 02apr09 1036: 1,5 µs
// !!! Zyklusdauer 25 µs !!!
if (Izeit_1 < 20000) //Interrupt-Timer = 20 000 ... (1 sec blink on/off)
{
Izeit_1 ++; // war: alle drei Sekunden wird 60000 erreicht
} // und Izeit_1 bleibt in der uint16-Grenze
else
{
PORTD ^= (1<<PD2); // LED auf Port PD2 toggeln
Izeit_1 = 0; // ansonsten: Rückstellen auf Null
icntdwn = icntdwn + 1; // Countdownzähler hoch(!!)zählen
if (icntdwn > 32400) // Countdownzähler geht maximal 9 Std.
icntdwn = 1;
}
if (Iblink < Ibzykl) // Blinkzyklus noch nicht zu Ende?
{
Iblink ++; // Counter für Blinkzyklus hochzählen
}
else // Blinkzyklus ist abgelaufen
{
Iblink = 1; // Counter für Blinkzyklus zurücksetzen
PORTB |= (1<<PB0); // bLED auf Port PB0 ein
}
if (Iblink == Iblitz) // Leuchtdauer des Blinkies
{
PORTB &= ~(1<<PB0); // bLED auf Port PB0 aus
}
PORTB &= ~(1<<PB3); // Zeitmessung ISR: LED auf Port PB3 ausschalten
}
/* ================================================== ============================ */
Im main läuft derzeit folgende Dummy-Schleife:
// ###>>> Erste pacerversion in C #####################>>>>>>>>
cli(); // Verbiete Interrupts während der folgenden
// ##### Dateninitialisierung ===================
Ibanz = 82; // Anzahl der blinkies pro Minute
Ibzykl = (20000 / Ibanz); // Berechne Blinkiezyklus
Ibzykl = Ibzykl * 60; // in 50µs-Zeitscheiben
Iblitz = 1000;
// Im Blinkiezyklus wird geblinkt
// Ibanz Anzahl der Blinkies pro Minute
// Ibzykl Blinkie-Abstand in 50µs-Einheiten
// Iblink der Counter für Blinkieabstand
// Iblitz Dauer des Blinkens in 50µs-Einheiten
sei(); // Abschluss der Initialisierung, erlaube Interrupts
while (1)
{
if (Izeit_1 <= 10)
PORTB |= (1<<PB1); // bLED auf Port PB1 an
if (Izeit_1 >= 10000)
PORTB &= ~(1<<PB1); // bLED auf Port PB1 aus
}
// ########### Ende des pacers #####################<<<<<<<<
Ergebnisse:
1) Die übliche Kontroll-LED auf PD2 toggelt wie bisher immer im 1-sec-Takt: 1 sec an - 1 sec aus.
2) Die Blinkies werden je nach Vorgabe der BpM korrekt erzeugt.
3) Die ungefähre ISR-Dauer wird mit 1,5 µs von der LED (Oszilloskop) bestätigt.
4) Die LED auf PB3 zur Messung der ISR-Dauer wird alle 25 µs eingeschaltet (5 µs/DIV, ziemlich genau 5 DIV).
5) Alle Variablen sind int16_t bis auf Izeit_1, die ist traditionell uint16_t.
Punkt 4 ist mir völlig schleierhaft. Die ISR sollte doch "nur" alle 50 µs laufen - da bekäme ich bei 5 µs/DIV auf meinem 10-DIV-Bildschirm gerade einen vollen Zyklus mit - es sind aber momentan 2.
Danke im Voraus