Forum: Mikrocontroller und Digitale Elektronik STM32 GPS Filtern


von Flo (Gast)


Lesenswert?

So versuche ja seit einer Woche bestimmte Zeichen aus einem NMEA 
Datensatz,
welches mir das GPS Modul über Uart an meinem STM32 versendet,
zu filter. Als erstes Versuche ich die Datensätze zu separieren, damit 
ich dann in meiner main Routine diese weiterbearbeiten kann.

nun, wenn ich
sendbyte_usart(data1[0]);
sendbyte_usart(data2[0]);

ausführe, sehe ich, dass beide nicht wie eigentlich erwartet das $ 
Zeichen zeigen (der NMEA Datensatz fängt mit $GP... an),
sondern data2 ist schon bereits bei G gelandet

also will heißen
1
data1[0] == '$';
2
data2[0] == 'G';


Wo liegt denn der Fehler das beide nicht mit $ anfangen???
Mein Interrupt siehe unten


1
void USART1_IRQHandler(void)
2
{
3
4
if (USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) 
5
{
6
7
state=next_state;
8
switch(state)
9
{
10
  case Warte_A:
11
  if(USART_ReceiveData(USART1) =='$')
12
  {
13
    data1[Ucounter++] = USART_ReceiveData(USART1);
14
    next_state = Sammel_A;
15
  }
16
  break;
17
  
18
  case Sammel_A:
19
  data1[Ucounter++] = USART_ReceiveData(USART1);
20
  next_state = Warte_B;  
21
  break;
22
  
23
  case Warte_B:
24
  if(USART_ReceiveData(USART1) =='$')
25
  {
26
    data2[Ucounter++] = USART_ReceiveData(USART1);
27
    next_state = Sammel_B;
28
  }
29
  break;    
30
31
  case Sammel_B:
32
  data2[Ucounter++] = USART_ReceiveData(USART1);
33
  next_state = Warte_A;
34
  break;
35
    
36
37
}
38
}  
39
}

Bitte schaut einmal drüber,
da das Projekt recht wichtig ist (Uni!-Thesis )

von holger (Gast)


Lesenswert?

>Bitte schaut einmal drüber,
>da das Projekt recht wichtig ist (Uni!-Thesis )

http://www.hausaufgaben.de

von Flo (Gast)


Lesenswert?

Ist das ein Versuch witzig zu sein?

Ich mein, ich habe da was, was auch funktioniert,
nur sehe ich den Fehler nicht,
und das ganze ist nicht gerade unwichtig.

von noch einer (Gast)


Lesenswert?

Ist nicht gerade unwichtig.... jetz aber. Debugging wäre auch was

von holger (Gast)


Lesenswert?

>Ist das ein Versuch witzig zu sein?

Nö.

>Ich mein, ich habe da was, was auch funktioniert,
>nur sehe ich den Fehler nicht,
>und das ganze ist nicht gerade unwichtig.

Mir doch egal. Fang noch mal von vorne an.
GPS Strings hab ich schon mit 8051 und AVR
auseinandergefummelt. Wenn du das mit einem
Cortex M3 nicht schaffst, dann... Naja.

von .- .-. (Gast)


Lesenswert?


von .- .-. (Gast)


Lesenswert?


von noch einer (Gast)


Lesenswert?

Empfänge die Daten erst mal mit einem PC. Die Debugmoeglichkeiten dort 
sind besser. Singlestep und Write-to-file sollten passen

von Flo (Gast)


Lesenswert?

Guten morgen, erstmal danke für die ganzen Posts...

Also per RS232-TTL-Wandler hab ich das Modul bereits am PC anschließen 
können,
das ist kein Problem.

Ich frag mich bloß,
unabhängig ob ich jetzt was genaueres Filter (z.B. $GPVTG),
was ich mit dem Code eh nicht mache,
wieso die Datensätze nicht vernünftg in den zwei data-Arrays
hin und her geschrieben werden.

Der Mikrocontroller ist so schnell das er die Datensätze mehrfalls 
aufruft,
wo wenn beide Arrays nicht von der selben Stelle anfangen,
ist schon irgendwas falsch.

Oder wäre es expliziet falsch das ganze mit einem Interrupt aufzuziehen?

