www.mikrocontroller.net

Forum: Compiler & IDEs UART empfang, immer ein zeichen "zu spät"


Autor: steckdose (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich beginne gerade mit der C-Programmierung mit AVRs und habe mir aus 
einigen Beispielen etwas zusammengebastelt, was mir per UART ein Zeichen 
empfangen soll und dann wieder per UART und auf einem HD44780-Display 
ausgeben soll, mit einem mega16.
Mein Compiler ist der avr-gcc 4.2.2, als IDE hab' ich das AVR-Studio und 
den Code schieb ich mit Ponyprog auf den Controller.

Wenn ich jetzt z.B. im Terminal ABCDEFG eintippe, dann wird bei einem 
Tastendruck immer nur das letzte Zeichen angezeigt. Also, wenn ich noch 
gar nichts gedrückt habe und drücke A dann zeigt es nichts an (Display 
und Terminal), drücke ich dann B, dann zeigt es A an, drücke ich dann C, 
dann zeigt es B an uswuswusw....

Zum Ansteuern der Displays habe ich Peter Fleury's lcdlib verwendet. Die 
lcd.h stelle ich jetzt mal nicht rein, da das Display ja soweit 
funktioniert, falls ihr sie doch sehen wollt, kann ich sie ja mit 
reinstellen.

Hier der Code, ich hoffe ihr könnt mir da helfen, ich hab mir schon 'ne 
halbe ewigkeit den Kopf darüber zerbrochen:
#define F_CPU 8000000L
#define BAUD 9600L
#define UBRR_VAL ((F_CPU+BAUD * 8)/(BAUD*16)-1)      //clever runde
#define BAUD_REAL (F_CPU/(16*(UBRR_VAL+1)))         //reale Baudrate
#define BAUD_ERROR ((BAUD_REAL*1000)/BAUD-1000)      //Fehler in Promille
#if ((BAUD_ERROR>10)||(BAUD_ERROR<-10))
#error Systematischer Fehler in der Baudrate größer 1% und damit zu hoch!
#endif

#include "lcd.h"
#include <avr/io.h>
#include <stdlib.h>
#include <inttypes.h>
#include <util/delay.h>
#include <avr/pgmspace.h>

int uart_putc(unsigned char c) {
    while (!(UCSRA & (1<<UDRE))){}// warten bis Senden moeglich
  UDR = c;                      // sende Zeichen
  _delay_ms(10);
  return(0);
}



void uart_puts (char *s) {
    while (*s) {   
      uart_putc(*s);
        s++;
    }
}

int init_uart(void) {
  UBRRH = UBRR_VAL >> 8;
  UBRRL = UBRR_VAL & 0xFF;
  UCSRB = (1<<RXEN)|(1<<TXEN);      //UART TX einschalten
  UCSRC = (1<<URSEL)|(1<<USBS)|(3<<UCSZ0);      //Asynchron 8N1
  UCSRB |= ( 1 << RXEN ); // UART RX einschalten
  return(0);
}


int main(void) {

  lcd_init(LCD_DISP_ON);
    lcd_clrscr();
    
  init_uart();
    uart_puts("blubb\r\n\r\n");
  
  while(1) {
      while (!(UCSRA & (1<<RXC)))   // warten bis Zeichen verfuegbar
          ;

      if(UDR == 0x0D) {     // \r\n am uart senden, wenn zeichen = ENTER-Taste
        uart_puts("\r\n");
      }
      else {
        uart_putc(UDR);
        if( (UDR >= 0x61 && UDR <= 0x7A) || (UDR >= 0x41 && UDR <= 0x5A) || (UDR >= 0x30 && UDR <= 0x39) || (UDR == 0x20) ) {
          //    nur aufs display ausgeben wenn das zeichen eines von denen ist
          //       a      bis      z    ODER        A     bis     Z     ODER        0      bis     9   ODER   <SPACE>
          lcd_putc(UDR);
        }
    //  }  
    }
  }


   return 0;                     
} 



Schonmal vielen Dank im Vorraus!

Autor: Matthias Lipinsky (lippy)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
      while (!(UCSRA & (1<<RXC)))   // warten bis Zeichen verfuegbar
          ;

     received = UDR;       // Zeichen abholen
      if(received == 0x0D) {     // \r\n am uart senden, wenn zeichen = ENTER-Taste
        uart_puts("\r\n");
      }
      else {
        uart_putc(received );
        if(   (received >= 0x61 && received <= 0x7A) 
           || (received >= 0x41 && received <= 0x5A) 
           || (received >= 0x30 && received <= 0x39) 
           || (received == 0x20)                       ) 
        {   
          lcd_putc(received );
        }
    //  }  
    }
  }

