mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik Verzweifle daren einen String mit UART einzulesen


Autor: mws (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Gemeinde,

ich hab da mal ein Problem, bei dem ich langsam verzweifle.

Ich möchte einen Komandoparser in meinen Mega32 bauen und dazu zunächst 
einmal einen String über die ser. Schnittstelle einlesen. Ich verwende 
Peter Fleury's uart.c um die Daten zu senden bzw zu empfangen.

Da in seiner Lib keine funktion enthalten ist um Strings zu lesen habe 
ich folgende Routine hinzugefügt:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/pgmspace.h>

#include "uart.h"

/* define CPU frequency in Mhz here if not defined in Makefile */
#ifndef F_CPU
#define F_CPU 16000000UL
#endif

/* 38400 baud */
#define UART_BAUD_RATE      38400      


void uart_gets( char* Input )
{
  char c = uart_getc();
  uart_putc( c );   // und gleich wieder zurückschicken, damit
                    // der Benutzer auch was sieht

  while( c != '\r' ) {
    *Input = c;
    Input++;
    c = uart_getc();
    uart_putc( c );
  }
  *Input = '\0';
}

int main()
{

  uart_init( UART_BAUD_SELECT(UART_BAUD_RATE,F_CPU) ); 
  
  sei();

  uart_puts("Hier geht es los\r\n>>");

  char Buffer[50];

  while( 1 ) {

    uart_gets( Buffer, 50);   // Auf eine Zeile vom Benutzer warten

    //
    // Testweise die komplette Zeile zurückschicken, so wie
    // sie vom µC empfangen wurde
    //
    uart_puts( "Ich habe verstanden : " );
    uart_puts( Buffer );
    uart_putc( '\n' );

    // war die Eingabe vom Benutzer der Text 'Test'
    if( strcmp( Buffer, "Test" ) == 0 ) {
      // Wenn ja, dann begrüsse ihn
      uart_puts( "Hallo Test\n" );
      uart_puts( "Wie gehts\n" );
    }
  }
}


Leider funktioniert das nicht so wie gedacht sondern es passieren zwei 
Dinge:

1. der Prompt wird angezeigt:
Hier gehts los
>>

2. bei der Eingabe werden die Buchstaben im Terminalfenster ausgegeben. 
Wenn ich Enter drücke springt die Anzeige an den Anfang der Zeile. Aber 
es wird nichts ausgegeben.

3. Wenn ich erneut Buchstaben eingebe werden diese wieder im Terminal 
dargestellt. Wenn ich dann zum zweiten Mal Enter drücke scheint sich der 
Controller zu reseten, denn ich bekomme wieder den Prompt
Hier geht es los
>>
angezeigt.

Kann mir mal einer einen Tipp geben, was ich da ggf. falsch mache?

Es macht übrigens auch keinen untershcied, ob ich mit Int arbeite 
(welches in der lib ja im oberen Byte eventuelle Fehler anzeigt) und den 
unteren Teil für den String nutze oder ob ich (wie oben) direkt mit char 
arbeite.

Gruß

mws

Autor: MWS (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
He, he, hallo mws :D

Du hast das hier durchgearbeitet ?

http://www.mikrocontroller.net/articles/AVR-GCC-Tu...

Denk' mal es ist nicht so perfekt, void uart_gets( char* Input ) mit 
einem Argument  zu definieren, aber mit 2 Argumenten aufzurufen:

uart_gets( Buffer, 50);

Gibt's da nicht Mecker vom Compiler ?

Interessant ist auch laut Tutorial:"...daher mit einem Return ('\n') 
abgeschlossen wird."

Was hat dann das hier in Deinem Quelltext zu bedeuten: while( c != '\r' 
)

Autor: Ben ___ (burning_silicon)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
wohl weil eigentlich immer CR+LF gesendet wird... \r\n oder ascii 13,10

Autor: Michael Schneider (mws)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi,

also ich hab die Variante mit dem MAXLEN natürlich auch ausprobiert aber 
wenn ich die verwende wartet wie Endlosschleife in main nicht bis ein 
kompletter String eingegeben ist sondern es läuft immer die "Ich habe 
verstanden:" Anzeige durch und man kann gar nichts eingeben.

Das ich auf '\r' prüfen muss weil mein Terminalprogramm scheinbar kein 
'\n' sendet hat auch ne Weile gedauert.

Das Gleiche Problem tritt aber auch auf, wenn ich als Zeilenende z.B das 
Semikolen verwende. :-(

mws

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
mws schrieb:
> Hallo Gemeinde,
>
> ich hab da mal ein Problem, bei dem ich langsam verzweifle.
>
> Ich möchte einen Komandoparser in meinen Mega32 bauen und dazu zunächst
> einmal einen String über die ser. Schnittstelle einlesen. Ich verwende
> Peter Fleury's uart.c um die Daten zu senden bzw zu empfangen.

Dann sieh dir das Demo vom Peter an oder lies dir wenigstens die Doku 
dazu durch.
uart_getc ist kein wartendes getc sondern kehrt auch dann zurück, wenn 
kein Zeichen vorliegt.

Autor: Michael Schneider (mws)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi,

ich hätte vielleicht nicht bis 3 Uhr hantieren sollen :-)
uart_getc ist kein wartendes getc sondern kehrt auch dann zurück, wenn
kein Zeichen vorliegt.
Genau das ist das "Problem" gewesen.

Ich hab die Lösung, die man mit Peters Lib benötigt mal angehängt:
/*************************************************************************
Function: uart_gets()
Purpose:  return array of char
Input:    Pointer to the array
      Len of the Array
      The charater used for end character
Returns:  none
**************************************************************************/
void uart_gets( char* input, char maxlen, char cr )
{
  unsigned int c;
  unsigned char strlen = 0;

    for(;;)
    {
        /*
         * Get received character from ringbuffer
         * uart_getc() returns in the lower byte the received character and 
         * in the higher byte (bitmask) the last receive error
         * UART_NO_DATA is returned when no data is available.
         *
         */
        c = uart_getc();
        if ( c & UART_NO_DATA )
        {
            /* 
             * no data available from UART 
             */
        }
        else
        {
            /*
             * new data available from UART
             * check for Frame or Overrun error
             */
            if ( c & UART_FRAME_ERROR )
            {
                /* Framing Error detected, i.e no stop bit detected */
                uart_puts_P("UART Frame Error: ");
            }
            if ( c & UART_OVERRUN_ERROR )
            {
                /* 
                 * Overrun, a character already present in the UART UDR register was 
                 * not read by the interrupt handler before the next character arrived,
                 * one or more received characters have been dropped
                 */
                uart_puts_P("UART Overrun Error: ");
            }
            if ( c & UART_BUFFER_OVERFLOW )
            {
                /* 
                 * We are not reading the receive buffer fast enough,
                 * one or more received character have been dropped 
                 */
                uart_puts_P("Buffer overflow error: ");
            }

            uart_putc( c );   // und gleich wieder zurückschicken, damit
                    // der Benutzer auch was sieht
      
            if (c != cr && strlen <= maxlen-1)
            {
               strlen++;
               *input = c;
               input++;
            }
            else
           {
               *input='\0';
               return;
          }
       }
   }
}/* uart_gets */

Autor: Zwölf Mal Acht (hacky)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Je nachdem woher ein String kommt, kann man sich's einfacher machen 
anstelle eines Null-terminierten Strings einen mit der Laenge am Anfang 
zu verwenden.

Autor: Ben ___ (burning_silicon)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
dabei gibts dann wieder andere probleme, z.b. wenn während der 
übertragung ein zeichen verloren geht. ich bevorzuge bei textübertragung 
daher die variante mit endmarkierung. das gibt zwar auch probleme wenn 
die endmarkierung verloren geht, aber wenn du 200 zeichen überträgst 
(davon 199 zeichen nutzdaten, eines länge oder endmarke) ist bei der 
endmarkierung-lösung nur das letzte zeichen kritisch. der controller 
kann auch ggf. sofort anhand einer prüfsumme feststellen, daß es einen 
übertragungsfehler gab, während man bei einer vorgegebenen länge erst 
auf ein timeout warten muß. großer nachteil: funktioniert nicht bei 
unbekannten binären daten, weil das als endmarkierung verwendete zeichen 
hier auch in den nutzdaten vorkommen kann. ohne umkodierung (entfernen 
des endmarkierungs-zeichen aus den nutzdaten) gehts hier nur mit 
bekannter länge.

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.