Nur zur kurzen Info:
Das ganze ist kein reiner GPS Logger,
die Daten müssen empfangen und zu weiteren
Berechnung weitergeführt werden

von mio (Gast)


Lesenswert?

Wo wird überall 'Ucounter' verändert?
Wie sind 'data1' & 'data2' initialisiert?

von Uwe (Gast)


Lesenswert?

Das empfange nund sammel in Puffern kann man schon im RX Interupt machen 
nur komplexere Berechnungen sollte man sein lassen. Aber ich versteh 
immer noch nicht was dein STM32 so langsam macht läuft der mit nem 
32768kHz Quarz ?
Ich denke das man sogar mit ner 72MHz version so um die 50MBit/s 
Datendurchsatz mit einigen Komplexeren Rechenoperationen hinbekommt ! 
Warum schaft dein System keine 38,4 KBit/s ? Ein solches NMEA Protokoll 
kann man sicherlich mit gutem Gewissen komplett im Interupt decodieren 
ohne Probleme zu bekommen. Ich denke du solltest dir ein paar Kapitel zu 
Zustandsautomaten (Statemachines) durchlesen kooperatives Multitasking 
bzw. manche kleinen Echtzeitbetriebsysteme sind nach diesem Prinzip 
aufgebaut.
Für dich wird das niemand programmieren wir helfen nur. Aber du mußt 
auch  die Stichworte Goo*ln und selber lesen. Zeichne doch einfach mal 
nen Statechart einer Statemachine die du in C gebastelt hast dort siehst 
du normalerweise schnell deine Fehler und kommst auch durch einfaches 
über legen darauf wie du weitermachen mußt. Du mußt dir halt denken du 
bist der Controller und deine Statemachine von anfang an durch gehen. Am 
Anfang geht dies besser mit Statecharts. Und du brauchst auch einen 
Resetzustand oder Anfangszustand in der die Staemachine einfach nur 
wartet bis was zu tun ist.

von Flo (Gast)


Lesenswert?

Uwe, ich gebe dir da recht,

ich möchte es auch alleine schaffen,
auch wenn gerade unmut und verzweiflung gerade breit macht,
da ich es nichtmals schaffen,
die datensätze zwischen zwei buffer (data1 und data 2) zu toggeln

der stm32 ist schnell genug (so denke ich)
da ich beim aufrufen in main,
den momentanen datensatz mehrmals aufruft,
(da ich nur erstmal einen char anzeigen lasse,
habe ich z.B. zich LLLLLLL... (von GLL) bevor der zum nächsten Satz z.B. 
MMMMMM... (von RMC) springt.
bis dieser geändert wird.

das geht z.B. wenn ich data2[4] senden lasse, bekomme ich das M wieder
(d.h. '$','G','P','R','M','C') was auch i.O. ist
bei data1[4], sendet er mir einmalig(!) das M, dannach nur die Cs

[natürlich wechseln die Datensätze durch, aber anhand der reihenfolge im 
register, kann man diesen verlauf erkennen.]

der momentane Code sieht so aus
1
#define Warte_A 0
2
#define Warte_B 1
3
#define Sammel_A 2
4
#define Sammel_B 3
5
6
//Globale Var
7
char data1[],data2[];
8
int Ucounter =0;
9
int state, next_state;
10
11
12
void USART1_IRQHandler(void)
13
{
14
15
if (USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) 
16
{
17
18
state=next_state;
19
switch(state)
20
{
21
  case Warte_A:
22
  if(USART_ReceiveData(USART1) =='$')
23
  {
24
    data1[Ucounter++] = USART_ReceiveData(USART1);
25
    next_state = Sammel_A;
26
  }
27
  break;
28
  
29
  case Sammel_A:
30
  
31
  if (USART_ReceiveData(USART1) != '\r')    
32
    {
33
      data1[Ucounter++] = USART_ReceiveData(USART1);      
34
    }
35
  else
36
    {
37
      data1[Ucounter] = '\0';
38
      next_state = Warte_B;
39
      Ucounter = 0;
40
    }  
41
  break;
42
  
43
  case Warte_B:
44
  if(USART_ReceiveData(USART1) =='$')
45
  {
46
    data2[Ucounter++] = USART_ReceiveData(USART1);
47
    next_state = Sammel_B;
48
  }
49
  break;    
50
51
  case Sammel_B:
52
53
  if (USART_ReceiveData(USART1) != '\r')   
54
    {
55
      data2[Ucounter++] = USART_ReceiveData(USART1);    
56
    }
57
  else
58
    {
59
      data2[Ucounter] = '\0';
60
      next_state = Warte_B;
61
      Ucounter = 0;
62
    }
63
  break;
64
    
65
66
}
67
}  
68
}

Also bevor es zum eigentlichen Filtern kommt,
sollten die Arrays korrekt sein...

Gibt es Verständnisfragen?

von mio (Gast)


Lesenswert?

Wo wird überall 'Ucounter' verändert?
Wie sind 'data1' & 'data2' initialisiert?

-----
Anmerkungen falls ich zu undeutlich war:
  -In deiner 1. Version wurde 'Ucounter' nicht resettet - jetzt ja schon 
:). Hat sich was gebessert?
  -Auch aus deinem 2. Code-Abschnitt ist nicht ersichtlich wie data1 + 2 
