Uart empfängt erst bei zweiten senden richtig

Gast #676232
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
}
Persönliche Seite #676252
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
1
/* Zeichen empfangen */
2
unsigned char uart_getc(void)
3
{
4
    while (!(UCSRA & (1<<RXC)));  // warten bis Zeichen verfuegbar
5
    return UDR;                   // Zeichen aus UDR an Aufrufer
6
                                  // zurueckgeben
7
}
8

9
int zeichen (void)
10
{
11
  unsigned char zeichen;
12

13
  fdevopen (uart_transmitt,NULL,0);
14

15
  for (;;)
16
  {
17
     printf("Bitte Befehl eingeben ");
18
     zeichen = uart_getc();
19

20
     switch (zeichen)
21
     {
22
        case 's':
23
        case 'S':
24
           printf("Motor Stop ");
25
           for(int h = 0; h< 20; h++)
26
              _delay_ms(20);
27
           break;
28

29
        case 'w':
30
        case 'W':
31
           printf("Motor an!");
32
           for(int h = 0; h< 20; h++)
33
              _delay_ms(20);
34
           break;
35

36
        default:
37
           printf("Falsche Eingabe!");
38
           break;
39
     }
40
  }
41
  // wird wegen for(;;) nie erreicht!
42
  return 0;
43
}
Gast #676257
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.
Gast #676264
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
Persönliche Seite #676286
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.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren