PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Inhalt in einem String löschen



mat-sche
14.05.2011, 20:26
Na nen juten Abend!

ich hab da mal ein Problem:

Ich empfange über einen UART einen String den ich per:


Config Serialin1 = Buffered , Size = 100 , Bytematch = All
Dim Gsm_rx_str As String * 100 At _rs232inbuf1 Overlay
angegeben habe. Nun empfange ich einmal 6 Zeichen, die mir richtig angezeigt werden



Sub Gsm_ok(byval Rxlen As Byte)
Do
If _rs_bufcountr1 >= Rxlen Then
Print "Gsm_rx_str " ; Gsm_rx_str
Gsm_rx_str = ""
Clear Serialin1
Exit Do
End If
Loop
End Sub
mit z.Bsp.: <\r><\n>OK<\r><\n>
Danach empfange ich 22 Zeichen die wiederum richtig angezeigt werden.
Aber jetzt.... danach empfange ich wieder 6 zeichen aber es werden dann im Anschluss noch die Zeichen aus der vorhergehenden Sendung mit ausgegeben. Die soll so nicht sein, ich dachte mit : Gsm_rx_str = "" sollte der String gelöscht werden. Aber das macht es nicht.

Nun... wie kann ich meinen dev. String den Inhalt löschen, ihn auf 0 setzen?

Würde mich für Hilfe sehr freuen !

Grüße MAT

Che Guevara
14.05.2011, 20:30
Hallo,

bin mir nicht ganz sicher, aber ich habe doch die starke Vermutung, dass dir das "At xxx Overlay" da dazwischenfunkt. Probier doch mal aus, dieses zu löschen (falls dies das Programm zulässt).

Gruß
Chris

mat-sche
14.05.2011, 20:46
Hi Chris,
jetzt macht es bei mir klick! Du hast natürlich recht! Ich werde das gleich mal testen...

for_ro
15.05.2011, 01:24
Dein Problem liegt mehr darin, dass im Byte_array _RS232INBUF1 kein String mit einem Stringendezeichen (0-Byte) abgelegt wird, sondern nur einzelne Bytes. Dein
Print Gsm_rx_str
wird aber so viele Zeichen ausgeben, bis irgendwann ein Stringende gefunden wird.
Wenn du nun mit
Gsm_rx_str = ""
das erste Zeichen auf Stringende setzt und dann wieder neue Zeichen einliest, stehen dahinter immer noch die alten Zeichen. Also wird dein Print die auch wieder ausgeben. Da hilft auch das
Clear Serialin1
nicht, da es auch nur das erste Byte von _RS232INBUF1 und den Zeichen Counter _RS_BUFCOUNTR1 auf 0 setzt.
Du musst also selber das Stringende Zeichen setzen. Das geht einfach so:
_RS232INBUF1(_RS_BUFCOUNTR1 + 1) = 0
_RS232INBUF1(_RS_BUFCOUNTR1) zeigt auf das letzte gelesene Zeichen, _RS232INBUF1(_RS_BUFCOUNTR1 + 1) also auf das danach. Vorsichtig musst du noch sein, wenn tatsächlich mal 100 Zeichen eingelesen werden, dass du dann nicht das 101. mit einer 0 beschreibst.

mat-sche
21.05.2011, 08:06
Nen guten,

@ for_ro:

vielen Dank für Deine ausgiebige Antwort! So wie Du das beschrieben hast, wurde es mir über die Zeit dann auch klar und von Dir bestätigt!
Ich überlege mir gerade, ob es nicht besser wäre, wenn ich nach der Auswertung des Buffers nicht den ganzen Buffer mit einer 0 überschreibe, abhängig von der Anzahl empfangener Zeichen:

rs232_dummy = Memcopy(mem_dummy , _RS232INBUF1 , _RS_BUFCOUNTR1 , 2)

was das aber an Rechenzeit bedarf weiß ich nicht....

mat-sche
22.05.2011, 13:52
Sooo....
Ich habe jetzt die obrige Form zur Löschung des _RS232INBUF1 genutzt. Da es ja einen Bytezähler für die eintreffen Byte gibt, kann dieser schön zum genauen Löschen des Empfangspuffer genutzt werden:
rs232_dummy = eine Bytevariable zur Zwischenspeicherung, die nicht weiter genutzt wird
mem_dummy = eine Bytevariable die ich missbrauche, in der steht nur eine Null drin, da ja der Buffer gelöscht werden soll
_RS232INBUF1 = hier wird jetzt die Null rein geschrieben, da es aber ein Bytearray ist muss dies für jede Stelle erhöht werden => dies besagt die 2 am Ende
_RS_BUFCOUNTR1 = der Counter sagt an wie oft _RS232INBUF1 mit einer Null beschrieben werden soll.

Zur Funktion von Memcopy nochmals die Hilfe lesen, dort steht alles drin :)