initialisiert werden.
  -Und was meinst du eigentlich mit "... wenn ich data2[4] senden lasse, 
..."?. Ich dachte du willst empfangen?

-----
Deine 2 Code-Beispiele unterscheiden sich funktional sehr stark.
Version 1 kann nicht so funktionieren wie du erwartest.
Version 2 sieht auf den ersten Blick besser aus...

von Ralf (Gast)


Lesenswert?

Hi Flo,

Deine zweite Lösung sieht eigentlich gut aus. Was ich aber ein wenig 
seltsam finde ist deine Deklaration der beiden Puffer:
char data1[],data2[];
Hier fehlt aus meiner Sicht eine Größenangabe wie:
char data1[100],data2[100];
Wenn ichs gerade richtig im Kopf habe kann ein NMEA Frame max. 83 
Character groß sein.
Ich habe gerade mal bei mir im Code eine solche deklaration ausprobiert. 
Bei mir gibt es keine Compiler Warnung aber die Deklarierten Arrays 
haben nur eine Größe von jew. einem Byte.
Schau bitte mal in deinem Map-File nach wie groß deine Puffer sind.

Heute Abend könnte ich Dir auch mal meinen NMEA Parser schicken. 
Vieleicht kannst Du da was kupfern.

Gruß,
Ralf

von mio (Gast)


Lesenswert?

@Ralf:
Nicht alles verraten!
Nur wenn man Probleme selber löst lernt man auch was dabei.
Außerdem finde ich abkupfern für eine Uni-Arbeit - lass es mich höflich 
ausdrücken - eher suboptimal.
Und es scheitert hier aktuell nicht am Parser, sondern schon an der 
Datenübernahme.

von Uwe (Gast)


Lesenswert?

Bei nachfolgendem text möchte ich gerne wissen was die Funktion
"USART_ReceiveData(USART1)" macht.
Denn wenn das eine blockierende funktion ist die darauf wartet das ein 
Zeichen empfangen wird dann kann das so nicht funktionieren.
Du solltest an nur einmal  VOR der ganzen switch Funktion das UDR 
Register
auslesen und in einer Variable speichern. Auf die Variable kannst du in 
späteren "case" und "if" Funktionen zugreifen.

