inputbin blockiert auch alle Timer

    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!

    • inputbin blockiert auch alle Timer

      Hallo an Alle,
      ich stelle fest, dass das warten auf ein Byte mittels inputbin auch die laufenden Timer blokiert, d.h die laufen nicht weiter. Kommen die Bytes an, laufen die Timer auch.
      Ist dieses Verhalten normal oder habe ich etwas übersehen?
      Vielen Dank für Eure Hilfe
      Sonni
    • Hier die Sub, die die Bytes erwartet:

      Quellcode

      1. Sub seriell()
      2. Start Timer1
      3. For Z = 1 To 200
      4. Inputbin , X
      5. If X = 150 Then
      6. Do
      7. N = N + 1
      8. Inputbin , Ar(n) , 1
      9. Loop Until Ar(n) = 150
      10. Next
      11. Stop Timer1
      12. End Sub
      Alles anzeigen
      Zur Erläuterung: Ich Empfange serielle Pakete, die immer mit Byte 150 beginnen und unterschiedlich lang sind und mit unvorhersehbaren Bytes enden. Deshalb ist der Buffer problematisch.
      Ich überprüfe 200x ob das Byte 150 angekommen ist und ab dann lese ich alle Bytes in das Array bis wieder 150 ankommt (nächstes Paket)
      Wenn der Datenstrom reisst, bleib das Programm hängen, weil nichts empfangen wird > Fatal!!!
      Mit $timeout=500000 dauert es mir bei 200x zu lange. Deswegen der Gedanke mit Timer1. Beim Overflow sollte etwas ausgegeben werden.
      Leider funktioniert das nicht. Der µC bleibt komplett stehen und wartet auf Bytes. Auch der Timer scheint angehalten zu sein.
      Ich hoffe, ich habe mich verständlich ausgedrückt!
      Sonni
    • Der Codeschnipsel zeigt nicht, wie dein Timer1 konfiguriert ist und ob der denn läuft.

      Andererseits steht ja in der Hilfe, dass Inputbin auf Zeichen wartet.
      Will man das nicht, kann man Inkey verwenden.

      Besser wäre es aber zu prüfen, ob überhaupt was angekommen ist mit IsCharWaiting() und dann erst die Empfangsroutine auszurufen.

      Da dein Paket immer mit 150 beginnt, könntest du auch den Empfang per Charmatch starten.

      Und inputbin blockiert die Timer nicht.
      Dazu müsste man die schon explizit per Stop Timer stoppen oder sie sind nicht konfiguriert.
    • sonnenschein schrieb:

      Hier die Sub, die die Bytes erwartet:
      Poste doch bitte ein Programm, damit der Fehler auch nachvollziebar wird.
      Es gibt noch mehr Stolpersteine.

      Wie du siehst, hat deine Leseroutine noch ein paar Schwierigkeiten. Du verwirfst z.B. jedes 2. Paket.

      Besser wartet man auf das erste Byte und legt alle nachfolgenden in ein Array.
      Wenn eine Zeit x keine Bytes mehr kommen, ist das Paket zu Ende und die Auswertung kann beginnen.

      Schade, dass du keinen Zugriff auf den Sender hast, der könnte ja Länge und Checksumme mitschicken
    • Hier eine ganzes Programm, das bereitrs in dieser ersten Testversion das genannte (Fehl)Verhalten zeigt:

      BASCOM-Quellcode

      1. $regfile = "m328pdef.dat"
      2. $crystal = 3686400
      3. $hwstack = 100
      4. $swstack = 100
      5. $framesize = 100
      6. $baud = 9600
      7. $lib "i2c_twi.lbx"
      8. Config Clock = User
      9. Twcr = &B00000100
      10. Config Timer0 = Timer , Prescale = 1024
      11. On Timer0 Tim0_isr
      12. Enable Timer0
      13. Config Timer1 = Timer , Prescale = 1024
      14. On Timer1 Tim1_isr
      15. Enable Timer1
      16. Stop Timer1
      17. Enable Interrupts
      18. Config Portc.1 = Output
      19. Dim Ar(135) As Byte
      20. Dim X as Byte
      21. Dim N as Integer
      22. Dim Z as Integer
      23. Dim T as Integer
      24. Dim C as bit
      25. Declare Sub seriell()
      26. Declare Sub Getdatetime()
      27. Do
      28. Toggle PortC.1
      29. If C = 1 Then
      30. Print _hour ; ":" ; _min ; ":" ; _sec
      31. Print "Anzahl empfangener Bytes: ";N
      32. For Z = 1 to N
      33. Print Ar(z)
      34. Next
      35. End if
      36. Waitms 100
      37. Loop
      38. Sub Seriell()
      39. C = 0
      40. Start Timer1
      41. For Z = 1 To 200
      42. '$timeout = 500000
      43. Inputbin , X
      44. If X = 150 Then
      45. Do
      46. N = N + 1
      47. '$timeout = 500000
      48. Inputbin , Ar(n) , 1
      49. Loop Until Ar(n) = 150
      50. If Ar(1) = 15 Then
      51. C = 1
      52. Stop Timer1
      53. Exit Sub
      54. End If
      55. Next Z
      56. Stop Timer1
      57. End Sub
      58. Sub Getdatetime()
      59. I2cstart
      60. I2cwbyte &HD0
      61. I2cwbyte 0
      62. I2cstart
      63. I2cwbyte &HD1
      64. I2crbyte _sec , Ack
      65. I2crbyte _min , Ack
      66. I2crbyte _hour , Ack
      67. I2crbyte X , Ack
      68. I2crbyte _day , Ack
      69. I2crbyte _month , Ack
      70. I2crbyte _year , Nack
      71. I2cstop
      72. _sec = Makedec(_sec) : _min = Makedec(_min) : _hour = Makedec(_hour)
      73. _day = Makedec(_day) : _month = Makedec(_month) : _year = Makedec(_year)
      74. End Sub
      75. Tim0_isr:
      76. T = T + 1
      77. If T = 1000 Then
      78. Stop Timer0
      79. Call Getdatetime()
      80. Print _hour ; ":" ; _min;":";_sec
      81. If Ischarwaiting() = 1 Then Call Seriell()
      82. Start Timer0
      83. End if
      84. Return
      85. Tim1_isr:
      86. Print "Kein RS-232 Signal"
      87. Return
      Alles anzeigen
      1. Im Hauptprogramm blinkt alle 100ms eine LED und wenn das empfangene Ar(1) Byte = 15 werden die Zeit und alle empfangene Bytes ausgegeben
      2. Timer0 läuft im Hintergrund und alle ca 75 Sec wird Timer0 gestoppt, die Zeit abgefragt und ausgegeben und wenn ein Byte wartet auch die Sub Seriell() aufgerufen. Wenn kein Byte wartet wird der Timer0 wieder eingeschaltet und es geht wieder zum Hauptprogramm zurück.
      3. Wenn der Sender Daten sendet werden diese in der Sub Seriell() empfangen und im Hauptprogramm ausgegeben. Timer1 wird zu Beginn der Sub eingeschaltet und je nach Ablauf wieder ausgeschaltet.
      Soweit, so gut! alles läuft wie es soll.
      ABER wenn während die Sub Seriell() läuft der Sender ausfällt, bleibt der AVR hängen und wartet auf Bytes (für immer).
      Deshalb dachte ich an Timer1, der nach ca 19 Sec etwas anderes auslösen könnte (z.B ein Hardware-Reset). Im obigen Testprogramm gibt er nur eine Meldung aus.
      DAS passiert jedoch NIE, der AVR bleibt für immer hängen.
      Aktiviere ich die $timeout, dauert es etwa 7 Minuten, dann geht es doch weiter mit Tim1_isr und ab dann ganz wie erwartet nur Punkt 1 & 2 (weil Sender ausgefallen und dadurch ischarwaiting = 0).

      Zu den Paketen: Der sendr sendet unregelmäßig. Alle Pakete beginnen mit Byte 150, mich interessieren aber nur diese, die mit Byte15 weiter gehen. Wenn ich nach 200x kein brauchbares Paket erwische, ist nicht schlimm. Nach ca 1 Minute versucht das Programm wieder "sein Glück".

      Und jetzt zu meiner ursprünglichen Frage zurück: Warum wird kein Tim1_isr ausglöst während inputbin vergeblich auf ein Byte wartet, obwohl Timer1 gestartet wurde ?

      Danke für Eure Hilfe
      Sonni

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

    • sonnenschein schrieb:

      Warum wird kein Tim1_isr ausglöst während inputbin vergeblich auf ein Byte wartet, obwohl Timer1 gestartet wurde ?
      Weil du noch im Timer0 steckst.

      Die ganze Programmkonstruktion ist [hier steht ein schlimmes Wort]

      Den seriellen Empfang mach im eigenen URXC Interrupt.
      Dort holst du das aktuelle Byte aus dem UDR und schaust, ob es 150 ist.
      Wenn ja, sagst du einer Statusvariable, dass sie jetzt den Wert 1 hat, N setzt du hier auf 1.
      Wenn nein, dann schaust du, ob Status = 1 ist und
      wenn ja, schaust du, ob das Byte aus dem UDR = 15 ist und gibst den Status dann den Wert 2.
      Wenn nein, dann schaust du ob Status = 2 ist, dann schreibst du dein Byte in Ar(n) und inkrementierst n.
      Wenn N dann einen Maximalwert hat, setzt du Status auf Null.

      Ganz einfache Statemachine ;)

      Der Vorteil, du brauchst kein Timer-Gefrickel und die ISR ist schnell, um die anderen Timer nicht zu sehr zu stören.
    • Hallo, ich gebe erste Rückmeldung:
      Mit der "quick and dirty" Methode, d.h. ich habe meinen besch..eidenden Code belassen und die Sub Serilell() lediglich über einen flag aus der Hauptschleife aufgerufen, wie Franz vorschlug. Das hat auf anhieb geklappt, wenn der Sender ausfällt greift der Timer1 und kehrt an die Hauptschleife zurück.
      Aus Freude an der Sache habe ich auch die elegante Methode von Michael versucht, habe bislang jedoch keine brauchbaren Pakete empfangen können. Vielleicht ist mein Code wieder besch.. Ich werde es aber weiter versuchen und wenn ich scheitere poste ich hier meinen Code wegen Verbesserungsvorschlägen.
      Schöne Pfingsten