Nach etlichen Mühen sollte es laufen. Sollte. Tuts nicht. Was sollte laufen und was läuft nicht?

Am mega16 auf der RNControl soll ein CTC-Interrupt eine Variable im 10 kHz Takt hochzählen (bis 50 000, danach 0...). Diese Zeitmarke wird in zwei externen ISR für EXT0 + EXT1 (von asynchronen Taktgebern - Drehgeber) ausgewertet.

Das komplette Programm wurde für Testzwecke auf die Timerroutinen zurückgestutzt und getestet. Testziel: LED auf PC4 toggeln.

Es geschieht - nein, nicht nix - noch schlimmer.

1) PC4 auf high (LED ist aus), auch PC2, 3 und 5.
2) PC0,1 und PC6,7 sind low (LED leuchtet) - das hatte ich nirgendwo gesagt.
3) Timer läuft wohl nicht - weil LED statisch aus ist.
4) andere PC-Ports sind auch statisch (sagt Oskar).

Will bitte jemand helfen?
A) Was habe ich bei der Timerinitialisierung falsch gemacht? bzw. besser
B) Wie mache ich die Timerinitialisierung richtig?
C) Ist die ISR ok?
D) na ja, wenn sonst was Übles auffällt

Die vollständige Quelle der Testvariante (ohne "andere" Routinen) mit der die hier beschriebene Fehlfunktion entsteht.

Code:
/* >> Diese ersten 2 Zeilen können zum Compilieren entfernt werden (muss nicht)
  Sicherung 17dez07 hhmm nach Datei ..C1..\2_drehzahlen\2_drehzahlen-xxx.c
 ===================================================================================
 ========== Beachte: printout aus AVRStudio geht (nur) bis col 85 ==================
  Target MCU        : ATmega16
  Target Hardware   : RNControl
  Target cpu-frequ. : 16 MHz, externer Quarzoszillator
 ===================================================================================
  Enthaltene Routinen:
	static inline void setportdon/~off
	void XTI_01_init( void )	// ISR ext0+1 initialisieren
	void TMR_0_init( void )		// Timer initialisieren 10 ms
	... (testweise gestrichen)
	SIGNAL (SIG_INTERRUPT0)		// ISR Motor/Speed1
	SIGNAL (SIG_INTERRUPT1)		// ISR Motor/Speed2
	SIGNAL(SIG_OVERFLOW0)
	int main(void)
 ===================================================================================
  *** Versionsgeschichte:
 ====================
 x11 17dez07 17:mmff Test - seltsame Ergebnisse - Timer timt nicht 
 x10 17dez07 15:43 Erster Codeausbau fertig zum Test (sichern und LED-Test mit 
 				dem Timer0
 x01 16dez07 23:42 Sichern des ersten Standes - ohne Timer-Interrupt-Routine
 x00 16dez07 14:30ff erster Aufbau
 ===================================================================================
  *** Aufgabenstellung : Messen von 2 Motordrehzahlen
  Es werden Impulse von zwei Gabellichtschranken am µC erfasst. Daraus werden
    zwei Drehzahlen errechnet.
    Drehzahlbereich von 0 (Stillstand) bis 1kHz (60 000 Upm)

    Grundlage wird ein Timerinterrupt mit ...

  Original: ...C1..\C-motst_x10\C_motst_x21_OK.c
 ===================================================================================
                                                                                  */
/* ============================================================================== */

#include <stdlib.h> 
#include <avr/io.h> 
#include <avr/interrupt.h>
/* Beachte C:\Programme\WinAVR-20070525\avr\include\avr\iom16.h */

#define MCU = ATMega16 

//   Mit Quarz 16 Mhz-CPU 
#define F_CPU  16000000 

/* ============================================================================== */
/*   Interrupt-Handler und -Adressen
Address Labels Code Comments
siehe C:\Programme\WinAVR-20070525\avr\include\avr\iom16.h sowie
Interruptvektoren/-vektortabelle in *doc2466, S 45+46 von AVR                    */

/* beachte: volatile!  und   Vorzeichenlos reicht für alle                   */
volatile uint16_t Iencdr1, Iencdr2;	/* Counter für Encoder-ticks
  Werden in der ISR hochgezählt und im main bei Gelegenheit
    (welcher? - nach 5 sec?) - spätestens aber beim Fahrtrichtungswechsel
    auf Null gesetzt. DAnn aber die Werte musv+musi entsprechend anpassen    */