> switch(state)
> {
>  case Warte_A:
>  if(USART_ReceiveData(USART1) =='$')
>  {
>    data1[Ucounter++] = USART_ReceiveData(USART1);
>    next_state = Sammel_A;
>  }
>  break;

von Florian G. (Firma: Student) (flogo)


Angehängte Dateien:

Lesenswert?

1
void USART1_IRQHandler(void)
2
{
3
4
if (USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) 
5
{
6
7
state=next_state;
8
switch(state)
9
{
10
  case Warte_A:
11
  if(USART_ReceiveData(USART1) =='$')
12
  {
13
    data1[Ucounter++] = USART_ReceiveData(USART1);
14
    next_state = Sammel_A;
15
  }
16
  break;
17
  
18
  case Sammel_A:
19
  
20
  if (USART_ReceiveData(USART1) != '\r')    
21
    {
22
      data1[Ucounter++] = USART_ReceiveData(USART1);      
23
    }
24
  else
25
    {
26
      data1[Ucounter] = '\0';
27
      next_state = Warte_B;
28
      Ucounter = 0;
29
    }  
30
  break;
31
  
32
  case Warte_B:
33
  if(USART_ReceiveData(USART1) =='$')
34
  {
35
    data2[Ucounter++] = USART_ReceiveData(USART1);
36
    next_state = Sammel_B;
37
  }
38
  break;    
39
40
  case Sammel_B:
41
42
  if (USART_ReceiveData(USART1) != '\r')   
43
    {
44
      data2[Ucounter++] = USART_ReceiveData(USART1);    
45
    }
46
  else
47
    {
48
      data2[Ucounter] = '\0';
49
      next_state = Warte_A; // war voher B
50
      Ucounter = 0;
51
    }
52
  break;
53
    
54
55
}
56
}  
57
}

also ich hatte noch ein Fehler im Programm, siehe Bemerkung.
also mio und ralf, ihr hattet anscheinend recht mit der initialisierung 
von data1 und data2.
Ich wußte schon das ein NMEA Datensatz max83 Charterzeichen beinhalten 
können,
wurde nur aufgrund meiner Misserfolge mißtrauisch,
und habs weggelassen.
bei aufruf im main programm lassen sich beide datastrings ohne 
fehleranzeigen, und wenn sie direkt hintereinander geschrieben sind -_-
aber diese sind komplett, was schonmal wichtig ist.
(siehe anhang)

Also vielen Dank nochmal für den Hinweis.

Ralf, auch wenns Mio nicht gerne sieht, würdest du mir einen riesen 
gefallen mit dem Parse Code machen,
ich verspreche auch das ich es erstmal alleine Versuche.

Mio, mit dem senden, das dient als kontrolle,
da ich nie wirlich den umgang mit dem debugger gelernt habe,
muss ich einwenig "erfinderisch" sein...
so sende ich das was ich gefiltert habe, um zu sehen obs korrekt ist,
wenns einmal läuft wird auch nichts mehr gesendet.

von Florian G. (Firma: Student) (flogo)


Lesenswert?

Uwe,
1
u16 USART_ReceiveData(USART_TypeDef* USARTx)
2
{
3
  /* Check the parameters */
4
  assert_param(IS_USART_ALL_PERIPH(USARTx));
5
  
6
  /* Receive Data */
7
  return (u16)(USARTx->DR & (u16)0x01FF);
8
}

Wenn ich es richtig deute,
ließt dieser nur den register aus.
mit einer blockierenden funktion meinst
du schleifen etc.

*ich sehs kommen, gleich klatscht es gleich für mich,
aber kein beifall*

von mio (Gast)


Lesenswert?

Punkt 1:
'USART_ReceiveData' liest aus dem UART-Datenregister 1 Byte aus. 
Richtig?

D.h., mit deinen if-Abfragen hast du das 1. Byte schon gelesen, und 
schreibst, aber das 2. in dein Array:
1
if (USART_ReceiveData(USART1) != '\r')    
2
{
3
  data1[Ucounter++] = USART_ReceiveData(USART1);      
4
}

Entweder du übersiehst hier jedes 2. Byte, oder ich übersehe deine 
Absicht :)

Punkt 2:
Wieviel Bytes kann dein UART-Datenregister puffern?
Du liest pro IRQ 2 Bytes aus. Unter Umständen enthält die Queue aber 
noch mehr Daten. Evtl. gibt es in der STM32-API eine Funktion die dir 
angibt wieviel Daten noch im Puffer enthalten sind.

von Florian G. (Firma: Student) (flogo)


Lesenswert?

ich komme nicht ganz dahinter was du mit punkt 1 meinst,
wenn du so meinst sind es zwei vorgänge.
meinst du damit mein mc käme damit in verzug?

müsste sich das nicht im terminal wiederspiegeln?
indem jedes zweite zeichen falsch wäre?

zu punkt zwei,
ich schau mal eben nach ;)

von Florian G. (Firma: Student) (flogo)


Lesenswert?

