Forum: Mikrocontroller und Digitale Elektronik Bascom UART Interrupt Problem


von Filth _. (filth)


Lesenswert?

Hallo,

ich habe ein Problem. Es sollen Daten von einem GPS Sensor gelesen 
werden. Speziell brauche ich nur die GPRMC und GPGGA Strings. Der Sensor 
sendet im NMEA format.

Allerdings wird irgendwie die Hälfte vom Empfang verschluckt, manchmal 
funktioniert es auch. Es scheint irgendein Timingproblem zu sein.

Hier ist der Code:
1
$regfile = "m644pdef.dat"
2
$crystal = 16000000
3
$hwstack = 128
4
$swstack = 512
5
$framesize = 128
6
$baud = 38400
7
$baud1 = 9600
8
9
10
' ************* GPS - TEIL ********************
11
Open "COM2:" For Binary As #2
12
Config Serialin = Buffered , Size = 100 , Bytematch = 10
13
14
Config Serialin1 = Buffered , Size = 100
15
Config Portb.6 = Input
16
17
Const Id_str_lg = 6                                         ' Länge des Identifiers
18
Dim Id_str As String * Id_str_lg                            ' ID String
19
Dim Buff_str_ovrl As String * 99 At _rs232inbuf0 Overlay    ' Einen String über den SerialIn Puffer legen
20
21
Dim Wr_ctr As Byte                                          ' Schreibzähler
22
Dim Wr_b As Byte
23
Dim Mc As String * 100                                      ' GPS MC - Teil
24
Dim Ga As String * 100                                      ' GPS GA - Teil
25
Dim Writestring As String * 30
26
Dim Length As Integer
27
Dim B_cpd As Byte                                           ' Hilfsvariable zum Kopieren der Bytes des Stringoverlays
28
Dim C_st As Byte
29
Mc = ""
30
Ga = ""
31
' ********************************************
32
33
34
35
Enable Interrupts
36
37
38
39
Do
40
41
Loop
42
43
End
44
45
46
47
48
'Daten vom Buffer auslesen
49
Serial0charmatch:
50
51
   Pushall
52
53
   B_cpd = _rs_bufcountr0 - 2                               ' Anzahl zu kopierender Zeichen des Pufferstrings
54
   C_st = _rs_head_ptr0 + 1                                 ' Startkopierposition im Pufferstring
55
56
   Id_str = Mid(buff_str_ovrl , C_st , Id_str_lg)           ' ID String holen, ab 2tem Zeichen, ohne $
57
58
   Print #2 , Buff_str_ovrl
59
60
   If Id_str <> "$GPGGA" And Id_str <> "$GPRMC" Then
61
      Clear Serialin
62
      Popall
63
      Return
64
   End If
65
66
   If Id_str = "$GPRMC" And Mc = "" Then
67
      Mc = Mid(buff_str_ovrl , C_st , B_cpd)                ' Puffer in den String kopieren, ohne $, ohne CR
68
   End If
69
70
   If Id_str = "$GPGGA" And Ga = "" Then
71
      Ga = Mid(buff_str_ovrl , C_st , B_cpd)                ' Puffer in den String kopieren, ohne $, ohne CR
72
   End If
73
74
75
   Clear Serialin
76
77
   Popall
78
Return

Die Ausgabe:
1
<\n>$GPGGA,205133.560,8960.0000,N,00000.0000,E,0,0,,137.0,M,13.0,M,,*46<\r>
2
<\n><\r>
3
<\n>$G33.560,V,8960.0000,N,00000.0000,E,0.00,0.00,190110,,,N*7C<\r>
4
<\n>M,,*46<\r>
5
<\n><\r>
6
<\n>$GPGGA,205133.760,8960.0000,N,00000.0000,E,0,0,,137.0,M,13.0,M,,*44<\r>
7
<\n><\r>
8
<\n>$G33.760,V,8960.0000,N,00000.0000,E,0.00,0.00,190110,,,N*7E<\r>
9
<\n>M,,*44<\r>
10
<\n><\r>
11
<\n>$GPGGA,205133.961,8960.0000,N,00000.0000,E,0,0,,137.0,M,13.0,M,,*4B<\r>
12
<\n><\r>
13
<\n>$G33.961,V,8960.0000,N,00000.0000,E,0.00,0.00,190110,,,N*71<\r>
14
<\n>M,,*4B<\r>
15
<\n><\r>
16
<\n>$GPGGA,205134.160,8960.0000,N,00000.0000,E,0,0,,137.0,M,13.0,M,,*45<\r>

Es wird immer nur der GPGGA-Teil aufgefangen. Hat evtl jemand eine Idee 
warum?

Danke

von Filth _. (filth)


Lesenswert?

Keiner eine Idee?

von spess53 (Gast)


Lesenswert?

Hi

>Keiner eine Idee?

>Config Serialin = Buffered , Size = 100

Evtl. Puffer zu klein?

MfG Spess

von Filth _. (filth)


Lesenswert?

Hi,

nein, daran dürfte es normallerweise nicht liegen, denn laut
http://tiny.cc/sMC3B
Auf Seite 7 sollte die Ausgabe bei etwa 68 Zeichen liegen. Das spricht 
auch dafür, dass es so ja auch schon funktioniert hat.

Kann es etwas mit dem voreilenden bzw nacheilenden Input-Problem zu tun 
haben?

von Karl H. (kbuchegg)


Lesenswert?

Wenn ich das richtig sehe, dann greifst du direkt auf den Buffer zu, den 
die RS232 benutzt um die Zeichen zu empfangen.