for_ro
22.05.2011, 15:22
Hallo mat-sche,
ich halte das Löschen des gesamten Bereichs zwar für überflüssig, aber wenn es jetzt funktioniert, ist es ja gut.
Sieht ein wenig nach Holzhammermethode aus. Dir geht dadurch der ganze Vorteil des Overlays verloren.

Richard
22.05.2011, 17:34
Hallo mat-sche,
ich halte das Löschen des gesamten Bereichs zwar für überflüssig, aber wenn es jetzt funktioniert, ist es ja gut.
Sieht ein wenig nach Holzhammermethode aus. Dir geht dadurch der ganze Vorteil des Overlays verloren.

Ich bin mir jetzt nicht wirklich sicher, aber anstatt x="" ...x = " " (könnte ?) auch klappen. Langsam komme ich aus dem Training. :-(

Gruß Richard

mat-sche
22.05.2011, 19:15
@for_ro

"Dir geht dadurch der ganze Vorteil des Overlays verloren."

Na eigentlich nicht!?! Ich lege ja mir einen String über den Bytebuffer weil ich dann damit weiter als String arbeiten kann und ich nicht extra eine for/next Schleife bauen müsste, um die Daten aus dem Buffer in den String zu bekommen. Und ich benötige nur für den Zeitraum bis zum neuen Empfang neuer Daten die Daten aus dem Bytebuffer...

Oder sehe ich da was falsch?
Nun ja, es ist die Hammermethode, aber so bin ich mir sicher, dass alle Zeichen im _RS232INBUF1 auf 0 liegen. Es koste Zeit die Bytes zu löschen.... ich werde nochmal darüber nachdenken :)

Aber Dank dennoch an alle und noch einen schönen Sonntag!

Grüße MAT

for_ro
22.05.2011, 19:34
Wenn du dir sicher sein kannst, dass während der String-Verarbeitung kein neues Zeichen eintrifft, wird das so schon funktionieren.
Allerdings dauert ein memcopy länger als ein einfaches str1=str2, keine Ahnung warum. Zumindestens im Sim ist das so.
Wie häufig kommen denn die Übertragungen und sind sie in regelmäßigen Abständen? Welche Baudrate benutzt du dabei?

PicNick
23.05.2011, 10:19
Das löschen kannst du dir sparen
aaaaaaaaaaaaaaaaaber:
Der Bascom _inuff ist ein Ringbuffer, d.h. wenn daten rein kommen, stehen die meist NICHT am Buffer anfang.
Über den direkt einen string zu "overlayen" funzt nicht,.

for_ro
23.05.2011, 10:34
Über den direkt einen string zu "overlayen" funzt nicht,.
Klar funktioniert das! Man muss nur den Buffer nach der Verarbeitung initialisieren (Clear SerialIn), so wie er das auch gemacht hat. Dann wird der Pointer und alles andere wieder auf Anfang gesetzt.

PicNick
23.05.2011, 10:54
Da der Ringbuffer in der ISR asynchron beschrieben wird, müsst man sicher sein können, dass während der o.a. verarbeitung bis zum clear nix reinkommt, denn sonst ist das weg. Zuverlässiger Empfang ist anders.
Aber jeder soll schreiben, wie er glaubt.

mat-sche
23.05.2011, 20:02
Na da hab ich ja was angezettelt..... :D

Alllssssoooo:

beide haben recht, sag ich mal so. In meiner Situation funktioniert das hervorragend. Der Vorteil eines Overlay ist, dass ich nicht extra die Werte aus dem Ringbuffer in eine Stringvariable einlesen muss.
Ich weiß wann und was in den Buffer gelegt wird und das ist mein Vorteil. Über


Serial1bytereceived:
Pushall
If Gsm_ini = 1 Then
Incr Byte_in_count
If Byte_in_count = 1 Then
Enable Timer0
Start Timer0
End If
Timer_count = 0
End If
Popall
Returnden Serial1bytereceived Interrupt bekomme ich mit, wann ein Zeichen in den Buffer gelegt wird. Dann starte ich einen Timer, über den ich dann das Ende abwarte. Also wenn kein Zeichen mehr rein kommt, dann läuft mein Timer über, setzt mir eine Variable und in einer Do - Loop lese ich dann den Buffer ein, setze den Counter wieder auf Null und leere den Buffer. Hier hatte ich das Problem, dass ich mit dem Overlay immer alle Zeichen im Buffer eingelesen habe und das wollte ich nicht.
Es geht hierbei um Einlesen von bestimmten Zeichen wie z.Bsp. das Eintreffen einer SMS oder das Klingeln meines GSM-Modems. Da ich ja das "Absenderhandy" steuere, weiß ich wie oft ich ein Handlung mache wie z.Bsp. das Klingeln oder das Senden einer SMS...

