Software UART mit 6,N,1

    This site uses cookies. By continuing to browse this site, you are agreeing to our Cookie Policy.

    • Software UART mit 6,N,1

      Hallo,

      ich suche nach einer Software Uart mit 6,N,1. Kennt jemand eine Möglichkeit da die Funktion in Bascom nur 7,N1 bzw. 8,N1 unterstützt?

      Habe im Netz einige Beispiele in Assembler gesehen aber da meine Fähigkeiten da sehr begrenzt sind, konnte ich damit keine Erfolge in absehbarer Zeit (mehrere Tage) erziehlen.

      Im Moment verwende ich halt einen ATMega328p mit Hardware Uart und behelfe mich so.

      Über Links oder Code Stücke in Bascom und Assembler wäre ich sehr dankbar.

      Liebe Grüße Jörg
    • Hallo,

      erstmal Danke für die Antworten.

      Es geht um ein Protokoll von einem Motorola MC145026 Chip, ähnlich des Märklin Motorola Protokolls.
      Es sollen von einem älteren Gerät (Fernsteuerung einer älteren Fräse) Daten empfangen weden und an die Fräse weitergegeben werden. Mit dem Oszi habe ich 6,N,1 bei 9600Baud herrausbekommen. Also hatten auch andere ähnliche Ideen wie Märklin.

      Zum probieren hatte ich bis jetzt einen Arduino Mega 2560 mit HW Uart verwendet. Doch leider ist der Platz begrenzt und ich würde lieber einen Attiny 84 dafür verwenden (liegen hier noch ein paar rum). Falls das nicht gehen sollte kommt halt für die nächsten 6-12 Monate eine Kiste dran. Dann geht die Maschine sowieso in Rente.

      LG Jörg
    • Das geht vermutlich schon, jedoch finde ich keine brauchbare Beschreibung der Protokolls
      Der Code des 2560 würde helfen. bzw:
      Muß es empfangen und senden Gleichzeitig können? (braucht zwei Timer)
      Wie viele Zeichen werden üblich/max übertragen?
      Gibt es Endzeichen? (z.B. CrLf)
      Gibt es Einzelzeichen? (wie z.B. "<" beim ESP)
      Oder Notzeichen? Auf die Sofort reagiert werden muß (Notaus,Motor blockiert...)

      Soll gesammelt/ausgewertet werden oder fängt Dein Code sowieso jedes einzelne Zeichen ab?
    • JOJO150272 wrote:

      Motorola MC145026 Chip
      Der Chip ist ja lt. Datenblatt ein Encoder.
      D.h. er kodiert die Eingangssignale an den Pins A1 bis A9 und sendet die eben kodiert am Datenpin raus.

      Diese IC's gibt bei Reichelt.

      Du willst also so ein Signal vom MC14026 mit dem tiny 84 empfangen und dann an die Fräse weiter leiten?
      Soll das Signal 1:1 sein, also unverändert?

      Was macht es für einen Sinn, das Signal zuerst zu dekodieren (von der Fernbedienung) und dann zu kodieren (für die Fräse)?
      Willst du da was mitloggen?

      Was hast du da vor?

      Im Datenblatt ist die Kodierung beschrieben.
      Bildschirmfoto vom 2022-11-01 09-59-42.png
      Ein Bitwert von den jeweiligen Inputs wird quasi als 16-Bit Wert übertragen.

      Da der Tiny84 keinen UART hat, sondern nur ein USI, wird man da wohl das Signal von Hand generieren müssen (Bit-Bänging).

      Für einen Transmitter:
      Eine Herangehensweise wäre, 16-Bit-Werte für HIGH, LOW und TRISTATE zu definieren und die im Takt eines Timers MSB-First auszugeben.

      BASCOM Source Code

      1. ' Kodierwerte (16 Bit) für High (One), Low (Zero) und Open (Tristate)
      2. Const DATA_ONE = &h7F7F
      3. Const DATA_ZERO = &h4040
      4. Const DATA_OPEN = &h7F40
      So könnte man die Inputs nacheinander beginnend mit Input A1 übertragen.

      Der Empfang wäre etwas schwieriger.

      Es ist die Frage, was du eigentlich genau bezwecken willst.
      Soll der Tiny als Empfänger, als Sender oder beides fungieren? Und was ist mit den Input-Leitungen und Datenleitung? Müssen die auch vom Tiny bereitgestellt werden?
      Also quase den MC14026 als AVR nachbauen?

      Vielleicht möchtest du die Community hier etwas mehr aufklären?

      Erst wenn klar ist, was die Aufgabe ist, kann man auch Code-Schnipsel bereitstellen.
    • Hallo,

      hier mal den Code mit den Veränderungen

      Source Code

      1. $Regfile="m2560def.dat"
      2. $Crystal=4000000
      3. $hwstack=40
      4. $swstack=16
      5. $framesize=32
      6. $Baud = 9600
      7. $Baud1 = 9600
      8. Dim RD_Wert(18) As Byte
      9. Dim WR_Wert(18) As Byte
      10. Do
      11. Inputbin RD_Wert , 18
      12. RD_Wert(6) = 14
      13. RD_Wert(6) = RD_Wert(6) - 3
      14. Printbin RD_Wert(1) ; 18
      15. Loop
      Display All
    • Mitch64 wrote:

      6N1 würde aufgehen, weil ja nich ein Start und ein Stop-Bit dazu käme
      Dann muß aber zwingend immer das 8.High und das 9. Low sein.


      @JOJO150272
      Arbeitet das Zuverlässig?
      Ist das nicht abenteuerlich? Wenn ein Zeichen verloren geht stimmt gar nichts mehr.
      Wie lang sind die Pausen zwischen zwei (18 Byte) Übertragungen?
      Wenn er sonst nichts machen muß würde auch ein Tiny 13 reichen .
      Gibt es einen Grund weshalb nicht
      15 RD_Wert(6) = 11
      Wird der Wr_wert benötigt?
    • Hallo an ALLE

      Mitch64 wrote:

      Ich habe ja nicht behauptet, dass 16 Bit UART-Signal übertragen werden. Sondern einfach 16 Bit.

      6N1 würde aufgehen, weil ja nich ein Start und ein Stop-Bit dazu käme. Sind 8 Bit. Das 2x = 16 Bit.

      Mit 7N1 und 8N1 geht das nicht.
      Ja so bin ich ja erst drauf gekommen das ein Motorola MC145026 verbaut sein könnte, was mich an die Eisenbahn meines Sohns erinnerte.


      Pluto25 wrote:

      Mitch64 wrote:

      6N1 würde aufgehen, weil ja nich ein Start und ein Stop-Bit dazu käme
      Dann muß aber zwingend immer das 8.High und das 9. Low sein.

      @JOJO150272
      Arbeitet das Zuverlässig?
      Ist das nicht abenteuerlich? Wenn ein Zeichen verloren geht stimmt gar nichts mehr.
      Wie lang sind die Pausen zwischen zwei (18 Byte) Übertragungen?
      Wenn er sonst nichts machen muß würde auch ein Tiny 13 reichen .
      Gibt es einen Grund weshalb nicht
      15 RD_Wert(6) = 11
      Wird der Wr_wert benötigt?

      - habe immer 8. High und 9. Low gesehn
      - was heist schon Zuverlässig, im Testbetrieb lief es
      - hat bis jetzt noch keine Funktion um unvollständige Telegramme festzustellen und dies auszusortieren
      - zwischen zwei Telegrammen liegt etwa eine 1 Sekunde
      - bestimmt würde auch ein anderer Tiny gehn, hatte halt nur noch einige Tiny84 und Tiny85 von der Modelbahn meines Sohns übrig

      - natürlich hast du recht das RD_Wert(6) = 11 reicht, ist noch vom ausprobieren der Werte für die Steuerung der Funktionen


      Bis jetzt empfange ich das Telegramm und verändere nur den RD_Wert(6) auf 11, in der Zukunft möchte ich noch zwei - drei andere Werte verändern.
      Auch könnte man die Telegramme an den PC senden zur Anzeige.

      Ich hatte halt nach einer SoftUart gesucht aller 6,N,1 und die Daten zu empfangen. Wenn das nicht geht muß ich halt mit einem Timer die Leveländerungen messen und mein Telegramm selber zusammen setzen oder mir einen Tiny mit HW Uart besorgen.
    • Dieser Code läuft auf einem Tiny13. Ich habe ihn etwas agepasst so das er mit einem T85 laufen sollte.
      (Nicht getestet)

      Source Code

      1. $regfile = "attiny85.dat"
      2. $crystal = 8000000
      3. $hwstack = 8
      4. $swstack = 0
      5. $framesize = 0
      6. $eepleave
      7. Config Base = 0
      8. Config Watchdog = 2048 '7
      9. Ddrb = $e4 '2
      10. Portb = 7 '4 = 1 '2 Tx b1=Rx
      11. On Int0 P_isr Nosave 'Pcint0 P_isr Nosave
      12. 'Mcucr = $2 'int0 falling funktioniert nicht?????
      13. Gimsk = $40 ' int0
      14. 'Baud 576 460,8 230,4 153,6 128 115 76,8 57,6 38,4 28,8 19,2 16 14,4 9,6
      15. '8Mhz 1 5 10- 12 14 23- 31 54 66 101 122 156 205
      16. Const Port_txd = Portb
      17. Const Pin_txd = 2
      18. Dim A As Byte , A2 As Byte , B As Byte
      19. Dim Ubuf(18) As Byte
      20. Dim C As Byte At Ubuf(_base) Overlay
      21. Dim D As Byte At Ubuf(_base) + 1 Overlay
      22. Declare Sub Printsw
      23. Declare Sub Printsw2(byreg R15 As Byte)
      24. Declare Sub Printcrlf
      25. Declare Sub Pause
      26. R14 = 205 '9600Baud bei 8Mhz
      27. Start Watchdog '3
      28. Enable Interrupts '1
      29. Do
      30. Do
      31. nop
      32. Loop Until R22 = 18
      33. For A = 0 To 17 'Bytes sind rechtsbündig
      34. Ubuf(a) = Ubuf(a) / 4
      35. Next '
      36. Ubuf(5) = 11
      37. For A = 0 To 17
      38. Call Printsw2(ubuf(a))
      39. Next
      40. R22 = 0
      41. Reset Watchdog '1
      42. Loop '2
      43. End
      44. Macro Bitdauer 'r17*4-1
      45. !nop
      46. !DEC r17
      47. !BRNE -2
      48. End Macro
      49. Sub Printsw2(byreg R15 As Byte) '5
      50. !CBI PORT_TXD,PIN_TXD '2 #10 Startbit
      51. Disable Interrupts '1
      52. nop '1
      53. nop '1
      54. ' nop '1
      55. !LDI r18,7 '1 ********* Bits+1 *****************
      56. !sec '1 Set Carry (Stopbit)
      57. _sw2_loop: ' Schleife Datenbits
      58. !mov r17,r14 '1 Bit-Dauer setzen
      59. Bitdauer '17 bei 6
      60. !ror r15 '1 Datenbits schieben (Datenbit ist nun im Carry-Flag)
      61. !SBIS SREG,0 '3/4 1-Bit oder 0-Bit ausgeben?
      62. !RJMP _SW2_Zero '2
      63. ' nop
      64. !SBI PORT_TXD,PIN_TXD '2
      65. !RJMP _SW2_Next
      66. _sw2_zero: '0-Bit ausgeben
      67. !CBI PORT_TXD,PIN_TXD '2
      68. ' nop
      69. nop
      70. _sw2_next:
      71. nop
      72. !DEC r18 '1 Bit-Zähler
      73. !BRNE _SW2_Loop '2 nächstes Datenbis ausgeben
      74. Enable Interrupts '1
      75. !mov r17,r14 '1
      76. Bitdauer
      77. End Sub
      78. P_isr:
      79. !PUSH r16 '2 verwendete Register sichern
      80. !IN r16,sreg '1
      81. !PUSH r16 '2
      82. !clr r24 '1 Leeren da nur 1 gefüllt
      83. !set '1 T=1 für Bitset r24
      84. !mov r17,r14 '1
      85. !DEC r17 '1 Warte Startbit
      86. !BRNE -1 '2 (3/4 Zeit)
      87. !ldi r26,6 '1 Bitzähler ******************************
      88. Lopx:
      89. !LSr r24 '1
      90. !dec r26 '1
      91. !mov r17,r14 '1
      92. !inc r17 '1 Warte Bitdauer
      93. Bitdauer 'r17*4-1
      94. !Sbic pinb,1 '2 Falls B3=1
      95. !bld r24,7 '1 Setze Bit 7
      96. !cpi r26,0 '1 Byte voll?
      97. !brne lopx '2/1 #10/11
      98. Loadadr Ubuf(_base) , X '1 Array Adresse holen
      99. !add r26,r22 '1 index addieren
      100. ' !CPI r24,10 '1 lf empfangen?
      101. ' !BRne Isr_1 '2 wenn nicht weiter zu isr1
      102. ' !ldi r21,1 '1 (Uneu=1)
      103. ' !jmp fertig '2
      104. Isr_1:
      105. !CPI r22,18 '1 ist 52? (Puffer voll)
      106. !BRsh fertig '2/1 Wenn >= nicht speichern
      107. '!cpi r24,$30 '1 ist $30?
      108. '!BRlo fertig '2/1 Wenn < nicht speichern
      109. '!cpi r24,$60 '1 ist $60?
      110. '!BRlo gros '2/1 Wenn < ist schon gros
      111. '!ANDI r24,$df '1 erzeuge Großbuchstaben
      112. ' Gros:
      113. !ST x,r24 '2 RxByte speichern
      114. !inc r22 '1 incr r22 (Uein)
      115. Fertig:
      116. !sbis pinb,1 '2
      117. !jmp fertig '2 Warte auf Stopbit ????
      118. !POP r16 '2
      119. !OUT SREG,r16 '1
      120. !POP r16 '2
      121. Return
      Display All
    • @Pluto25
      Sie ISR läuft nicht sicher.
      Zum einen werden mehrere Register nicht gesichert
      nicht gesicherte Register:
      17
      26
      24
      26
      22

      Zudem verwendest du das x-Register zum Speichern von Daten (ST x,..). Es wird aber nur r26 gesetzt, nicht aber r27.
      Wohin wird denn da gespeichert?

      Du kannst ja nicht sicherstellen, dass @JOJO150272 in der Hauptschleife was rein schreibt, was diese Register verwendet.

      Also x-Register und die obigen in der ISR sichern, dann passt es.
    • Bei 9600 bliebe genug Zeit sie zu sichern, jedoch funktionieren dann die hohen Baudraten nicht mehr.
      Wenn etwas zu kommt muß sicher kontrolliert werden ob die Isr was schredden würde. Und ob R14 Bestand hat.
      Eine Art Timeout wäre sinnvoll
      z.B. if r22=1 start timer.....Timer ovf: R22=0

      Mitch64 wrote:

      Wohin wird denn da gespeichert?
      genau dahin wo es hingehört :D R27 wird beim Loadadr gesetzt
      Der Tiny13 hatte nicht genügend Ram um R27 zu ändern. Bei dem 85 hingegen muß darauf geachtet werden das die Byte-Grenze nicht überschritten wird. (oder R27 bearbeiten)