Forum: Mikrocontroller und Digitale Elektronik UART String empfangen


von wojtek (Gast)


Lesenswert?

Hallo zusammen ich habe ein Problem um einen String zu empfangen und 
brauche Hilfe.
Habe meinen µC AVR MT128 mit Hyperterminal verbunden, ich kann Zeichen 
senden  und string senden.
Ein einzelnes Zeichen kann ich auch empfangen aber ich muss ein String 
empfangen können. Diese string möchte ich dann wider an den uart senden 
können.
Eigentlich möchte ich GPS Daten empfangen um sie zu vergleichen. wenn 
die Daten übereinstimmen soll dann ein 433 MHZ Sender eine  Schranke 
öffnen.

was ich habe ist folgendes  empfangen von einzelnen zeichen

  unsigned char test=uart_getc();    // zeichen wird eingelesen
      if (test)
      {
      uart_putc(test);   // zeichen wird ausgegeben
      }

ich muss zugeben ich bin ein Anfänger und währe froh für ein bisschen 
Hilfe.

von Tim T. (tim_taylor) Benutzerseite


Lesenswert?


von spess53 (Gast)


Lesenswert?

Hi

>Eigentlich möchte ich GPS Daten empfangen um sie zu vergleichen. wenn
>die Daten übereinstimmen soll dann ein 433 MHZ Sender eine  Schranke
>öffnen.

Das Ereignis wird nach mehreren Stunden Wartezeit an der gleichen Stelle 
bestimmt auch mal eintreten. Mit C kann ich dir nicht helfen. Aber mir 
deinem Ansatz wird es nicht so funktionieren, wie du denkst.

MfG Spess

von Wojtek S. (wojtek)


Lesenswert?

wie meinst du das ?
ich bekomme NEMA Daten geliefert und diese sind eindeutig.
ich will einen vergleich machen und wenn die werte übereinstimmen dann 
soll der 433 Mhz Sender das Signal senden um die Schranke zu öffnen, 
wenn die Schranke dann passiert wurde und das Auto hat sich bewegt dann 
ändern sich auch die NEMA Daten und der vergleich stimmt nicht mehr und 
der Sender sendet nicht mehr.

wieso soll das nicht gehen verstehe ich nicht wäre nett wen du das 
genauer beschreiben würdest.

von JetztAber (Gast)


Lesenswert?

Weil es Gleichheit nicht gibt. Die Koordinaten beinhalten ein Rauschen, 
abhaengig von Wetter, Tageszeit, Satelliten, usw. Dh auch wenn du vor 
dem Tor stehst, so ist die koordinate einmal daneben, dann dahinter usw. 
Der Standardansatz wird sein, mit einem Radius, wo man innerhalb sein 
muss zu arbeiten.

von Karl (Gast)


Lesenswert?

Ich knüpf hier mal an... Mich würde es interessieren, wie man einen 
gesendeten String korrekt puffert und mit einem Befehlsrepertoir 
vergleicht in C++. Wie sicher ist es bei so einer seriellen Verbindung, 
dass bei korrekter Beschaltung des Quarzes und richtigen Einstellungen 
zb bei max 115kbauds. Können da einzelne Zeichen verloren gehen, wenn 
man die Zeichen im Interrupt in ein Array puffert? Macht man das mit 
einem Array? Oder gibt  es da bessere Lösungen um gleich den stream der 
UART mit einem String im flash zu vergleichen?
Danke und Gruß
Karl

von spess53 (Gast)


Lesenswert?

Hi

>wie meinst du das ? ich bekomme NEMA Daten geliefert und diese sind >eindeutig.

Das heisst, selbst wenn du deinene GPS-Empänger nicht bewegst, wirst du 
trotzdem ständig andere Koordinaten empfangen.

MfG Spess

von Karl H. (kbuchegg)


Lesenswert?

Karl wrote:
> Ich knüpf hier mal an... Mich würde es interessieren, wie man einen
> gesendeten String korrekt puffert und mit einem Befehlsrepertoir
> vergleicht in C++.

