Problem mit Software RS232

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

    • Problem mit Software RS232

      Ich habe da ein kleines Problem mit einer RS232 als Softwarevariante.

      Gegeben ist ein ATmega328p welcher mit Baudratenquarz 11.0592MHz und natürlich korrekter Angabe im Programm betrieben wird.
      Davon wird die HW-RS232 verwendet um via TTL-USB-Adapter mit einem PC zu kommunizieren und eine SW-RS232 um mit einem Modul welches mittels seriellen Befehlen kommuniziert zu "sprechen".
      Beide Schnittstellen sind mit 9600,8,N,1 konfiguriert, die HW-Schnittstelle ist zudem gepuffert.

      Es zeigt sich, dass mindestens das erste selten auch noch das zweite Zeichen vom µC falsch eingelesen wird (vom Modul wird aber korrekt gesendet wie ein parallel angeschlossener zweiter TTL-USB Adapter zeigt).

      So werden vom Modul die folgenden Bytes AA 0C 02 01 47 00 gesendet aber vom µC öfters aber nicht immer als D5 0C 02 01 47 00 empfangen (selten aber doch auch D5 8C 02 01 47 00).
      AA= BIN-10101010
      D5= BIN-11010101
      0C= BIN-00001100
      8C= BIN 10001100

      Die SW-Schnittstelle wird mit
      Open "COMD.3:9600,8,n,1" For Output As #255
      Open "COMD.4:9600,8,n,1" For Input As #254
      geöffnet
      Eingelesen wird über die Funktion Inputbin #254 , Receive(0) (unter Verwendung von $timeout weil es auch Modul-Antworten mit einer vorerst unbekannten Länge gibt).
      Die zum Modul gesendeten Befehle funktionieren einwandfrei. Wäre da ein "Verschlucker" würde nämlich nichts geantwortet werden weil der Befehlsstring Checksum-gesichert ist und wenn die CS nicht stimmen würde, eben keine Antwort vom Modul kommt.

      Ich bin zwar in der glücklichen Lage, die ersten beiden Bytes nicht zu benötigen, hätte es aber schon gerne, dass auch die ersten beiden Bytes korrekt erkannt werden.

      Was könnte die Ursache für dieses "Fehlverhalten" sein?
      Der µC wurde übrigens schon durch einen anderen ersetzt, auch die Interrupts (da wird aber aktuell nur eine LED gesteuert) wurden schon deaktiviert was aber auch zu keinem Erfolg führte.
      Würde die Frequenz nicht stimmen, würde doch die gesamte Kommunikation nicht funktionieren und nicht nur immer reproduzierbar die ersten beiden empfangenen Bytes der SW-Schnittstelle.
    • Pluto25 wrote:

      versuch mal Open COMD.4:9550
      Sogar +/-200 ändert nichts wesentliches.
      Umso höher der "Korrekturwert" umso schlechter der "Empfang" ist aber auch logisch. Die letzten drei Bytes sind aber auch da noch korrekt.
      Vom Oszi ist wieder mal der Akku defekt, eventuell bastel ich da morgen was, dann schau ich mir mal das Signal an.
      Im übrigen ändert auch ein anderes Modul nichts, das zeigt das gleiche Verhalten.
      Was mich aber wundert ist der Umstand, wenn das Signal nicht sauber wäre, warum das am PC über ein TTL-USB-Modul dann nicht auffällt.
    • Das Problem hatte ich vor einigen Jahren auch mit inputbin#. Es gab darüber eine Diskussion im MCS-Forum. Kann sein dass das in irgendeiner Version gelöst wurde (und wieder zurück kam?) Es gab da viele Merkwürdigkeiten, sodass inputbin# auch als unbrauchbar bezeichnet wurde.
      Ich brauchte später inputbin# (und Printbin#) nicht mehr, konnte alles in einem dickerem xmega erledigen.
    • Hi,
      ich erinnere mich dunkel daran, dass ich mit SW Uart und INPUTBIN auch nix hinbekommen habe.
      Habe eben nochmal in die Hilfe zu "OPEN" geschaut:

      The statements that support the device are PRINT , INPUT , INPUTHEX , INKEY and WAITKEY

      Zumindest ist es da auch nicht aufgeführt...


      egal... ich denke, dass dein Programmdurchlauf zu viel Zeit beansprucht und die Empfangsroutine nicht schnell genug mit dem Einlesen ist.
      Geh doch mal auf 300Bd um das zu verifizieren...

      Ich hatte mal für Ben (Bens Hobby Corner) eine Software erstellt, wo es nötig war, einen Software Uart zu verwenden. Das ging schnell auch nur gut mit einem Interrupt!
      Siehe Punkt #9 benshobbycorner.tk/bzijlstra/software/examples/wiz610wi.htm

      COMD.2 sollte INT0 sein...
      Code first, think later - Natural programmer :D
    • six1 wrote:

      ich denke, dass dein Programmdurchlauf zu viel Zeit beansprucht
      :D
      Der Programmablauf ist
      PrintBin...
      InputBin...

      Viel schneller bekomme ich das nicht hin (ein Waitms xx zwischen den beiden Befehlen verschlimmert das ganze dann eher nur).
      Es verändert aber nichts, wenn sich der InputBin in einer SUB befindet (so oder so das gleiche falsche Verhalten)

      six1 wrote:

      Geh doch mal auf 300Bd
      Das geht leider nicht, das Modul hat unveränderbar 9600,8,N,1.

      six1 wrote:

      COMD.2 sollte INT0 sein...
      Die Platine ist eigentlich fertig, daher ist das aktuell wohl leider auch keine Option.
      Außerdem stolpere ich wahrscheinlich am Inkey() weil im zu erwartenden Datenstrom durchaus auch CHR(0) vorkommen können.

      Ich werde aber heute die anderen bisher eingegangene Tipps auch noch durchprobieren.
      Wenn alle Stricke reißen, bleibt dass dann wie es ist (das ist ja kein Herzschrittmacher a_38_b45e201d ).
      Die notwendigen Nutzdaten kommen ja korrekt und die ersten beiden Bytes interessieren mich soweit nicht wirklich (als Perfektionist stört es mich halt ein wenig und werde das für künftige Projekte berücksichtigen).

      Ich könnte aber die empfangenen Daten dennoch auf Korrektheit überprüfen, da die ersten beiden korrekten Bytes bekannt sind und man das gegen die übermittelte Checksum prüfen könnte.
      Das erste Byte muss dabei eigentlich immer AA sein (ist das Startbyte) und das zweite ist das Befehlsbyte. Erst das dritte Byte sollte korrekt sein, das steht für die Anzahl der nun folgenden Nutzbytes (dadurch weiss man dann auch die Gesamtlänge der Antwort). Das letzte Byte wäre dann die "Prüfsumme".
      Das hat sich irgend ein Chinese mal so ausgedacht ^^ .

      Da dieser Datenstrom nun mal aus Bytes zwischen Null und 255 bestehen kann sehe ich keine andere Möglichkeit des senden und empfangen der Daten (vor allem bei gegebener Hardware). Oder irre ich mich da?
    • six1 wrote:

      Auf D.4 liegt PCINT20
      Nur schlägt da doch auch INKEY() zu was kein Nullbyte kann was aber in der aktuellen Anwendung durchaus vorkommen kann.

      Nachdem ich mein Programm mal zu Probe mit der BasCom-Version 2081 kompiliert hatte, stellte ich fest, dass da das Programm gar nicht funktionierte.
      Also wurde das in der aktuellen 2082 wohl implementiert (ob irrtümlich oder absichtlich sei mal dahingestellt) funktioniert dort aber offenbar noch nicht einwandfrei.

      Ich habe das jetzt so gelöst, dass ich die ersten beiden Bytes (die sind ja bekannt) immer mit den korrekten Werten überschreibe und aus dem Datensatz die Prüfsumme bilde und dann mit der übertragenen gegenprüfe.
      So kann ich feststellen ob die Daten plausibel sind und kann die zur Not auch nochmals anfordern.
      Das ganze ist ja kein Atomreaktor sondern nur ein einfaches Soundausgabemodul :D .

      Bleibt halt nur die Frage wie man künftig bei einer Software-RS232 mit einfachen Mitteln Daten empfangen kann?
      Das Problem sind ja die im Datenstrom möglichen Nullbytes, weil mit normalen Zeichenketten funktioniert das ja soweit ich das bisher beobachten konnte)
    • Zitronenfalter wrote:

      Bleibt halt nur die Frage wie man künftig bei einer Software-RS232 mit einfachen Mitteln Daten empfangen kann?
      Vielleicht hilft das:

      Source Code

      1. $regfile = "attiny84.dat"
      2. $crystal = 8000000
      3. $hwstack = 64
      4. $swstack = 64
      5. $framesize = 64
      6. Config Base = 0
      7. '$sim
      8. Config Lcdpin = Pin , Db4 = Porta.0 , Db5 = Porta.1 , Db6 = Porta.2 , Db7 = Porta.3 , E = Portb.1 , Rs = Portb.0
      9. Config Lcd = 16 * 2 'R/W pin muss auf Gnd liegen
      10. Initlcd
      11. Cursor Off Noblink
      12. Cls
      13. Dim Uinbuf(32) As Byte ',Dummy as byte (nötig falls uinstr <uinbuf)
      14. Dim Uinstr As String * 32 At Uinbuf Overlay
      15. Dim Uein As Byte , Uneu As Byte , Uwait As Byte , Uw2 As Byte
      16. Dim A As Byte
      17. Dim Bgut As Byte , B2gut As Byte
      18. 'Baud 256 128 115 57,6 56 38,2 28,8 19,2 14,4 9,6 4,8 2,4 -
      19. '8Mhz 5 14 16 36 37 56 76 116 156 237 - - -
      20. '4Mhz - 5 6 16 17 26 36 56 76 116 237 - -
      21. '2Mhz - - - 6 6 12 16 56 36 56 116 237 -
      22. '1Mhz - - - - - - 6 11 16 26 56 116 237
      23. Uwait = 238 '9600 Baud
      24. Dim Temp As Byte , Tempi As Integer , Tempw As Word , Tempstr As String * 6
      25. Dim Templ As Byte At Tempw Overlay
      26. Dim Temph As Byte At Tempw + 1 Overlay
      27. Uinstr = "Hallo, hier Tiny"
      28. On Pcint0 P_isr Nosave
      29. Pcmsk0 = $40 'Nur a.6
      30. Gimsk = $10 'Nur PCint0 (0-7)
      31. Ddra = $bf 'A6-RX =input
      32. Enable Interrupts
      33. 'Deflcdchar 0 , 32 , 14 , 17 , 17 , 32 , 17 , 17 , 14 'Zur 0 Byte darstellung
      34. Do
      35. Locate 1 , 1
      36. Lcd "Empfangen:"
      37. Lcd Uein
      38. Lcd " "
      39. Lowerline
      40. Lcd Uinstr
      41. If Uneu = 1 Then
      42. If Uein < 16 Then
      43. For A = 0 To Uein
      44. Lcd Uinbuf(a)
      45. Next
      46. Do
      47. Lcd ""
      48. Incr A
      49. Loop Until A >= 16
      50. Uneu = 0
      51. Uein = 0
      52. Else
      53. For A = 0 To 15
      54. Lcd Uinbuf(a)
      55. Next
      56. End If
      57. wait 2
      58. End If
      59. Loop
      60. End
      61. P_isr: '55 7µs / 2 nosave
      62. !Sbic pina,6 '2 if a.6=0 überspringe nächsten Befehl
      63. !jmp Ist1 ' gehe zum ende
      64. !PUSH r16 '2 verwendete Register sichern
      65. !IN r16,sreg '1
      66. !PUSH r16 '2
      67. !PUSH r17 '2 Uein
      68. !PUSH r24 '2 RxByte
      69. !PUSH r26 '2
      70. !PUSH r27 '2 # 17
      71. Gimsk = 0 '2 pcint stop
      72. !set '1 T=1 für Bitset r24
      73. !clr r24 '1 leeren da nur 1 gefüllt wird
      74. !lds r16,{Uwait} '2 hole Uwait
      75. !ldi r26,8 '1 #3
      76. Lopx:
      77. !LSr r24 '1
      78. !dec r26 '1
      79. !ldi r17,255 '1
      80. Lop0:
      81. !inc r17 '1
      82. !cpse r16,r17 '1 /2
      83. !jmp lop0 '2
      84. !Sbic pina,6 '2
      85. !bld r24,7 '1 #5/6 b=0 10b=1
      86. !cpi r26,0 '1
      87. !brne lopx '2/1 #10/11
      88. !lds r17,{uein} '2
      89. Loadadr Uinbuf , X '2 Array Adresse holen
      90. !add r26,r17 '1 index addieren
      91. !ST x,r24 '2 RxByte speichern
      92. !CPI r17,31 '1 Vergleiche mit 32
      93. !BRsh ISR_1 '2 Wenn >= zu Isr:1
      94. !inc r17 '1 incr r17 (Uein)
      95. !STS {uein},r17 '2
      96. Isr_1:
      97. !CPI r24,10 '1 lf empfangen?
      98. !BRne ISR_3 '2 wenn nicht weiter zu isr3
      99. !ldi r16,1 '1
      100. !STS {uneu},r16 '2 uneu=1
      101. !inc r26
      102. !clr r16
      103. !st x,r16 ' nullbyte für Uinstr
      104. Isr_3:
      105. Gimsk = $10 '2 'pcint frei
      106. !POP r27 ' verwendete Register wieder herstellen
      107. !POP r26
      108. !POP r24
      109. !POP r17
      110. !POP r16
      111. !OUT SREG,r16
      112. !POP r16
      113. Ist1: '# 10 wenn 1
      114. Return
      Display All
      Es müsste an Prozesssor ,Clock,Pin und interrupt angepasst werden. Dann setzt es ein Fertig Flag nach dem Empfang von LF (Zeile 105) Das kann natürlich auch eine Null sein. Auch braucht der Puffer keine 32 Bytes (Zeile100)
      Endet der Satz immer mit einem Nullbyte? Ist er immer 6 Byte lang?
    • Pluto25 wrote:

      Endet der Satz immer mit einem Nullbyte? Ist er immer 6 Byte lang?
      Nein und nein, kann aber sein, das letzte Byte ist immer die Prüfsumme und kann einen Wert zwischen Null und 255 einnehmen.
      Wenn Daten zurückgegeben werden kann das vierte Byte Null sein wenn das Ergebnis <256 ist.
      Es gibt Befehle da ist die Anzahl der zu empfangenden Zeichen im vornherein klar (da sind es dann meistens immer sechs Zeichen), es gibt aber auch Befehle, da "erfährt" man die Länge erst durch Empfang des dritten Bytes welches die Anzahl der nun kommenden Datenbytes angibt (z.B. ein Dateiname der unterschiedlich lang sein kann). Abgeschlossen wird so ein Datentelegramm immer mit der Prüfsumme welche das LowByte der Summe aller Bytes (excl. Prüfbyte) ist. Es gibt also keinerlei Steuerzeichen sondern nur eine bestimmte Anzahl von Bytes

      Aber wie gesagt, meine zuletzt beschriebene "Lösung" funktioniert ausgezeichnet und umschifft das Problem ganz gut.
      Sollte ich wieder in die Verlegenheit kommen mit einer SW-RS232 so komische Datentelegramme zu verarbeiten werde ich dann einen anderen Ansatz wählen und auch auf die hier dargestellten Codeschnipsel zurückgreifen.
    • Hallo Zitronenfalter,
      ich habe mal das DY50 Fingerprint Modul von AndersL aus dem MCS Forum nachgebaut.
      Da lief der SW UART mit 57600 ausgezeichnet.
      Er hat das so gemacht:

      Open "comd.2:57600,8,n,1" For Input As #2 '>TX connection on DY50
      Open "comd.3:57600,8,n,1" For Output As #1 '>RX connection on DY50
      'hier kommen einige Printbins vor dem letzten
      Printbin #1 , X
      'und dann direkt das Inputbin
      Inputbin #2 , Index(1) , 12 ' will fill 12 bytes starting at index 1.

      Funktioniert bei mir mit 2.0.8.2 ohne Fehler.

      Viele Grüße
      Franz
    • Mitch64 wrote:

      Verwenden denn die Module auch ein Baudraten-Quarz?
      Die haben wohl gar keinen Quarz.
      Das sind simple MP3-Module mit verbauten Flashspeicher (die -FL-Variante).
      Das verwendet folgendes Datentelegramm:
      &HAA ist das Startbyte, gefolgt vom Befehlsbyte,
      dann kommt die Anzahl der Parameter (0 bis N)
      wenn Parameter dann ab hier die Parameter
      und das ganze wird schließlich beendet mit der Prüfsumme die nicht anderes ist als eine Addition aller vorangegangenen Bytes in ein Byte.

      War der Befehl eine Abfrage dann kommt zurück
      &HAA
      das Befehlsbyte
      die Anzahl der Parameter (1 bis N, weil bei einer Abfrage ja jedenfalls was zurückkommen muss)
      die Prüfsumme (wie oben ermittelt)
      Bei einem ausführenden Befehlsbyte wird nichts zurückgegeben.