Forum: Compiler & IDEs anwendung uart_getc() von fleury


von Newbie (Gast)


Lesenswert?

Guten Abend!

Kennt jmd die UART Library von Peter Fleury genauer? Ich habe jetzt 
einige Versuche unternommen, aber ich schaff es einfach nicht die uart 
einzulesen und die eingabe als String weiterzuverarbeiten.
Die Funktion uart_getC() gibt ja auch einen Wert vom Typ unsigned int 
zurück.

Was ich nicht ganz Verstehe ist, bei dem zugehörigen Testprogramm wird 
einmal die UART mit c = uart_getc(); eingelesen, und später wieder mit 
uart_putc( (unsigned char) c); wieder ausgegeben. Wenn ich aber versuche 
selbst c umzuwandeln und in eine Variable zu speichern bekomme ich immer 
Fehlermeldungen ( error: incompatible types in assignment).
der Versuch schaut so aus:

eingabe = (unsigned char) c;

Ich möchte eigentlich einen String über die UART empfangen und 
auswerten.

Wer könnte mir hier weiterhelfen? Ich verstehe das ganze sowieso nicht 
ganz. Ich lade das UART Testprogramm von Fleury in den Controller und 
schicke über ein Terminalprogramm zum Beispiel "Test" rein und es kommt 
auch wieder "Test" zurück. Aber von uart_getc() wird doch ein Integer 
übergeben? Der kann doch maximal einen Buchstaben darstellen??
Sorry, bin noch ein wenig neu auf dem Gebiet und steh ein wenig aufm 
Schlauch...

von Karl H. (kbuchegg)


Lesenswert?

Nein.
Der Grund warum in C alle getc Funktionen (und auch
uart_getc gehört dazu) einen anderen Return Typ als
char haben, liegt darin, dass diese Funktionen
* alle char die möglich sind
* einen zusätzlichen Wert für EOF
liefern können müssen.

Würden die xxxxgetc Funktionen nur einen Return Typ
von char haben, dann könnten sie dich nicht über
EOF (End of File) informieren.

Das ist alles. Der Return Wert kann, sofern er nicht
EOF ist (und bei einer uart_getc wird EOF wohl auch
nicht auftreten), problemlos in einen char gecastet
werden und auch als solcher weiterverarbeitet werden.

von Karl H. (kbuchegg)


Lesenswert?

> Wenn ich aber versuche
> selbst c umzuwandeln und in eine Variable zu speichern bekomme ich immer
> Fehlermeldungen ( error: incompatible types in assignment).
> der Versuch schaut so aus:
>
> eingabe = (unsigned char) c;
>
> Ich möchte eigentlich einen String über die UART empfangen und

Wenn der Compiler die Fehlermeldung
incompatible types
ausgibt, denkst du nicht, dass dann die beteilgten Datentypen
interessant wären?

Also: Welchen Datentyp hat den nun eingabe?

von Karl H. (kbuchegg)


Lesenswert?

Und bevor wir weiterraten, denk auch mal
über Folgendes nach:

> Ich möchte eigentlich einen String über die UART empfangen und
> auswerten.

Woher weist du denn, dass der String zu Ende ist?
Was ich meine ist: Wenn da jetzt ein Haufen Zeichen
über die UART hereinkommt, woran erkennst du dass
ein String zu Ende ist und ein neuer anfängt?

Oft benutzt man dazu ein spezielles Zeichen, zb Return.

Dann funktioniert das dann ja im Prinzip so
1
  char Eingabe[100];
2
  int Count;
3
  char c;
4
5
  Count = 0;
6
  c = uart_getc();
7
  while( c != '\n' ) {
8
    Eingabe[Count++] = c;
9
    c = uart_getc();
10
  }
11
  Eingabe[Count] = '\0';

(ohne Fehlerprüfung zwecks Einfachheit. Im realen Code
solltest du natürlich prüfen ob Count nicht zu gross wird).

Also:
  Zeichen wird von der UART gelesen
  Solange dieses Zeichen nicht das 'End Of String' Zeichen ist
     Zeichen im String speichern
     nächstes Zeichen lesen

  String laut C Kovention fertigstellen, indem mit einem
  \0 abgeschlossen wird.


von Rolf Magnus (Gast)


Lesenswert?

