Soft UART

    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!

    • Hallo,

      ich mühe mich seit einigen Tagen mit einer Routine für eine Softwareuart. Irgendwie läuft sie ja auch aber mich macht eine Sache stutzig. Der Sprung zurück in die Do Loop kommt nach dem Senden der Daten und dann springt der Kontroller wieder raus, aber wohin?? Ich erkenne das an LED_2. Nach einem Reset blinkt sie, sobald Daten übertragen werden geht sie dauerhaft aus. Bei der nächsten Übertragung geht sie dauerhaft an. LED_3 und LED_5 sind zur Kontrolle ob die Routine angesprungen wird. Was hab ich falsch gemacht?


      Quellcode

      1. $regfile = "m328pdef.dat"
      2. $crystal = 8000000
      3. $hwstack = 100
      4. $swstack = 80
      5. $framesize = 700
      6. $baud = 9600
      7. On Urxc Onrxd
      8. Enable Urxc
      9. 'Ports out gesamten Port c als Ausgabeport
      10. Config Portc = Output
      11. Led_5 Alias Portc.5
      12. Led_4 Alias Portc.4
      13. Led_3 Alias Portc.3
      14. Led_2 Alias Portc.2
      15. Led_1 Alias Portc.1
      16. Config Int0 = Falling
      17. On Int0 Serielle_lesen
      18. Open "comd.2:9600,8,n,1" For Input As #1
      19. Open "comd.7:9600,8,N,1" For Output As #2
      20. Enable Int0
      21. 'Timer
      22. Config Timer1 = Timer , Prescale = 256 , Clear Timer = 1
      23. Ocr1a = 31250 - 1
      24. Enable Oc1a
      25. Enable Interrupts
      26. Dim A As String * 30
      27. Dim Int0_flag As Bit
      28. Dim C As Byte
      29. Dim S As String * 220
      30. Dim Empfangene_daten As String * 220
      31. Dim N As Byte
      32. Dim Flag_gefunden As Byte
      33. Dim Flag_text_senden As Byte
      34. Led_1 = 1 : Led_2 = 0 : Led_3 = 0 : Led_4 = 0 : Led_5 = 0 : Waitms 100
      35. Led_1 = 0 : Led_2 = 1 : Led_3 = 0 : Led_4 = 0 : Led_5 = 0 : Waitms 100
      36. Led_1 = 0 : Led_2 = 0 : Led_3 = 1 : Led_4 = 0 : Led_5 = 0 : Waitms 100
      37. Led_1 = 0 : Led_2 = 0 : Led_3 = 0 : Led_4 = 1 : Led_5 = 0 : Waitms 100
      38. Led_1 = 0 : Led_2 = 0 : Led_3 = 0 : Led_4 = 0 : Led_5 = 1 : Waitms 100
      39. Led_1 = 0 : Led_2 = 0 : Led_3 = 0 : Led_4 = 0 : Led_5 = 0 : Waitms 100
      40. On Oc1a Anzeigen
      41. N = 0
      42. Do
      43. Toggle Led_2
      44. Waitms 100
      45. If Int0_flag = 1 Then Gosub Daten_einlesen
      46. Loop
      47. End
      48. Daten_einlesen:
      49. Disable Int0
      50. Led_3 = 1
      51. Do
      52. Get #1 , C
      53. If C <= 13 Then Exit Do
      54. A = A + Chr(c)
      55. Loop
      56. Print#2 , A;
      57. A = ""
      58. Int0_flag = 0
      59. Enable Int0
      60. Return
      61. 'Timer Betriebsanzeige
      62. Anzeigen:
      63. Toggle Led_1
      64. Led_5 = 0
      65. Led_3 = 0
      66. Return
      67. '##################################### Soft uart #########################
      68. Serielle_lesen:
      69. Led_5 = 1
      70. Int0_flag = 1
      71. Return
      72. '##################################### uart ##############################
      73. Onrxd:
      74. Incr N
      75. S = S + Chr(udr)
      76. If Udr = $3e Then Flag_text_senden = 1
      77. If Udr = 13 Then
      78. If N < 3 Then
      79. N = 0 : S = ""
      80. Else
      81. Empfangene_daten = S
      82. Flag_gefunden = 1
      83. N = 0 : S = ""
      84. End If
      85. End If
      86. If N > 220 Then Decr N
      87. Return
      Alles anzeigen
      Gruß, Martin
    • Wenn jemand spricht wartet er nicht 100 ms . Bis dahin gibts keine Daten mehr die ein get hören könnte.
      Es ist ja nichts vorhanden was sie vorher einsammeln würde
      Es wäre ein Versuch wert die "Daten_einlesen" als int0 isr auszuführen. Gewöhnlich wird der bascom Sw-Uart mit Input benutzt was aber ein Problem ist wenn dann keiner was sagt.
      Mit einer eigenen Uart Routine hatte ich ein ungelöstes Problem mit dem Falling. Es funktioniert mit Low Level.
    • Pluto25 schrieb:

      Wenn jemand spricht wartet er nicht 100 ms .
      Ja, das ist sonderbar aber die daten kommen an.


      Pluto25 schrieb:

      Es wäre ein Versuch wert die "Daten_einlesen" als int0 isr auszuführen.
      das habe ich als erstes versucht allerdings hab ich da nie was empfangen. Mache mich nochmal an die Arbeit.

      Aber warum blinkt LED_2 in der Main Loop nicht mehr nach der ersten Übertragung? Für mich sieht es aus wie wenn die Main Loop nur nach jeder Übertragung einmal angesprungen wird.
    • Hallo Martin,
      du musst bedenken, dass die "Falling" Bedingung für INT0 auch ausgelöst wird, wenn du INT0 abgeschaltet hast. D.h., die erste fallende Flanke löst INT0 aus, dann disablest su INT0 und liest du die Daten ein. Anschließend gibst du INT0 wieder frei. Da in der Zwischenzeit sicherlich noch einmal eine fallende Flanke gekommen ist, wird sofort wieder die INT0 ISR aufgerufen. Dort wird wieder das Flag gesetzt und die Main-Loop ruft die Einlese Routine auf. Für die ist aber jetzt nichts zu tun, die Übertragung wurde ja gerade abgeschlossen, also wartet sie bis zur nächsten Übertragung.
      Wenn du den Aufbau so lassen willst, wie er jetzt ist, dann musst du das Flag löschen, unmittelbar bevor du den INT0 wieder frei gibst.
      @Pluto Das ist auch der Unterschied zu deinem Level Interrupt, der ja nirgendwo gespeichert wird und deswegen auch nach der Übertragung nicht direkt wieder auslöst.
    • Franz schrieb:

      du musst bedenken, dass die "Falling" Bedingung für INT0 auch ausgelöst wird, wenn du INT0 abgeschaltet hast.
      Oh, das habe ich nicht bedacht.


      Franz schrieb:

      dann musst du das Flag löschen, unmittelbar bevor du den INT0 wieder frei gibst.
      Meinst Du so mit Eifr.int0 = 1 ?

      Quellcode

      1. Daten_einlesen:
      2. Disable Int0
      3. Led_3 = 1
      4. Do
      5. Get #1 , C
      6. If C <= 13 Then Exit Do
      7. A = A + Chr(c)
      8. Loop
      9. Print#2 , A;
      10. A = ""
      11. Int0_flag = 0
      12. 'Eifr = &B00000001
      13. Eifr.int0 = 1
      14. Enable Int0
      15. Return
      Alles anzeigen
      dann wird jede zweite Übertragung verschluckt.

      Franz schrieb:

      Wenn du den Aufbau so lassen willst,
      Ich finde nicht so wirklich eine andere Möglichkeit. Möchte nicht in der Do Loop auf Daten warten. Überlege mir schon auf den 328PB um zu steigen. Der hat zwei UART.

      Gruß, Martin
    • Das Flag heißt aber INTF0. Da beide konstanten den Wert 0 haben, merkst du das nicht. Ich würde es aber trotzdem ändern.

      Deine Main Loop macht ja praktisch nichts anderes als immer wieder für 100ms zu warten. Irgendwann zwischendrin kommt der Interrupt, also im Mittel bei 50ms. Nach Ausführung der ISR wird dann nochmal im Mittel 50ms gewartet. Bei 9600 Baud laufen dabei etwa 50 Zeichen durch, die die Einlese Routine nicht sieht. Das musst du definitiv ändern, wenn du eine zuverlässige Erkennung der Daten schaffen willst.

      Ich weiß nicht, was dein Controller sonst noch zu tun hat und ob du dir leisten kannst, in der INT0 ISR solange zu bleiben, bis alle Zeichen eingelesen sind. Du erwartest scheinbar ziemlich vielen Zeichen, da der String auf 220 dimensioniert ist, also über 200ms. Wenn das ok ist, würde ich die Daten dort einlesen.
      Wenn nicht, dann wird es etwas komplizierter. Du könntest dann ein Zeichen in der ISR einlesen und die dann verlassen. Bis zum Start des nächsten Zeichens gibt es eine kleine Pause, die der Rest des Programm nutzen könnte, um weiterzumachen. Da die aber in der Regel weniger als die Länge eines Bits ist, befindet sich dein Programm immer noch mindestens 90% der Zeit in der ISR.
      Wenn das immer noch nicht ok ist, dann würde ich die Bits selber einlesen, wofür du aber einen Timer brauchst, der wahrscheinlich nur das machen kann.

      Mit SoftUART einlesen ist halt wesentlich schwieriger, als ausgeben. Evtl. ist dann die PB Variante einfacher.
    • Franz schrieb:

      Du erwartest scheinbar ziemlich vielen Zeichen, da der String auf 220 dimensioniert ist
      Das ist für die Hardware UART. Die ist für die Kommunikation mit einem SIM800. Die zweite Schnittstelle wollte ich für die Kommunikation mit einem PC. Damit wollte ich den Kontroller programmieren und über einen Bootloader flashen (wegen Updates und so).

      Vielen Dank für Deine Hilfe. Werde mich einem anderen Kontroller zuwenden.

      Gruß, Martin
    • Pac-Man schrieb:

      allerdings hab ich da nie was empfangen....
      über einen Bootloader flashen
      Vermutlich wartete die Bascom Routine auf das schon vorhandene Startbit.
      Für den Bootlader besser den HW Uart (Platznot) Aber der Sim 800 kann problemlos an einen SW Uart.
      Er könnte auch Daten sammeln und sich bei 13 melden.

      Franz schrieb:

      Du könntest dann ein Zeichen in der ISR einlesen
      Das ist die beste Möglichkeit da man nie weiß ob und wann wieder eins kommt. ein Timer könnte Sinn machen wenn es bei nur 9600 bleibt. Dann könnte die Main zwischen jedem Bit weiterarbeiten.

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

    • Franz, Pluto, Michael und all die Anderen, vielen Dank für die Hilfe und Tipps. Ich bin wirklich sehr dankbar für die Hilfe die ich hier bekommen. Ich kenne andere Foren in denen man nach einer Frage erst mal eine Watschen rechts und links bekommt und dann noch zwei drei so ins Gesicht. Den Rest beharken sich dann die Anderen ohne jemals wieder zum Thema zurück zu kommen. Hier fühle ich mich mit meinen teils naiven Fragen sehr gut auf genommen.

      Ich arbeite die Anregungen von dem Forum hier oft im stillen für mich auf. Bei meinem Problem SIM800L bin ich fast fertig dank Eurer Tipps. Beim Problem Stunden, Minuten, Tage warte ich noch auf einen Quarz. Die Zeit Zählung mache ich nicht mehr selbst sondern jetzt mit Config Clock=User. Alles Sachen die ich ohne Eure Anregung wohl eher nicht oder sehr umständlich gelöst hätte. Das jetzige Problem SW UART werde ich wohl etwas zurück stellen. Durch einen anderen Kontroller werde ich wahrscheinlich schneller zum Erfolg kommen.

      Bascom ist für mich wie ein Werkzeugkasten. Ich nehme eine Nuss raus und probiere ob sie passt. Wenn nicht, nehme ich eine andere. Ihr Profis seht schon anhand der Schraube welche Nuss, Rätsche genommen werden muss und mit welchem Drehmoment sie rechts oder links herum angezogen werden muss. Für mich ist das noch ein sehr langer Weg.


      OK, meine Antwort hat jetzt nicht wirklich mit dem Thema was zu tun aber es war mir schon länger ein Anliegen mich für Euer Verständnis und Eure Hilfe zu bedanken. All diejenigen die sich hier täglich bemühen die Fragen zu beantworten sollten sich natürlich eingeschlossen fühlen. SO GEHT FORUM!

      Gruß, Martin
    • Pluto25 schrieb:

      Weiß der SIM800L die Uhrzeit nicht? Dann könnte er so hin und wieder damit rausrücken/gefragt werden um die Uhr zu synchronisieren?
      Ja, genau. Das mache ich ja eben ein mal alle 24 Stunden. Dazwischen muss ich halt von Hand selbst zählen. Config Clock=User passt da genau dazu. Muss nicht mal das Datum und die Uhrzeit bearbeiten. Kann alles direkt so übergeben. :thumbup:
    • Pac-Man schrieb:

      Hier fühle ich mich mit meinen teils naiven Fragen sehr gut auf genommen.
      Ja in anderen Foren bekommste ja auch gleich mal die Antwort "wechsel doch zu C++, das ist viel besser als Bascom". Es gibt aber auch Hinweise im Netz, dass Bascom besseren und schnelleren Code erzeugt. Und es ist einfacher für Einsteiger :)
      Eine Lösung habe ich nicht, aber mir gefällt Ihr Problem.
    • Hallo Martin,
      weil du dich so nett bedankt hast, habe ich dir mal eine etwas abgewandelte Routine erstellt, die bei mir ohne Probleme läuft.
      Da ich aktuell einen anderen Controller habe, der mit 115200 Baud immer 112 Byte rausschickt, habe ich die als Input genommen. Es kommen bis zu 5 Telegramme pro Sekunde. Deckt also deinen Bereich locker ab.

      In der ISR wird immer nur ein Zeichen eingelesen, d.h. kein Abschalten des INT0, nur das Flag muss natürlich auch gelöscht werden.
      Die Pause zwischen den Bits ist recht klein, daher musste ich etwas tricksen (Overlay, nosave) um schnell genug zu sein. Bei deinen 9600 Baud ist das bestimmt nicht nötig.
      Du kannst es ja mal ausprobieren und berichten.

      BASCOM-Quellcode

      1. $regfile = "m88pdef.dat"
      2. $crystal = 20000000
      3. $hwstack = 32
      4. $swstack = 10
      5. $framesize = 40
      6. $baud = 115200
      7. Dim A As String * 120 , A_ovly(120) As Byte At A Overlay
      8. Dim Int0_flag As Byte
      9. Dim C As Byte
      10. Dim Rcv_cnt As Byte
      11. Open "comd.2:115200,8,n,1" For Input As #1
      12. Config Int0 = Falling
      13. On Int0 Serielle_lesen Nosave
      14. Enable Int0
      15. Enable Interrupts
      16. Do
      17. If Int0_flag = 1 Then
      18. Int0_flag = 0
      19. Print A
      20. End If
      21. Loop
      22. End
      23. '##################################### Soft uart #########################
      24. Serielle_lesen:
      25. $asm
      26. push r24
      27. IN r24, SREG
      28. push r24
      29. push r10
      30. push r11
      31. push r16
      32. push r18
      33. push r25
      34. push r26
      35. push r27
      36. $end Asm
      37. C = Inkey(#1)
      38. If C >= 32 Then
      39. Incr Rcv_cnt
      40. A_ovly(rcv_cnt) = C
      41. Elseif C = 10 Then
      42. A_ovly(rcv_cnt + 1) = 0
      43. Int0_flag = 1
      44. Rcv_cnt = 0
      45. End If
      46. $asm
      47. pop r27
      48. pop r26
      49. pop r25
      50. pop r18
      51. pop r16
      52. pop r11
      53. pop r10
      54. pop r24
      55. Out Sreg , R24
      56. pop r24
      57. $end Asm
      58. Return
      59. '##################################### uart ##############################
      Alles anzeigen