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


von Frank (Gast)


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
}

von Stefan B. (stefan) Benutzerseite


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
}

von 2916 (Gast)


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.

von Frank (Gast)


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

von Stefan B. (stefan) Benutzerseite


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.

von Frank (Gast)


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

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.