volatile uint16_t Iz_ysecv1, Iz_ysecv2;	/* Zeitmarke "µsec"
  des vorletzten Interrupts in der Einheit 100 Mikrosekunden. Ist der Wert des
  hochlaufenden Timers zum Interruptzeitpunkt i-1                            */
volatile uint16_t Iz_yseci1, Iz_yseci2;	/* Zeitmarke "µsec"
    des letzten Interrupts in der Einheit 100 Mikrosekunden. Ist der Wert des
    hochlaufenden Timers zum Interruptzeitpunkt i (letzter Interrupt)        */
volatile uint16_t Iz_diff1, Iz_diff2;	/* Zeitdifferenz
  Beim Abarbeiten des Interrupts wird yseci mit time1 belegt und diff aus der
    Differenz yseci-ysecv errechnet. Danach wird yseci nach ysecv kopiert.
    Im main wird aus diff die Drehzahl berechnet.                            */
volatile uint16_t Izeit_1;			/* Timer läuft hoch
  Die Interruptroutine läuft mit 10 kHz (Möglicherweise sind 100 kHz besser)
    Beim Start des Timers läuft der Zähler time1 hoch und wird nach 5 sec -
    also beim Wert 50 000 - wieder auf Null gesetzt. Dabei werden die Werte
    ysecv und yseci angepasst                                                  */
/* ============================================================================== */

/* ============================================================================== */

/* =================================================================================
   ##### Hier ISR und ISR - Initialisierung(en)
================================================================================= */
/* ===  Initialisierung fuer EXT_INT0/1 auf Pin 16+17/mega16(32)  ==================
$002 jmp SIG_INTERRUPT0 ; IRQ0 Handler und
$004 jmp SIG_INTERRUPT1 ; IRQ1 Handler                  */
void XTI_01_init( void )	
{				//Initialisiere beide Interrupts auf rising edge
				//  d.h. MCUCR ISC00,01,10+11 auf 1 (doc,S68)
    MCUCR |= (1<<ISC11)|(1<<ISC10)|(1<<ISC01)|(1<<ISC00);
    GICR  |= (1<<INT1)|(1<<INT0);	//  und erlaube diese I´s in GICR
}
/* ============================================================================== */


/* ===  Initialisierung fuer Timer0 8-bit mega16(32)  ==============================
Aufruf als  SIGNAL (SIG_OVERFLOW0)                  */
void TMR_0_init( void )	
{				//Initialisiere 8-Bit-Timer auf 10 kHz
    TCCR0 |= (1<<CS02 | 0<<CS01 | 1<<CS00); // Prescaler 1024 / Clock <- CPU
    TCCR0 |= (1<<WGM01 | 0<<WGM00);	// Timer im CTC-Mode
    TCNT0 = 0x64;   			// Timer0 Counter 0x64 für 10ms bei 16Mhz 

    TIMSK |= (1<<OCIE0); 		// Compare Match IRQ 

}
/* ============================================================================== */


/* ===  Nicht unterbrechbare ISR für EXT_INT0 auf Pin 16/PD2/mega16(32)  ======== */
/* Routine setzt einfach einen Zähler hoch. Der Zähler wird im main
     ausgelesen ##>> cli/sei setzen <<## und nach 2 (od. 5) hunderstel Sekunden
     auf den Speicher WEG_L/_R vorzeichenrichtig aufaddiert und dann zurückgesetzt.
     ##>> Beim Richtungswechsel (cli/sei) wird der Zähler ausgelesen und genullt,
     damit ist eine saubere Wegmessung möglich.
     Der zugehörige Motor auf RNControl auf PB0/PB1 = li,re und PD5 Geschwind.
     Der alternat.  Motor auf RNControl auf PC7/PC6 = li,re und PB4 PWM/Geschw.
$002 jmp EXT_INT0 ; IRQ0 Handler                  */
SIGNAL(SIG_INTERRUPT0)
{
    Iencdr1 ++;			//zähle Counter/encoder 1 hoch
    Iz_yseci1 = Izeit_1;		//Weise musi den akt. Timerwert zu
    Iz_diff1 = Iz_yseci1-Iz_ysecv1;	    //Neue Zeit-Differenz1 ausrechnen
    Iz_ysecv1 = Iz_yseci1;		//der aktuelle Zeitwert wird "Alter"
}
/* ============================================================================== */


