Hallo,
auf meinem ATmega328 Arduino gehen mir die Timer aus. Bisher habe ich
vermieden Timer0 zu verwenden, weil Arduino es für einen Zähler einsetzt
um z.B. die delay() Funktion zu realisieren.
Der Timer0 erzeugt 976,56 mal pro Sekunde einen Interrupt zu einer
Arduino Funktion, die die Zeit aufaddiert. Ich würde mich jetzt gerne
vor die Arduino Intterupt Routine setzen. Also den Originalvektor der
Arduino Routine sichern und durch meine eigene Funktion ersetzen. Nun
meine Befehle in der neuen Interrupt Funktion abarbeite und dann wieder
in den Vektor von Arduinos Interruptroutine zurückspringen.
Weiß jemand ob und wie das geht?
Beste Grüße
stero
Wenn du viele Timer brauchst verwende doch Software-Timer.
Hänge dich in irgendeine ISR bei der die die Zeitkonstante gerade gut
passt und rufe dort (am besten kurz bevor die ISR verlassen wird) eine
Funktion "Tick()" auf.
In der kannst du dann beliebig viele neue Timer erstellen:
1
uint16u16_Timer1=0xFFFF;
2
3
voidTick(void)
4
{
5
if(u16_Timer1==0xFFFF)
6
{
7
//mache nix da der Timer nicht gestartet ist.
8
//zu starten den Timer1 auf einen Wert <0xFFFF setzen
9
}
10
else
11
{
12
//Timer1 läuft
13
if(u16_Timer1>0)
14
{
15
//Timer ist noch nicht abgelaufen
16
u16_Timer1--;
17
}
18
else
19
{
20
//Timer ist abgelaufen..
21
//irgend ne Funktion oder Makro aufrufen:
22
timeout_Timer1();
23
//oder auch ne variable setzen und die dann pollen:
Hallo Benjamin,
vielen Dank für deine Antwort.
Ich benutze nicht alle Timer um Interrupts auszulösen, sondern um direkt
ohne Interruptaufruf die Ausgangspins zu toggeln. Wenn da jedesmal ein
Intterruptvektor angesprungen werden müßte, wäre das leider zu
Rechenzeitaufwendig.
Man könnte vielleicht versuchen den Interrupt schneller zu machen, als
der Originalcode von GCC. Der macht allerhand zeitfressende Sicherungen
vor und nach der Interruptroutine. Aber da begibt man sich natürlich auf
dünnes Eis, wenn man das alles selber machen will.
ja, es kommt natürlich drauf an welche Zeiten du benötigst und wie
schnell dein uC taktet.
es hängt von der Größe deiner Interrupt-Vektor-Tabelle ab ob du vor dem
Aufruf der ISR noch platz hast um einen Ausgang zu toogeln.
Bei den meisten AVRs dürftest du da schlechte Karten haben.
Es gibt allerdings bei gcc einen Befehl bzw. eine #pragma Anweisung um
eine leere ISR zu erstellen, d.h. es werden keine Register gesichert und
zurück geschrieben. Wenn du also weiß das du keine Register veränderst
kannst du das nehmen, dann bist du in 2-3 Takten in dem Code.
Wenn das Ausgang toogeln sehr schnell sein muss, die "ursprüngliche" ISR
aber nicht kannst du eine leere ISR erstellen, deinen Ausgang setzen,
dann die Register manuell sichern, dann die "ursprüngliche" ISR
Aufrufen, dann die Register zurückschreiben und die ISR verlassen.
Hallo Benjamin,
das mit dem Toggeln kann der ATmega ja auch ganz ohne CPU Belastung. Ich
nutze den "clear on compare match" Modus von Timer2 und die PWM Ausgabe
auf dem dazugehörigen OC2B-Pin.
Ich probiere noch einen anderen Weg, indem ich direkt die Arduino
Bibliothek mit dem original Interruptaufruf erweitere.
Als letzten Befehl schreibe ich in die original Arduiono Timer0 ISR
Routine einen Funktionsaufruf an eine über Funktionspointer einstellbare
Funktion.
Diese Funktion kann ich dann hoffentlich - wenn es endlich mal klappen
würde - aus dem Hauptprogramm heraus auf meine Erweiterung der Timer0
ISR zeigen lassen. Eigentlich sollte es klappen, aber er schreibt mir
immer eine Fehlermeldung mit "undefined reference". Ich arbeite daran...
:]
Hallo Benjamin,
hier gibt es Auswertungen zu den von dir Vorgeschlagenen kurzen
Interruptzeiten:
http://www.embeddedrelated.com/usenet/embedded/show/1437-1.php
Wie man das viele gepushe und gepoppe verringern kann steht hier im
Abschnitt "ISR mit eigenem Prolog/Epilog":
http://www.rn-wissen.de/index.php/Avr-gcc
Im Folgenden der interessante Abschnitt daraus. Ich hoffe der Autor
vergibt mir die ungefragte Kopie:
______________________________________________________________
Wenn man in einer ISR komplett eigenes Zeug machen will, dann definiert
man eine nackte Funktion. Mit naked befreit man die Routine vom
Standard-Prolog/Epilog.
Dabei ist darauf zu achten, daß die ISR mit reti (return from interrupt)
zurückkehrt und evtl. verwendete Register und den Status (SREG) sichert.
#include <avr/io.h>
void _attribute_ ((naked))
SIG_OVERFLOW0 (void)
{
// Port B.6 = 0
// Diese Instruktion verändert nicht das SREG und kein anderes
Register
// so daß der eigentliche Code nur 1 Befehl lang ist
_asm_ __volatile (
"cbi %0, %1" "\n\t"
"reti"
:
: "M" (_SFR_IO_ADDR (PORTB)), "i" (6)
);
}
Stephan R. schrieb:> Diese Funktion kann ich dann hoffentlich - wenn es endlich mal klappen> würde - aus dem Hauptprogramm heraus auf meine Erweiterung der Timer0> ISR zeigen lassen.
Wenn du direkt in der IVT verzweigen willst dürfte die Größe der IVT nur
ausreichen wenn du das Register-Paar das der IJMP Befehl verwendet
dauerhaft für die Adresse der jeweiligen ISR reservierst.
Lohnt sich IMO nicht nur um den Sprung in eine naked-ISR einzusparen.
Benjamin F. schrieb:> Wenn du direkt in der IVT verzweigen willst dürfte die Größe der IVT nur> ausreichen wenn du das Register-Paar das der IJMP Befehl verwendet> dauerhaft für die Adresse der jeweiligen ISR reservierst.> Lohnt sich IMO nicht nur um den Sprung in eine naked-ISR einzusparen.
Indem ich mich hinter die ohnehin vorhandene Arduino Timer0
Interruptroutine hänge, nutze ich, das bereits alle Register gesichert
und restauriert werden. Bis auf das Anspringen und Zurückspringen zu
meiner ergänzenden Interruptroutine entsteht kein Overhead und das, ohne
sich über Register auf Assembler Ebene Gedanken machen zu müssen.
Wichtig für meine Anwendung ist aber besonders, das ich die anderen
beiden Timer für andere Aufgaben frei behalte.
Die Lösung, durch Ändern der Original Arduino Dateien sich hinter die
Arduino Timer0 Interruptroutine zu hängen, funktioniert jetzt. Ich habe
im Arduino Forum meine modifizierte wiring.c und Arduino.h Datei
eingestellt. Aufgerufen wird das sehr bequem direkt aus dem Sketch.
Neben diesen zwei Dateien habe ich auch ein kleines Beispiel gemacht,
wie man es aus dem Sketch aufruft:
http://arduino.cc/forum/index.php?topic=87945.0
VG Stephan
Eine eigene Frage?
Dieser Thread ist über 14 Jahre alt.
Stell sie in einem eigenen Thread – dort lesen mehr Leute mit, und sie wird öfter und schneller beantwortet.