Wenn wir schon einmal dabei sind, in der Serial1bytereceived Interruptroutine sollte ich laut der Hilfe vorher die Register sichern:push/popAll. Ich weiß nun nicht genau warum dies gemacht werden soll und ob es nötig wäre. Kann mir jemand von Euch dies erklären?

Na gut, bin auf Antworten gespannt :) und wünsch ein schönen Abend!

for_ro
23.05.2011, 22:15
Da der Ringbuffer in der ISR asynchron beschrieben wird, ...
Was meinst du damit?
Wenn ein Zeichen empfangen wurde, wird eine separate ISR angesprungen, die das Zeichen in den RingBuffer schreibt und die Counter erhöht.
Anschließend wird zum Label Serial1bytereceived gesprungen. Nun kann man den Inhalt auswerten.
Finde ich ziemlich synchron.

for_ro
23.05.2011, 22:31
... den Serial1bytereceived Interrupt bekomme ich mit, wann ein Zeichen in den Buffer gelegt wird. Dann starte ich einen Timer, über den ich dann das Ende abwarte. Also wenn kein Zeichen mehr rein kommt, dann läuft mein Timer über, setzt mir eine Variable und in einer Do - Loop lese ich dann den Buffer ein, setze den Counter wieder auf Null und leere den Buffer. Hier hatte ich das Problem, dass ich mit dem Overlay immer alle Zeichen im Buffer eingelesen habe und das wollte ich nicht.
Ich mag halt lieber die direkte Verarbeitung in der URXC ISR. Dann hast du selber die Kontrolle. Benutzt du Config SerialIn ... dann kannst du erst danach eingreifen.
Deinen Timer könntest du dabei so lassen wie er ist, nur rufst du die ISR direkt auf, wenn ein Zeichen empfangen wurde. Das ist auch nichts anderes als ByteMatch=All.


Wenn wir schon einmal dabei sind, in der Serial1bytereceived Interruptroutine sollte ich laut der Hilfe vorher die Register sichern push/popAll. Ich weiß nun nicht genau warum dies gemacht werden soll und ob es nötig wäre. Kann mir jemand von Euch dies erklären?

Wie schon geschrieben, erzeugt Bascom bei Verwendung von Config SerialIn automatisch ein ISR, die beim Empfang jedes Zeichens aufgerufen wird. Die steht aber nicht in deinem QuellCode. Von dort aus wird dein Label angesprungen.
Da Bascom Register während des Programmablaufs verwendet und man nie weiß, bei welchem Befehl der Interrupt auftrat, muss man alle Register sichern, die in der ISR verwendet werden. Dies macht der Compiler auch für seine ISR.
Wenn dann aber zu deinem Label gesprungen wird und dort weitere Befehle verwendet werden, müssen deren benutzte Register auch wieder gesichert werden. Die Empfehlung ist dann pushall, falls man nicht weiß, welche Register dies sind.

mat-sche
29.05.2011, 14:56
Hi for_ro,


Ich mag halt lieber die direkte Verarbeitung in der URXC ISR. Dann hast du selber die Kontrolle. Benutzt du Config SerialIn ... dann kannst du erst danach eingreifen.
Deinen Timer könntest du dabei so lassen wie er ist, nur rufst du die ISR direkt auf, wenn ein Zeichen empfangen wurde.

wie würde denn solch eine direkte Verarbeitung in der ISR dann aussehen, hättest Du bitte mal ein Beispiel?
In meinem Programm habe ich auch das Phänomen, dass während eines bestimmten Ablaufes der Kontroller resettet wird und ich weiß nicht warum.

Danke & Gruß MAT

for_ro
29.05.2011, 17:12
Anfangen würde ich z.B. so:


Dim Uart_buffer As String * 100
Dim Byte_empfangen As Byte
Dim Buffer_overlay(101) As Byte At Uart_buffer Overlay
Dim Buffer_pointer As Byte

On Urxc Urxc_isr
Enable Urxc
Enable Interrupts

Do
'deine Hauptschleife
Loop

End

Urxc_isr:
If Buffer_pointer < 100 Then Incr Buffer_pointer 'falls zuviele zeichen kommen, ist hier die Bremse
Byte_empfangen = UDR
'hier könntest du jetzt einige Checks machen, wie z.B. auf CR/LF oder auch eine Vorauswertung des Empfangs
'wenn du z.B. das CR/LF gar nicht im Buffer abspeichern willst, dann lässt du den Befehl eben weg und setzt stattdessen nur ein Flag
'welches du dann in der Hauptschleife auswertest.
'auf die Art musst du nicht so viel machen, wenn deine Übertragung vollständig ist, sondern verteilst
'dies auf die relativ langen Pausen zwischen den eingehenden Zeichen

'hier kannst du auch deinen Timer starten um zu überprüfen, ob die Übertragung nicht aus irgendeinem Grund aufgehört hat

Buffer_overlay(buffer_pointer) = Byte_empfangen 'und schließlich das Zeichen im Buffer abspeichern
Return