Forum: Mikrocontroller und Digitale Elektronik Falsche Anzeige nach Spannungsverlust


von Stefan O. (oele22)


Lesenswert?

Guten Tag alle zusammen,

ich benutze das Board AVR-MT-128 von ATmel und den GPS-Empfänger 
EM-406A. Der GPS-Empfänger übermittelt die Daten (NMEA 1083 Protokoll) 
über serielle Schnittstelle RS232 an das Board. Hier wird dann z.B. die 
UTC und die aktuelle Position auf dem LCD-Display angezeigt.

Ich programmiere mit AVR Studio 5.1 in C.

Die übermittelten Zeichen werden sequentiell an das Board geschickt. 
Dieses liest das aktuelle Zeichen ein. Wenn das Zeichen '$' detektiert 
wird, werden die nachfolgenden Zeichen in einen String gespeichert, bis 
erneut ein '$' detektiert wird. Das Zeichen '$' markiert den Start eines 
vollständigen Datensatzes des Protokolls. Der String wird dann mit einem 
bestimmten Teilstring verglichen. Ist dieser vorhanden, werden bestimmte 
Werte aus dem String dann auf dem Display angezeigt (z.B. aktuelle 
Position).

Nun zu meinem Problem:

Nach Spannungsverlust beim Board werden nicht mehr die richtigen Daten 
angezeigt. Ein erneutes Aufspielen meines Programmes auf das Board 
beseitigt den Fehler nicht. Erst wenn ich von ATmel ein Demo-Code auf 
das Board spiele und dann meinen Code, dann werden wieder korrekte Daten 
angezeigt.

Demo-Code:
http://www.watterott.com/de/AVR-MT-128

Woran könnte das liegen?

Gruß Stefan

von Georg G. (df2au)


Lesenswert?

Da die Glaskugel gerade zum Polieren weg ist, kannst du vielleicht noch 
einige Zusatzinfos geben: Was bedeutet "falsche Anzeige"? Chinesische 
Schrift? Oder Uhrzeit falsch?

Der Fehler deutet auf eine fehlende oder falsche Initialisierung eines 
der Bauteile hin. Speziell zum Thema "LCD" geistern hier diverse 
optimistische (um es höflich auszudrücken) Beispiele durch das Forum. 
Wobei mir unverständlich ist, warum alles immer wieder neu erfunden 
werden muss.

von Karl H. (kbuchegg)


Lesenswert?

Ins Blaue geraten:

Da wird halt dein Code irtgendeine Initialisierung nicht machen, die der 
Demo-Code schon macht.

Um dem auf die Spur zu kommen, würde ich mir als erstes mal die 
Datensätze ansehen, so wie sie vom GPS kommen, nachdem dein Board 
stromlos war. Die dann vergleichen mit dem was daherkommt, nachdem das 
Demo-Programm die Initialisierung vervollständigt hat. Vielleicht führt 
das zu was, vielleicht auch nicht - aber einen Versuch ist es erst mal 
wert rauszufinden, wo da die Unterschiede liegen.

von Stefan O. (oele22)


Lesenswert?

Vielen Dank für eure Antworten. In letzter Zeit hatte ich viel zu tun 
und bin dementsprechend noch nicht weiter gekommen.

