Mehrfachverwendung von Timern inkl. getrennter ISR

    Diese Seite verwendet Cookies. Durch die Nutzung unserer Seite erklären Sie sich damit einverstanden, dass wir Cookies setzen. Weitere Informationen

    Aufgrund technischer Veränderungen ist der Mailverkehr innerhalb des Forums (Private Nachrichten) nur noch eingeschränkt möglich. Die Einschränkung ist notwendig, um zusätzliche Betriebskosten für das Forum zu vermeiden. Näheres zu den Hintergründen im Thread "Aktuelles zum Forum".Wir bitten um Verständnis.

    Hinweis kann nach Kenntnisnahme deaktiviert werden!

    • Mehrfachverwendung von Timern inkl. getrennter ISR

      Hallo zusammen
      ich habe eine Frage: ist es möglich einen Timer mehrfach zu verwenden; z.B. in einem Programmteil als Timer und in einem anderen Programmteil als Counter. Die Programmteile werden nie gleichzeitig ausgeführt. Einfach ein Config Timer.... mit ISR-Sprungziel vor der Verwendung funktioniert nicht (ISR already defined). Ist es nicht möglich das Sprungziel dynamisch zu ändern? Kann nur ein Sprungziel verwendet werden und muss dann in der ISR das Ganze auseinandergebröselt werden? Eine meiner ISR ist schon lange genug.
      In der Timer-Hilfe wird etwas von mysetting erwähnt, verstanden habe ich es nicht ganz ?(
      Vielen Dank für euren Kommentar
      jepe
    • Hallo Pluto
      Danke für den Tip.
      Da ich den Counter im einen Fall als reinen Zähler verwende kann ich den Overflow-Interrupt verwenden. Ich nehme an dies ist bei BASCOM der Normalfall bei Überlauf "On Timerx Sprungziel".
      Im anderen Fall soll eine genaue Zeit erzeugt werden. Bis jetzt wird der Counter mit einem Wert geladen und er zählt dann hoch wieder bis zum Überlauf. In diesem Fall das gleiche ISR-Sprungziel.
      Nun sollte es aber möglich sein von 0 aus zu zählen bis zu einem Compare-Wert (z.B. im Register OCR0A). In diesem Falle wird ein CompareA-Interrupt erzeugt, der eine andere ISR-Sprungadresse hat.
      Ist meine Überlegung richtig?
      btw. Wenn in BASCOM Config Timerx verwendet wird dann wird wohl nur der Normalmode unterstützt (gibt ja auch nur einen Interrupt: On Timerx Sprungziel; wohl TOV0). Die restlichen Möglichkeiten müssen dann wohl auf Registerebene programmiert werden.
      btw. In der Hilfe ist dann ein Fehler, dort steht für Setzen von TOV0 "Set Tifr.1" ; es wäre jedoch "Set Tifr0.0" oder Set TOV0 ?

      Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von jepe ()

    • jepe schrieb:

      Ist es nicht möglich das Sprungziel dynamisch zu ändern? Kann nur ein Sprungziel verwendet werden und muss dann in der ISR das Ganze auseinandergebröselt werden?
      Hallo Jepe

      Wie Pluto schon sagt, ist es nicht möglich, für einen einzelnen Interrupt wie Timer1-Overflow zwei ISR-Routinen zu definieren.

      Aber das ist auch gar nicht nötig.

      Man kann hingehen und in der eigentlichen ISR verzweigen. Dabei kann man Calls auf externe Routinen aufrufen.
      Somit kannst du also deine 2 ISR-Routinen, die du brauchst für Timer und Counter in eigene Sub's schreiben und von der eigentlichen ISR per If-Abfrage in die eine oder andere Routine einen Call machen.

      Ich schreibe gleich noch mal ein kleines Beispiel und stelle das hier ein.

      Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von Mitch64 ()

    • Hier das Beispiel.
      Zwecks Übersichtlichkeit wurde das Programm aufgeteilt in das Haupt-Programm (Main.bas) und eine Include-Datei namens Timer.inc, die die ISR- und die Timer-Konfiguration enthält.

      Zunächst mal zum Hauptprogramm.

      In Zeile 18 wird das Timer-Modul eingebunden. Das enthält unter anderem 2 Routinen, mit denen der Mode für den Timer1 konfiguriert werden kann.
      Diese Aufrufe sind in der Hauptschleife in Zeile 30 und 32 zu sehen. Der Name der Sub ist selbsterklärend.
      Im laufenden Betrieb kann der Mode umgeschaltet werden.
      Das mach in der Demo jetzt vielleicht wenig Sinn, zeigt aber wie man es machen kann.

      BASCOM-Quellcode: Main.bas

      1. ' Demo:
      2. ' Timer1 als Timer und Counter mit Überlauf-Interrupt dynamisch Umschaltbar.
      3. ' Normalerweise steht in der ISR bei Counter-Betrieb ein anderer Code als im Timer-Betrieb.
      4. ' Zwei ISR's sind nicht möglich für einen Interrupt-Vektor.
      5. ' Daher hier eine Lösung, wie das Problem umgangen werden kann.
      6. '
      7. $Regfile = "M8def.dat"
      8. $HWStack = 30
      9. $SWStack = 30
      10. $Framesize = 40
      11. $Crystal = 8000000
      12. Config SubMode = New
      13. $Include "Include\Timer.inc" ' Modul Timer einbinden
      14. ' ----------------------------------------------------------------------------
      15. ' Hauptschleife
      16. ' ----------------------------------------------------------------------------
      17. Enable Interrupts
      18. Do
      19. ' So kann der Mode für den Timer umgeschaltet/aktiviert werden
      20. Call Set_Timer1_As_Timer() ' Timer-Betrieb
      21. Wait 10
      22. Call Set_Timer1_As_Counter() ' Counterbetrieb
      23. Wait 10
      24. Loop
      Alles anzeigen

      Dann weiter zum Kern.
      Wird die Include eingebunden, wird eine Variable varTimerMode definiert und 2 Konstanten, die den Timer-Mode repräsentieren sollen. Siehe Zeile 6, 8 und 9.

      Vom Hauptprogramm werden die Routinen Set_Timer1_as_Counter() oder Set_Timer1_As_Timer() aufgerufen. Diese sind ab den Zeilen 60 bzw. ab 69 zu finden.
      Darin wird nur der Timer konfiguriert und in der Variablen der entsprechende Mode gespeichert.

      Kommen wir zur ISR.
      In Zeile 15, 16 wird die ISR-Routine definiert und aktiviert, die ab Zeile 22 zu finden ist. Diese ISR prüft nun lediglich, welchen Wert die Variable varTimerMode hat und springt abhängig davon in die Routinen, die je nach Timer-Mode auszuführen sind.
      Diese Unterprogramme kann man jetzt fast als ISR für die jeweiligen Modes betrachten.

      BASCOM-Quellcode: Timer.inc

      1. ' Timer-Modul
      2. ' ----------------------------------------------
      3. ' Interne Variablen / Konstanten für das Modul
      4. ' ----------------------------------------------
      5. Dim varTimerMode as Byte ' Speichert, ob man im Timer- oder Counter-Betrieb ist
      6. Const TIMER_MODE = 1 ' mögliche Mode's für den Timer
      7. Const COUNTER_MODE = 2
      8. ' ----------------------------------------------
      9. ' ISR-Routine für Timer1-Overflow-Interrupt
      10. ' ----------------------------------------------
      11. On OVF1 ISR_Timer1_OVF ' ISR festlegen
      12. Enable OVF1
      13. ' ----------------------------------------------
      14. ' Dies ist die ISR-Routine, die per Timer1-Overflow aufgerufen wird.
      15. ' ----------------------------------------------
      16. Sub ISR_Timer1_OVF()
      17. Select Case varTimerMode ' Welcher Modus wird verwendet?
      18. Case COUNTER_MODE
      19. Call ISR_Timer1_Counter() ' Routine, die bei Counter-Betrieb auszuführen ist
      20. Case TIMER_MODE
      21. Call ISR_Timer1_Timer() ' Routine, die bei Timer-Betrieb auszuführen ist
      22. End Select
      23. End Sub
      24. ' ----------------------------------------------
      25. ' Diese Routine kann man jetzt als ISR-Routine
      26. ' bei Timer-Überlauf für Counter-Betrieb betrachten.
      27. ' Sie wird von der eigentlichen ISR angesprungen.
      28. ' ----------------------------------------------
      29. Sub ISR_Timer1_Counter()
      30. ' Hier der Code, der bei Counter-Betrieb abzuarbeiten ist
      31. Timer1 = 100 ' Counter mit 100 Vorladen
      32. End Sub
      33. ' ----------------------------------------------
      34. ' Diese Routine kann man jetzt als ISR-Routine
      35. ' bei Timer-Überlauf für Timer-Betrieb betrachten.
      36. ' Sie wird von der eigentlichen ISR angesprungen.
      37. ' ----------------------------------------------
      38. Sub ISR_Timer1_Timer()
      39. ' Hier der Code, der bei Timer-Betrieb abzuarbeiten ist
      40. Timer1 = 20000 ' Timer mit 20000 vorladen
      41. End Sub
      42. ' ----------------------------------------------
      43. ' Konfiguriert Timer als Counter
      44. ' ----------------------------------------------
      45. Sub Set_Timer1_As_Counter()
      46. Config Timer1 = Counter , Edge = Rising ' Timer als Counter konfigurieren
      47. varTimerMode = COUNTER_MODE ' Den Mode für die ISR merken
      48. End Sub
      49. ' ----------------------------------------------
      50. ' Konfiguriert Timer als Timer
      51. ' ----------------------------------------------
      52. Sub Set_Timer1_as_Timer()
      53. Config Timer1 = Timer , Prescale = 1024 ' Timer als Timer konfigurieren
      54. varTimerMode = TIMER_MODE ' Den Mode für die ISR merken
      55. End Sub
      Alles anzeigen
      Der Code ist ausreichend kommentiert, damit man das nachvollziehen kann.
      Löst das dein Problem?
    • @Pluto25: Ich arbeite mit dem ATMega1284P und dort ist TOV0 das Overflow-Bit des Timer0. Ich dachte immer die Bitbezeichnungen in der Atmel-Familie sind eindeutig.

      @Mitch64: Vielen Dank für das ausführliche Beispiel a_42_02cc30b2 , also in der ISR die 2 Fälle auseinanderbröseln.
      Letzte Nacht habe ich jedoch versucht den Vorschlag von Pluto25 umzusetzen um auf Registerebene die 3 verschieden möglichen ISR zu verwenden. Scheint allerdings etwas Tricky zu sein da bei der Verwendung von Timer-Compare automatisch ein Ausgang geschaltet wird (so habe ich es verstanden, war aber schon früh am Morgen || ). Da ich jedoch momentan nicht zuhause bin kann ich das Resultat nicht überprüfen. Ich weiss auch nicht ob der von BASCOM verwendete Interrupt ( On Compare0A Compare0_irq ) der Richtige ist resp. an eine andere Adresse als ( On Timer0 Timer0_irq ) springt.

      Nochmals vielen Dank euch beiden für eure Hilfe.
      jepe
    • jepe schrieb:

      da bei der Verwendung von Timer-Compare automatisch ein Ausgang geschaltet wird
      Kann, muß aber nicht. Die pwm Pins haben je zwei bits mit dehnen sie konfiguriert werden:
      00= nicht reagieren=normal zu nutzender Pin
      01=toggle schaltet bei jedem Match um
      10=clear
      11=Set
      Das Mysetting arbeitet entweder gar nicht (Meaga8) oder betrifft nur den Presaler
      Das Config kann jedoch beliebig oft in Code aufgerufen werden und setzt damit den Zustand der beim nächsten Start Timer ausgeführt wird.