Versuchs mal so. DU solltest das UDR Register nur dann lesen, wenn ein 
Zeichen empfangen wurde. Ich weiß nicht, was passsiert,w enn du das 
immer wieder abholst

Autor: Falk Brunner (falk)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@ steckdose (Gast)

>und Terminal), drücke ich dann B, dann zeigt es A an, drücke ich dann C,
>dann zeigt es B an uswuswusw....

>int uart_putc(unsigned char c) {
>    while (!(UCSRA & (1<<UDRE))){}// warten bis Senden moeglich
>  UDR = c;                      // sende Zeichen
>  _delay_ms(10);

Was soll das hier?

>  return(0);
>}

Die Funktion braucht keinen Rückgabewert.

Warum baust du dir nicht equivalent ein getc()?

Aber jetzt kommt das Problem.

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

Kann man machen, besser ist aber eine Funktion ala getc();

>      if(UDR == 0x0D) {     // \r\n am uart senden, wenn zeichen = ENTER-Taste

Ist hier prinzipielle auch noch richtig, ABER . . .

>        uart_puts("\r\n");
>      }
>      else {
>        uart_putc(UDR);

DAS geht mal fix schief! Auf UDR darf man nur EINMAL lesend zugreifen, 
sonst bringt man mal fix den UART durcheinander. Man muss UDR in eine 
Variable kopieren, damit kann man dan machen was man will. Ergo. getc 
ist dirngend notwendig.

char getc(void) {
   while (!(UCSRA & (1<<RXC)));
   return UDR;
}

Wenn man dann schreibt

 char tmp;
 while(1) {
      tmp = getc();

      if(tmp == 0x0D) {     // \r\n am uart senden, wenn zeichen = ENTER-Taste
        uart_puts("\r\n");
      }
      else {
        uart_putc(tmp);
        if( (tmp >= 0x61 && tmp <= 0x7A) || (tmp >= 0x41 && tmp <= 0x5A) || (tmp >= 0x30 && tmp <= 0x39) || (tmp == 0x20) ) {
          //    nur aufs display ausgeben wenn das zeichen eines von denen ist
          //       a      bis      z    ODER        A     bis     Z     ODER        0      bis     9   ODER   <SPACE>
          lcd_putc(tmp);
        }
    //  }  
    }
  }

sollte es passen.

MFG
Falk

Autor: steckdose (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ahhh vielen Dank :)

Nun hab' ich noch eine Frage, ein "Buchstabe" (der AVR hat das ja als 
Hex/Bin in seinem Speicher) hat ja kein Vorzeichen. Es funktioniert 
beide Male, wenn ich received als char oder als unsigned char definiere. 
Was macht da mehr Sinn?

Autor: Sven P. (haku) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
unsigned char macht mehr Sinn. Ist aber oft egal, weil der Compiler 
automatisch annimmt, dass du mit "char" eigentlich ein vorzeichenloses 
Dingchen meinst.

Informier dich mal über die Optionen von GCC:

-fsigned-char
-funsigned-char

Autor: Falk Brunner (falk)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@ steckdose (Gast)

>Nun hab' ich noch eine Frage, ein "Buchstabe" (der AVR hat das ja als
>Hex/Bin in seinem Speicher) hat ja kein Vorzeichen. Es funktioniert
>beide Male, wenn ich received als char oder als unsigned char definiere.
>Was macht da mehr Sinn?

Ist Jacke wie Hose. Eigentlich wäre unsigned logisch.

MfG
Falk

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

Bewertung
0 lesenswert
nicht lesenswert
Was du dir aber undebingt angewöhnen sollst: Schmeiss dir
nicht selbst Prügel zwischen die Beine.

Es gibt keinen Grund, da mit ASCII Codes um sich zu schmeissen.
Deine Abfrage kann man auch so schreiben
        if( (tmp >= 'a' && tmp <= 'z') ||
            (tmp >= 'A' && tmp <= 'Z') ||
            (tmp >= '0' && tmp <= '9') ||
            (tmp == ' ') ) {

Hier kann man ganz deutlich sehen, wie dein ursprünglicher
Kommentar sich in Code verwandelt hat und damit überflüssig
geworden ist (was an sich gut ist: Der beste Kommentar ist
einer den man weglassen kann)

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.