Jetzt sendet aber dein GPS weiter, während du noch den vorhergehenden 
String bearbeitest. D.h. während du einen String auswertest, wird der 
Anfang des Strings schon von den nächsten eintreffenden Zeichen 
überschrieben.

Nicht mit Overlay arbeiten, sondern den String umkopieren. Dann hast du 
Zeit den String zu bearbeiten, während im Hintergrund die nächsten 
Zeichen eintrudeln.

Denk auch drann, dass die Ausgabe des Strings auch Zeit braucht. Zeit in 
der wiederrum weitere Zeichen eintrudeln.

von Filth _. (filth)


Lesenswert?

Hallo Karl Heinz,

stimmt das macht Sinn.
Aber ich kopiere den String ja eigentlich mit:
1
 Id_str = Mid(buff_str_ovrl , C_st , Id_str_lg)           ' ID String holen, ab 2tem Zeichen, ohne $

Oder reicht es so nicht? Wie würdest du es lösen?

Gruß
Alex

von Karl H. (kbuchegg)


Lesenswert?

Alex G. schrieb:
> Hallo Karl Heinz,
>
> stimmt das macht Sinn.
> Aber ich kopiere den String ja eigentlich mit:
>
>
1
>  Id_str = Mid(buff_str_ovrl , C_st , Id_str_lg)           ' ID String
2
> holen, ab 2tem Zeichen, ohne $
3
>

Und wer sagt dir, dass in der Zeit die vergeht, bis BASCOM die Funktion 
aufruft und den PushAll gemacht hat, der Anfang von buff_str_ovrl nicht 
schon von den nächsten Zeichen überschrieben wurde?

Wie gehts denn weiter?

   Id_str = Mid(buff_str_ovrl , C_st , Id_str_lg)           ' ID String 
holen, ab 2tem Zeichen, ohne $

   Print #2 , Buff_str_ovrl

Du gibst danach den kompletten Buff_str_ovrl aus und anhand deines Logs 
ist ersichtlich

<\n>$GPGGA,205133.560,8960.0000,N,00000.0000,E,0,0,,137.0,M,13.0,M,,*46< 
\r>
<\n><\r>
<\n>$G33.560,V,8960.0000,N,00000.0000,E,0.00,0.00,190110,,,N*7C<\r>

dass da offenbar schon mit dem Buffer irgendwas passiert ist. Meines 
wissens beginnt kein NMEA Datensatz mit $G33.560

Etwas später machst du dann

   Clear Serialin

wodurch du alle Zeichen des nächsten Datensatzes, die in der 
Zwischenzeit eingetrudelt sind, verwirfst. Wenn also dein GPS in der 
ZWischenzeit gesendet hat (nur als Beispiel)

  $GPGGA,205133.560,8960.0000,N,00

dann verwirfst du das. Dein GPS Gerät kriegt das aber nicht mit und 
sendet munter weiter
   00.0000,E,0,0,,137.0,M,13.0,M,,*46

Bis irgendwann ein Zeilenende kommt und du anfängst diese Zeile 
auszuwerten. Die fängt jetzt aber nicht mit &GPGGA oder $GPRMC an, 
sondern mit 00.0000 weil du ja schlauerweise alles vorhergehende 
gelöscht hast :-)

> Oder reicht es so nicht? Wie würdest du es lösen?

Abchecken, ob das GPS Gerät Handshake unterstützt und es sofort nach dem 
Empfang einer Zeile zum Schweigen bringen.
Wenn das nicht geht, dann wirds wohl darauf hinauslaufen, die empfangene 
Zeile sofort in einem String in Sicherheit zu bringen und mit der Kopie 
zu arbeiten. Auf jeden Fall aber nicht dem BASCOM mit irgendwelchen 
clear Aktionen in die Buffer Verwaltung hineinpfuschen, BASCOM muss die 
volle Kontrolle über den Inhalt des Buffers haben, nur dann hast du eine 
Chance, dass die Zeilen auch vollständig sind.

Wenn sich das zeitlich nicht ausgeht, und das erste eintrudelnde Zeichen 
schon kommt, ehe die Zeile in Sicherheit gebracht werden kann, dann 
kannst du den BASCOM Mechanismus zum Empfang einer Zeile überhaupt nicht 
benutzten sondern musst dir selbst was machen, das mittels Double 
Buffering das Problem löst.

von Klemm (Gast)


Lesenswert?

Deine ISR läuft an, sobald die erste Zeile empfangen wurde. Derweil Du 
den uC in der ISR beschäftigst, rauscht die 2. Zeile an Dir vorbei. 
Vermute ich mal.. :-)

Wozu brauchst Du interrupts und der ganzen config .. Schnickschnack? Du 
wirst ohnehin nicht jede Zeile interpretieren können. Einfacher so 
(Pseudocode, aber einfach umzusetzen:

do
  Emfangen:
  do
    do:loop until rxd
  loop until UDR = 10
  do
    if rxd then stringbuffer = stringbuffer + UDR
  loop until <Zeilenende "10" empfangen>
  do
    if rxd then stringbuffer = stringbuffer + UDR
  loop until <Zeilenende "10" empfangen>

  'jetzt haben wir mit Sicherheit 2 vollständige Zeilen

  Verarbeiten:
  'alles bis zum ersten Zeilenende wegwerfen
  'Stringbuffer enthält jetzt 2 saubere Zeilen

loop

Das Empfangen kann man natürlich noch schöner machen mit einer 
Schleife..

von Peter (Gast)


Lesenswert?

Sub Serial0bytereceived(s As String)
  S = ""
  Do
    B = Inkey()
    Select Case B
       Case 0
       Case 13
       Case 10 : If S <> "" Then Exit Do
       Case Else
         S = S + Chr(b)
    End Select
  Loop
End Sub

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.