Archiv verlassen und diese Seite im Standarddesign anzeigen : CTC + timer0 auf mega16 - geben keinen Interrupt (auch m168)
oberallgeier
17.12.2007, 17:32
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.
/* >> 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:
#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
Hallo,
in der AVR-Studio Simulation läuft es. Hast du irgend eine Optimierung eingestellt? Nimm die mal raus.
Gruß
Jens
oberallgeier
17.12.2007, 18:29
Ohhh - danke - ich werd es abends testen
Hubert.G
17.12.2007, 19:22
Irgendwie ist mir deine Taktrechnung nicht klar. Du teilst die 16Mhz durch 1024 mit dem Prescaler, ergibt 15625Hz, stellst den CompareMatch auf 0x64 das ist dez. 100 und sehe gerade du hast auf ext.Clock-Source gestellt und nicht auf Prescaler 1024
Den TCNT0 musst du auf 156 stellen für 100Hz
PS: Zu PortC sehe ich nur das du das Port auf Ausgang stellst aber nur mit PC4 was machst, damit sind die restlichen Pin auf L
oberallgeier
17.12.2007, 19:56
Hallo Hubert.G, hallo McJenso,
@McJenso - ich habe die Optimierung von -Os gestellt auf -O0. Der Maschinenfile wurde auch wirklich um über 40% länger - aber leider nicht lauffähiger.
@Hubert.G - Hoffentlich kringelst Du Dich nicht über die dämlichen Fehler von dem alten "Bergler". Ja, das mit dem Prescaler steht noch auf der Änderungsliste - das ist noch nicht erledigt (Berechnungs-Excel gesucht - nicht gefunden - IRGENDEINENWERT reingeschrieben :( ).
Aber der Klops ist natürlich die ext.Clock. Da hatte ich mich gleich um ZWEI Zeilen verguckt :(.
Ich lese das doc2466, Stand 2466P–AVR–08/07 (03.12.2007-runtergeladen bei Atmel), Seite 85, da steht:
CS02 CS01 CS00 Description
...
1 0 1 clkI/O/1024 (From prescaler)
Die ext. Clock ist 110 oder 111. Und das ist ja mein code:
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 IRQHmmmm :MistPC
Trotzdem danke für Eure Hilfe. Doof ist ja, dass es wie Assembler aussieht - und in Assembler bekam ich sowas immer zum Laufen (obwohl meine Assembler-Ziele bedeutend weniger Beine hatten :) ). Ich werde mich weiter bemühen.
Hubert.G
17.12.2007, 21:10
Ein 0<<CS01 schreibt man nicht, ist nämlich sinnlos und irritiert nur, wenn dann so ~(1<<CS01)
Hubert.G
17.12.2007, 21:32
Und wenn du den Compare-Wert nicht ins TCNT0 sondern ins OCR0 schreibst könnte sich die Funktion auch verbessern.
oberallgeier
17.12.2007, 21:57
Grüß Dich Hubert.G,
danke für Deinen Hinweis zum 0<<CS01 . Es ist mein doofer Hang zur Perfektion (na ja - nach dem Motto - ich weiss nicht ob es richtig ist, aber lieber einmal zuviel... und dann wars doch falsch). Es ist beruhigend, wenn man immer wieder geduldig auf Fehler hingewiesen wird - und die Hilfe immer kommt. Danke.
](*,) ](*,) doof ist es, wenn bei der RNControl läuft:
1) Das "Lauflicht" - alle 8 LED´s werden nacheinander geschaltet - auf einem mega32 läuft. Hab ich gerade ausprobiert.
2) die mittlere 4-er Gruppe von PortC beim mega16 "halbhoch" hängen bleibt. Es sind jene Kontakte, an denen kein L293 oder Widerstände hängen.
3) Deshalb hatte ich auch die getoggelte LED in der Mitte von PortC leider nicht leuchten sehen.
4) Beim toggeln der LED auf PortC6 in der ISR läufts.
Manchmal will man das Zeugs wirklich wegwerfen - nicht nur smileyhaft :). Na ja - wollen - aber dann doch nicht tun. Nun kann ich in Ruhe weiter C-code generieren :).
Danke - und schönen Abend.
oberallgeier
17.12.2007, 22:05
... Compare-Wert nicht ... sondern ...Ach herrje.
Na ja, nicht wegen der Arbeit - aber dann muss ich diese ganze Litanei im doc nochmal durchlesen *brrrrrrrr*
Danke und schönen Abend
Hubert.G
17.12.2007, 22:08
Hast du den JTAG in den Fuses abgeschaltet.
oberallgeier
17.12.2007, 22:29
? ? ? ?
Ok, das hatte ich jetzt nicht gelesen, das habe ich nur überflogen. Daran hatte ich GARNICHT gedacht - auch vorher nix gelesen.
ABER: im ersten Anlauf hatte ich (soweit ich mich erinnern kann - ok, hab nachgesehen, es ist so) pinc4 genommen - und beim Setzen ALLER acht LEDS brennen wirklich nur die von 2 bis 5 nicht. 0, 1 und 6, 7 brennen (brannten).
... the pull-up resistors on pins PC5(TDI), PC3(TMS) and PC2(TCK) will be activated ...
Da scheint noch ein Programmierer (diesmal der von ATMEL) so gründlich zu sein wie ich :) und hat halt den Pin mittendrin gleich mitgenommen - oder?
Sachlich: Ok, danke Hubert.G - ich hab also das doc überflogen, die fuses ausgelesen, JTAGEN gesetzt/gelöscht - und nun läufts. Puhhhhh.
Und die logische Induktion müsste jetzt heissen - dann läuft der restliche Code auch (relativ ? ? sicher :) ).
Schönen Abend,
oberallgeier
18.12.2007, 18:36
Hallo Hubert.G,
das war eine feine Hilfestellung, nochmal danke. Und es wurde ein langer Abend daraus, bzw. eine kurze Nacht. Mittlerweile läuft der Timer0 mit 10 kHz und zählt die Zeitmarke entsprechend (LED ändert alle 10 000 Interrupts ihre Meinung), die PWM´s mit timer1 und L293 treiben die Motoren rauf und runter - und ich warte auf zwei Gabellichtschranken für extInt0 und ~1.
UART habe ich ganz rausgeworfen, ebenso Bezüge auf delay.h und delay_basic.h. Neben <stdlib.h>, <avr/io.h> und <avr/interrupt.h> läuft nur eine eigene "..h", die <avr/io.h> ist aber wohl auch überflüssig - die habe ich noch nicht durchgelesen.
Eine abschließende Frage: habe ich mit diesen Interruptroutinen überhaupt eine Chance eine USART-Ausgabe zu machen? Ich wollte gerne die aktuellen Ansteuerungsparameter am Terminal ausgeben. Ohne Interruptroutinen gings, aber ich vermute sicher, die bringen das serielle Timing ausreichend durcheinander. Meine Tests zwischen 2400 und 38400 Baud - auch mit abweichenden Sende- und Empfangsparametern - gaben nur Schotter - meist Nullen und einige Eurozeichen :). Und mein I2C ist noch immer nicht absehbar :(.
Schönen Abend,
Hubert.G
18.12.2007, 22:05
Doch UART sollte kein Problem sein, mit und ohne Interrupt.
oberallgeier
19.12.2007, 16:21
Tut mir leid, noch immer Probleme, aber andere (ist eigentlich off topic). Das geringere ist: UART läuft nur ohne Interrupt - sobald ich "sei;" sage, gehts nicht mehr - habe ich aber vorerst zur Seite geschoben.
Aktuelles Problem: trotzt sicherer Funktion von Timer0 (LED´s signalisieren ihre Funktion korrekt ) läuft der extInt0 nicht (und auch nicht der extInt1).
Der code:
/* ================================================== ===============================
##### 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 Timer mega16(32) =====================================
SIGNAL (SIG_OVERFLOW0)
Beachte zu TIMSK:
OCIE2 TOIE2 TICIE1 OCIE1A OCIE1B TOIE1 OCIE0 TOIE0 TIMSK
Read/Write R/W R/W R/W R/W R/W R/W R/W R/W
Initial Value 0 0 0 0 0 0 0 0
rncontrol 0 0 1 1 1 1 0 0 hex 3c
###>>> dieser Wert wird GESETZT, d.h. Bit 0, 1, 6 und 7 gehen auf NULL.
Hier wird: TIMSK |= (1<<OCIE0) mit ODER! eingeführt, d.h.
1
*/
void TMR_0_init( void )
{ //Initialisiere 8-Bit-Timer auf 10 kHz
TCCR0 |= (1<<CS01 | 1<<CS00); // Prescaler 1/64 / Clock <- CPU
TCCR0 |= (1<<WGM01 | 0<<WGM00); // Timer im CTC-Mode
OCR0 = 25; // Preset 25 für 100µs 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"
{
if (Iencdr1 == 5000);
PORTC ^= (1<<PC3); //LED4 toggeln alle 5000 Interrupts
}
PORTC ^= (1<<PC4); //LED5 toggeln bei JEDEM Interrupt
}
/* ================================================== ============================ */
/* ================================================== ============================ */
/* === 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"
PORTC ^= (1<<PC5); //LED6 toggeln bei JEDEM Interrupt
}
/* ================================================== ============================ */
/* ================================================== ============================ */
/* === 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)
{
{
if (Izeit_1 <= 10000)
Izeit_1 ++; //Zeitstand Interupt-Timer läuft von 1 .. 10 000
else
Izeit_1 = 0;
}
{ // von hier bis Ende (LED2 toggeln) nur Testphase
if (Izeit_1 == 1)
PORTC ^= (1<<PC2); //LED3 toggeln alle Sekunde
}
PORTC ^= (1<<PC1); //LED2 toggeln jeden Interrupt
}
/* ================================================== ============================ */
läßt die LED auf PC1 genau mit 0,1 ms blinken, die LED auf PC2 im Sekundenrhythmus - 10 000 mal 0,1 ms - aber die in den ISR für extInt0 und ~1 angesprochenen LED´s tun nichts.
Ich habe PD2 und PD3 mit 10k gegen GND geschaltet und taste sie von Hand auf Vcc. Es geschieht nichts :(.
Frage:
Ist die Initialisierung in void XTI_01_init( void ) korrekt?
Sind die ISR SIGNAL(SIG_INTERRUPT0) und die SIGNAL(SIG_INTERRUPT1) korrekt?
Ich gehe davon aus, dass der mega16 seine Interrupt-Vektortabelle über die <avr/interrupt.h> einlädt. Das ist doch ok? Sonst würde ja schon die ISR für Timer0 nicht laufen. Und in der iom16.h steht ja auch:
/* Interrupt vectors */
/* Vector 0 is the reset vector. */
/* External Interrupt Request 0 */
#define INT0_vect _VECTOR(1)
#define SIG_INTERRUPT0 _VECTOR(1)
/* External Interrupt Request 1 */
#define INT1_vect _VECTOR(2)
#define SIG_INTERRUPT1 _VECTOR(2)
... und das ist genau meine Schreibweise.
Danke im Voraus.
Hubert.G
19.12.2007, 18:08
Mit was programmierst du eigentlich, diese GCC-Version ist schon veraltet. Wenn du das AVR-Studio verwendest kannst du ziemlich viel simulieren.
Sonst poste den gesamten Code, dann kann ich ihn mal simulieren.
oberallgeier
19.12.2007, 18:46
Schönen Abend, Hubert.G,
seit dem 10. Nov. läuft bei mir:
AVR Studio 4.13.557 Service Pack 1
GUI Version 4, 13, 0, 557
und
WinAVR 2007 0525
davor hatte ich (am 09. Nov. 07 von sourceforge.net geholt und installiert):
AVR Studio 4.12.460
GUI Version 4, 12, 0, 460
mit Servicepack 2
das lief aber garnicht stabil bei mir.
Ach - mit dem kompletten Code wollte ich den Thread nicht zumüllen. So toll ist der nicht (blos viele Kommentare, weil ich mir so wenig merken kann).
/* >> Diese ersten 2 Zeilen können zum Compilieren entfernt werden (muss nicht)
Sicherung 19dez07 1654 nach Datei ..C1..\2_drehzahlen\2_drehzahlen-x26.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:
#include "mlib-M16_x10_jwt.h"
static inline void setportd(c)on(off)
void Motst_aufab(void) // Mot li+re, vor+zur, aufab
void XTI_01_init( void ) // ISR external Intrrpt 0+1 initialisieren
void TMR_0_init( void ) // ISR Timer0 initialisieren
SIGNAL (SIG_INTERRUPT0) // ISR Motor/Speed1 erfassen
SIGNAL (SIG_INTERRUPT1) // ISR Motor/Speed2 erfassen
SIGNAL(SIG_OUTPUT_COMPARE0) // Timer0 ISR, Zeitmarke hochzählen
int main(void)
================================================== =================================
*** Versionsgeschichte:
====================
x26 19dez07 16:54 Test: Zähle in ISR SIG_INTERRUPT0 Iencodr1 hoch und
zünde LED auf PortC3 wenn er auf 5000 ist LED auf PC4 toggeln bei
jedem Interrupt0 und PC5 toggeln bei jedem Interrupt1 ### nix
x25 18dez07 18:12 Zustand: ISR OUTPUT_COMPARE0 toggelt LED 2 + 5,
MotorPWM läuft, Start-LED läuft..... ### Library MUSS M16conform sein ###
x23b 18dez07 15:34 erstellt nach x24, durch x23 ohne USART+sound OK
mit "alter" motstlib_x10_jwt.h. Motorroutinen laufen (lt. Oskar).
x24 18dez07 14:50 UART und sound läuft nicht korrekt mit ISR => gestrichen =>
ABER jetzt ist natürlich die Datenerkennung nicht mehr möglich.
Läuft nicht mit motstlib_x20_jwt
x23 18dez07 12:22 x21 wieder übernommen und ISR für Timer0 umbenannt von
SIGNAL(SIG_OVERFLOW0) nach SIGNAL(SIG_OUTPUT_COMPARE0) OK
x22 18dez07 12:05ff alles zusammenstreichen bis auf die "Grundversion" mit
TMR_0_ ... und so 12:05 geht nix
x21 18dez07 11:53
Nachtrag aus x14. Test: TMR_0_init() + sei() <==> dann läuft nix mehr :(
x20 17dez07 23:43ff
Nachtrag der Berichtigungen aus der Testversion 2_drehzahlen-xxxok.c
x14 18dez07 10:17 Bessere Dokumentation in TMR_0_init, LED auf PD4 wird getoggelt
x12 18dez07 00:22 Läuft mit der richtigen Frequenz
xxxok 17dez07 23:40 Testversion mit ordentlichem Interrupt - Frequenz stimmt nicht
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
18dez07 00:04 - - läuft noch nicht
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 */
#include "mlib-M16_x10_jwt.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 */
/*### Variablenliste, global ###*/
uint8_t i=1, kre=1, kli=1;
uint8_t min=15, max=122;
/* 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 */
/* ================================================== ============================ */
// ### Portroutinen und waitms aus RNContr Demo C
// *### Ports setzen auf HIGH/LOW ###
static inline void setportdon(const uint8_t n)
{PORTD |= (1<<n);} //set PORTD.n high
static inline void setportdoff(const uint8_t n)
{PORTD &= ~(1<<n);} //set PORTD.n low
static inline void setportcon(const uint8_t n)
{PORTC |= (1<<n);} //set PORTC.n high
static inline void setportcoff(const uint8_t n)
{PORTC &= ~(1<<n);} //set PORTC.n low
/*### Motortest mit tiny2313 auf exp2313-232/2 mit motL293-aufsteck/1
Anschluss (1+3) als negativ (schwarz), Anschluss (2+4) als positiv
================================================== ============================ */
void Motst_aufab(void) // Mot li+re, vor+zur, aufab
{
Mlinksvor();
Mrechtsvor();
setPWMlinks(0);
setPWMrechts(0);
waitms(40);
for(uint16_t i=10; i<199; i=i+1)
{
kre=i;
kli=i+2;
setPWMlinks(kli);
setPWMrechts(kre);
waitms(1000);
}
waitms(1000);
for(uint16_t i=199; i>10; i=i-1)
{
kre=i;
kli=i+2;
setPWMlinks(kli);
setPWMrechts(kre);
waitms(1000);
}
setPWMlinks(0);
setPWMrechts(0);
Mlinksstop();
Mrechtsstop();
waitms(300);
}
/* ================================================== ============================ */
/* ================================================== ===============================
##### 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 Timer mega16(32) =====================================
SIGNAL (SIG_OVERFLOW0)
Beachte zu TIMSK:
OCIE2 TOIE2 TICIE1 OCIE1A OCIE1B TOIE1 OCIE0 TOIE0 TIMSK
Read/Write R/W R/W R/W R/W R/W R/W R/W R/W
Initial Value 0 0 0 0 0 0 0 0
rncontrol 0 0 1 1 1 1 0 0 hex 3c
###>>> dieser Wert wird GESETZT, d.h. Bit 0, 1, 6 und 7 gehen auf NULL.
Hier wird: TIMSK |= (1<<OCIE0) mit ODER! eingeführt, d.h.
1
*/
void TMR_0_init( void )
{ //Initialisiere 8-Bit-Timer auf 10 kHz
TCCR0 |= (1<<CS01 | 1<<CS00); // Prescaler 1/64 / Clock <- CPU
TCCR0 |= (1<<WGM01 | 0<<WGM00); // Timer im CTC-Mode
OCR0 = 25; // Preset 25 für 100µs 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"
{
if (Iencdr1 == 5000);
PORTC ^= (1<<PC3); //LED4 toggeln alle 5000 Interrupts
}
PORTC ^= (1<<PC4); //LED5 toggeln bei JEDEM Interrupt
}
/* ================================================== ============================ */
/* ================================================== ============================ */
/* === 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"
PORTC ^= (1<<PC5); //LED6 toggeln bei JEDEM Interrupt
}
/* ================================================== ============================ */
/* ================================================== ============================ */
/* === 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)
{
{
if (Izeit_1 <= 10000)
Izeit_1 ++; //Zeitstand Interupt-Timer läuft von 1 .. 10 000
else
Izeit_1 = 0;
}
{ // von hier bis Ende (LED2 toggeln) nur Testphase
if (Izeit_1 == 1)
PORTC ^= (1<<PC2); //LED3 toggeln alle Sekunde
}
PORTC ^= (1<<PC1); //LED2 toggeln jeden Interrupt
}
/* ================================================== ============================ */
// ------------------------------------------------------------------
/*### Hauptschleife ###*/
int main(void)
{
// DDRB=0x3f; // 0011 1111 -> Ports B für Motor als Ausgänge
// DDRD=0x08; // 0000 1000 -> PortsD 3 als Ausgang
/* Im Unterschied zur Vorlage (für tiny2313 ist dieser Code für den ATMega16
auf RNControl <==> nimm dortige Initialisierungen mit folgender Änderung
Encoder-Eingang 1 PortA1
Encoder-Eingang 2 PortA2
*/
/*###Initialisierungsphase### Direkt aus RNContorl-test.c importiert*/
//Pins bzw. Ports als Ein-/Ausgänge konfigurieren
DDRA |= 0x00; //00000000 -> alle Analogports als Eingänge
DDRB |= 0x03; //00000011 -> PB0 und PB1 Kanäle des rechten Motors
DDRC |= 0xFF; //11111111 -> PC6 und PC7 linker Mot, Rest LEDs/Lauflicht
DDRD |= 0xB0; //10110000 -> D4 PWM linker Motors, PD5 rechter Mot
//Initialisierungen
setportcon(0); setportcon(1); setportcon(2); setportcon(3);
setportcon(4); setportcon(5); setportcon(6); setportcon(7); //LEDs aus
// setportdoff(7); //Speaker aus
init_timer1(); //Initialisierung Timer für PWM
// USART_Init(UBRR); //USART initialisieren
TMR_0_init(); //Initialisiere den Timer0-Interrupt (10 kHz)
sei(); //Globalen Interrupt freigeben
for(i=0; i<20; i++)
{
setportcoff(0); //2 sek blinken mit LED3 nach dem Reset -
waitms(15); // damit man kurze resets besser erkennt
setportcon(0);
waitms(85);
}
for(;;){
setportcoff(0);
waitms(1000);
setportcon(0);
waitms(1000);
Mlinksstop();
Mrechtsstop();
setPWMlinks(0);
setPWMrechts(0);
Motst_aufab();
}
}
In Assembler hatte ich immer (na ja, gelegentlich) im AVRStudio mit dem Debugger ganz gut Fehlersuche praktiziert. Das hab ich mit C auch schon versucht - da läuft der CPU-Lüfter so schön hoch :) oder :( ? - aber ich bin meist nicht auf die Breakpoints gekommen. Da ich im letzten Monat eine Festplatte (Klar, die C:) - aber nur das System - und ein Netzteil geliefert hatte und da die Hilfe mir nicht EINDEUTIG sagte, dass debuggen in C möglich ist, hab ich da vorerst bei C nix weiter gemacht.
Danke für die Mühe, (und sorry, ich muss zu einer Abendveranstaltung)
oberallgeier
19.12.2007, 18:48
Die Version mit der USART-Ausgabe (war für das letzte posting zu umfangreich) ist :
/* >> Diese ersten 2 Zeilen können zum Compilieren entfernt werden (muss nicht)
Sicherung 18dez07 1222 nach Datei ..C1..\2_drehzahlen\2_drehzahlen-x23ok.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 ext_int_init (void) // ISR ext1+2 initialisieren <<< offen
void tmr_int_init (void) // Timer ISR initialisieren <<< offen
################################# diese beiden Routinen sind ISR
Timer fehlen
void USART_Init( unsigned int baud )
void sendchar(unsigned char c)
void sendUSART(char *s)
void Motst_aufab(void) // Mot li+re, vor+zur, aufab
SIGNAL (SIG_INTERRUPT0) // ISR Motor/Speed1
SIGNAL (SIG_INTERRUPT1) // ISR Motor/Speed2
int main(void)
================================================== =================================
*** Versionsgeschichte:
====================
x23 18dez07 12:22 x21 wieder übernommen und ISR für Timer0 umbenannt von
SIGNAL(SIG_OVERFLOW0) nach SIGNAL(SIG_OUTPUT_COMPARE0) OK
x22 18dez07 12:05ff alles zusammenstreichen bis auf die "Grundversion" mit
TMR_0_ ... und so 12:05 geht nix
x21 18dez07 11:53
Nachtrag aus x14. Test: TMR_0_init() + sei() <==> dann läuft nix mehr :(
x20 17dez07 23:43ff
Nachtrag der Berichtigungen aus der Testversion 2_drehzahlen-xxxok.c
x14 18dez07 10:17 Bessere Dokumentation in TMR_0_init, LED auf PD4 wird getoggelt
x12 18dez07 00:22 Läuft mit der richtigen Frequenz
xxxok 17dez07 23:40 Testversion mit ordentlichem Interrupt - Frequenz stimmt nicht
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
18dez07 00:04 - - läuft noch nicht
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 */
#include "motstlib_x10_jwt.h"
#define MCU = ATMega16
// Mit Quarz 16 Mhz-CPU
#define F_CPU 16000000
#define BAUD 38400
#define UBRR (unsigned int)(F_CPU / BAUD / 16 - 0.5)
/* ================================================== ============================ */
/* 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 */
/*### Variablenliste, global ###*/
// uint8_t i=1, k=1, max=120, min=35;
uint8_t i=1, kre=1, kli=1;
uint8_t min=15, max=122;
char id_MCU [30];
/* 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 */
/* ================================================== ============================ */
// ### Portroutinen und waitms aus RNContr Demo C
// *### Ports setzen auf HIGH/LOW ###
static inline void setportdon(const uint8_t n)
{PORTD |= (1<<n);} //set PORTD.n high
static inline void setportdoff(const uint8_t n)
{PORTD &= ~(1<<n);} //set PORTD.n low
static inline void setportcon(const uint8_t n)
{PORTC |= (1<<n);} //set PORTC.n high
static inline void setportcoff(const uint8_t n)
{PORTC &= ~(1<<n);} //set PORTC.n low
/*### Senden per USART - RS232-Kommunikation ###*/
/*Zum senden von Zeichen im Hauptprogramm entweder
char irgendwas[] = "meintext";
sendUSART(irgendwas); oder direkt
sendUSART("meinText"); verwenden. */
/*
================================================== =================================
Dieser Codeschnipsel ähnlich 2313-doc, S 121 */
void USART_Init( unsigned int baud )
{ // Set baud rate
UBRRH = (unsigned char)(baud>>8);
UBRRL = (unsigned char)baud; // Enable receiver and transmitter
UCSRB = (1<<RXEN)|(1<<TXEN); // Set frame format: 8data, 2stop bit
UCSRC = (3<<UCSZ0);
}
// ------------------------------------------------------------------
void sendchar(unsigned char c)
{
while(!(UCSRA & (1<<UDRE))) //Warten, bis Senden möglich ist
{
}
UDR = c; //schreibt das Zeichen aus 'c' auf die Schnittstelle
}
// ------------------------------------------------------------------
void sendUSART(char *s) //*s funktiniert wie eine Art Array - auch bei
// einem String werden die Zeichen (char)
// einzeln ausgelesen - und auf die
// Sendeschnittstelle übertragen
{
while(*s)
{
sendchar(*s);
s++;
}
}
/*### Motortest mit tiny2313 auf exp2313-232/2 mit motL293-aufsteck/1
Anschluss (1+3) als negativ (schwarz), Anschluss (2+4) als positiv
hier für m16/RNControl
================================================== ============================ */
void Motst_aufab(void) // Mot li+re, vor+zur, aufab
{
char worti[5], wortkli[5], wortkre[5];
Mlinksvor();
Mrechtsvor();
setPWMlinks(0);
setPWMrechts(0);
waitms(40);
sendUSART("\r\nMotortest ~x21\r\n");
sendUSART("PWM-Stellwerte\r\n");
sendUSART("_n__li__re\r\n");
for(uint16_t i=10; i<199; i=i+1)
{
kre=i;
kli=i+2;
setPWMlinks(kli);
setPWMrechts(kre);
waitms(1000);
utoa(i, worti, 10);
utoa(kli, wortkli, 10);
utoa(kre, wortkre, 10);
sendUSART(worti);sendUSART(" ");
sendUSART(wortkli);sendUSART(" ");
sendUSART(wortkre);sendUSART("\r\n");
}
waitms(1000);
/* sendUSART("tiny2313\r\n");
sendUSART("PWM-Stellwerte\r\n");
sendUSART("_n__li__re\r\n");
Ausgeblendet wegen Speicherplatzbedarf */
for(uint16_t i=199; i>10; i=i-1)
{
kre=i;
kli=i+2;
setPWMlinks(kli);
setPWMrechts(kre);
waitms(1000);
// utoa(i, worti, 10);
// utoa(kli, wortkli, 10);
// utoa(kre, wortkre, 10);
// sendUSART(worti);sendUSART(" ");
// sendUSART(wortkli);sendUSART(" ");
// sendUSART(wortkre);sendUSART("\r\n");
}
setPWMlinks(0);
setPWMrechts(0);
Mlinksstop();
Mrechtsstop();
waitms(300);
}
/* ================================================== ============================ */
/* ================================================== ===============================
##### 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 Timer mega16(32) =====================================
SIGNAL (SIG_OVERFLOW0)
Beachte zu TIMSK:
OCIE2 TOIE2 TICIE1 OCIE1A OCIE1B TOIE1 OCIE0 TOIE0 TIMSK
Read/Write R/W R/W R/W R/W R/W R/W R/W R/W
Initial Value 0 0 0 0 0 0 0 0
rncontrol 0 0 1 1 1 1 0 0 hex 3c
###>>> dieser Wert wird GESETZT, d.h. Bit 0, 1, 6 und 7 gehen auf NULL.
Hier wird: TIMSK |= (1<<OCIE0) mit ODER! eingeführt, d.h.
1
*/
void TMR_0_init( void )
{ //Initialisiere 8-Bit-Timer auf 10 kHz
TCCR0 |= (1<<CS01 | 1<<CS00); // Prescaler 64 / Clock <- CPU
TCCR0 |= (1<<WGM01 | 0<<WGM00); // Timer im CTC-Mode
OCR0 = 25; // Preset 25 für 100µs 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 << PC1); //LED toggeln
}
/* ================================================== ============================ */
// ------------------------------------------------------------------
/*### Hauptschleife ###*/
int main(void)
{
// DDRB=0x3f; // 0011 1111 -> Ports B für Motor als Ausgänge
// DDRD=0x08; // 0000 1000 -> PortsD 3 als Ausgang
/* Im Unterschied zur Vorlage (für tiny2313 ist dieser Code für den ATMega16
auf RNControl <==> nimm dortige Initialisierungen mit folgender Änderung
Encoder-Eingang 1 PortA1
Encoder-Eingang 2 PortA2
*/
/*###Initialisierungsphase### Direkt aus RNContorl-test.c importiert*/
//Pins bzw. Ports als Ein-/Ausgänge konfigurieren
DDRA |= 0x00; //00000000 -> alle Analogports als Eingänge
DDRB |= 0x03; //00000011 -> PB0 und PB1 Kanäle des rechten Motors
DDRC |= 0xFF; //11111111 -> PC6 und PC7 linker Mot, Rest LEDs/Lauflicht
DDRD |= 0xB0; //10110000 -> D4 PWM linker Motors, PD5 rechter Mot
//Initialisierungen
setportcon(0); setportcon(1); setportcon(2); setportcon(3);
setportcon(4); setportcon(5); setportcon(6); setportcon(7); //LEDs aus
setportdoff(7); //Speaker aus
init_timer1(); //Initialisierung Timer für PWM
USART_Init(UBRR); //USART initialisieren
TMR_0_init(); //Initialisiere den Timer0-Interrupt (10 kHz)
sei(); //Globalen Interrupt freigeben
for(i=0; i<20; i++)
{
setportcoff(3); //2 sek blinken nach dem Reset - damit man
waitms(15); // kurze resets besser erkennt
setportcon(3);
waitms(85);
}
for(;;){
setportcoff(3);
waitms(1000);
setportcon(3);
waitms(1000);
/* Mlinksstop();
Mrechtsstop();
setPWMlinks(0);
setPWMrechts(0);
Motst_aufab(); */
}
}
die lief aber nur ohne Interrupt (die Quelle ist relativ "roh", sorry).
Hubert.G
19.12.2007, 20:17
Ich kann mit nicht vorstellen das dieser Code irgendwie compilierbar ist.
Aktuelle AVR-libc ist 1.4.7 oder 1.5.1
Eine zusammenarbeit von waitms(xx) und Interrupt ist ohnehin problematisch.
oberallgeier
20.12.2007, 01:18
Ich sass etwas auf heissen Kohlen weil ich meine beiden *lib*.h nicht mitgegeben hatte. Die unterschiedlichen Versionen verwenden unterschiedliche Bibliotheken. Die waitms(xx) wollte ich schon rauswerfen, sie stammt aus der header-Datei zum RNControl-Demoprogramm. Sie dient hier eher untergeordneten, also unkritischen Pausen, daher habe ich sie vorerst doch noch benutzt. WENN ich die zukünftig noch nutzen muss, werde ich sie vom Timerwert aus der SIG_OUTPUT_COMPARE0 ableiten.
Die beiden geposteten Progrämmchen hatte das AVRStudio aber compiliert ? ! ? ?
Bei der Übersetzung der "2_drehzahlen-x26.c" bekomme ich vom AVRStudio folgende build-meldungen:
Build started 20.12.2007 at 00:42:01
avr-gcc.exe -I"D:\pro-fils_D\computer+mcontroller\C1 mC Projekte\2_drehzahlen\util" -mmcu=atmega16 -Wall -gdwarf-2 -std=gnu99 -O0 -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums -MD -MP -MT 2_drehzahlen.o -MF dep/2_drehzahlen.o.d -
c ../2_drehzahlen.c
avr-gcc.exe -mmcu=atmega16 -Wl,-Map=2_drehzahlen.map 2_drehzahlen.o -o 2_drehzahlen.elf
avr-objcopy -O ihex -R .eeprom 2_drehzahlen.elf 2_drehzahlen.hex
avr-objcopy -j .eeprom --set-section-flags=.eeprom="alloc,load" --change-section-lma .eeprom=0 --no-change-warnings -O ihex 2_drehzahlen.elf 2_drehzahlen.eep || exit 0
c:\Programme\WinAVR-20070525\bin\avr-objcopy.exe: there are no sections to be copied!
avr-objdump -h -S 2_drehzahlen.elf > 2_drehzahlen.lss
AVR Memory Usage
----------------
Device: atmega16
Program: 1870 bytes (11.4% Full)
(.text + .data + .bootloader)
Data: 24 bytes (2.3% Full)
(.data + .bss + .noinit)
Build succeeded with 0 Warnings...
und die 2_drehzahlen.lss sieht so aus: (siehe nächstes Posting - Zeichenlimit ist überschritten).... aber diesen Code bin ich noch nicht durchgegangen. Aber die SIG_INTERRUPT0 sieht darin "glaubhaft" aus. Anmerkung: Ich habe erst vorhin festgestellt, dass es so eine Datei nach dem Compilieren gibt. Wie gesagt: ich bin eher Anfänger.
Der hexfile läuft auf meiner RNControl mit korrekter Funktion der TimerIRS - also das Zeitraster stimmt und auch z.B. das Umschalten der LED zum vorgegebenen Zählerstand innerhalb der ISR. Auch die Motoransteuerung funktioniert korrekt - bis auf die zeitliche Genauigkeit der waitms - klar. Es fehlt vollständig die Funktion der IRS für die beiden externen Interrupts.
Ich weiss leider nicht, wo die AVR-libc benutzt wird - da sehe ich noch nach. Zu meiner Schande muss ich gestehen, dass ich von dieser lib erst seit Deiner Bemerkung weiss. Das user manual der lib trägt den Titel
avr-libc Reference Manual
1.4.6
Generated by Doxygen 1.4.7
Tue May 15 14:56:11 2007
. . . das wäre doch (fast) die von Dir genannte Aktualität?
Soweit ich das also betrachtet hatte (als C-Anfänger) sah das alles glaubhaft aus, bis auf die ausbleibenden externen Interrupts. Jetzt weiss ich nicht weiter.
oberallgeier
20.12.2007, 01:25
Die 2_drehzahlen.lss:
2_drehzahlen.elf: file format elf32-avr
Sections:
Idx Name Size VMA LMA File off Algn
0 .text 00000748 00000000 00000000 00000094 2**1
CONTENTS, ALLOC, LOAD, READONLY, CODE
1 .data 00000006 00800060 00000748 000007dc 2**0
CONTENTS, ALLOC, LOAD, DATA
2 .bss 00000012 00800066 00800066 000007e2 2**0
ALLOC
3 .stab 00000378 00000000 00000000 000007e4 2**2
CONTENTS, READONLY, DEBUGGING
4 .stabstr 00000071 00000000 00000000 00000b5c 2**0
CONTENTS, READONLY, DEBUGGING
5 .debug_aranges 00000020 00000000 00000000 00000bcd 2**0
CONTENTS, READONLY, DEBUGGING
6 .debug_pubnames 000001a9 00000000 00000000 00000bed 2**0
CONTENTS, READONLY, DEBUGGING
7 .debug_info 00000511 00000000 00000000 00000d96 2**0
CONTENTS, READONLY, DEBUGGING
8 .debug_abbrev 000000d5 00000000 00000000 000012a7 2**0
CONTENTS, READONLY, DEBUGGING
9 .debug_line 00000433 00000000 00000000 0000137c 2**0
CONTENTS, READONLY, DEBUGGING
10 .debug_frame 00000140 00000000 00000000 000017b0 2**2
CONTENTS, READONLY, DEBUGGING
Disassembly of section .text:
00000000 <__vectors>:
0: 0c 94 2a 00 jmp 0x54 ; 0x54 <__ctors_end>
4: 0c 94 e4 01 jmp 0x3c8 ; 0x3c8 <__vector_1>
8: 0c 94 45 02 jmp 0x48a ; 0x48a <__vector_2>
c: 0c 94 47 00 jmp 0x8e ; 0x8e <__bad_interrupt>
10: 0c 94 47 00 jmp 0x8e ; 0x8e <__bad_interrupt>
14: 0c 94 47 00 jmp 0x8e ; 0x8e <__bad_interrupt>
18: 0c 94 47 00 jmp 0x8e ; 0x8e <__bad_interrupt>
1c: 0c 94 47 00 jmp 0x8e ; 0x8e <__bad_interrupt>
20: 0c 94 47 00 jmp 0x8e ; 0x8e <__bad_interrupt>
24: 0c 94 47 00 jmp 0x8e ; 0x8e <__bad_interrupt>
28: 0c 94 47 00 jmp 0x8e ; 0x8e <__bad_interrupt>
2c: 0c 94 47 00 jmp 0x8e ; 0x8e <__bad_interrupt>
30: 0c 94 47 00 jmp 0x8e ; 0x8e <__bad_interrupt>
34: 0c 94 47 00 jmp 0x8e ; 0x8e <__bad_interrupt>
38: 0c 94 47 00 jmp 0x8e ; 0x8e <__bad_interrupt>
3c: 0c 94 47 00 jmp 0x8e ; 0x8e <__bad_interrupt>
40: 0c 94 47 00 jmp 0x8e ; 0x8e <__bad_interrupt>
44: 0c 94 47 00 jmp 0x8e ; 0x8e <__bad_interrupt>
48: 0c 94 47 00 jmp 0x8e ; 0x8e <__bad_interrupt>
4c: 0c 94 9a 02 jmp 0x534 ; 0x534 <__vector_19>
50: 0c 94 47 00 jmp 0x8e ; 0x8e <__bad_interrupt>
00000054 <__ctors_end>:
54: 11 24 eor r1, r1
56: 1f be out 0x3f, r1 ; 63
58: cf e5 ldi r28, 0x5F ; 95
5a: d4 e0 ldi r29, 0x04 ; 4
5c: de bf out 0x3e, r29 ; 62
5e: cd bf out 0x3d, r28 ; 61
00000060 <__do_copy_data>:
60: 10 e0 ldi r17, 0x00 ; 0
62: a0 e6 ldi r26, 0x60 ; 96
64: b0 e0 ldi r27, 0x00 ; 0
66: e8 e4 ldi r30, 0x48 ; 72
68: f7 e0 ldi r31, 0x07 ; 7
6a: 02 c0 rjmp .+4 ; 0x70 <.do_copy_data_start>
0000006c <.do_copy_data_loop>:
6c: 05 90 lpm r0, Z+
6e: 0d 92 st X+, r0
00000070 <.do_copy_data_start>:
70: a6 36 cpi r26, 0x66 ; 102
72: b1 07 cpc r27, r17
74: d9 f7 brne .-10 ; 0x6c <.do_copy_data_loop>
00000076 <__do_clear_bss>:
76: 10 e0 ldi r17, 0x00 ; 0
78: a6 e6 ldi r26, 0x66 ; 102
7a: b0 e0 ldi r27, 0x00 ; 0
7c: 01 c0 rjmp .+2 ; 0x80 <.do_clear_bss_start>
0000007e <.do_clear_bss_loop>:
7e: 1d 92 st X+, r1
00000080 <.do_clear_bss_start>:
80: a8 37 cpi r26, 0x78 ; 120
82: b1 07 cpc r27, r17
84: e1 f7 brne .-8 ; 0x7e <.do_clear_bss_loop>
86: 0e 94 e5 02 call 0x5ca ; 0x5ca <main>
8a: 0c 94 a3 03 jmp 0x746 ; 0x746 <_exit>
0000008e <__bad_interrupt>:
8e: 0c 94 00 00 jmp 0 ; 0x0 <__vectors>
00000092 <waitms>:
/*### Programm pausieren lassen ###*/
/*Pausenwert ist nur experimentell !*/
void waitms(uint16_t ms)
{
92: cf 93 push r28
94: df 93 push r29
96: cd b7 in r28, 0x3d ; 61
98: de b7 in r29, 0x3e ; 62
9a: 24 97 sbiw r28, 0x04 ; 4
9c: 0f b6 in r0, 0x3f ; 63
9e: f8 94 cli
a0: de bf out 0x3e, r29 ; 62
a2: 0f be out 0x3f, r0 ; 63
a4: cd bf out 0x3d, r28 ; 61
a6: 9c 83 std Y+4, r25 ; 0x04
a8: 8b 83 std Y+3, r24 ; 0x03
for(; ms>0; ms--)
aa: 0f c0 rjmp .+30 ; 0xca <waitms+0x38>
{
uint16_t __c = 4000;
ac: 80 ea ldi r24, 0xA0 ; 160
ae: 9f e0 ldi r25, 0x0F ; 15
b0: 9a 83 std Y+2, r25 ; 0x02
b2: 89 83 std Y+1, r24 ; 0x01
__asm__ volatile (
b4: 89 81 ldd r24, Y+1 ; 0x01
b6: 9a 81 ldd r25, Y+2 ; 0x02
b8: 01 97 sbiw r24, 0x01 ; 1
ba: f1 f7 brne .-4 ; 0xb8 <waitms+0x26>
bc: 9a 83 std Y+2, r25 ; 0x02
be: 89 83 std Y+1, r24 ; 0x01
c0: 8b 81 ldd r24, Y+3 ; 0x03
c2: 9c 81 ldd r25, Y+4 ; 0x04
c4: 01 97 sbiw r24, 0x01 ; 1
c6: 9c 83 std Y+4, r25 ; 0x04
c8: 8b 83 std Y+3, r24 ; 0x03
ca: 8b 81 ldd r24, Y+3 ; 0x03
cc: 9c 81 ldd r25, Y+4 ; 0x04
ce: 00 97 sbiw r24, 0x00 ; 0
d0: 69 f7 brne .-38 ; 0xac <waitms+0x1a>
d2: 24 96 adiw r28, 0x04 ; 4
d4: 0f b6 in r0, 0x3f ; 63
d6: f8 94 cli
d8: de bf out 0x3e, r29 ; 62
da: 0f be out 0x3f, r0 ; 63
dc: cd bf out 0x3d, r28 ; 61
de: df 91 pop r29
e0: cf 91 pop r28
e2: 08 95 ret
000000e4 <init_timer1>:
"1: sbiw %0,1" "\n\t"
"brne 1b"
: "=w" (__c)
: "0" (__c)
);
}
}
/*### PWM-Routinen zur Motoransteuerung -- aus rncontrol.h ###*/
/* #####>>>>> Hier müssen die Motorports der RNControl umbenannt werden. Sie sind
------------
Teile gelöscht wegen limitierter Posting-Länge
/* ================================================== ===============================
##### 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
35e: cf 93 push r28
360: df 93 push r29
362: cd b7 in r28, 0x3d ; 61
364: de b7 in r29, 0x3e ; 62
// d.h. MCUCR ISC00,01,10+11 auf 1 (doc,S68)
MCUCR |= (1<<ISC11)|(1<<ISC10)|(1<<ISC01)|(1<<ISC00);
366: a5 e5 ldi r26, 0x55 ; 85
368: b0 e0 ldi r27, 0x00 ; 0
36a: e5 e5 ldi r30, 0x55 ; 85
36c: f0 e0 ldi r31, 0x00 ; 0
36e: 80 81 ld r24, Z
370: 8f 60 ori r24, 0x0F ; 15
372: 8c 93 st X, r24
GICR |= (1<<INT1)|(1<<INT0); // und erlaube diese I´s in GICR
374: ab e5 ldi r26, 0x5B ; 91
376: b0 e0 ldi r27, 0x00 ; 0
378: eb e5 ldi r30, 0x5B ; 91
37a: f0 e0 ldi r31, 0x00 ; 0
37c: 80 81 ld r24, Z
37e: 80 6c ori r24, 0xC0 ; 192
380: 8c 93 st X, r24
382: df 91 pop r29
384: cf 91 pop r28
386: 08 95 ret
00000388 <TMR_0_init>:
}
/* ================================================== ============================ */
/* === Initialisierung fuer Timer mega16(32) =====================================
SIGNAL (SIG_OVERFLOW0)
Beachte zu TIMSK:
OCIE2 TOIE2 TICIE1 OCIE1A OCIE1B TOIE1 OCIE0 TOIE0 TIMSK
Read/Write R/W R/W R/W R/W R/W R/W R/W R/W
Initial Value 0 0 0 0 0 0 0 0
rncontrol 0 0 1 1 1 1 0 0 hex 3c
###>>> dieser Wert wird GESETZT, d.h. Bit 0, 1, 6 und 7 gehen auf NULL.
Hier wird: TIMSK |= (1<<OCIE0) mit ODER! eingeführt, d.h.
1
*/
void TMR_0_init( void )
{ //Initialisiere 8-Bit-Timer auf 10 kHz
388: cf 93 push r28
38a: df 93 push r29
38c: cd b7 in r28, 0x3d ; 61
38e: de b7 in r29, 0x3e ; 62
TCCR0 |= (1<<CS01 | 1<<CS00); // Prescaler 1/64 / Clock <- CPU
390: a3 e5 ldi r26, 0x53 ; 83
392: b0 e0 ldi r27, 0x00 ; 0
394: e3 e5 ldi r30, 0x53 ; 83
396: f0 e0 ldi r31, 0x00 ; 0
398: 80 81 ld r24, Z
39a: 83 60 ori r24, 0x03 ; 3
39c: 8c 93 st X, r24
TCCR0 |= (1<<WGM01 | 0<<WGM00); // Timer im CTC-Mode
39e: a3 e5 ldi r26, 0x53 ; 83
3a0: b0 e0 ldi r27, 0x00 ; 0
3a2: e3 e5 ldi r30, 0x53 ; 83
3a4: f0 e0 ldi r31, 0x00 ; 0
3a6: 80 81 ld r24, Z
3a8: 88 60 ori r24, 0x08 ; 8
3aa: 8c 93 st X, r24
OCR0 = 25; // Preset 25 für 100µs bei 16Mhz
3ac: ec e5 ldi r30, 0x5C ; 92
3ae: f0 e0 ldi r31, 0x00 ; 0
3b0: 89 e1 ldi r24, 0x19 ; 25
3b2: 80 83 st Z, r24
TIMSK |= (1<<OCIE0); // Compare Match IRQ
3b4: a9 e5 ldi r26, 0x59 ; 89
3b6: b0 e0 ldi r27, 0x00 ; 0
3b8: e9 e5 ldi r30, 0x59 ; 89
3ba: f0 e0 ldi r31, 0x00 ; 0
3bc: 80 81 ld r24, Z
3be: 82 60 ori r24, 0x02 ; 2
3c0: 8c 93 st X, r24
3c2: df 91 pop r29
3c4: cf 91 pop r28
3c6: 08 95 ret
000003c8 <__vector_1>:
}
/* ================================================== ============================ */
/* === 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)
{
3c8: 1f 92 push r1
3ca: 0f 92 push r0
3cc: 0f b6 in r0, 0x3f ; 63
3ce: 0f 92 push r0
3d0: 11 24 eor r1, r1
3d2: 2f 93 push r18
3d4: 3f 93 push r19
3d6: 4f 93 push r20
3d8: 5f 93 push r21
3da: 8f 93 push r24
3dc: 9f 93 push r25
3de: af 93 push r26
3e0: bf 93 push r27
3e2: ef 93 push r30
3e4: ff 93 push r31
3e6: cf 93 push r28
3e8: df 93 push r29
3ea: cd b7 in r28, 0x3d ; 61
3ec: de b7 in r29, 0x3e ; 62
Iencdr1 ++; //zähle Counter/encoder 1 hoch
3ee: 80 91 68 00 lds r24, 0x0068
3f2: 90 91 69 00 lds r25, 0x0069
3f6: 01 96 adiw r24, 0x01 ; 1
3f8: 90 93 69 00 sts 0x0069, r25
3fc: 80 93 68 00 sts 0x0068, r24
Iz_yseci1 = Izeit_1; //Weise musi den akt. Timerwert zu
400: 80 91 72 00 lds r24, 0x0072
404: 90 91 73 00 lds r25, 0x0073
408: 90 93 6b 00 sts 0x006B, r25
40c: 80 93 6a 00 sts 0x006A, r24
Iz_diff1 = Iz_yseci1-Iz_ysecv1; //Neue Zeit-Differenz1 ausrechnen
410: 20 91 6a 00 lds r18, 0x006A
414: 30 91 6b 00 lds r19, 0x006B
418: 80 91 6c 00 lds r24, 0x006C
41c: 90 91 6d 00 lds r25, 0x006D
420: a9 01 movw r20, r18
422: 48 1b sub r20, r24
424: 59 0b sbc r21, r25
426: ca 01 movw r24, r20
428: 90 93 71 00 sts 0x0071, r25
42c: 80 93 70 00 sts 0x0070, r24
Iz_ysecv1 = Iz_yseci1; //der aktuelle Zeitwert wird "Alter"
430: 80 91 6a 00 lds r24, 0x006A
434: 90 91 6b 00 lds r25, 0x006B
438: 90 93 6d 00 sts 0x006D, r25
43c: 80 93 6c 00 sts 0x006C, r24
{
if (Iencdr1 == 5000);
440: 80 91 68 00 lds r24, 0x0068
444: 90 91 69 00 lds r25, 0x0069
PORTC ^= (1<<PC3); //LED4 toggeln alle 5000 Interrupts
448: a5 e3 ldi r26, 0x35 ; 53
44a: b0 e0 ldi r27, 0x00 ; 0
44c: e5 e3 ldi r30, 0x35 ; 53
44e: f0 e0 ldi r31, 0x00 ; 0
450: 90 81 ld r25, Z
452: 88 e0 ldi r24, 0x08 ; 8
454: 89 27 eor r24, r25
456: 8c 93 st X, r24
}
PORTC ^= (1<<PC4); //LED5 toggeln bei JEDEM Interrupt
458: a5 e3 ldi r26, 0x35 ; 53
45a: b0 e0 ldi r27, 0x00 ; 0
45c: e5 e3 ldi r30, 0x35 ; 53
45e: f0 e0 ldi r31, 0x00 ; 0
460: 90 81 ld r25, Z
462: 80 e1 ldi r24, 0x10 ; 16
464: 89 27 eor r24, r25
466: 8c 93 st X, r24
468: df 91 pop r29
46a: cf 91 pop r28
46c: ff 91 pop r31
46e: ef 91 pop r30
470: bf 91 pop r27
472: af 91 pop r26
474: 9f 91 pop r25
476: 8f 91 pop r24
478: 5f 91 pop r21
47a: 4f 91 pop r20
47c: 3f 91 pop r19
47e: 2f 91 pop r18
480: 0f 90 pop r0
482: 0f be out 0x3f, r0 ; 63
484: 0f 90 pop r0
486: 1f 90 pop r1
488: 18 95 reti
0000048a <__vector_2>:
}
/* ================================================== ============================ */
/* ================================================== ============================ */
/* === 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)
{
48a: 1f 92 push r1
48c: 0f 92 push r0
48e: 0f b6 in r0, 0x3f ; 63
490: 0f 92 push r0
492: 11 24 eor r1, r1
494: 2f 93 push r18
496: 3f 93 push r19
498: 4f 93 push r20
49a: 5f 93 push r21
49c: 8f 93 push r24
49e: 9f 93 push r25
4a0: af 93 push r26
4a2: bf 93 push r27
4a4: ef 93 push r30
4a6: ff 93 push r31
4a8: cf 93 push r28
4aa: df 93 push r29
4ac: cd b7 in r28, 0x3d ; 61
4ae: de b7 in r29, 0x3e ; 62
Iencdr2 ++; //zähle Counter/encoder 2 hoch
4b0: 80 91 66 00 lds r24, 0x0066
4b4: 90 91 67 00 lds r25, 0x0067
4b8: 01 96 adiw r24, 0x01 ; 1
4ba: 90 93 67 00 sts 0x0067, r25
4be: 80 93 66 00 sts 0x0066, r24
Iz_yseci2 = Izeit_1; //Weise Iz_yseci den akt. Timerwert zu
4c2: 80 91 72 00 lds r24, 0x0072
4c6: 90 91 73 00 lds r25, 0x0073
4ca: 90 93 6f 00 sts 0x006F, r25
4ce: 80 93 6e 00 sts 0x006E, r24
Iz_diff2 = Iz_yseci2-Iz_ysecv2; //Neue Zeit-Differenz2 ausrechnen
4d2: 20 91 6e 00 lds r18, 0x006E
4d6: 30 91 6f 00 lds r19, 0x006F
4da: 80 91 74 00 lds r24, 0x0074
4de: 90 91 75 00 lds r25, 0x0075
4e2: a9 01 movw r20, r18
4e4: 48 1b sub r20, r24
4e6: 59 0b sbc r21, r25
4e8: ca 01 movw r24, r20
4ea: 90 93 77 00 sts 0x0077, r25
4ee: 80 93 76 00 sts 0x0076, r24
Iz_ysecv2 = Iz_yseci2; //der aktuelle Zeitwert wird "Alter"
4f2: 80 91 6e 00 lds r24, 0x006E
4f6: 90 91 6f 00 lds r25, 0x006F
4fa: 90 93 75 00 sts 0x0075, r25
4fe: 80 93 74 00 sts 0x0074, r24
PORTC ^= (1<<PC5); //LED6 toggeln bei JEDEM Interrupt
502: a5 e3 ldi r26, 0x35 ; 53
504: b0 e0 ldi r27, 0x00 ; 0
506: e5 e3 ldi r30, 0x35 ; 53
508: f0 e0 ldi r31, 0x00 ; 0
50a: 90 81 ld r25, Z
50c: 80 e2 ldi r24, 0x20 ; 32
50e: 89 27 eor r24, r25
510: 8c 93 st X, r24
512: df 91 pop r29
514: cf 91 pop r28
516: ff 91 pop r31
518: ef 91 pop r30
51a: bf 91 pop r27
51c: af 91 pop r26
51e: 9f 91 pop r25
520: 8f 91 pop r24
522: 5f 91 pop r21
524: 4f 91 pop r20
526: 3f 91 pop r19
528: 2f 91 pop r18
52a: 0f 90 pop r0
52c: 0f be out 0x3f, r0 ; 63
52e: 0f 90 pop r0
530: 1f 90 pop r1
532: 18 95 reti
00000534 <__vector_19>:
}
/* ================================================== ============================ */
/* ================================================== ============================ */
/* === 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)
{
534: 1f 92 push r1
536: 0f 92 push r0
538: 0f b6 in r0, 0x3f ; 63
53a: 0f 92 push r0
53c: 11 24 eor r1, r1
53e: 2f 93 push r18
540: 8f 93 push r24
542: 9f 93 push r25
544: af 93 push r26
546: bf 93 push r27
548: ef 93 push r30
54a: ff 93 push r31
54c: cf 93 push r28
54e: df 93 push r29
550: cd b7 in r28, 0x3d ; 61
552: de b7 in r29, 0x3e ; 62
{
if (Izeit_1 <= 10000)
554: 80 91 72 00 lds r24, 0x0072
558: 90 91 73 00 lds r25, 0x0073
55c: 27 e2 ldi r18, 0x27 ; 39
55e: 81 31 cpi r24, 0x11 ; 17
560: 92 07 cpc r25, r18
562: 50 f4 brcc .+20 ; 0x578 <__vector_19+0x44>
Izeit_1 ++; //Zeitstand Interupt-Timer läuft von 1 .. 10 000
564: 80 91 72 00 lds r24, 0x0072
568: 90 91 73 00 lds r25, 0x0073
56c: 01 96 adiw r24, 0x01 ; 1
56e: 90 93 73 00 sts 0x0073, r25
572: 80 93 72 00 sts 0x0072, r24
576: 04 c0 rjmp .+8 ; 0x580 <__vector_19+0x4c>
else
Izeit_1 = 0;
578: 10 92 73 00 sts 0x0073, r1
57c: 10 92 72 00 sts 0x0072, r1
}
{ // von hier bis Ende (LED2 toggeln) nur Testphase
if (Izeit_1 == 1)
580: 80 91 72 00 lds r24, 0x0072
584: 90 91 73 00 lds r25, 0x0073
588: 81 30 cpi r24, 0x01 ; 1
58a: 91 05 cpc r25, r1
58c: 41 f4 brne .+16 ; 0x59e <__vector_19+0x6a>
PORTC ^= (1<<PC2); //LED3 toggeln alle Sekunde
58e: a5 e3 ldi r26, 0x35 ; 53
590: b0 e0 ldi r27, 0x00 ; 0
592: e5 e3 ldi r30, 0x35 ; 53
594: f0 e0 ldi r31, 0x00 ; 0
596: 90 81 ld r25, Z
598: 84 e0 ldi r24, 0x04 ; 4
59a: 89 27 eor r24, r25
59c: 8c 93 st X, r24
}
PORTC ^= (1<<PC1); //LED2 toggeln jeden Interrupt
59e: a5 e3 ldi r26, 0x35 ; 53
5a0: b0 e0 ldi r27, 0x00 ; 0
5a2: e5 e3 ldi r30, 0x35 ; 53
5a4: f0 e0 ldi r31, 0x00 ; 0
5a6: 90 81 ld r25, Z
5a8: 82 e0 ldi r24, 0x02 ; 2
5aa: 89 27 eor r24, r25
5ac: 8c 93 st X, r24
5ae: df 91 pop r29
5b0: cf 91 pop r28
5b2: ff 91 pop r31
5b4: ef 91 pop r30
5b6: bf 91 pop r27
5b8: af 91 pop r26
5ba: 9f 91 pop r25
5bc: 8f 91 pop r24
5be: 2f 91 pop r18
5c0: 0f 90 pop r0
5c2: 0f be out 0x3f, r0 ; 63
5c4: 0f 90 pop r0
5c6: 1f 90 pop r1
5c8: 18 95 reti
000005ca <main>:
}
/* ================================================== ============================ */
// ------------------------------------------------------------------
/*### Hauptschleife ###*/
int main(void)
#### dies gelöscht wegen begrenzter Posting-länge
00000746 <_exit>:
746: ff cf rjmp .-2 ; 0x746 <_exit>
oberallgeier
20.12.2007, 17:19
Nun bin ich doch etwas in Sorge. Meine Assemblerroutine am tiny13 für den externen Interrupt läuft auch nicht. Da muss es irgendwo einen geheimen Code geben - oder ich versteh das doc2535 von ATMEL nicht :(.
Hubert.G
20.12.2007, 17:40
Zu deinem GCC nochmal, du hast anscheinend nur das Manual von 1.4.6, ab dieser Version gibt es kein SIGNAL (SIG_OVERFLOW0) mehr, da heist es ISR(TIMER0_OVF_vect) und einiges andere mehr.
oberallgeier
20.12.2007, 20:10
Danke Hubert.G für den Hinweis - ich bin gerade dabei, Software und "Handware" = Dokumentation auf Vordermann zu bringen und mich etwas besser einzulesen.
Als Fingerübung hatte ich inzwischen einen tiny13 diesen extInt0 aufgetragen - und mittlerweile auch hier dazugelernt. Aber das nutzt leider bei der Variante "C" für den mega16 garnix.
Ach so, ja, und in meiner ...\include\avr\iom16.h
... Manual von 1.4.6, ab dieser Version ... kein SIGNAL (SIG_OVERFLOW0) mehr, da heist es ISR(TIMER0_OVF_vect) und einiges andere mehr.da stehen beide Namen. Mal sehen, was die Alternative bringt.
Schönen Abend,
Hubert.G
20.12.2007, 21:42
In deinem Prog das du mir geschickt hast fehlt der Aufruf für die Initialisierung des externen Interrupt XTI_01_init( )
oberallgeier
20.12.2007, 23:23
Hallo Hubert.G,
vor Jahren hatte ich schon festgestellt, dass eigene Fehler sehr schwierig zu finden sind - na ja, mein Fehler fällt ja auch eher unter Schlamperei :(. Jetzt läuft´s, klar - dank Deiner Hilfe. ABER das Gute ist nun - ich habe bei dieser Lektion eine Menge über C gelernt.
oberallgeier
09.01.2008, 09:04
Hallo Ihr,
einen schönen Abend erstmal. Danke für eure Hilfe und Ratschläge.
Ich habe das oben genannte Programm und die zugehörige Header-Datei in Anlehnung an die Demo für die RNControl mit Hilfe von hier (danke Hubert.G - habe dabei ein bisschen projektorientiertes C gelernt) auf den mega16 (in der RNControl) gebracht und danach erfolgreich auf einen tiny2313. Der war mir zu speicherarm, daher der Umstieg auf den 168. Und nun sitze ich den zweiten Tag (die zweite Nacht) und nix geht voran :(.
Die fuses passen - der 168 läuft nett, die Kontroll-LED blinkt (zum Auftakt - vor allen möglichen Initialisierungen) und der USART läuft auch schon hübsch.
... Einige Registernamen und Bedeutungen haben sich beim mega168 auch geändert (Timer z.B.)... Das war in einem anderen Thread (https://www.roboternetz.de/phpBB2/viewtopic.php?p=342234#342234). Ja, leider muss ich das schmerzhaft, na ja, nicht wirklich - blos sehr zeitaufwendig - erleben. Ausserdem läuft mein Timer0 schon wieder nicht (CTC, 50µsec Timer für mehrere Zwecke).
void TMR_0_init( void )
{ //Initialisiere 8-Bit-Timer auf 10 kHz
TCCR0A |= (1<<WGM01); // Timer im CTC-Mode (doc S104)
TCCR0B |= (1<<FOC0A); // Forde Output Compare A (doc S105)
TCCR0B |= (1<<CS01); // Prescaler 1/8 / Clock <- CPU (doc S106)
OCR0A = 100; // Preset 100 für 50µs bei 16Mhz
TIMSK0 |= (1<<OCIE0A); // Compare Match IRQ
}
mit der ISR
/* === Nicht unterbrechbare ISR für timer ====================================== */
/* Diese Routine zählt hoch im Takt 20 kHz. Der Zählerwert wird von den ISR für
EXT_INT0 und -INT1 ausgelesen und den Werten Iz_yseci zugewiesen ...... */
// #define SIG_OUTPUT_COMPARE0A _VECTOR(14), siehe doc2545, S 63
SIGNAL(SIG_OUTPUT_COMPARE0A)
{
{
if (Izeit_1 < 60000) //Zeitstand Interrupt-Timer läuft von 1 .. 60 000
Izeit_1 ++; // d.h. alle 3 Sekunden wird der Stand erreicht
else
{ Izeit_1 = 0; // ansonsten: Rückstellen auf Null und
PORTC ^= (1<<PC2); } //LED3 toggeln, bei Izeit_1 max 60000 => 3 sec
}
PORTC ^= (1<<PC1); //LED2 toggeln, bei (prsc=1/8, OCR0=100)=> 0,050 ms
}
/* ================================================== ============================ */
/* ================================================== ============================ */
/* === HAUPTProgramm ================================================== ========= */
Es ist sogar leider so, dass USART läuft, aber keine PWM solange keine Interrupts erlaubt sind, aber natürlich eben dieser Timer nicht. Andersrum - wenn ich "sei" aktiviere, dann läuft kein USART - auch keine PWM und kein Timer0. Aber die main-Routine wird dauernd teilweise abgearbeitet . . . . offenbar ohne Aufruf der enthaltenen Routinen (sieht man am Blinzeln der LED :() und ohne die (ok, ok, die unschönen..) waitms nach dem Setzen von "sei".
/* ================================================== ============================ */
/* === HAUPTProgramm ================================================== ========= */
/* Initialisierungen, LED1 kurzblinken als Signal für Programmstart,
Ausgabe des Indentifizierungsstrings per USART
*/
int main(void)
{
/* Encoder-Eingang 1 PortD2
Encoder-Eingang 2 PortD3 */
/*###Initialisierungsphase### */
//Pins bzw. Ports als Ein-/Ausgänge konfigurieren
DDRB |= 0x87; //10000111 -> PB0- B2: Mot 1,2 + PWM 1,2/3,4, PB7 Mot 1,2
DDRC |= 0x7F; //01111111 -> PC0 .. 6 , kein PC7-Pin
DDRD |= 0xF0; //11110000 -> PD6,7 Mot 3,4 sowie PD2,3 extInt
//Initialisierungen
setportcon(0); setportcon(1); setportcon(2); //Ports C (m168 hat nur 7)
setportcon(3); setportcon(4); setportcon(5); //... aus
init_tmrPWM(); //Initialisierung Timer für PWM
init_USART0(MYUBRR); //USART0 initialisieren mit wählbarer Baudrate (s.o.)
TMR_0_init(); //Initialisiere den Timer0-Interrupt (10 kHz)
XTI01_init(); //Initialisiere den externen Interrupt 0 und 1
for(i=0; i<20; i++)
{
setportcoff(0); //2 sek blinken mit LED1 nach dem Reset -
waitms(15); // damit man kurze resets besser erkennt
setportcon(0);
waitms(85);
}
waitms(1000);
sei(); //Globalen Interrupt freigeben
setportcoff(0);
waitms(2000);
setportcon(0);
waitms(2000);
sendUSART("FLEX168 mit 2drehzmess-168.c\r\n");
sendUSART("Version ~x05 vom 08jan08 23:42 mit (sei)\r\n");
sendUSART("Timer ist initialisiert auf 50 µsec ? ? ?\r\n");
for(;;){
setportcoff(0);
waitms(1000);
setportcon(0);
waitms(1000);
Mlinksstop();
Mrechtsstop();
setPWMlinks(0);
setPWMrechts(0);
Motst_aufab();
setportcoff(0);
waitms(1000);
setportcon(0);
waitms(1000);
}
}
Ich habe das oben genannte Programm und die zugehörige Header-Datei in Anlehnung an die Demo für die RNControl mit Hilfe von hier (danke Hubert.G - habe dabei ein bisschen projektorientiertes C gelernt) auf den mega16 (in der RNControl) gebracht und danach erfolgreich auf einen tiny2313. Der war mir zu speicherarm, daher der Umstieg auf den 168. Und nun sitze ich den zweiten Tag (die zweite Nacht) und nix geht voran :(.
Hätte da bitte jemand mal einen Rat? Ich sehe also einen Reset nach Setzen von "sei" und habe keinen Schimmer, warum das so ist. Danke im Voraus
oberallgeier
09.01.2008, 19:52
Mittlerweile sehe ich, dass der µC in eine kurze Schleife (immer wieder reset?) fällt, sobald ich den hier vorgestellten Interrupt erlaube, aber auch bei "sei" für nur einen externen Interrupt ohne dem Timer0 - der garnicht auftreten konnte (Pull down am Eingang).
Hubert.G
10.01.2008, 11:30
Wenn es ein Reset ist solltest du es an der LED an PortC0 erkennen. Ich glaube aber eher das du dich in deinen Interrupts verfängst. In jeden Interrupt eine LED die aufleuchtet wenn er angesprungen wird.
Wenn du der Meinung bist der Timer0 funktoniert nicht, dann probier ihn alleine, ohne drumherum aus. Probier alle Interrupts alleine aus und wenn sie dann funktionieren, dann erst stöpsle sie mit den anderen Programmteilen zusammen.
oberallgeier
10.01.2008, 12:11
Danke m.a.r.v.i.n, danke Hubert.G,
heute nacht hatte ich schon einen Umbau gemacht "Abfangen" falscher Interrupts. Erstmal nur die zwei benachbarten Interrupts. Jetzt gehe ich dran, die ganze Liste abzufangen und mit Blinkzeichen zu melden. (Wenn das nicht klappt, mach ich Rauchzeichen draus und mache wieder auf dem mega16 weiter). Danke.
oberallgeier
11.01.2008, 17:10
... In jeden Interrupt eine LED die aufleuchtet wenn er angesprungen wird... Hei, war das ein hübsche Arbeit :(.
Zuerst natürlich:
PCICR = 0x00; // Verbiete ALLE Pin-Change-Interrupts
PCMSK0 = 0x00; // Verbiete ALLE Pin-Change-Interrupts an den entspr. Pins
PCMSK1 = 0x00; // Verbiete ALLE Pin-Change-Interrupts an den entspr. Pins
PCMSK2 = 0x00; // Verbiete ALLE Pin-Change-Interrupts an den entspr. Pins
und dann nach diesem Muster
/* ================================================== ============================ */
/* === ISR für Timer1 Input Capt =============== */
/* Routine setzt LED auf Port PC1 1 Mal = Vektor 11 */
SIGNAL(TIMER1_COMPA_vect)
{
PORTC |= (1<<PC1); // Setze Port C1
PORTC |= (1<<PC2); // Setze Port C2
waitms(500); // Warte (einfach irre lang)
PORTC &= ~(1<<PC1); // Lösche Port C1
waitms(500); // Warte (einfach irre lang) 1
}
/* ================================================== ============================ */ . . . so ähnlich für alle 25 Vektoren. Nicht wirklich BCD und die waits brrrrrr - ok sagte ich mir, wenn er dorthin interruptet, dann ist er sowieso schon am Rande des Chaos. ABER - ich hatte damit den Fehler auf die Gegend um den vec 14 - Timer0-compx/OVF lokalisiert. Völlig rätselhaft. Für heute habe ich genug. Ich mache mit dem mega16 oder 32 weiter, leider geometrisch vier mal so gross und nur bis 16 MHz. Den m168 lege ich erstmal zu Seite - schade :(.
Hubert.G
11.01.2008, 19:14
Warum alle 25 Vektoren? Es hätte genügt die von dir initialisierten zu überprüfen.
Ich glaube auch nicht das der Timer0OVF direkt das Problem ist. Die Initialisierung dafür ist korrekt.
oberallgeier
11.01.2008, 22:28
Danke für die Aufmunterung! Ich habe mir also doch noch ein feineres Netz (mit jeweils nur drei Vektoren) zum Fehlerfischen gemacht - und der TIMER1_OVF_vect ist ins Netz gegangen. Es war schon doof von mir, die RICHTIGEN Passagen zur Fehlersuche an euch Freunde zu geben und die FALSCHE Passage beim Initialisieren der PWM für mich zu behalten.
TIMSK1 |= (1<<TOIE1); // heisst eben nicht: Tmr/Cntr1 Overflow interrupt disabled. Jetzt steht dort TIMSK1 &= ~(1<<TOIE1); und "alles" läuft prächtig und den armen mega168 hatte ich stunden- ja, tagelang verwünscht - obwohl DER es garnicht war :).
Der gegenwärtige Föhn könnte also einfach mein Seufzer der Erleichterung sein . . .
Powered by vBulletin® Version 4.2.5 Copyright ©2024 Adduco Digital e.K. und vBulletin Solutions, Inc. Alle Rechte vorbehalten.