Ich lese im RM0008 von 8Bit Data Value.

Wenn ich es richtig verstanden habe,
kann man den Status anzeigen lassen,
ob RXNE noch gefüllt ist oder nicht.
Man kann diesen Status (Flag) auch aufheben,
somit müsste der MC wieder von vorne
das DR Register überschreiben können.

War das deine Idee gewesen? ^^

von mio (Gast)


Lesenswert?

Quasi.

Du hast Recht:
"...Bit 5 RXNE: Read data register not empty
This bit is set by hardware when the content of the RDR shift register 
has been transferred to the USART_DR register. An interrupt is generated 
if RXNEIE=1 in the USART_CR1 register..."

Das macht der alles in Hardware.

Punkt 1 ist damit auch obsolet.

von Florian G. (Firma: Student) (flogo)


Lesenswert?

Ich habe mal deinen Einwand zu dem Thema Restbits berücksichtigt,
USART_ClearFlag(USART1, USART_FLAG_RXNE);
es machte keinen Unterschied.

Es ist auch die Frage ob es sinnvoll ist direkt das RXNE-InterruptFlag 
mit zu löschen...

Ich habe den Code leicht überarbeitet,
laut Terminal überschreibt er eine Zeile zich mal,
Bis dieser einen Zeilensprung macht,
und sich wiederüberschreibt...
müsste er nicht jedes cr lf mitkriegen, und auch darstellen?
schließlich hat er in der Bedingung
wenn letztes Zeichen \r und das neuste Zeichen \t,
dann soll er noch das neue Zeichen übernehmen,
bevor er zum nächsten state wechselt, gell?
1
void USART1_IRQHandler(void)
2
{
3
4
if (USART_ClearFlag(USART1, USART_IT_RXNE) != RESET) 
5
{
6
7
state=next_state;
8
switch(state)
9
{
10
  case Warte_A:
11
  if(USART_ReceiveData(USART1) =='$')
12
  {
13
    data1[Ucounter++] = USART_ReceiveData(USART1);
14
    next_state = Sammel_A;
15
  }
16
  break;
17
  
18
  case Sammel_A:
19
  
20
  if ((USART_ReceiveData(USART1) != '\r') && (data1[Ucounter-1] != '\t'))    
21
    {
22
      data1[Ucounter++] = USART_ReceiveData(USART1);      
23
    }
24
  else
25
    {
26
      data1[Ucounter++] = USART_ReceiveData(USART1);
27
      data1[Ucounter] = '\0';
28
      next_state = Warte_B;
29
      USART_ClearFlag(USART1, USART_FLAG_RXNE);
30
      Ucounter = 0;
31
    }  
32
  break;
33
  
34
  case Warte_B:
35
  if(USART_ReceiveData(USART1) =='$')
36
  {
37
    data2[Ucounter++] = USART_ReceiveData(USART1);
38
    next_state = Sammel_B;
39
  }
40
  break;    
41
42
  case Sammel_B:
43
44
  if ((USART_ReceiveData(USART1) != '\r') && (data2[Ucounter-1] != '\t'))   
45
    {
46
      data2[Ucounter++] = USART_ReceiveData(USART1);    
47
    }
48
  else
49
    {
50
      data2[Ucounter++] = USART_ReceiveData(USART1);
51
      data2[Ucounter] = '\0';
52
      next_state = Warte_A;
53
      USART_ClearFlag(USART1, USART_FLAG_RXNE);
54
      Ucounter = 0;
55
    }
56
  break;
57
    
58
59
}
60
}  
61
}

von Florian G. (Firma: Student) (flogo)


Lesenswert?

So ich bin endlich beim Parsen angelangt,

und bekomme eine Fehlermeldung,
die ich nicht ganz nachvollziehen kann

main.c(525): error:  #167: argument of type "int" is incompatible with 
parameter of type "const char *restrict"

die Fehlermeldung bekomme ich bei allen strtokunktionen,
dabei nutze ich garkein int?!

Hier der Quelltext

die Arrays sind als Char deklariert