Hier erstmal mein Code:
1
#include "avr/io.h"      // IO Definitionen für den Microcontroller
2
#include "iom128.h"      // Definitionen für den ATmega128
3
#include "string.h"         // Funktionen für Zeichenketten 
4
5
#include "system.h"// Beinhaltet grundlegende Definitionen  und Funktionen
6
#include "bits.h"  // Definiert die einzelnen Bits
7
#include "lcd.h"   // Funktionen für das LCD-Display
8
#include "delay.h" // Funktionen zur Zeitverzögerung 
9
10
/*
11
** Definitionen
12
*/
13
#define    B1        (PINA&BIT0)  // Buttons
14
#define    B2        (PINA&BIT1)
15
#define    B3        (PINA&BIT2)
16
#define    B4        (PINA&BIT3)
17
#define    B5        (PINA&BIT4)
18
19
/*
20
** Hauptprogramm
21
*/
22
int main()
23
{  
24
  // Deklarationen
25
  unsigned char  Ch=0;  // Aktuell eingelesenes Zeichen
26
  char    Str [100]; // NMEA-Protokoll besteht aus Datensätzen mit maximal 82 Zeichen
27
  int        k=0;        // Laufvariable zum Durchlaufen des Strings
28
  int        m=0;        // Laufvariable
29
  
30
  int        bed=0;        // Bedingung für String
31
  int        len=0;
32
  int        auswahl=1;
33
  char      str2[]="$GPGGA";  // Teilstring zum Auslesen der GPS-Daten
34
  char      *pointer;      // Pointer zur Markierung des gefundenden Strings
35
  int        beg=0;        // Zähle die Kommas, Beginnendes Komma
36
  int        end=0;        // Zähle die Kommas, Nachfolgendes Komma
37
  
38
/*
39
** Initialisierungen
40
*/
41
  PORT_Init();
42
  UART_Init(4800);    // Baudrate des GPS-Empfängers: 4800
43
  delay_ms(100);
44
  LCD_Init();
45
  delay_ms(10);
46
  
47
/*
48
** Welcome
49
*/
50
  SEND_CMD(DISP_ON);
51
  delay_ms(10);              
52
  SEND_CMD(CLR_DISP); 
53
   delay_ms(10);  
54
  SEND_CMD(DD_RAM_ADDR);
55
  delay_ms(10);
56
  SEND_STR("Willkommen!");
57
  delay_ms(500); 
58
  SEND_CMD(CLR_DISP);
59
60
/*
61
** Endless loop
62
*/    
63
  while (1)
64
  {  
65
/*
66
**********************************************************************************************************************
67
** Einlesen der ankommenden GPS-Daten und Darstellung auf dem LCD-Display                      **
68
**********************************************************************************************************************
69
*/
70
    // Lösche Display-Anzeige
71
    if (B2 == 0)
72
    {
73
      SEND_CMD(CLR_DISP);
74
    }
75
    
76
    // Wähle aktuelle Anzeige aus    
77
    if (B3 == 0)
78
    {
79
      delay_ms(50); // Verzögerung, damit der Button geklickt werden kann
80
      auswahl++;
81
      if (auswahl == 5)
82
      {
83
        auswahl = 1;
84
      }
85
    }
86
    
87
    Ch = UART_Receive(); // Aktuelles Zeichen einlesen                
88
      
89
    // Zeichen zwischen Anfang und Ende einlesen
90
    if (bed == 1 && Ch != '$' && Ch)                  
91
    {
92
      Str[k] = Ch;  
93
      k = k + 1;      
94
    }
95
    
96
    // Letztes Zeichen einlesen
97
    if (bed == 1 && Ch == '$')
98
    {          
99
      pointer = strstr(Str,str2); // Pointer zeigt auf den Anfang der Stelle, wo die Zeichenkette gefunden wurde                      
100
      len = strlen(Str);          
101
                    
102
      if (pointer) 
103
      {            
104
        switch(auswahl)
105
        {
106
          // Anzeige der Uhrzeit
107
          case 1 :
108
          SEND_CMD(CLR_DISP);
109
          SEND_STR("UTC: ");
110
          beg = Str_Komma(Str,1); // Uhrzeit: Zwischen Komma 1 und 2
111
          end = Str_Komma(Str,2);
112
          for(m=beg;m<beg+6;m++)  // +6, um die 6 Ziffern der Uhrzeit zu erhalten 
113
          {
114
            SEND_CHAR(Str[m]); 
115
            if (m == beg+1 || m == beg+3)
116
            {
117
              SEND_CHAR(':');
118
            }
119
          }
120
          break;
121
          
122
          // Anzeige der verfügbaren Satelliten
123
          case 2:
124
          SEND_CMD(CLR_DISP);
125
          SEND_STR("Satelliten: ");
126
          beg = Str_Komma(Str,7); // Satelliten: Zwischen Komma 7 und 8
127
          end = Str_Komma(Str,8);
128
          for(m=beg;m<end-1;m++)
129
          {
130
            SEND_CHAR(Str[m]); 
131
          }
132
          break;
133
            
134
          // Anzeige Breitengrad
135
          case 3:
136
          SEND_CMD(CLR_DISP);
137
          SEND_STR("LAT: ");
138
          beg = Str_Komma(Str,2); // Breitengrad: Zwischen Komma 2 und 3
139
          end = Str_Komma(Str,3);
140
          for(m=beg;m<end-1;m++)
141
          {
142
            SEND_CHAR(Str[m]); 
143
          }
144
          break;
145
            
146
          // Anzeige Längengrad
147
          case 4:
148
          SEND_CMD(CLR_DISP);
149
          SEND_STR("LON: ");
150
          beg = Str_Komma(Str,4); // Längengrad: Zwischen Komma 4 und 5
151
          end = Str_Komma(Str,5);
152
          for(m=beg;m<end-1;m++)
153
          {
154
            SEND_CHAR(Str[m]); 
155
          }
156
          break;
157
        }        
158
      }            
159
      k = 0;        // Laufvariable zurücksetzen
160
      bed = 0;      // Bedingung zurücksetzen  
161
    }
162
    
163
    // Start zum Einlesen des Strings
164
    if (bed == 0 && Ch == '$')  // Zeichen $ leitet Datensatz ein
165
    {              
166
      Str_Init(Str,'0');    // String Inhalt mit '0' initialisieren
167
      bed = 1;
168
      Str[k] = Ch;      // Schreibe $ an erster Stelle des Strings
169
      k = k + 1;    
170
    }  
171
  }
172
  return 0;
173
}

