www.mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik Fleury's Uart, wie string empfangen?


Autor: ProblemBär (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Leute,

ich will mit der Uart Lib von Fleury einen String vom PC zum AVR 
schicken. Einzelne Zeichen Funktionieren ach wunderbar, aber ich möchte, 
dass alle Zeichen erst in einen char Array geschrieben werden und das 
dann beispielsweise komplett zurückgegeben wird ( Später natürlich eine 
andere Anwendung). Wie muss ich denn die for-Schleife erweitern, dass 
erst der komplette String ausgegeben wird?
int main(void)
{
    unsigned int c;
  char test[20];
  int i;
  
  /*
     *  Initialize UART library, pass baudrate and AVR cpu clock
     *  with the macro 
     *  UART_BAUD_SELECT() (normal speed mode )
     *  or 
     *  UART_BAUD_SELECT_DOUBLE_SPEED() ( double speed mode)
     */
    uart_init( UART_BAUD_SELECT(UART_BAUD_RATE,F_CPU) ); 
    
    /*
     * now enable interrupt, since UART library is interrupt controlled
     */
    sei();
    
    /*
     *  Transmit string to UART
     *  The string is buffered by the uart library in a circular buffer
     *  and one character at a time is transmitted to the UART using interrupts.
     *  uart_puts() blocks if it can not write the whole string to the circular 
     *  buffer
     */
    //uart_putc('\r');
  i=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: ");
            }
            /* 
             * send received character back
             */
      test[i] = c;
      i++;
      uart_puts(test);




        }
    }
    
}

