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.
oder in einer gekürzten Fassung, mit den "kritischen" Routinen: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(;;) { } }
Danke im VorausCode:#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 } /* ============================================================================== */







Zitieren


Lesezeichen