> eingabe = (unsigned char) c;

Von welchem Typ sind eingabe und c? Warum unsigned char (Der Typ für 
Zeichen ist char)?

von Peter Fleury (Gast)


Lesenswert?

In der Doku zu meiner Lib steht beschrieben wieso ich einen unsigned int 
als return Wert von uart_getc() vorgesehen habe und wie dieser 
Return-Wert auszuwerten ist.

Bei uart_putc() habe ich bewusst unsigned char vorgesehen, damit man 
auch binäre Werte (bytes) verschicken kann.

von Newbie (Gast)


Lesenswert?

Also, hier bin ich wieder.

Hab mir aus euren Anregungen folgenden Code gebastelt:

int main(void)
{
    unsigned int c;
    char Eingabe[10];
  int Count;
  DDR_LED |= (1<<LED1);

    uart_init( UART_BAUD_SELECT(UART_BAUD_RATE,F_CPU) );
    sei();
    for(;;)
    {
        Count = 0;
      c = uart_getc();
    if( c != UART_NO_DATA )
    {
      while( c != UART_NO_DATA )
        {
        Eingabe[Count++] = c;
          c = uart_getc();

        }
      Eingabe[Count] = '\0';


         if (Eingabe == "ein")
      {
        PORT_LED |= (1<<LED2);
        uart_puts("ok");
      }

      if (Eingabe == "aus")
      {
        PORT_LED &= (0<<LED2);
        uart_puts("ok");
      }

      uart_puts(Eingabe);
    }


  }
}

(wie erstellt man übrigens so ein weißes Feld mit Code wie beim Eintrag 
von H.Buchegger?)

Ich will per Befehl eine LED ein oder ausschalten. Mit der Ausgabe 
uart_puts(Eingabe); kontrolliere ich ob der String richtig empfangen 
wurde.
Das klappt auch einwandfrei, der String den ich rein schicke kommt auch 
wieder raus.
Nur die LED bleibt dunkel und die Meldung "ok" wird auch nicht gesendet. 
Was ist jetzt daran noch faul?? Überseh ich wieder irgendwas mit meinen 
wenigen C Kenntnissen? Also die LED funktioniert wenn man sie anschalten 
will, an ihr liegt es nicht.

von Joe D. (kosmonaut_pirx)


Lesenswert?

hallo,
bitte durchlesen, wie man in C strings vergleicht.

if (Eingabe == "aus")

was macht das? richtig, einen pointer-vergleich. 'Eingabe' ist ein 
Pointer auf das erste Element von 'Eingabe'. "aus" ist irgendwas. bin 
mir nicht sicher, wie der compiler das casted, aber es ist ganz bestimmt 
nicht der string "aus". vermutlich wird daraus ein pointer, der den wert 
der ascii-zeichen für "aus" als wert trägt. aber das tut auch nichts zur 
sache, der vergleich ist schlichtweg verkehrt.
mach es doch einfacher: mit einem buchstaben, z.B. 'e', die led an, mit 
einem 'a' wieder aus? oder wenn unbedingt ein string sein muss, dann 
eine routine für den vergleich selber schreiben. oder noch besser in der 
avr-libc nachschauen, was es dafür gibt.

besser auch überdenken, was das hier machen tut:
PORT_LED &= (0<<LED2);

bye kosmo
(btw: kA, wie man code hervorhebt)

von Karl heinz B. (kbucheg)


Lesenswert?

Strings vergleicht man übrigens in C so:
1
#include <string.h>
2
3
....
4
....
5
6
7
    if( strcmp( Eingabe, "aus" ) == 0 ) {
8
      // Eingabe ist gleich dem String "aus"
9
      ...

Tu dir selbst einen Gefallen und hol dir aus der
nächsten Buchhandlung ein C-Buch. Du wirst es nicht
bereuen. Alleine die Zeit die du mit dem
Versuch&Irrtum_und_dann_doch_nicht_rauskriegen
vergeudest, macht die Investition lohnenswert.
Kostet doch nicht die Welt :-)

Ein Forum oder eine Newsgroup kann ein gedrucktes
Buch, dass du neben dem Monitor liegen hast,
nun mal ncht ersetzen.

von Karl heinz B. (kbucheg)


Lesenswert?

Die Hervorhebung macht man übrigens so:

Eckige_Klammer_auf C Eckige_Klammer_zu

hier kommt der Programmtext

Eckige_Klammer_auf /C Eckige_Klammer_zu

von Newbie (Gast)


Lesenswert?

Ich habe sogar ein C Buch, war aber halt echt der Meinung das das ganze 
funktioniert, bin wohl etwas VB verseucht, da hätte es bestimmt 
funktioniert ;) Also ich bin eigentlich nicht zu Faul zum nachschlagen 
;)

Das Problem an der ganzen Sache ist, dass ich im Rahmen einer 
Projektarbeit einen Controller in C programmieren muss. Leider habe ich 
nicht die Zeit das ich ein C Buch von vorne bis hinten durcharbeite. Ich 
such mir halt die Themen raus die ich brauche und probier sie aus. 
Leider scheitert das ganze dann manchmal wieder an den Grundkenntnissen. 
Ich bin mit der Vorgehensweise auch nicht zufrieden aber im Augenblick 
sehe ich leider keine andere Möglichkeit.

Bei dem Programm gehts mir auch nicht um irgendeine LED sondern rein um 
die Kontrolle ob der String richtig angekommen ist oder nicht, bevor ich 
ihn weiterverarbeite.

Es funktioniert im übrigen auch mit der strcmp funktion noch nicht ;) Es 
wird keine 0 zurückgegeben, sonst müsste meine Kontroll ausgabe "ok" 
erscheinen.

Ich such mal weiter, falls jemand einen Fehler gefunden hat... ;)

von Joe D. (kosmonaut_pirx)


Lesenswert?

möglicherweise noch ein CR mit drin, aber zugegeben, ich kenne die 
fleury-lib nicht.

von Karl heinz B. (kbucheg)


Lesenswert?

> Es funktioniert im übrigen auch mit der strcmp funktion noch nicht ;) Es
> wird keine 0 zurückgegeben, sonst müsste meine Kontroll ausgabe "ok"
> erscheinen.

Tip: Lass dir mal den empfangenen String Zeichen für
Zeichen als Hex-Code ausgeben. Oft verstecken sich da
'unsichtbare' Zeichen im String, die man bei normaler
Ausgabe entweder gar nicht sieht, oder übersieht.
Leerzeichn sind zb. so ein Kandidat. Der String
"aus" ist nun mal nicht gleich dem String " aus", oder
"aus\n".
1
void uart_puts_hex( const char* String )
2
{
3
  char Digits[5];
4
5
  while( *String ) {
6
    itoa( *String, Digits, 16 );
7
    uart_puts( Digits );
8
    uart_putc( ' ' );
9
    uart_putc( *String );
10
    uart_putc( ' ' );
11
    String++;
12
  }
13
}

Das gibt dir den Text "aus ", zb so aus:
61 a 75 u 73 s 20

Jeweils vor einem Buchstaben wird sein ASCII Code in HEX ausgegeben.
Damit sieht man seh schön, dass da nach dem s noch was kommt, und
was das ist (0x20 ist der ASCII Code für Leerzeichen).

Es empfiehlt sich überhaupt zuerst immer mal zu kontrollieren,
was über die Schnittstelle reinkommt. Nicht darauf vertrauen
das das schon stimmen wird. Überprüfen!
D.h. das was da rein kommt, sofort wieder rausschicken.
1
   c = uart_getc();
2
   if( c != UART_NO_DATA )