Indem man die Aufgaben aufteilt.
Du hast 2 voneinander unabhängige Themenkreise
zum einen muss ein String empfangen werden
zum anderen muss dieser String ausgewertet werden

String empfangen kann man im Grunde genauso machen, wie das in dem 
Tutoriallink weiter oben angegeben ist. In C++ würde man als 
Speicherfläche nicht unbedingt ein char Array nehmen, sondern mit einer 
String Klasse, zb std::string arbeiten, aber das Prinzip ist haarscharf 
dasselbe

Wie man die String Auswertung macht, hängt davon ab, wie komplex die 
definierte Komamndo-Sprache gestaltet wird und auch wie umfangreich 
diese ist.
Im einfachsten Fall ist das einfach nur ein Vergleich mit vorgegebenen 
Schlüsselwörtern und entsprechenden Aktionen dazu. Im komlpiziertesten 
Fall könnte man Techniken aus dem Compilerbau dazu benutzen um den 
empfangenen String in Einzelteile zu zerlegen und die Bedeutung des 
Empfangenen zu entschlüsseln.


> Wie sicher ist es bei so einer seriellen Verbindung,
> dass bei korrekter Beschaltung des Quarzes und richtigen Einstellungen
> zb bei max 115kbauds. Können da einzelne Zeichen verloren gehen, wenn
> man die Zeichen im Interrupt in ein Array puffert?

Da den eigentlichen Empfang eines einzigen Zeichens ja die Hardware, 
unabhängig von deinem Programm macht, geht das schon mal relativ sicher 
gut. Störungen am Kabel mal aussen vor gelassen.

In deinem Programm muss nur sicher gestellt sein, dass du die Zeichen 
nur rechtzeitig abholst. Mit einer Interrupt Steuerung ist das auch kein 
Problem.

Bleibt nur noch: In deiner Interrupt Routine musst du die Zeichen 
irgendwo Zwischenspeichern. Du hast dafür keine endlose Speicherfläche 
zur Verfügung, also muss auch sichergestellt sein, dass die
ertens ausreichend gross dimensioniert ist
das Hauptprogramm auch eine Chance hat, den Buffer wieder mal 
auszuleeren

> Macht man das mit
> einem Array?

Kann man machen. In C++ und bei einem einigermassen potenten µC könnte 
man auch einen std::vector oder einen std::string benutzen. Die künmmern 
sich dan selbsttätig darum, dass der Bufferspeicher vergrößert wird, 
falls notwendig.

> Oder gibt  es da bessere Lösungen um gleich den stream der
> UART mit einem String im flash zu vergleichen?

Keine gute Idee.
Aufgabenteilung ist eines der wichtigsten Prinzipien in der 
Programmierung. Nur dadurch ensteht der Bausteincharakter von 
Bibliotheken. Der Empfang eines Strings hat erst mal nichts, aber auch 
gar nichts damit zu tun, was du mit dem String weiter machen möchtest. 
Also vermisch die Dinge auch nicht.

von Karl (Gast)


Lesenswert?

@Karl Heinz:
Vielen Dank für die sehr gute Beschreibung.
Das mit der Aufgabenteilung habe ich soweit verstanden, allerdings habe 
ich noch probleme zu verstehen, was du mit den Namespaces meinst. std 
(using namespace std) habe ich mal benutzt um consolenprogramme zu 
schreiben und um die Standardein und -ausgabe zu lesen und schreiben, 
mehr aber leider noch nicht.

Da mein "Befehlssatz" eher mager (maximal 6-8Zeichen) sein soll, und ich 
mich mit Arrays besser auskenne, als mit Namespaces, bleibt mir erstmal 
nix anderes übrig, als das mit Arrays zu erschlagen.

Nehmen wir mal an, ich empfange in der ISR die Zeichen und ich 
beschreibe jedesmal ein char array[i]=UDR, welcher vorher mit "\0" 
gefüllt ist und inkrementiere i solange bis entweder enter gedrückt wird 
oder i überläuft...
Dann hätte ich doch schon mal mein Befehl gepuffert? und zwar in einem 
nullterminierten char array, also ein String?
Und in der main könnte ich dann mein string mit meinem 
"Befehlsrepertoir" vergleichen mit zb stricmp()?
vergleicht die bibfunktion stricmp() denn ein Array mit 
Nullterminierung, mit einem "xxxxxx"string?
Würde mich über jede Hilfe und jeden Tip sehr freuen
Vielen Dank nochmal, lg
Karl