/* ============================================================================== */
/* ===  Nicht unterbrechbare ISR für EXT_INT1 auf Pin 17/PD3/mega16(32)  ======== */
/* Routine setzt einfach einen Zähler hoch.
      Sonst wie ISR für EXT_INT0 für Motor auf PC7/PC6 = li,re und PB4 PWM/Geschw.
$004 jmp EXT_INT1 ; IRQ1 Handler                  */
SIGNAL(SIG_INTERRUPT1)
{
    Iencdr2 ++;			//zähle Counter/encoder 2 hoch
    Iz_yseci2 = Izeit_1;		//Weise Iz_yseci den akt. Timerwert zu
    Iz_diff2 = Iz_yseci2-Iz_ysecv2;	//Neue Zeit-Differenz2 ausrechnen
    Iz_ysecv2 = Iz_yseci2;		//der aktuelle Zeitwert wird "Alter"
}
/* ============================================================================== */


/* ============================================================================== */
/* ===  Nicht unterbrechbare ISR für timer ====================================== */
/* Diese Routine zählt hoch im Takt 10 kHz.setzen.
      Dieser Wert wird von den beiden anderen ISR ausgelesen und den Werten

*/
// SIGNAL(SIG_OVERFLOW0)
// #define SIG_OUTPUT_COMPARE0	//Interuptvektor, siehe Tabelle
SIGNAL(SIG_OUTPUT_COMPARE0)
{
    Izeit_1 ++;              //Zeitstand des Interupt-Timers



    PORTC ^= (1 << PC4);	//LED toggeln



}
/* ============================================================================== */




// ------------------------------------------------------------------ 
/*### Hauptschleife ###*/ 
int main(void) 
{
	DDRC |= 0xFF;	//11111111 -> PC6 und PC7 linker Mot, Rest LEDs/Lauflicht

    TMR_0_init();
    sei();

for(;;)	{ 
	}
}
oder in einer gekürzten Fassung, mit den "kritischen" Routinen:

Code:
#include <stdlib.h> 
#include <avr/io.h> 
#include <avr/interrupt.h>
/* Beachte C:\Programme\WinAVR-20070525\avr\include\avr\iom16.h */

#define MCU = ATMega16 

//   Mit Quarz 16 Mhz-CPU 
#define F_CPU  16000000 

/* ============================================================================== */
/*   Interrupt-Handler und -Adressen
Address Labels Code Comments
siehe C:\Programme\WinAVR-20070525\avr\include\avr\iom16.h sowie
Interruptvektoren/-vektortabelle in *doc2466, S 45+46 von AVR                    */

/* beachte: volatile!  und   Vorzeichenlos reicht für alle                   */

volatile uint16_t Izeit_1;			/* Timer läuft hoch
  Die Interruptroutine läuft mit 10 kHz (Möglicherweise sind 100 kHz besser)
    Beim Start des Timers läuft der Zähler time1 hoch und wird nach 5 sec -
    also beim Wert 50 000 - wieder auf Null gesetzt. Dabei werden die Werte
    ysecv und yseci angepasst                                                  */
/* ============================================================================== */



/* =================================================================================
   ##### Hier ISR und ISR - Initialisierung(en)
================================================================================= */



/* ===  Initialisierung fuer Timer0 8-bit mega16(32)  ==============================
Aufruf als  SIGNAL (SIG_OVERFLOW0)                  */
void TMR_0_init( void )	
{				//Initialisiere 8-Bit-Timer auf 10 kHz
    TCCR0 |= (1<<CS02 | 0<<CS01 | 1<<CS00); // Prescaler 1024 / Clock <- CPU
    TCCR0 |= (1<<WGM01 | 0<<WGM00);	// Timer im CTC-Mode
    TCNT0 = 0x64;   			// Timer0 Counter 0x64 für 10ms bei 16Mhz 

    TIMSK |= (1<<OCIE0); 		// Compare Match IRQ 

}
/* ============================================================================== */




/* ============================================================================== */
/* ===  Nicht unterbrechbare ISR für timer ====================================== */
/* Diese Routine zählt hoch im Takt 10 kHz.setzen.
      Dieser Wert wird von den beiden anderen ISR ausgelesen und den Werten

*/
// SIGNAL(SIG_OVERFLOW0)
// #define SIG_OUTPUT_COMPARE0	//Interuptvektor, siehe Tabelle
SIGNAL(SIG_OUTPUT_COMPARE0)
{
    Izeit_1 ++;              //Zeitstand des Interupt-Timers



    PORTC ^= (1 << PC4);	//LED toggeln



}
/* ============================================================================== */
Danke im Voraus