Irgendwie hab ich voll den Knoten im Hirn und komm nich weiter:(

Autor: ProblemBär (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
hat keiner ne idee?

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

Bewertung
0 lesenswert
nicht lesenswert
Ist doch schon mal ein schöner Ansatz.

Du solltest dir zur Gewohnheit machen, für in sich abgeschlossene
Aufgaben eine eigene Funktion zu machen.

In deinem Fall lautet die Aufgabe: Empfange einen String, wobei
auf den String gewartet werden kann.

Soweit so gut. Aber: Woher weist du eigentlich, dass ein String
zu Ende ist. Nur weil bei einem Aufruf von uart_getc() kein
Character zurückkommt, heist das ja nicht, das deswegen der
String zu Ende ist. Es könnte ja auch sein, dass der Benutzer
am anderen Ende einfach nur langsamer tippt.
-> Du musst dich für eine Strategie entscheiden, mit der
du zweifelsfrei erkennen kannst, dass der String jetzt zu
Ende ist.
Oft wird dazu der Empfang des Zeichens '\n' (Return) benutzt.
Für viele Benutzer ist es mitlerweile zur zweiten Natur geworden
eine Eingabe durch Druck auf 'Return' zu beenden. Und genau
das ist dann für deine Funktion das Kennzeichen, dass der String
zu Ende ist.

Was muss deine Funktion also machen? Formulier das mal
umgangssprachlich

  es muss irgendwo ein character Array geben, in dem
  empfangene Zeichen zwischengespeichert werden können um
  den C-String aus den einzelnen Zeichen aufzubauen

  so muss in einer Schleife auf jeweils den Empfang eines
  Zeichens warten

  War das Zeichen ein '\n', dann ist der Text komplett
  übertragen worden. In guter C-Manier, wird an den bisherigen
  Text im character Array noch ein '\0' angehängt um daraus einen
  gültigen C-String zu machen und die Funktion ist zu Ende.

  War das Zeichen kein '\n', dann wird es ganz einfach an den
  bisherigen Text im character Array angehängt. Das erfordert
  allerdings, dass man weiss, wo denn das letzte Zeichen im
  Array eingefügt wurde -> man braucht eine Variable dafür.

  Je nach Bedarf ist es auch eine gute Idee, das Zeichen über
  die UART wieder zurück zu schicken, damit der Benutzer auch
  sieht was er tippt.

  Wenn du willst, kannst du auch rudimentäre Edit-Funktionalität
  einbauen, um zb. dem Benutzer die Möglichkeit zu geben, mittels
  Backspace wieder zurückzugehen:
     Wird ein '\b' empfangen, so verminderst du die Textzählung um 1
     und gibst die Sequenz '\b', ein Leerzeichen und noch ein '\b'
     aus.

  Wie auch immer, es geht auf jeden Fall in der Schleife innerhalb
  der Funktion weiter. Diese Schleife innerhalb der Funktion kann
  nur durch den Empfang eines '\n' verlassen werden.

Tja. Das wars dann auch schon. Damit hast du eine Funktion, die
auf den Erhalt eines Textes (einer Eingabezeile) wartet. Und die
verwurschtest du dann in deiner main() Schleife weiter.

Autor: Stefan B. (stefan) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Den String solltest du immer mit einem Nullbyte abschliessen.

      test[i] = c;
      i++;
      test[i] = '\0'; // <===

Du solltest nie mehr Zeichen in das Array test reinschreiben als Platz 
reserviert ist.

    if (i < (20-1)) // -1 wg. abschliessendem Nullbyte
    {
      test[i] = c;
      i++;
      test[i] = '\0'; // <===
    }

Im Moment gibst du bei jedem empfangenen Zeichen den String in test aus, 
so weit er bereit gefüllt ist. Schlauer wäre es, den String erst 
auszugeben, wenn das Zeilenendezeichen empfangen wurde oder der String 
"voll" ist.

    if (c == '\n' || i == (20-1))
    {
      uart_puts(test);
      i = 0;          // zurücksetzen für nächsten String
      test[i] = '\0'; // leerer String
    }

Autor: ProblemBär (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
wow danke, echt nett von euch, ich glaub mit den super tipps werd ichs 
hinkriegen;)

Autor: ProblemBär (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
eine frage hätt ich dann doch noch. hab das ganze jetzt mal in meinen 
code eingebaut und es funktioniert auch...aber leider immer nur einmal. 
Ich gebe einen String im terminal ein, dieser wird wie er soll 
verarbeitet, und auch wieder ausgegeben. gebe ich dann den nächsten 
string ein, so wird er nicht mehr verarbeitet, jedoch noch ausgegeben. 
bei der nächsten eingabe passiert dann garnichts mehr:( nicht über die 
merkwürdigen umrechnungen und hin und herschiebereien das wundern, das 
wird alles noch vereinfacht^^ aber wo liegt das problem, dass das 
programm nicht bei jedem neu eingebenen String normal weiterarbeitet? ( 
Die eingegeben Strings haben immer die Länge 64)

Autor: ProblemBär (Gast)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
oh, hier noch der code

Autor: ProblemBär (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
ok, problem gelöst, die spi_init musste in aus der if bedingung 
raus...danke nochmal

Autor: Maik (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo ich möchte jetzt auch nochmal auf die Thematik UART Lib und String 
empfangen zurück kommen.

Ich verwende den Mega32 jedoch ist es mir nicht möglich einen String zu 
empfangen und anschließend auszugeben.
Einzelne Zeichen zu empfangen und senden geht fehlerfrei.

Ich habe dabei die UART LIB von Peter Fleury mit Interupts verwendet und 
zudem den Quellcode aus dem AVR-GCC Tutorial.

Ich würde mich über Tipps freuen.
/* Include Dateien */
#include <stdlib.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/signal.h>
#include <avr/pgmspace.h>

#include "uart.h"

/* CPU Frequenz definieren */
#define F_CPU 16000000UL

/* Baudrate 19200 */
#define UART_BAUD_RATE      19200

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';
}


/* main */
int main(void)
{
  unsigned int c;
  char Line[40];      // String mit maximal 39 zeichen

    /* UART initialisieren*/
    uart_init( UART_BAUD_SELECT(UART_BAUD_RATE,F_CPU) );
    /* Interupts freigeben*/
    sei();

    for(;;)
        {
            // Empfangenes Zeichen speichern
            c = uart_getc();
            if ( c & UART_NO_DATA )
            {
                 //Keine Daten vorhanden
            }
            else
            {
                 //Neue Daten sind vorhanden
                 //Überprüfung auf Fehler
                if ( c & UART_FRAME_ERROR )
                {
                    //FRAMING ERROR festgestellt, z.B. kein Stop Bit vorhanden
                    //uart_puts_P("UART Frame Error: ");
                }
                if ( c & UART_OVERRUN_ERROR )
                {
                    //OVERRUN ERROR festgestellt, z.B. zuvor empfangenes Zeichen konnte
                    //noch nicht verarbeitet werden -> Datenverlust
                    uart_puts_P("UART Overrun Error: ");
                }
                if ( c & UART_BUFFER_OVERFLOW )
                {
                  //BUFFER OVERFLOW festgestellt, z.B. zuvor empfangenes Zeichen konnte
                    //noch nicht gelesen werden -> Datenverlust
                  uart_puts_P("Buffer overflow error: ");
                }
                 //Empfangenes Zeichen verarbeiten
                uart_putc( (unsigned char)c );
                uart_gets( Line, sizeof( Line ) );
                uart_putc( (unsigned char) sizeof( Line ) );
                uart_puts( Line );
            }
        }
}

Gruß
Maik

Autor: Stefan Ernst (sternst)
Datum:

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

Dein Problem ist, dass die Funktion uart_getc der Fleury-Lib eben 
nicht auf ein Zeichen wartet.

Autor: Maik (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Mh okay da ist etwas dran.
Jedoch dachte ich ist diese Lib Interuptgesteuert?
Oder irre ich da?

Wenn Nein, dann würde mich interessieren ob und wie ich diese Lib 
anpassen muss oder ob ich dann selber mir ne funktion uart_getc() 
schreiben muss....

Denn eigentlich ist diese Lib ja schon ganz net.

Autor: Stefan Ernst (sternst)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Maik wrote:

> Jedoch dachte ich ist diese Lib Interuptgesteuert?

Eben, deshalb wartet die Funktion ja auch nicht. Wenn die Funktion immer 
so lange warten würde, bis ein Zeichen da ist, welchen Sinn hätte dann 
der Interrupt gesteuerte Empfang?

> Wenn Nein, dann würde mich interessieren ob und wie ich diese Lib
> anpassen muss oder ob ich dann selber mir ne funktion uart_getc()
> schreiben muss....

Es wäre sinnvoller, die Funktion uart_gets anzupassen.

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

Bewertung
0 lesenswert
nicht lesenswert
Maik wrote:

> Wenn Nein, dann würde mich interessieren ob und wie ich diese Lib
> anpassen muss oder ob ich dann selber mir ne funktion uart_getc()
> schreiben muss....

Wozu?
Das lustige ist:
In deiner main() hast du ein perfektes Beispiel dafür, wie man uart_getc 
aus der Fleury Lib korrekt einsetzt.

Vielleicht einfach mal die Beispiele, die mit der Lib kommen, studieren 
und abklären ob deine Vorstellungen darüber wie die Lib zu benutzen ist 
richtig sind, ehe man drangeht eine gut funktionierende Lib 
umzuschrieben :-)

Autor: Maik (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
So jetzt hab ich mich nochmal mit der Lib beschäftigt.
Die empfangen Zeichen hängen ja in einem Ringpuffer und die uart_getc 
holt sich die zeichen aus diesem puffer. Dies geschieht ja bei jedem 
Durchlauf der FOR-Schleife im main. So und dann wird ja auch direkt 
überprüft ob jetzt ein Zeichen da ist oder ein Fehler aufgetreten ist 
oder nicht.
Soweit so gut.

Wenn ich also jetzt einen String empfangen möchte muss ich mich ans Ende 
der ELSE Funktion hängen, da dann ja gewährleistet ist, das ein Zeichen 
korreckt empfangen wurde und verfügbar ist zur weiterverarbeitung.

jetzt habe ich dann meine uart_gets() Funktion dahingehend umgebaut.
Also diese While schleife weg und durch if ersetzt.
Hier jetzt nochmal der Teil in der main
...
               //Empfangenes Zeichen verarbeiten
                uart_gets( Line, sizeof( Line ), (unsigned char)c );

            }
            if (flag == 1)
            {
        flag=0;
        //uart_puts(Line);
        uint8_t i=0;

        while (i < sizeof (Line))
        {
          uart_putc(Line[i]);
          i++;
        }
            }
        }
}

und hier die Funktion uart_gets()
void uart_gets( char* Buffer, uint8_t MaxLen, unsigned char c)
{
  uint8_t StringLen = 0;

                  // Warte auf und empfange das nächste Zeichen

                  // Sammle solange Zeichen, bis:
                  // * entweder das String Ende Zeichen kam
                  // * oder das aufnehmende Array voll ist
  if( c != '\n' && StringLen < MaxLen - 1 )
  {
    *Buffer++ = c;
    StringLen++;
    //uart_putc((unsigned char)c );
    //uart_puts("\n");
    //uart_puts("Zeichen empfangen\n");

  }
  if( c == '\n')
  {
                    // Noch ein '\0' anhängen um einen Standard
                    // C-String daraus zu machen
      *Buffer = '\0';
      flag=1;
      //uart_putc((unsigned char)c );
      //uart_puts("\n");
      //uart_puts("Ende des Strings\n");
  }

}

Soweit ich das jetzt testen konnte führt er diese funktion auch richtig 
aus.
Jedoch habe ich das gefühl, das der string nicht richtig in das Array 
LINE wandert.
Ebenso glaube ich hab ich noch nen Knoten im Kopf wie ich das Array dann 
wieder an den PC zurücksenden kann.
Ich habe zum testen einfach mal jedes Feld des Arrays mit uart_getc() 
ausgegeben, jedoch kommt da alles andere an als das was ich gesendet 
habe.

Achso, die Variable flag ist
volatile uint8_t flag = 0;

Würde mich um weitere Tipps sehr freuen.

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

Bewertung
0 lesenswert
nicht lesenswert
Das ist aber ziemlich umständlich zu benutzen :-)

Warum lässt du nicht einfach uart_gets im Prinzip so wie sie ist, und 
jubelst ihr einen Ersatz für uart_getc unter, der tatsächlich auf das 
Eintreffen eines Zeichens wartet? Ist doch mit der uart_getc aus der Lib 
kein Problem sowas zu machen.
uint8_t uart_getc_wait()
{
  unsigned int c;

  do {
    c = uart_getc();
  } while( c == UART_NO_DATA );

  return (uint8_t)c;
}

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

  NextChar = uart_getc_wait();         // 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_wait();
  }

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


> Jedoch habe ich das gefühl, das der string nicht richtig in das
> Array LINE wandert.

Das ist richtig. So wie uart_gets momentan geschrieben ist, ist 
uart_gets darauf angewiesen, dass es die Kontrolle behält, während sie 
einen String empfängt. WEnn du das so umändern möchtest, dass das 
Empfangen eines Strings komplett im Hintergrund ohne aktives Warten 
erfolgt, dann geht das so nicht. Die Funktion uart_gets müsste dazu 
wissen, wo das nächste Zeichen im Buffer abzulegen ist. Und das wird ihr 
in der Argumentliste nun mal nicht mit übergeben.

Autor: Maik (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Vielen Dank Karl heinz, jetzt funktioniert es.
Ich denke die völlig autake lösung werde ich ein anderes mal anstreben.

Vielleicht noch für die Nachwelt.
Wenn interesse besteht könnte man diese Variante auch ins AVR-GCC Tut 
übernehmen.

Autor: Sven Bayer (mainframeosx)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Kann hier mal jemand einen Kompletten simple source erstellen, ich 
werkle seit Tagen rum und bekomme alles (HIN) aber nicht das was ich 
will. Ich stehe hier gerade voll auf dem schlauch.

Beitrag #3986001 wurde von einem Moderator gelöscht.
Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Sven Schwiecker schrieb:
> Kann hier mal jemand einen Kompletten simple source erstellen, ich
> werkle seit Tagen rum und bekomme alles (HIN) aber nicht das was ich
> will. Ich stehe hier gerade voll auf dem schlauch.

Was gefällt dir denn an der Lösung von 2009, 2 Postings weiter oben, 
nicht?

Beitrag #3986011 wurde vom Autor gelöscht.
Beitrag #3986019 wurde vom Autor gelöscht.
Autor: Sven Bayer (mainframeosx)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Sie gefällt mir ganz gut, jedoch wo setzte ich uart_getc_wait und 
uart_gets im source code nun ein?

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

Bewertung
0 lesenswert
nicht lesenswert

char inLine[40];

int main()
{
....

  while( 1 ) {
    uart_gets( inLine, sizeof( inLine ) );

    uart_puts( "Hi. Ich hab verstanden: \"" );
    uart_puts( inLine );
    uart_puts( "\"\r\n" );
  }
}

Autor: Sven Bayer (mainframeosx)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich habe das Problem gelöst, mein Client hatte kein Zeilenende also \r 
oder \n gesendet, da wartet der Controller ewig.

: Bearbeitet durch User

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.