und die verwendeten Funktionen:
1
// Hilfsfunktion zum Initialiseren des LCD-Displays
2
void _E (void)
3
{
4
  E_HIGH;
5
  delay_us(5);  // Gebe dem LCD-Display Zeit zum Ausführen des Befehls.
6
  E_LOW;
7
}
8
9
// Initialisiere das LCD-Display
10
void LCD_Init()
11
{
12
  RS_LOW;
13
  delay_ms(110);
14
15
  PORTC = 0b00110000;          // Setze D4, D5 Port zu 1
16
  _E();                // High->Low zu E Port (Puls)
17
  delay_ms(80);
18
  PORTC = 0b00110000;          // Setze D4, D5 Port zu 1
19
  _E();                // High->Low zu E Port (Puls)
20
  delay_ms(80);
21
  PORTC = 0b00110000;          // Setze D4, D5 Port zu 1
22
  _E();                // High->Low zu E Port (Puls)
23
  delay_ms(80);
24
  PORTC = 0b00100000;          // Setze D4 zu 0, D5 Port zu 1. Wechsel in den 4 Bit Modus.
25
  _E();                // High->Low zu E Port (Puls)
26
}  
27
    
28
// Sende ein Char zum LCD-Display
29
void SEND_CHAR (unsigned char c)
30
{   
31
  data = 0b00001111 | c;            // Nehme oberes Nibble
32
  PORTC = (PORTC | 0b11110000) & data;    // Setze D4-D7
33
  RS_HIGH;                    // Setze LCD-Display in Datenmodus
34
  _E();
35
  data = c << 4;                // Nehme unteres Nibble
36
  PORTC = (PORTC & 0b00001111) | data;  // Setze D4-D7 (nur PORTC4-PORTC7)
37
  RS_HIGH;                     // Setze LCD-Display in Datenmodus
38
  _E();
39
}               
40
    
41
// Sende ein Kommando zum LCD-Display
42
void SEND_CMD (unsigned char c)
43
{    
44
  delay_ms(LCD_CHAR_SPEED);                // Delay für LCD Char
45
  data = 0b00001111 | c;            // Nehme oberes Nibble
46
  PORTC = (PORTC | 0b11110000) & data;    // Setze D4-D7
47
  RS_LOW;                    // Setze LCD-Display in Datenmodus
48
  _E();    
49
  data = c << 4;                //Nehme unteres Nibble
50
  PORTC = (PORTC & 0b00001111) | data;  // Setze D4-D7 (nur PORTC4-PORTC7)
51
  RS_LOW;                    // Setze LCD-Display in Datenmodus
52
  _E();
53
}  
54
                  
