mikrocontroller.net

Forum: Compiler & IDEs Uart empfängt erst bei zweiten senden richtig


Autor: Frank (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo

Ich versuche gerade den uart aus dem Tuto.
Funzt alles soweit, nur wenn ich am pc einen buchstaben sende
empfange ich im AVR erst beim zweiten senden des Buchstabens den 
Richtigen.
So sieht mein Code aus:
int  zeichen (void){


  for (;;){
 fdevopen (uart_transmitt,NULL,0);
   printf("Bitte Befehl eingeben ");
   uart_getc();



  if (UDR != 's'&& UDR !='w'){


   printf("Falsche Eingabe!");

                                }
  if (UDR == 's'){


   printf("Motor Stop ");
  for(int h = 0; h< 20; h++){
  _delay_ms(20);}
   printf("Bitte Befehl eingeben! ");
                    }


 if (UDR == 'w'){
  printf("Motor an!");

                 }

  for(int h = 0; h< 20; h++){
  _delay_ms(20);}

  }

  return(0);}
Uns so empfange ich:

/* Zeichen empfangen */
int uart_getc(void)
{

    while (!(UCSRA & (1<<RXC)));  // warten bis Zeichen verfuegbar


    return UDR;                   // Zeichen aus UDR an Aufrufer 
zurueckgeben
}

Autor: Stefan B. (stefan) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Puh, das ist hard stuff!

UDR kannst du nicht beliebig oft abfragen. Nach dem Abfragen wird es 
nämlich gelöscht! Die Abfrage muss an einer Stelle zentral erfolgen; die 
Routine dafür hast du schon: uart_getc
/* Zeichen empfangen */
unsigned char uart_getc(void)
{
    while (!(UCSRA & (1<<RXC)));  // warten bis Zeichen verfuegbar
    return UDR;                   // Zeichen aus UDR an Aufrufer
                                  // zurueckgeben
}

int zeichen (void)
{
  unsigned char zeichen;

  fdevopen (uart_transmitt,NULL,0);

  for (;;)
  {
     printf("Bitte Befehl eingeben ");
     zeichen = uart_getc();

     switch (zeichen)
     {
        case 's':
        case 'S':
           printf("Motor Stop ");
           for(int h = 0; h< 20; h++)
              _delay_ms(20);
           break;

        case 'w':
        case 'W':
           printf("Motor an!");
           for(int h = 0; h< 20; h++)
              _delay_ms(20);
           break;

        default:
           printf("Falsche Eingabe!");
           break;
     }
  }
  // wird wegen for(;;) nie erreicht!
  return 0;
}

Autor: 2916 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Und wo laeuft das Program ? Aufm AVR ? Aha. Was ist wenn solcher Mist 
wie printf() laenger dauert wie ein Zeichen zu empfangen ? Printf() 
gehoert da sowieso nicht hin. Mach was anderes ... zB einen Pin wackeln 
und mit'm Scope anschauen.

Autor: Frank (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo
Danke für Hilfe!

Wieso wird case'w' z.B. zweimal hingeschrieben? Ich habe uart_getc doch 
auch nur am Anfang einmal aufgerufen?? Aber komischerweise gehts mit 
deinem Code.
Kannst Du mir das nochmal erklären.
Frank

Autor: Stefan B. (stefan) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
case 'w':
case 'W':

Ist ein Zusatzfeature. Wenn du mal im Sendeprogramm aus Versehen 
CAPSLOCK eingeschaltet hast, funktionieren dann die Befehle mit 
Grossbuchstaben auch.

Jedes Lesen von UDR in deinem Code ist eigentlich eine Abfrage des UART. 
Aber du machst das öfters, ohne dass wie in uart_getc gewartet wird, bis 
ein Zeichen vorhanden ist. D.h. es kann (und wird) passieren, dass du im 
if das UDR ausliest, wenn gerade ein "halbes" Zeichen in UART steht. Du 
bekommst dadurch Unsinn für deinen Programmablauf geliefert und - 
schlimmer - du löschst das halbe Zeichen und verstümmelst das nächste 
Zeichen mit dem Rest der "noch in der Leitung steckt". Einmal lesen, der 
Variable zeichen zuweisen und dann zeichen auswerten.

Für später, wenn du fitter im Programmieren bist, im Hinterkopf 
behalten: Die Auswertung darf auch nicht zu lange dauern, weil der UART 
wenige (je nach µC) Zeichen zwischenpuffern kann. Wenn zu selten 
abgefragt wird (400ms Warten ist für µC/UART eine Ewigkeit), gehen 
Zeichen verloren, wenn der Puffer voll ist. Man kann da durch 
interruptgesteuerte UART-Abfragen und grössere Puffer (Ringpuffer) 
besser programmieren.

Autor: Frank (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Achso, jedem if (UDR  ==  ...   Aufruf frage ich den Uart ab.Dann hätte 
ich ja   im meinem Code nur UDR in eine andere Variable schieben müssen 
und diese abfragen, dann wärs gegangen.
Vielen Dank

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.