3
   {
4
      while( c != UART_NO_DATA )
5
        {
6
        Eingabe[Count++] = c;
7
          c = uart_getc();
8
9
          /*****/
10
          uart_putc( c );
11
          /*****/
12
13
        }
14
      Eingabe[Count] = '\0';
15
16
      /*****/
17
      uart_puts( "\nEmpfangen: " );
18
      uart_puts_hex( Eingabe );
19
      /*****/

Wenn dann alles so funktioniert wie du dir das vorstellst,
dann entfernst du diese zusätzlichen Ausgaben wieder.

von Newbie (Gast)


Lesenswert?

Vielen Dank wieder erst mal!
Wieder sehr hilfreiche tips, aber es funktioniert bei mir iwie nicht.

ich bekomme vom Controller 65 e 69 i 6E n zurück. Das sollte ja 
eigentlich genau der String sein den ich reinschick.
Aber das mit dem strcmp funktioniert immernoch nicht...



von Karl heinz B. (kbucheg)


Lesenswert?

Ich kann dir nur sagen, dass strcmp 100% funktioniert.
Wenn also strcmp keine 0 zurückliefert, dann sind
die Strings für den µC nicht gleich. Irgendwo muss
es also einen Unterschied geben.

Was ist wenn du folgende Abwandlung probierst
1
   c = uart_getc();
2
   if( c != UART_NO_DATA )
3
   {
4
      while( c != UART_NO_DATA )
5
        {
6
        Eingabe[Count++] = c;
7
          c = uart_getc();
8
9
          /*****/
10
          uart_putc( c );
11
          /*****/
12
13
        }
14
      Eingabe[Count] = '\0';
15
16
      /*****/
17
      uart_puts( "\nEmpfangen: \"" );
18
      uart_puts( Eingabe );
19
      uart_puts( "\"" );
20
      /*****/
21
22
     if( strcmp( Eingabe, "ein" ) == 0 ) {
23
       ....

Das was du dem µC schickst, muss in einer Zeile, eingerahmt
von " stehen.
Da muss also stehen:
   Eingabe: "ein"

Wenn deine Ausgabe nicht so aussieht, wenn da irgendwelche
unmotivierten Zeilenumbrüche sind, dann enthält Eingabe
nicht den Text "ein" und strcmp wertet das nicht als gleich.

(Mir ist dieses:

      while( c != UART_NO_DATA )

mehr als suspekt. Woher weiss denn uart_getc, dass da nichts
mehr kommt? uart_getc kann ja nicht in die Zukunft schauen
und feststellen, dass der Benutzer am Terminal auf einen
Kaffee gegeangen ist, bevor er die Eingabe abgeschlossen hat.
Ich denke immer noch, dass du da einen gewaltigen Denkfehler
hast.

Ich würde es so probierern:
1
   c = uart_getc();
2
   if( c != UART_NO_DATA )
3
   {
4
      // Lese solange, bis von der anderen Seite die
5
      // Return Taste betätigt wurde.
6
      while( c != '\n' )
7
      {
8
         if( c != UART_NO_DATA ) {
9
           Eingabe[Count++] = c;
10
           c = uart_getc();
11
         }
12
      }
13
 
14
      Eingabe[Count] = '\0';

Anstatt von Return kann man auch jedes anderer Zeichen
benutzen, dass in den Daten sonst nicht vorkommt.

von Newbie (Gast)


Lesenswert?

hm, also bezüglich Eingabe abschließen. Ich geh mal davon aus das das 
Terminalprogramm Hterm nicht jeden Eingabe Zeichenweise rausgibt sobald 
die Taste gedrückt wurd sonder alles was ich eingegeben habe auf einmal 
Byte für Byte oder nicht? Wozu muss ich dann mit Return die Eingabe 
quasi beenden? Vieleicht ist das ja mein Denkfehler?
Bin bis jetzt leider noch nicht dazu gekommen die Programmänderung 
auszuprobieren.

von Karl H. (kbuchegg)


Lesenswert?

> Ich geh mal davon aus das das
> Terminalprogramm Hterm nicht jeden Eingabe Zeichenweise rausgibt

Doch, das tun Terminals normalerweise.
In den Moment in dem du eine Taste drückst (oder loslässt)
wird auch schon das Zeichen über die Leitung geschickt.

Das macht auch Sinn:
zum einen braucht dadurch das Terminal keinen lokalen Editor
  um Fehleingaben korrigieren zu können.
zum anderen wären ja sonst keine interaktiven Programme, die
  auf einzelne Tastendrücke reagieren, möglich.

Die universellste Lösung ist immer noch, wenn das Terminal
das tut, was seine Aufgabe ist: Alles was über die Schnittstelle
hereinkommt anzeigen; alles was am Keyboard getippt wird
über die Schnittstelle rausschicken. Aus allen anderem hält
es sich raus und überlässt es dem treibenden Programm zu
entscheiden was zb. bei einem 'Cursor rechts' zu geschehen
hat. Das kann bedeuten, dass der Cursor tatsächlich um eine
Stelle nach rechts gehen soll. Das kann aber auch bedeuten,
dass der Cursor ins nächste Eingabefeld geschickt wird, oder
dass dein 'UFO-Flak-Geschütz' um ein Pixel nach rechts geschickt
wird.

von Uwe L. (uwe_l)


Lesenswert?

Hallo!

ich versuche mit der UART Library von Peter Fleury die empfangenen 
Zeichen zu einem String zusammen zusetzten um eine Abfrage zu 
realisieren, wobei ich auf diesen Beitrag gestoßen bin. Dabei bin ich 
wie hier beschrieben vorgegangen und habe es mit
1
 if( strcmp( Eingabe, "links" )==0)
 versucht aber leider ohne erfolg.

 Was habe ich übersehen oder mache ich falsch?


1
char uart_put_auswertung()
2
{
3
      Count = 0;
4
         c = uart_getc();
5
         if( c != UART_NO_DATA )
6
         {
7
            while( c != UART_NO_DATA )
8
9
            {
10
              Eingabe[Count++] = c;
11
                c = uart_getc();
12
            }    
13
14
            Eingabe[Count] = '\0';
15
16
        if( strcmp( Eingabe, "links" )==0) 
17
        {      
18
          Bitverschieben_links();
19
          uart_puts("links");
20
        }
21
        if( strcmp( Eingabe, "rechts" )==0) 
22
        {      
23
          Bitverschieben_rechts();
24
          uart_puts("rechts");
25
        }        
26
        
27
        uart_puts( Eingabe );
28
      }
29
30
}


Die Ausgabe
1
uart_puts( Eingabe );
 außerhalb der If-Abfrage ist Korrekte allerdings ist die If-Abfrage 
niemals 0(True).

Ich finde meinen Fehler nicht vielleicht hat von euch jemand die Idee!

Danke

von Peter D. (peda)


Lesenswert?

Es ist immer angeraten, alte Leichen auszugraben.
Der Leser ist dann erstmal stundenlang beschäftigt, Fragen zu lösen, die 
eh keinen mehr interessieren.

Und wenn er sich dann mühsam bis zum letzten Post gearbeitet hat, ist er 
stinksauer und wird nicht antworten.

Oder er liest nur den ersten Beitrag und antwortet auf die Frage von 
2006.


Peter

von Uwe L. (uwe_l)


Lesenswert?

Danke für die Antwort!

ich wollte keinen neuen Tread aufmachen da ich mich an diesen Beiträgen 
orintiert habe.

Ich wollte niemand verärgern oder so.

Uwe

von Karl H. (kbuchegg)


Lesenswert?

Uwe Lang schrieb:

>          c = uart_getc();
>          if( c != UART_NO_DATA )
>          {
>             while( c != UART_NO_DATA )
>
>             {
>               Eingabe[Count++] = c;
>                 c = uart_getc();
>             }
>
>             Eingabe[Count] = '\0';

Diese ganze Vorgehensweise ist Müll.
Das ist sie heute genauso, wie sie es 2006 war.
Nur hab ich mir damals noch nicht getraut, das so deutlich zu sagen.

Und im Übrigen, wenn ich mir den Thread so durchlese, habe ich damals 
eigentlich ganz gute Hinweise gegeben, was die Probleme sein können 
(bzw. sind) und wie man den Dingen auf den Grund geht.
Wenn man natürlich einfach nur den Code von irgendwo rauskopiert, dann 
wird das nix.

von Uwe L. (uwe_l)


Lesenswert?

Du hast den Hinweis gegeben:

Der String
"aus" ist nun mal nicht gleich dem String " aus", oder
"aus\n".






void uart_puts_hex( const char* String )
{
  char Digits[5];

  while( *String ) {
    itoa( *String, Digits, 16 );
    uart_puts( Digits );
    uart_putc( ' ' );
    uart_putc( *String );
    uart_putc( ' ' );
    String++;
  }
}


Das gibt dir den Text "aus ", zb so aus:
61 a 75 u 73 s 20

das habe ich gemacht und bei mir kommt es genau so raus wie es sein soll 
ohne irgendwelche Leerzeichen oder ähnlichem.
Aber sorry das ich kein Vollprofie wie du bin und schon seit 2006 oder 
sogar läger damit beschäftige.

Ich kopiere mal sowas um es zu testen und dann zu verstehen!

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.