55
// Sende einen String zum LCD-Display
56
void SEND_STR(unsigned char* str)
57
{
58
  unsigned int i = 0;
59
  unsigned int k = 1;
60
  unsigned int l = 2;
61
62
  SEND_CMD(DD_RAM_ADDR);  // DD_RAM_ADDR: 1. Zeile vom Display
63
64
  while(str[i]!='\0')    // Schleife bis zum Ende des Strings
65
  {    
66
    SEND_CHAR(str[i]);  
67
        
68
    if (i == k*15)    // Wenn die 1. Zeile gefüllt ist, gehe in die 2-te
69
    {
70
      SEND_CMD(DD_RAM_ADDR2);  // DD_RAM_ADDR2: 2. Zeile vom Display
71
      k = k + 2;
72
    }
73
    if (i == l*15)    // Wenn die 2. Zeile gefüllt ist, gehe in die 1-te
74
    {
75
      SEND_CMD(DD_RAM_ADDR);
76
      l = l + 2;
77
    }
78
79
    i++;
80
  }
81
}
82
83
// Sende einen Integer zum LCD-Display
84
// Stellt nur runde Zahlen dar. Kommastellen werden abgeschnitten/ignoriert
85
void SEND_INT(long a)
86
{
87
  int C[20];
88
  unsigned char Temp=0, NumLen = 0;
89
  if (a < 0)            // Darstellung negativer Zahlen
90
  {
91
    SEND_CHAR('-');
92
    a = -a;
93
  }
94
  do
95
  {  
96
    Temp++;
97
    C[Temp] = a % 10;      // Integer durch 10 und modulo 10 rechnen, um jede einzelne Ziffer/Stelle der Zahl zu erhalten
98
    a = a/10;          // z.B. 124 -> Berechnung von 4 2 1
99
  }
100
  while (a);
101
  NumLen = Temp;
102
  for (Temp = NumLen; Temp>0; Temp--) 
103
  {
104
    SEND_CHAR(C[Temp] + 48);   // + 48 dez = + 30 hex = 0 in ASCII
105
  }
106
}
107
// Initialisiere die Ports
108
void PORT_Init()
109
{
110
 // Ports          Data direction register
111
  PORTA = 0b00000000;    DDRA = 0b01000000;  // Setze Relay/LED als Ausgang
112
  PORTB = 0b00000000;    DDRB = 0b00000000;
113
  PORTC = 0b00000000;    DDRC = 0b11110111;  // LCD-Display
114
  PORTD = 0b00000000;    DDRD = 0b00000000;  
115
  PORTE = 0b00000000;    DDRE = 0b00110000;  // Setze Buzzer als Ausgang (Bit4 = 1, Bit5 = 1)
116
  PORTF = 0b00000000;    DDRF = 0b00000000;  
117
  PORTG = 0b00000000;    DDRG = 0b00000000;  
118
}
119
/*
120
** Funktionen für die UART-Schnittstelle
121
*/
122
123
// Initialisiere den UART
124
void UART_Init(uint32_t Baud)
125
{
126
  unsigned int BaudRate = OSCSPEED / (16 * Baud) - 1;  // Asynchroner Modus, siehe Seite 173 im Handbuch
127
128
  UBRR1H = (unsigned char) (BaudRate>>8);    // Setze die BaudRate der Register UBRR1H und UBRR1L
129
  UBRR1L = (unsigned char) BaudRate;      // Wichtig: UBRRH muss vor UBRRL beschrieben werden.
130
  
131
  UCSR1A = 0b00000000;
132
  UCSR1B = (1<<TXEN1)|(1<<RXEN1);    // Senden und Empfangen
133
  UCSR1C = (1<<UCSZ11)|(1<<UCSZ10);  
134
135
//  UCSR1B = UCSR1B | 0b00011000;   // Ermögliche Empfangen und Senden (Bit3 = 1, Bit4 = 1)
136
//  UCSR1C = UCSR1C | 0b10000110;  // Setze Frame Format: 8 data (Bit1 = 1, Bit2 = 1), 1 stop bit (Bit3 = 0)
137
}
138
139
// Empfange Daten über UART nonstop
140
unsigned char UART_Receive(void)
141
{
142
  //   while(!(UCSR1A & (1<<RXC1)));
143
  if (UCSR1A & (1<<RXC1))  
144
    return UDR1;      
145
  else            
146
    return 0;
147
}
148
149
// Sende Daten über UART
150
void UART_Transmit(unsigned char data)
151
{
152
  while (!(UCSR1A & (1<<UDRE1)));  // Warte, bis Buffer bereit ist zum Empfangen
153
154
  UDR1 = data;          // Sende Daten
155
}
156
157
/*
158
** Funktionen zur Stringverarbeitung
159
*/
160
161
162
// Initialisiere Strings 
163
void Str_Init(char* str, char init)
164
{
165
  int j = 0;
166
  while (j<strlen(str))
167
  {
168
    str[j] = init;
169
    j++;
170
  }
171
}
172
173
// Zähle Kommas in String
174
int Str_Komma(char* str, int n) // n: Anzahl der Kommas entspricht dem Wert, der angezeigt werden soll z.B. Uhrzeit
175
{
176
  int summe = 0;
177
  int i = 0;
178
  for (i=0;i<strlen(str);i++)
179
  {
180
    if (str[i] == ',')
181
    {
182
      summe++;  // Anzahl der Kommas
183
    }
184
    if (summe == n)
185
    {
186
      return i+1; // Gebe die 1. Stelle nach dem Komma zurück
187
    }
188
  }
189
}
190
191
// Buzzer
192
void Buzzer(void)
193
{ 
194
  BUZZ1_LOW;      
195
  BUZZ2_HIGH;
196
  delay_us(125);
197
    BUZZ2_LOW;
198
  BUZZ1_HIGH;
199
  delay_us(125);
200
}