von Karl H. (kbuchegg)


Lesenswert?

Karl wrote:

> Nehmen wir mal an, ich empfange in der ISR die Zeichen und ich
> beschreibe jedesmal ein char array[i]=UDR, welcher vorher mit "\0"
> gefüllt ist und inkrementiere i solange bis entweder enter gedrückt wird
> oder i überläuft...

Yep.

> Dann hätte ich doch schon mal mein Befehl gepuffert? und zwar in einem
> nullterminierten char array, also ein String?

Genau

> Und in der main könnte ich dann mein string mit meinem
> "Befehlsrepertoir" vergleichen mit zb stricmp()?
> vergleicht die bibfunktion stricmp() denn ein Array mit
> Nullterminierung, mit einem "xxxxxx"string?

Klingt doch nach einem guten Plan.

Das hier könnte dir noch ein paar Ideen liefern
http://www.mikrocontroller.net/articles/FAQ#Funktionszeiger

von Helmut L. (helmi1)


Angehängte Dateien:

Lesenswert?

Hier hast du mal ein Beispiel wie man so was macht

Die Funktion PutChar sendet ein Zeichen aus und die Funktion GetChar 
liest ein Zeichen ein
Die Routine CharCount Gibt zurueck ob ueberhaupt ein Zeichen zum 
einlesen da ist

Der empfangene String muss mit einem CR abgeschlossen sein und steht 
anschliessend in szStr zur weiterverarbeitung zu verfuegung.

Wenn ein kompleter String eingelesen wurde gibt die Funktion eine 1 
zurueck sonst eine 0

Gruss Helmi

von Frank G. (dg1sbg)


Lesenswert?

Karl heinz Buchegger wrote:
> Karl wrote:
>> Ich knüpf hier mal an... Mich würde es interessieren, wie man einen
>> gesendeten String korrekt puffert und mit einem Befehlsrepertoir
>> vergleicht in C++.
>
> Indem man die Aufgaben aufteilt.
> Du hast 2 voneinander unabhängige Themenkreise
> zum einen muss ein String empfangen werden
> zum anderen muss dieser String ausgewertet werden

Exakt. Und das mit dem String empfangen geht ganz gut mit ein paar 
fertigen Libraries, dies es gibt - z.B. 
http://homepage.hispeed.ch/peterfleury/avr-software.html .

Viel Erfolg!

Gruß,
   Frank

von Wojtek S. (wojtek)


Lesenswert?

Hallo habe immer noch Probleme mit dem empfangen von Strings.
Ich benutze die Funktion in einer Header

/* Zeichen empfangen */
uint8_t uart_getc(void)
{
    while (!(UCSRA & (1<<RXC)))   // warten bis Zeichen verfuegbar
        ;
    return UDR;                   // Zeichen aus UDR an Aufrufer 
zurueckgeben
}

void uart_gets( char* Buffer, uint8_t MaxLen )
{
  uint8_t NextChar;
  uint8_t StringLen = 0;

  NextChar = uart_getc();         // Warte auf und empfange das nächste 
Zeichen

                                  // Sammle solange Zeichen, bis:
                                  // * entweder das String Ende Zeichen 
kam
                                  // * oder das aufnehmende Array voll 
ist
  while( NextChar != '\n' && StringLen < MaxLen - 1 ) {
    *Buffer++ = NextChar;
    StringLen++;
    NextChar = uart_getc();
  }

                                  // Noch ein '\0' anhängen um einen 
Standard
                                  // C-String daraus zu machen
  *Buffer = '\0';
}

in der Main rufe ich
           char Line[10];      // Array vom Typ int
           uart_gets( Line, sizeof( Line ) / sizeof( Line[0] ) );
nun will ich den String nachdem ich 10 Zeichen bzw enter gedrückt habe 
wider ausgeben auf den Heiperterminal und es geht nicht.
ich benutze dafür
                   uart_puts(Line);