1
void GPSFilter(void)
2
{
3
int o=0;
4
char *pToken;
5
char *pToken2;
6
7
if (state == Warte_B)
8
  {
9
  strcpy(GPSdata1, data1);
10
11
    if (strstr(GPSdata1,"VTG") != 0)
12
      { 
13
        GPIO_SetBits(GPIOE,GPIO_Pin_4);
14
             
15
        pToken = strtok(data1,",");
16
        for(o=0; o==7; o++)
17
          {
18
            pToken = strtok(NULL, ','); // 
19
          }
20
        strcpy(GPSdata, pToken);
21
22
        pToken2 = strtok(GPSdata, '.');
23
        strcpy(gesucht1,pToken2);
24
        pToken2=strtok(GPSdata, '.');
25
        strcpy(gesucht2, pToken2);
26
        o=0;  
27
        v = atoi(GPSdata1);
28
        n = atoi(GPSdata2);
29
        GPSFilVTG =1;
30
      }
31
    
32
      
33
    else if (strstr(GPSdata1,"GGA") != 0)
34
      { 
35
      GPIO_SetBits(GPIOE,GPIO_Pin_6);
36
      gesuchtstd[0]= data1[6];
37
      gesuchtstd[1]= data1[7];
38
      gesuchtmin[0]= data1[8];
39
      gesuchtmin[1]= data1[9];
40
      gesuchts[0]= data1[10];
41
      gesuchts[1]= data1[11];
42
      gesuchtms[0]= data1[13];
43
      gesuchtms[1]= data1[14];
44
      gesuchtms[2]= data1[15];
45
      std = atoi(gesuchtstd);
46
      min = atoi(gesuchtmin);
47
      s = atoi(gesuchts);
48
      ms = atoi(gesuchtms);
49
      GPSFilGGA =1;
50
      }  
51
  }
52
  
53
if (state == Warte_A)
54
  {
55
  strcpy(GPSdata2, data2);
56
    if (strstr(GPSdata1,"VTG") != 0)
57
      { 
58
        GPIO_SetBits(GPIOE,GPIO_Pin_4);
59
             
60
        pToken = strtok(data2,",");
61
        for(o=0; o==7; o++)
62
          {
63
            pToken = strtok(NULL, ',');
64
          }
65
        strcpy(GPSdata, pToken);
66
67
        pToken2 = strtok(GPSdata, '.');
68
        strcpy(gesucht1,pToken2);
69
        pToken2=strtok(GPSdata, '.');
70
        strcpy(gesucht2, pToken2);
71
        o=0;  
72
        v = atoi(GPSdata1);
73
        n = atoi(GPSdata2);
74
        GPSFilVTG =1;
75
      }
76
    
77
      
78
    else if (strstr(GPSdata2,"GGA") != 0)
79
      { 
80
      GPIO_SetBits(GPIOE,GPIO_Pin_6);
81
      gesuchtstd[0]= data1[6];
82
      gesuchtstd[1]= data1[7];
83
      gesuchtmin[0]= data1[8];
84
      gesuchtmin[1]= data1[9];
85
      gesuchts[0]= data1[10];
86
      gesuchts[1]= data1[11];
87
      gesuchtms[0]= data1[13];
88
      gesuchtms[1]= data1[14];
89
      gesuchtms[2]= data1[15];
90
      std = atoi(gesuchtstd);
91
      min = atoi(gesuchtmin);
92
      s = atoi(gesuchts);
93
      ms = atoi(gesuchtms);
94
      GPSFilGGA =1;
95
      } 
96
  }

von holger (Gast)


Lesenswert?

>main.c(525): error:  #167: argument of type "int" is incompatible with
>parameter of type "const char *restrict"

',' z.B. ist kein String.

von Florian G. (Firma: Student) (flogo)


Lesenswert?

ach käse, danke für den hinweis

von HPF (Gast)


Lesenswert?

Hi Flo,

machts dir was aus deinen Code hochzuladen?
Ich hab mein GPS modul an der USART2 hängen. Momentan lese ich noch in 
einer Schleife alle Daten aus. Ich würde gerne wie du ein Interrupt 
haben der mir mein "GPS-Buffer" füllt und sobal der NMEA Satz komplett 
ist diesen auf mein Terminal (hab ich mit USB VCOM realisiert) ausgibt.

Viele Grüße

Hans P.

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.