Es werden falsche Daten aus dem String gezeigt. Vorher wird zum Beispiel 
UTC: hh:mm:ss auf dem Display sekündlich aktualisiert und angezeigt. 
Nach dem Spannungsverlust wird auch weiterhin UTC:   :  :   dargestellt. 
Allerdings wird zwischen den Doppelpunkten nun nicht mehr die korrekte 
Uhrzeit angezeigt, sondern ein Schwall von Daten aus dem String.

Woran kann es liegen? Was verändert sich dadurch, wenn ich zunächst ein 
Demo-Code aufspiele und dann meinen Code? Ich bin ziemlich ratlos und 
wäre dankbar über jedigliche Hilfe.

Gruß Stefan

von Udo S. (urschmitt)


Lesenswert?

Kommen denn nach dem Stromausfall noch korrekte Datensätze aus dem GPS 
Modul?
Wenn nein, dann stimmt die Initialisierung des GPS Moduls nicht.
Prüfen indem man die Daten zum PC sendet (Terminalprogramm)

von Michael (Gast)


Lesenswert?

Ohne das jetzt durchzulesen: So lange Codes hängt man als Dateianhänge 
an und füllt nicht gleich mehrere Bildschirmseiten damit!

Netiquette -> Äußere Form -> Punkt 3

http://www.mikrocontroller.net/articles/Netiquette#.C3.84u.C3.9Fere_Form

von Karl H. (kbuchegg)


Lesenswert?

Puh.
Du hast da ein ganz schönes Durcheinander in der Stringbearbeitung 
veranstaltet.

Dein
char Str[100];

ist zuallererst mal uninitialisiert.
Und daran ändert sich auch in weiterer Folge nichts. Du hast nirgends in 
deinem Code die Gewissheit, dass du es mit einem gültigen, sauberen 
String zu tun hast.

Wenn ich dir einen Vorschlag machen darf: Vergiss solche Funktionen wie 
Str_Init. Die wiegen dich nur fälschlich in Sicherheit, machen aber 
nicht das was du erwartest.