bei mir funktioniert das nicht was mache ich falsch

die uart_puts sieht so aus ist in einer Header

int uart_putc(unsigned char c)
{
  while (!(UCSR1A & 0b00100000));  //waiting until buffer is ready to 
receive

  UDR1 = c;            // sende zeichen
  return 0;
}

void uart_puts (char *s)
{
    while (*s)
    {
        uart_putc(*s);
        s++;
    }
}

wenn ich einen string senden will z.b. mit
uart_puts("hallo welt"); habe ich keine Probleme

von Karl H. (kbuchegg)


Lesenswert?

Wojtek Szopieraj wrote:

Hier gehts auf ...
> uint8_t uart_getc(void)
> {
>     while (!(UCSRA & (1<<RXC)))   // warten bis Zeichen verfuegbar
>         ;
>     return UDR;                   // Zeichen aus UDR an Aufrufer
> zurueckgeben
> }

also UDR

Während hier gehts um

> int uart_putc(unsigned char c)
> {
>   while (!(UCSR1A & 0b00100000));  //waiting until buffer is ready to
> receive
>
>   UDR1 = c;            // sende zeichen
>   return 0;
> }

also UDR1

Hast du wirklich 2 unabhängige USART im Einsatz?

von Wojtek S. (wojtek)


Lesenswert?

kleiner Fehler beim kopieren,
benutze nur den UCSR1A
uint8_t uart_getc()
{
  if (UCSR1A & 0b10000000)  //if there is unreaded data
    return UDR1;
  else            //no unreaded data
    return 0;
}


trotzdem weiß ich nicht weiter.
kann es daran liegen dass das Programm in einer endlos- schleife läuft 
und dass wenn ich eine Zeichenkette eingeben will de µC dass gar nicht 
merkt ?

von Karl H. (kbuchegg)


Lesenswert?

Wojtek Szopieraj wrote:
> kleiner Fehler beim kopieren,
> benutze nur den UCSR1A
> uint8_t uart_getc()
> {
>   if (UCSR1A & 0b10000000)  //if there is unreaded data
>     return UDR1;
>   else            //no unreaded data
>     return 0;
> }
>

Diese uart_getc kann aber mit dem uart_gets von weiter oben nicht 
funktionieren.

Sollen wir noch länger weiterraten oder bist du gewillt dein komplettes 
Programm mal zu posten?

von Wojtek S. (wojtek)


Angehängte Dateien:

Lesenswert?

vielleicht sieht man jetzt besser was ich falsch mache

von Karl H. (kbuchegg)


Lesenswert?

1
uint8_t uart_getc()
2
{
3
  if (UCSR1A & 0b10000000)  //if there is unreaded data
4
    return UDR1;
5
  else            //no unreaded data
6
    return 0;
7
}
8
9
 
10
void uart_gets( char* Buffer, unsigned int MaxLen )
11
{
12
  unsigned int NextChar;
13
  unsigned int StringLen = 0;
14
  NextChar = uart_getc();         // Warte auf und empfange das nächste Zeichen

die uart_getc wartet nicht auf ein Zeichen, sondern kehrt sofort zurück. 
Wobei ein Return Wert von 0 angibt, dass kein Zeichen vorliegt.
Ich sehe aber in der uart_gets nichts, was tatsächlich auf ein Zeichen 
warten würde. Im Gegenteil: Der Kommentar deutet darauf hin, dass 
uart_gets auf die Funktion uart_getc baut, dass diese auf ein Zeichen 
wartet.

Mit anderen Worten: die uart_gets füllt in Windeseile den Buffer mit 0 
Bytes an und kehrt zurück. uart_gets liefert damit einen Leerstring.

Die uart_getc, die du ursprünglich gepostet hast, hätte auf ein Zeichen 
gewartet. Warum hast du sie abgeändert?

von Wojtek S. (wojtek)


Lesenswert?

vielen dank es geht, jetzt habe ich es auch gesehen dass ich ein was 
übergebe wenn kein Zeichen ankommt, ich bin ein Anfänger und aus Fehlern 
lernt man :)

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.