LIN - Bascom Problem bei Ischarwaiting

    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!

    • LIN - Bascom Problem bei Ischarwaiting

      Hallo Liebe Basic Gemeinde,

      ich möchte gern mit einem Attiny841 Signal vom LIN Bus lesen.

      Dazu habe ich mir eine State Maschine gebastelt, welche nach dem Erkennen des Break-Signals die UART aktiviert. Dieses Funktioniert soweit.
      Das Problem was ich habe ist, dass ich das Sync Byte nicht richtig lese.

      Im Bild (in der Farbe blau) die Daten, welche zum RxD des Controllers gehen. Die rote Kurve ist die LED, welche ich zum debuggen nutz.


      Quellcode

      1. Config Com1 = 19200 , Synchrone = 0 , Parity = None , Stopbits = 1 , Databits = 8 , Clockpol = 0
      2. Config Com2 = 19200 , Synchrone = 0 , Parity = None , Stopbits = 1 , Databits = 8 , Clockpol = 0
      3. Config Serialin0 = Buffered , Size = 10
      4. Config Serialin1 = Buffered , Size = 10
      5. Open "com1:" For Binary As #1
      6. Open "com2:" For Binary As #2
      7. $include "State.inc"
      8. $include "Ports_def.inc"
      9. $include "Timer.inc"
      10. Waitms 500
      11. Call Setstate(waiting_for_break) ' Festlegen des Anfangs-Zustands
      12. Enable Timer0
      13. Enable Interrupts 'enable global ints
      14. '*******************************************************************************
      15. Dim Temp As Byte
      16. Dim Empfangsbuffer(10) As Byte
      17. Dim Cnt As Byte
      18. Do
      19. Select Case Getstate()
      20. ' -----------------------------------------------------
      21. Case Waiting_for_break
      22. ' -----------------------------------------------------
      23. If Isstatechanged() = True Then ' Code wird 1x ausgeführt nach Zustandswechsel
      24. Gosub Disable_uart0_rxd ' UART ausschalten
      25. Timer0 = False 'Reset Counter
      26. Print#2 , "WAIT_FOR_BREAK"
      27. End If
      28. If Rxd0 = False Then
      29. Start Timer0 'Starte Zeitmessung vom Breakpulse
      30. Led = True
      31. Else
      32. If Timer0 < Breaktime Then
      33. Timer0 = 0 'Pulse zu klein
      34. End If
      35. If Timer0 > Timeout Then
      36. Timer0 = 0 'Pulse zu lang
      37. End If
      38. If Timer0 >= Breaktime And Timer0 <= Timeout Then 'Pule = Break
      39. Timer0 = 0
      40. Gosub Enable_uart0_rxd 'UART einschalten
      41. Clear Serialin0 'clear Buffer
      42. Setstate(sync) 'Pule = Break
      43. End If
      44. Led = False
      45. End If
      46. ' -----------------------------------------------------
      47. Case Sync
      48. ' -----------------------------------------------------
      49. If Isstatechanged() = True Then ' Code wird 1x ausgeführt nach Zustandswechsel
      50. Clear Serialin0
      51. Led = True
      52. End If
      53. Temp = Ischarwaiting(#0) 'was there a char?
      54. Led = Temp
      55. If Temp = 1 Then
      56. Temp = Inkey(#0)
      57. If Temp = 55 Then
      58. Setstate(address)
      59. Print#2 , "go to Address"
      60. Else
      61. Setstate(waiting_for_break)
      62. Print#2 , "Error " ; Temp
      63. End If
      64. End If
      65. .
      66. .
      67. .
      Alles anzeigen

      Man sieht, an dem kurzen Impuls in der roten Linie, dass er viel zu früh ein Byte in der UART erkennt. Im Code ist es zwischen Zeile 76...79.

      Kann mir da einer auf die Sprünge helfen.

      VG
      Dateien
      • LIN1.png

        (71,1 kB, 22 mal heruntergeladen, zuletzt: )

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

    • Hallo Bassist,
      ich denke dein Problem ist eher der Break-Impuls. Für den UART sieht der aus wie ein zu langes 0-Byte. Deswegen kommt er nicht synchron an die Daten.
      Ich würde das im ersten Ansatz so machen:
      • RXD abschalten, dafür PCINT2 einschalten.
      • Fallende Flanke des Break Impulses erkennen
      • Steigende Flanke des Break Impulses erkennen und PCINT2 abschalten, RXD einschalten.
      • Jetzt warten, bis alle UART Daten empfangen sind, dann wieder den PCINT2 einschalten und RXD aus.
    • Hallo Franz,

      das mache ich genau so ;)

      Beim ersten betretten des Zustandes "Waiting_for_break" wird die UART abgeschalten.

      Quellcode

      1. If Isstatechanged() = True Then ' Code wird 1x ausgeführt nach Zustandswechsel
      2. Gosub Disable_uart0_rxd ' UART ausschalten
      3. Timer0 = False 'Reset Counter
      4. Print#2 , "WAIT_FOR_BREAK"
      5. End If
      6. .
      7. .
      8. .
      9. Disable_uart0_rxd:
      10. $asm
      11. cbi UCSR0B,4
      12. $end Asm
      13. Return
      Alles anzeigen


      Hier wird dann die Länge gemessen die der RxD0 auf Masse ist.

      Quellcode

      1. If Rxd0 = False Then
      2. Start Timer0 'Starte Zeitmessung vom Breakpulse
      3. Led = True
      4. Else
      5. If Timer0 < Breaktime Then
      6. Timer0 = 0 'Pulse zu klein
      7. End If
      8. If Timer0 > Timeout Then
      9. Timer0 = 0 'Pulse zu lang
      10. End If
      11. If Timer0 >= Breaktime And Timer0 <= Timeout Then 'Pule = Break
      12. Timer0 = 0
      13. Gosub Enable_uart0_rxd 'UART einschalten
      14. Clear Serialin0 'clear Buffer
      15. Setstate(sync) 'Pule = Break
      16. End If
      17. Led = False
      18. End If
      Alles anzeigen
      Alles was länger oder kürzer ist wird ignoriert und er lauert auf den nächsten Impulse.

      Wenn die Zeit passt wird die UART aktiviert und in den Zustand "Sync" gewechselt, mit den o. g. Problem.
      Das funktioniert auch wie gesagt, kann man an der LED im Oszi Bild ganz gut erkennen. Jedoch wird diese dann im Sync sofort auf Masse gezogen --> weil er der Meinung ist ein Zeichen Empfangen zu haben...



      VG
    • Sorry, aber das konnte ich an deinem Code Fragment nicht erkennen.
      Du setzt die LED auf High, wenn der erste PCINT kommt und wieder auf Low beim zweiten?
      Und dann setzt du die LED wieder auf High beim Beginn des UART Lesens? Und dierkt danach wieder auf Low. Warum?
      Es scheint mir auch recht kompliziert zu sein, was du programmiert hast. Kannst du das nicht mal auf das Wesentliche reduzieren und komplett hier zeigen?
      Befürchtest du, dass du Zeichen verpasst und hast deswegen Serialin=Buffered verwendet?
    • Anbei der Code ohne $Include sonst wird es zu viel info.

      Die LED ist für mich aktuell nur zum Debuggen gedacht. Print-Ausgaben sind leider zu langsam und blokieren das Programm. Die UART läuft nur mit 19200.


      Quellcode

      1. $regfile = "ATtiny841.dat"
      2. $crystal = 8000000
      3. $hwstack = 32
      4. $swstack = 32
      5. $framesize = 32
      6. $prog &HFF , &HE2 , &HDF , &HFF ' generated. Take care that the chip supports all fuse bytes.
      7. Const True = 1
      8. Const False = 0
      9. Const Controller = 2
      10. Const Waiting_for_break = 1
      11. Const Sync = 2
      12. Const Address = 3
      13. Const Daten = 4
      14. Const Chksum = 5
      15. Const Breaktime = 85 ' 13 Bitzeiten
      16. Const Timeout = Breaktime + 40
      17. Const Lin_receiv_address = &H1A
      18. Config Com1 = 19200 , Synchrone = 0 , Parity = None , Stopbits = 1 , Databits = 8 , Clockpol = 0
      19. Config Com2 = 19200 , Synchrone = 0 , Parity = None , Stopbits = 1 , Databits = 8 , Clockpol = 0
      20. Config Serialin0 = Buffered , Size = 10
      21. 'Config Serialin1 = Buffered , Size = 10 , Bytematch = 55
      22. Open "com1:" For Binary As #1
      23. Open "com2:" For Binary As #2
      24. $include "State.inc"
      25. $include "Ports_def.inc"
      26. $include "Timer.inc"
      27. Waitms 500
      28. Call Setstate(waiting_for_break) ' Festlegen des Anfangs-Zustands
      29. Enable Timer0
      30. Enable Interrupts 'enable global ints
      31. '*******************************************************************************
      32. Dim Temp As Byte
      33. Dim Empfangsbuffer(10) As Byte
      34. Dim Cnt As Byte
      35. Do
      36. Select Case Getstate()
      37. ' -----------------------------------------------------
      38. Case Waiting_for_break
      39. ' -----------------------------------------------------
      40. If Isstatechanged() = True Then ' Code wird 1x ausgeführt nach Zustandswechsel
      41. Gosub Disable_uart0_rxd ' UART ausschalten
      42. Timer0 = False 'Reset Counter
      43. Print#2 , "WAIT_FOR_BREAK"
      44. End If
      45. If Rxd0 = False Then
      46. Start Timer0 'Starte Zeitmessung vom Breakpulse
      47. 'Print#2 , "*";
      48. Led = True
      49. Else
      50. If Timer0 < Breaktime Then
      51. Timer0 = 0 'Pulse zu klein
      52. End If
      53. If Timer0 > Timeout Then
      54. Timer0 = 0 'Pulse zu lang
      55. End If
      56. If Timer0 >= Breaktime And Timer0 <= Timeout Then 'Pule = Break
      57. Timer0 = 0
      58. Gosub Enable_uart0_rxd 'UART einschalten
      59. Clear Serialin0 'clear Buffer
      60. Setstate(sync) 'Pule = Break
      61. End If
      62. Led = False
      63. End If
      64. ' -----------------------------------------------------
      65. Case Sync
      66. ' -----------------------------------------------------
      67. If Isstatechanged() = True Then ' Code wird 1x ausgeführt nach Zustandswechsel
      68. 'Print#2 , "SYNC"
      69. Clear Serialin0
      70. Led = True
      71. 'Waitms 1
      72. End If
      73. ' Hier Code, der immer ausgeführt wird
      74. Temp = Ischarwaiting(#0) 'was there a char?
      75. Led = Temp
      76. If Temp = 1 Then
      77. Temp = Inkey(#0)
      78. If Temp = 55 Then
      79. Setstate(address)
      80. Print#2 , "go to Address"
      81. Else
      82. Setstate(waiting_for_break)
      83. Print#2 , "Error " ; Temp
      84. End If
      85. End If
      86. ' -----------------------------------------------------
      87. Case Address
      88. ' -----------------------------------------------------
      89. If Isstatechanged() = True Then ' Code wird 1x ausgeführt nach Zustandswechsel
      90. Print#2 , "ADDRESS"
      91. Clear Serialin0
      92. Temp = 0
      93. End If
      94. ' Hier Code, der immer ausgeführt wird
      95. ' ..
      96. Temp = Inkey(#0)
      97. If Temp = Lin_receiv_address Then
      98. Setstate(daten)
      99. Print#2 , "go to Daten"
      100. Else
      101. Setstate(waiting_for_break)
      102. Print#2 , "Error"
      103. End If
      104. ' -----------------------------------------------------
      105. Case Daten
      106. ' -----------------------------------------------------
      107. If Isstatechanged() = True Then ' Code wird 1x ausgeführt nach Zustandswechsel
      108. Print#2 , "DATEN"
      109. Clear Serialin0
      110. Temp = 0
      111. End If
      112. While Ischarwaiting(#0) = 1 'Buffer auslesen
      113. Empfangsbuffer(temp) = Inkey()
      114. Incr Temp
      115. If Temp >= 10 Then Exit While
      116. Wend
      117. For Cnt = 1 To Temp
      118. Print#2 , Empfangsbuffer(cnt)
      119. Next
      120. ' Hier Code, der immer ausgeführt wird
      121. ' ..
      122. ' Exitbedingungen (Ereignisse), die einen Zustandswechsel verursachen
      123. ' ..
      124. ' -----------------------------------------------------
      125. Case Chksum
      126. ' -----------------------------------------------------
      127. If Isstatechanged() = True Then ' Code wird 1x ausgeführt nach Zustandswechsel
      128. If Temp = 0 Then
      129. Setstate(waiting_for_break)
      130. Print#2 , "Nix Empfanen"
      131. End If
      132. End If
      133. ' Hier Code, der immer ausgeführt wird
      134. ' ..
      135. ' Exitbedingungen (Ereignisse), die einen Zustandswechsel verursachen
      136. ' ..
      137. 'If Taster_aus = 0 Then ' Taste-Aus betätigt
      138. ' Setstate(zustand_led_aus)
      139. 'End If
      140. End Select
      141. Loop
      142. Isr_pcint0:
      143. Return
      144. Disable_uart0_rxd:
      145. $asm
      146. cbi UCSR0B,4
      147. $end Asm
      148. Return
      149. Enable_uart0_rxd:
      150. $asm
      151. sbi UCSR0B,4
      152. $end Asm
      153. Return
      Alles anzeigen
      Ich benutze kein PCINT sondern frag den PIN ab Rxd0 ist der ALIAS für den Pina.2

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

    • Hi
      Es freut mich zu sehen, dass sich mal jemand meinen Lexikon-Eintrag angesehen und den versucht hat anzuwenden.

      Die Abfrage IsStateChanged() dient eigentlich dazu, beim Eintritt in einen Neuen Zustand eine Aktion auszulösen.

      Bei deiner LED z.B. schaltest du sie in 1. State anhängig vom RxD-Pegel an und aus.
      Und wenn du dann wechselst in den 2. State, schaltest du sie wieder ein im Block IsStateChanged().

      Aktionen möglichst in dem State auslösen, der diese Aufgabe inne hat.

      In deinem Fall würde ich im 1. State 'Waiting_for_Break' den Pin RxD einfach pollen, geht der auf Low einen weiteren Zustand aktivieren, der auf die High-Flanke wartet.
      Dort wird dann bei steigender Flanke der State 'Sync' gesetzt. Also 3 Zustände. Der 2. ist ein Hilfszustand.

      In deinem Code ist nicht klar, welche Baudrate du hast, und ob das Lin-Signal überhaupt mit Uart gelesen werden kann.
      Könnte ja auch ein Timing-Problem sein. MCU-Takt ist ja auch unbekannt.

      Auch unklar ist, wie du den UART deaktivierst. Schaltest du nur den RxD-Interrupt aus oder schaltest du wirklich den Uart aus?
      Den müsste man dann vielleicht nach dem Einschalten wieder Initialisieren?

      Am besten den ganzen Code hier einstellen, oder zumindest so gekürzt, dass er lauffähig und compilierbar ist.
    • Ich glaube hier ist dein Problem:

      BASCOM-Quellcode

      1. If Rxd0 = False Then
      2. Start Timer0 'Starte Zeitmessung vom Breakpulse
      3. Led = True
      4. Else
      5. If Timer0 < Breaktime Then
      6. Timer0 = 0 'Pulse zu klein
      7. End If
      8. If Timer0 > Timeout Then
      9. Timer0 = 0 'Pulse zu lang
      10. End If
      11. If Timer0 >= Breaktime And Timer0 <= Timeout Then 'Pule = Break
      12. Timer0 = 0
      13. Gosub Enable_uart0_rxd 'UART einschalten
      14. Clear Serialin0 'clear Buffer
      15. Setstate(sync) 'Pule = Break
      16. End If
      17. Led = False
      18. End If
      Alles anzeigen
      In Zeile 1 willst du doch den Timer starten, um die Zeit zu messen, richtig?
      Der Low-Pegel bleibt aber ne Weile stehen und du nullst den Timer immer wieder. (Der Low-Pegel dauert wohl 13 Bitlängen an).

      Dann willst du, wenn der Pegel hoch geht (Else Zweil ab Zeile 6) die Zeit auswerten,
      Aber die hast du ja die ganze Zeit auf 0 gehalten.

      Du musst die High-Low-Flanke erkennen.
      Der startet den Timer, und wenn die Low-High-Flanke kommt, musst du den Zählerwert nehmen und auswerten.
      Abhängig davon war dann der Start-Puls (Low-Puls) gültig oder eben nicht.

      Wenn du das mit Statemachine machen willst, kannst du 3 Zustände nehmen.
      Der 1. Erkennt die neg- Flanke und wechselt zu state 2
      State 2 Startet den Timer beim Eintritt und Pollt nach dem High-Pegel. (Erkennung ansteigende Flanke). Wird der High Pegel detektiert, in Zustand 3 wechseln.
      Zustand 3 aktiviert den UART und empfängt das erste Byte, evtl auch mehr.

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

    • Hallo Zusammen,

      @Franz
      >> Hier benutzt du den PCINT doch gar nicht. Wie stellst du denn die fallende Flanke des Break Impulses fest

      Ich frag den PIN ab.

      @Mitch64
      Start Timer0 ist nur das Setzten des Enable Bits, dadurch wird der Timer nicht auf 0 gesetzt.

      Wie schon geschieben die Auswertung des Break Signals funktioniert so wunderbar. Zeigt ja auch die LED im Oszi Bild die würde doch sonst nicht so leuchten wie das Break Signal anliegt ;)

      Das Problem ist das im zweiten State ein Zeichen in der UART erkannt wird obwohl keins da ist.

      VG
    • Hi,
      in dem letzten vollständigen Code steht in Zeile 108
      If Temp = 55 Then
      dass muss entsprechend deines Bildes mit den Signalpegeln Hex sein, also
      If Temp = &H55 Then

      Außerdem solltest du dir die Inkey() und Ischarwaiting() einmal ansehen.

      Dort steht manchmal nichts, manchmal #0 und manchmal #1, wobei #1 wohl richtig ist.


      Ich habe Die Status Prints rausgenommen und bei mir funktioniert das so.
    • Hallo zusammen,
      Das Thema hier ist ja schon etwas älter aber vielleich kann mich trotzdem jemand etwas helfen.
      Da ich mich gerade intensiv mit dem LIN-Bus beschäftige war ich erfreut auch etwas in Bascom zu finden.
      Leider fehlt's bei mir noch am Verständnis...
      Zuerst mal in die "State Maschine" eingelesen und soweit verstanden.
      Timer0 habe ich erst mal allgemein eingefügt, ABER die Zeile 56 wird bei der Syntaxkontrolle als Fehler angezeigt:
      Timer0 = false (also timer0=0).

      Ist dieser Timer was spezielles?
      MfG Andreas
    • Ich meine mich dunkel zu erinnern, vor langer Zeit auch mal das Problem gehabt zu haben, dass Bascom bei einem Tiny den Befehl "Timer0 = ..." irgendwie nicht akzeptiert hat.

      Damals hat mir dann jemand den Tip gegeben, direkt das Register zu beschreiben (beim Tiny45: TCNT0 = 0), und das hat funktioniert.

      Schau doch mal im Datenblatt wie das Zähl-Register des Timer0 heißt und setzte es direkt auf 0.
    • papaandreas schrieb:

      Es ist der Code von "Bassist", so wie oben.
      Und genauso wie bei dessen Code fehlen die Infos zu den Include-Dateien.
      Was genau steht in Deiner Timer.inc, sowie in den anderen Include-Dateien?

      Deine Fehlermeldung tritt beim ersten Zugriffsversuch auf Timer0 auf. Vielleicht ist Dein Timer gar nicht konfiguriert?
    • Ihr habt natürlich recht, ich war der Auffassung das der Timer nicht so relevant ist da doch eigentlich nur die Durchläufe ausgewertet werden; scheint aber nun nicht so zu sein.

      Dies hatte ich erst mal als Timer eingefügt:
      " Config Timer0 = Timer , Prescale = 1024 'Konfiguriere Timer0 alle 0.00012800819252432 aufruf
      On Timer0 Isr_pcint0 "
      Ich muß aber gestehen das ich Teile des Programms noch nicht verstehe.

      Frage: ist es möglich, und im Programm so realisiert, das man Rx der seriellen Schnittstelle gleichzeitig auch als PIN deffinieren kann?

      Bascom Vollversion, 2.0.7.8
      Herzlichen Dank, Andreas
    • Grundsätzlich hat der AVR (Mega) mindestens einen Hardware-UART, dabei stehen die Pins für RxD und TxD fest.

      Willst du die Pins für TxDund RxD selber festlegen, musst du einen Software-UART konfigurieren.
      Das hat aber für das Programm folgen.

      Interrupts während des Empfangs und Sendens sind je nach Art Tabu, auch gehen Empfangs-Buffer und Sende-Buffer nicht mehr.
      Und auch IsCharWaiting funktioniert bei Soft-UART nicht. Zudem ist die Prozessorauslastung höher, weil ja der Empfang per Software gemacht wird.

      Man sollte immer den Hardware-UART dem Software-UART vorziehen, wenn nicht explozit etwas dagegen spricht.

      Aber um deine Frage zu beantworten.

      papaandreas schrieb:

      ist es möglich, und im Programm so realisiert, das man Rx der seriellen Schnittstelle gleichzeitig auch als PIN deffinieren kann?
      Ja, aber mit Folgen, die ich eben beschrieben habe.
      Und nein, im Programm vom Bassist ist es ohne weiteres nicht möglich.