Kümmere dich bei der Stringverarbeiteung immer selbst darum, dass du am 
Ende eines Strings ein \0 Zeichen hast, welches den String terminiert. 
Solange dieses \0 Zeichen nicht an der richtigen Stelle ist, kannst du 
keine Funktionen wie strlen, strstr, etc. aufrufen!

zb hier
1
   Ch = UART_Receive(); // Aktuelles Zeichen einlesen                
2
      
3
    // Zeichen zwischen Anfang und Ende einlesen
4
    if (bed == 1 && Ch != '$' && Ch)                  
5
    {
6
      Str[k] = Ch;  
7
      k = k + 1;      
8
    }
9
    
10
    // Letztes Zeichen einlesen
11
    if (bed == 1 && Ch == '$')
12
    {

mach hinten an den String EXPLIZIT das \0 Zeichen rein und du hast es 
mit einem gültigen String zu tun, den du mit strstr untersuchen kannst
1
    // Letztes Zeichen einlesen
2
    if (bed == 1 && Ch == '$')
3
    {          
4
      Str[k] = '\0';
5
      ...

Genauso hier

    // Start zum Einlesen des Strings
    if (bed == 0 && Ch == '$')  // Zeichen $ leitet Datensatz ein
    {
      Str_Init(Str,'0');    // String Inhalt mit '0' initialisieren
[/C]
welches offenbar benutzt wird, um das erste mal auf den '$' zu 
synchronisieren. Du kannst hier nicht Str_Init aufrufen! Du hast noch 
keinen gültigen String in Str. Ganz abgesehen davon, was soll das 
bringen, da überall ein '0' reinzuschreiben? Das braucht kein Mensch.
1
    // Start zum Einlesen des Strings
2
    if (bed == 0 && Ch == '$')  // Zeichen $ leitet Datensatz ein
3
    {              
4
      Str[0] = '$';
5
      Str[1] = '\0';
6
      k = 1;    
7
    }

Im übrigen ist dein Code ziemlich unübersichtlich. Was soll 'bed' 
bedeuten? Offensichtlich ist das eine Variable, mit der du festhalten 
willst, ob sich dein Programm mit den GPS Daten synchronisiert hat. Dann 
nenn die Variable auch so und mach dir 2 große Blöcke in die Schleife:
* was soll mit dem Zeichen passieren, solange noch nicht synchronisiert 
wurde
* was soll mit dem Zeichen passieren, wenn sich das Programm auf den 
Anfang des NMEA Datensatzes synchronisiert hat.

Es gibt keinen Grund, dass du da 25 if hast, in denen du ständig bed 
abfrägst. Die erste Frage nach erhalt eines Zeichens lautet: Sind wir 
synchronisiert, ja oder nein.
1
  Synchronized = FALSE;
2
3
  while( 1 ) {
4
5
     ....
6
7
    Ch = UART_Receive();
8
9
    if( !Synchronized ) {
10
11
      if( ch == '$' ) {
12
        Str[0] = '$';
13
        Str[1] = '\0';
14
        k = 1;
15
        Synchronized = TRUE;
16
      }
17
    }
18
19
    else {
20
      if( Ch != '$' ) {
21
        Str[k++] = Ch;
22
23
      else {
24
        Str[k] = '\0';
25
26
        .... Diesen Datensatz auswerten
27
28
        .... und neuen anfangen
29
        Str[0] = '$';
30
        Str[1] = '\0';
31
        k = 1;
32
      }
33
    }
34
  }

(und wenn man sich das mal im Detail überlegt, benötigt eigentlich kein 
Mensch das '$' an der ersten Position im String. Denn dieses '$' steht 
sowieso IMMER String. Und wenn es sowieso IMMER vorhanden ist, dann 
braucht das auch keiner. Denn ob du "$GPGGA" in diesem String suchst, 
oder nur "GPGGA" macht auch keinen wirklichen unterschied mehr. Zumal du 
weißt, dass dieses GPGGA sowieso am Stringanfang vorkommen muss. D.h. du 
wirst da nicht strstr benutzen, sondern strncmp um abzutesten, ob die 
ersten 4 Buchstaben im String "GPGGA" lauten. In der traditionellen 
Kette "Eingabe - Verarbeitung - Ausgabe" gibt es 3(!) Stellen, an denen 
die Dinge schief gehen können. Ja, da gehört auch die Eingabe mit dazu. 
Also muss man das kontrollieren!



Soweit so gut. Du hast nämlich noch ein weiteres Problem: Deine 
Auswertung bzw. das Hinschreiben auf das LCD kostet alles Zeit. In 
dieser Zeit kann aber das GPS schon beginnen, den nächsten NMEA 
Datensatz rauszuschicken. Sobald du das erste Zeichen nicht richtig 
mitbekommst, ist deine ganze Auswertung gefährdet. D.h. der ganze Ansatz 
mit Polling der UART ist schon mal nicht der Schlaueste. Wenn du eine 
UART Gegenstelle nicht am Senden hindern kannst, dann brauchst du eine 
Interrupt-getriebene UART Empfangsroutine mit einer FIFO, welche die 
Zeichen mal kurz zwischenspeichert, solange dein Programm noch mit der 
Auswertung beschäftigt ist.

Und dann: ehe du dich an die Auswertung machst, SIEH DIR DEN STRING AN, 
DEN DEIN PROGRAMM EMPFANGEN HAT. Ich hab dir das damals schon ans Herz 
gelegt und ich tu es heute wieder! Wenn dein String, den du aus den 
Daten vom GPS empfängst schon nicht der ist, den du erwartest, dann 
kannst du auswerten bis du schwarz wirst - da kommt nichts gescheites 
raus! Also muss man das als allererstes kontrollieren! Was genau 
empfängt dein Programm vom GPS? Das ist die Frage, der du dich stellen 
musst. Ehe du das nicht weißt, brauchst du dich gar nicht daran 
versuchen mit den Daten (von denen du nicht weißt wie sie aussehen) 
irgendwas anzufangen.

von Stefan O. (oele22)


Lesenswert?

Vielen Dank erst einmal für eure hilfreichen Kommentare!

@  Karl Heinz Buchegger

Was wäre denn die einfachste Möglichkeit sich den Inhalt des Strings 
anzeigen zu lassen?

Gruß Stefan

von Karl H. (kbuchegg)


Lesenswert?

Stefan O. schrieb:

> Was wäre denn die einfachste Möglichkeit sich den Inhalt des Strings
> anzeigen zu lassen?

?
Du hast doch ein LCD, oder nicht?

von Stefan O. (oele22)


Lesenswert?

Ich wollte eigentlich fragen, ob ich mir den Inhalt des Strings am PC 
anzeigen lassen kann. Ich würde den Inhalt des Strings gerne als ganzes 
sehen. Auf dem Display kann ich ja nur 16 Zeichen pro Zeile anzeigen 
lassen (Display hat 2 Zeilen).

von Karl H. (kbuchegg)


Lesenswert?

Stefan O. schrieb:
> Ich wollte eigentlich fragen, ob ich mir den Inhalt des Strings am PC
> anzeigen lassen kann.

Tja.
Wenn du nicht noch eine UART hast oder einen Debugger, mit dem du den µC 
online debuggen kannst, dann ... gar nicht

> Ich würde den Inhalt des Strings gerne als ganzes
> sehen. Auf dem Display kann ich ja nur 16 Zeichen pro Zeile anzeigen
> lassen (Display hat 2 Zeilen).

Tja. Damit wirst du leben müssen, dass du nicht mehr Möglichkeiten hast. 
Du kannst nur das Beste daraus machen. (Aber wenn die ersten 10 Zeichen 
des Strings gut aussehen und die letzten 10 Zeichen, dann ist die 
Wahrscheinlichkeit schon sehr gross, dass der Rest dazwischen auch 
stimmt. Und bei 2 Zeilen a 16 Character, kannst du dir in den beiden 
Zeilen ja diese 'Stellvertreter' ausgeben lassen)

von Stefan O. (oele22)


Angehängte Dateien:

Lesenswert?

@ Karl Heinz Buchegger

Das Anzeigen des Strings auf dem LCD-Display habe ich getestet und es 
funktioniert gut. Der String wird mit dem richtigen Inhalt beschrieben. 
Ich habe es in HTerm verglichen.

Mein Programm habe ich so wie du es mir vorgeschlagen hast 
umstrukturiert. Der Initialisierungsfehler ist nun behoben :-).

Mein Problem ist nun, dass auf dem LCD-Display z.B. die Uhrzeit nun 4 
Sekunden lang kontinuierlich anzeigt wird und dann für 6 Sekunden stehen 
bleibt. Danach erst wird wieder die richtige Uhrzeit für weitere 4 
Sekunden kontinuierlich angezeigt, dann wieder Stillstand, usw..

Könnte dies daran liegen, wie du schon vermutet hast, dass ich keine 
Interrupt-getriebene UART Empfangsroutine benutze, sondern nur über 
Polling des UARTs? Oder könnte es auch noch ein anderer Grund sein?

Anbei der Code.

von Bonzo (Gast)


Lesenswert?

Und dann ist noch alles blockierend geschrieben - uaaaaahhhhhhhhhhh

von Stefan O. (oele22)


Lesenswert?

@ Bonzo:

Was meinst du mit "blockierend geschrieben"?

von Uwe (de0508)


Lesenswert?

Stefan,

gemeint ist mit "blockierend" die vielen Delay.

Auf einem µC arbeitet man anderes -- eventorientiert, d.h.

Liegt ein RS232-Zeichen im Empfangspuffer vor, dann..

Wurde eine Taste gedrückt, losgelassen, lange gedrückt, usw.

Ist eine Zykluszeit, z.B. 1ms, abgelaufen, dann update das LCD und 
bearbeite Prozess 1, 2 ...

Schreibe ein Einfach zulese des Programm, verwende Funktionen zur 
Modularisierung und einfache zu lesende Programmanweisungen..

Kurz um Warten ist sehr schlecht.

von Bonzo (Gast)


Lesenswert?

Blockierend bedeutet, es wird ueberall gewartet bis etwas beendet ist. 
Zum einen ist das schade fuer die Zeit, zum anderen kann ja etwas worauf 
man wartet nicht eintreten. Sowas ist dann extrem schwierig zu debuggen, 
der Prozessor wartet irgend wo.
Besser ist mit einer oder mehreren Zustandsmaschinen zu arbeiten. Und 
dann wird genau an einem Ort im ganzen Code gewartet, das waere dann der 
schnelle Poll-Loop im Main, der die verschiedenen Zustaende prueft und 
abarbeitet. Am Ende dieses Loops kann man dann, falls gewuenscht auch in 
den Sleep gehen.
Die Zusatndsmaschine ist viel einfacher zu debuggen, denn man kann ja 
den Zustand zB per serieller Schnittstelle oder per LED 
abfragen/aufgeben lassen.
Die einzelnen Interrupts machen nur was minimal zu tun ist, setzten eine 
Boolean und lassen den Prozessor im Main Lop das Passende erledigen.

von Stefan O. (oele22)


Lesenswert?

Die delays werden in meinem Programm hauptsächlich nur bei der 
Initialisierung und dem Willkommensgruß verwendet. Was hat das damit zu 
tun, dass auf dem LCD-Display z.B. die Uhrzeit nun 4
Sekunden lang kontinuierlich anzeigt wird und dann für 6 Sekunden stehen
bleibt? Dies wiederholt sich dann periodisch...

von Karl H. (kbuchegg)


Lesenswert?

>    Ch = UART_Receive(); // Aktuelles Zeichen einlesen

Das blockiert bis vom GPS das nächste Zeichen kommt

Und solange nicht ein kompletter Datensatz korrekt empfangen wird, gibt 
es auch keine Updates.

Ich sagte doch schon: lass dir endlich mal anzeigen, was du eigentlich 
empfängst. Du glaubst es ja nicht, dass man mit Stochern im Nebel nicht 
weiter kommt. Dann musst du es eben auf die harte Tour lernen.

Das wichtigste ist ja immer, dass es eine Wilkommensnachricht gibt :-)

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.