Hallo zusammen, habe eine Frage: Kann man in Bascom den Interrupt-Vektor z.B. Timer1-Overflow auf eine andere Routine (Label) umbiegen? Ich möchte von einer Variablen (Mode) gesteuert unterschiedliche Konfigurationen machen. Select Case Mode Case 0 : gosub ConfigurationA Case 1 : gosub ConfigurationB End select Nun möchte ich je nach Konfiguration den Timer1-Overflow Interrupt auf unterschiedliche Unterroutinen (Labels) legen. ConfigurationA: On Timer1 ISR_ConfigA Return ConfigurationB: On Timer1 ISR_ConfigB Return Und jetzt habe ich ein Problem. Bascom 1.11.9.1 meckert beim Kompilieren mit der Fehlermeldung, dass die ISR bereits definiert ist. Der Compoler hat ja recht, aber wie kann ich diese Fehlermeldung umgehen? Kann ich mit Out oder einem anderen Bascom Befehl die Adresse des Interrupt-Handlers andern? Wenn nein, wie kann ich es in einem Assemblerblock $ASM $End ASM anstellen? Weis jemand bescheid? Mit LoadLabel kann ich die Adresse der ISR-Routine ermitteln. Aber wie bekomme ich den Wert in die Vektortabelle Adresse $008?
Mach Dir ne globale Variable und pack eine If-Abfrage in die (eine) ISR. Geht bestimmt auch noch anders. Aber so in die Richtung musst Du gehen.
Globale Variable und in der ISR abfragen funktioniert bei unkritischen Interrupts. Meiner muß sehr schnell abgearbeitet werden. Deshalb möchte ich eine 2. Interrupt-Routine in der Vektor-Tabelle eintragen! Aber wie?
>... sehr schnell abgearbeitet werden.
Dann würde ich aber C anstelle von Basic empfehlen!
> Deshalb möchte ich eine 2. Interrupt-Routine in der Vektor-Tabelle > eintragen! > > Aber wie? Das geht einfach nicht. Ein Interrupt hat genau eine Interrupt Routine. Woher sollte der Prozessor (welcher eigentlich?) wissen welche Routine jetzt gerade drankommen soll? Was z.B. geht: - If Abfrage oder Switsch-Case - Deine ISR kann die aktuell gewünschte Routine über einen Funktionspointer aufrufen, da musst du dann keine IFs abarbeiten. (Keine Ahnung ob Bascom Funktionspointer kann)
Hast nichtmal geschrieben um was für eine CPU es sich handelt. Ich nehm mal an ein AVR (der Nickname und Bascom). Mit Bascom kenn ich mich nicht aus, aber nen AVR hat seine Interrupt-Vektoren im Flash. Den Flash kann man auch im Betrieb löschen und neu schreiben, hab ich aber noch nicht gemacht (kenn ich mich also nicht mit aus). Vielleicht gibt es da ja ein Weg... Wenn das geht, dann darf man das ca. 10000 mal. ;-) Wenn es Zeitkritisch ist, warum dann nicht die Interrupt Funktion in Assembler oder C und wie bereits geschrieben eine globale Variable verwenden. In C wäre das sowas wie:
1 | #define CONFIG_A 1
|
2 | #define CONFIG_B 2
|
3 | volatile static uint8_t configuration; |
... irgendwo in der initialisierung / main() ...
1 | configuration = CONFIG_A; /* oder CONFIG_B */ |
und dann die Interrupt-Routine
1 | ISR(TIMER1_OVF_vect) |
2 | {
|
3 | switch(configuration) { |
4 | case CONFIG_A: |
5 | /* dies und jenes erledigen */
|
6 | break; |
7 | case CONFIG_B: |
8 | /* was völlig anderes erledigen */
|
9 | break; |
10 | default:
|
11 | /* die schaltung in brand setzen weil
|
12 | * der Interrupt mit falscher Konfig
|
13 | * gestartet wurde - oder vielleicht
|
14 | * was weniger drastisches wie einen
|
15 | * fehler signalisieren und anhalten
|
16 | * oder neustarten? */
|
17 | }
|
18 | }
|
Wie das nun in Bascom umzusetzen ist ist mir völlig unklar, aber vielleicht kann man in Bascom ja auch assembler und/oder C untermischen. Auf jeden Fall sollte dir Idee doch nun klarer sein, oder? Wenn ja, dann kann man das vielleicht auch in Bascom so umsetzen. Wenn es aber so Zeitkritisch ist daß es auf einzelne Instruktionen ankommt und Bascom keine Kontrolle darüber bietet, dann wäre sicher C und/oder Assembler eine bessere Wahl. PS: Ich habe keinerlei Ahnung von Bascom, kann leider kein Passenderes Beispiel fabrizieren. PPS: Ach Mist, während ich hier rumtipsel wurde nu schon X mal switsch erwähnt. Und da Johnny Maxwell schon "Switch-Case" gesagt hab glaub ich auch Bascom kann sowas, also kann man das Beispiel ja so übernehmen ;-)
> Kann man in Bascom den Interrupt-Vektor z.B. Timer1-Overflow auf > eine andere Routine (Label) umbiegen? Ja, das ist generell kein Problem, egal bei welchem Controller und/oder Sprache. Der Trick ist, Du musst den Interrupt-Vektor einfach nur ausreichend warm machen, bis er hellrot glühend ist, dann kannst Du ihn problemlos verbiegen.
Unbekannter wrote: ... > Der Trick ist, Du musst den Interrupt-Vektor einfach nur ausreichend > warm machen, bis er hellrot glühend ist, dann kannst Du ihn problemlos > verbiegen. LOL Wichtig ist es auch Sand einzufüllen, sonst kann er beim Biegen einknicken und das wars dann. ;) /me hat ein steampunk mikrocontroller vor augen, da ist immer etwas klempnerarbeit nötig ;)
>Globale Variable und in der ISR abfragen funktioniert bei unkritischen >Interrupts. >Meiner muß sehr schnell abgearbeitet werden. Die Anwendung, bei der eine Switch-Verzweigung innerhalb einer Interruptroutine nachweislich zu einem Zeitproblem führt, möchte ich aber auch mal sehen. >Deshalb möchte ich eine 2. Interrupt-Routine in der Vektor-Tabelle >eintragen! Aber wie? Nein, das kannst Du vergessen. Der Interruptvektor ist fest im Controller verdrahtet. Beispiel: Der T/C1-Overflow-Interrupt beim ATmega8 springt immer auf die Flash-Adresse 9 (siehe Datenblatt). Das kannst Du nicht ändern. Normalerweise steht in der Interrupttabelle für jeden benutzten Interrupt eine "rjmp [Sprungmarke]"-Instruktion. Dies ist der theoretisch frühestmögliche Ansatzpunkt für ein Springen zu unterschiedlichen Interruptroutinen. Mit einem 'ijmp' statt des 'rjmp ...' wäre das möglich. Das Sprungziel muss dann in ZH:ZL abgelegt werden und ist somit jederzeit zur Laufzeit änderbar. Ein ijmp braucht soviel Taktzyklen wie ein rjmp, nämlich 2.
Michael Löffler schrieb: > Und da Johnny Maxwell schon "Switch-Case" gesagt hab glaub ich > auch Bascom kann sowas, also kann man das Beispiel ja so übernehmen ;-) Ich hab keine Ahnung von Bascom! Aber kann mir kaum vorstellen, dass es da kein Switch-Case Äquivalent gibt. Zur Originalfrage: Switch-Case sollte als jump table kompiliert werden, viel schneller kriegt man das auch anders nicht hin. Wenn das schon zeitlich nicht ausreicht, was soll dann die eigentliche Funktion noch machen? Ausnahme: Der Interrupt Vektor ist RAM (gibts z.B. beim Cypress FX2). Dann kann man den einfach bei Bedarf ändern. Spielt hier aber glaub ich keine Rolle, leider wissen wir aber immer noch nicht welcher Prozessor gemeint ist. PS: @Micha R.: Das hier fast niemand Bascom verwendet, sollte dir vielleicht auch zu denken geben :)
AVRFan wrote: >>Globale Variable und in der ISR abfragen funktioniert bei unkritischen >>Interrupts. >>Meiner muß sehr schnell abgearbeitet werden. > > Die Anwendung, bei der eine Switch-Verzweigung innerhalb einer > Interruptroutine nachweislich zu einem Zeitproblem führt, möchte ich > aber auch mal sehen. Sehe ich auch so. Insbesondere die super exakte Zeitangabe "sehr schnell" läßt vermuten, daß überhaupt keinerlei Zeitbetrachtungen angestellt wurden. Warscheinlich klemmts an irgendeiner ganz anderen Stelle und dannn wird planlos versucht an irgendnem Schräubchen zu drehen, in der vagen Hoffnung, es könnte vielleicht helfen (wird es zu 99,99% aber nicht). Man muß schon die Ursachen genauer ergründen und hat dann konkrete Werte (xx Zyklen oder xx µs), mit denen man auch was anfangen kann. Und erst dann kann man an der richtige Schraube drehen. Oftmals ist aber nur eine Umstellung des Programmablaufs die richtige Schraube. Blöd nur, wenn man erst gar keinen Programmablaufplan erstellt hatte. Dann weiß man aber zumindest die genaue Ursache, warum es klemmt. Nämlich weil man völlig planlos drauf los programmiert hat. Peter
Planlos drauflos programmiert ist dies keines wegs. Hier handelt es sich um einen Prozessor AVR ATmega 8, getaktet mit 3,686400 MHZ. Die 3,6864 MHz weil noch eine serielle schnittstelle implementiert ist. Zur Anwendung: An Port T1 liegt eine Frequenz an bis zu 1MHz. Die Frequenz soll ermittelt werden. Dazu zählt der Timer 1 die ankommenden Flanken. Timer 2 verwende ich als Zeitbasis (10ms) Nun verwende ich 2 Interrupts, die Timer1 Overflow und die Timer2 OC2. ' OC2-Interrupt von Timer 2 ' wird alle 0,01 Sekunden aufgerufen ISR_Zeitbasis: incr ZeitBasisCount select case ModeNr case ModeFrequency if ZeitBasisCount = ZeitBasisMax then ZaehlerLow = Timer1 Timer1 = 0 Zaehler = ZaehlerHigh Shift Zaehler , Left , 16 Zaehler = Zaehler or ZaehlerLow Flags.0 = 1 ZaehlerHigh = 0 ZeitBasisCount = 0 end if case ModePulseCounter nop End Select Return ' Überlauf Timer1 ISR_Timer1: incr ZaehlerHigh 'Toggle LEDRed Return Wenn ich in die OC2-Interrupt-Routine noch mehr select Case-Fälle reinmache, stimmt meine Frequenz nicht mehr (zeigt zu wenig). Schnelleres Wuarz hilft nicht viel, habe schon 16MHz probiert. Deshalb war meine Idee, die Select Case-Fälle in einzelne ISR-Routinen zu packen und den Interrupt von OC2 auf unterschiedlichen Routinen zu legen. Eine Idee?
Micha R. wrote: > Wenn ich in die OC2-Interrupt-Routine noch mehr select Case-Fälle > reinmache, stimmt meine Frequenz nicht mehr (zeigt zu wenig). Das ist in der Tat sehr merkwürdig. Bei 10ms Interruptrate sind ja 36000 Zyklen Zeit zwischen den Interrupts. Derweil müßte ein Interrupthandler eigentlich ganze Romane schreiben können. Schau Dir mal das Assemblerlisting des Interrupthandlers an. Peter
Welches Assembler-Listing? Bascom erzeugt ein BIN-File und ein HEX-File. Da stehen nur Zahlen. Habe im Bascom Simulator mal die Laufzeit geprüft von ISR OC2, wenn Bedingung ZeitBasicCount=ZeitBasisMax erfüllt ist. Bascom zeigt mit bis an die Position Return (ISR OC2) 327 Zyklen an mit 0,08870 Milli-Sekunken an. Wenn Bedingung nicht erfüllt ist: 91 Zyclen bei 0,02468 ms Hilft das weiter?
Dei Bin- oder Hexfile kannst du durch einen Dissassembler schicken. Aber bestimmt wird Bascom auch ein Listfile rausschreiben können, wo der erzeugte Assemblercode ausgegeben wird.
Bascom kann das wohl nicht. Konnte jedenfalls keine einstellbare option im Compiler finden.
Micha R. wrote: > Bascom zeigt mit bis an die Position Return (ISR OC2) 327 Zyklen an mit > 0,08870 Milli-Sekunken an. 327 Zyklen klingt o.k. für Bascom. Jetzt mußt Du bloß noch rauskriegen, warum das die Messung beeinflußt. Wenn man die Messung per Interrupt startet und stoppt, sollten sich die Ausführungszeiten ja weitgehend kompensieren, bzw. eine konstante Differenz kann man vom Zählergebnis abziehen. Für genaue Frequenzmessung ist es besser, die Eingangsfrequenz auf T0 und ICP1 zu legen. T1 mißt dann die Zeit für T0 Perioden. Peter
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.