Forum: Mikrocontroller und Digitale Elektronik Daten vom UART am LCD ausgeben


von L. J. (luke1)


Lesenswert?

Hallo Leute,

Ich denke ich habe ein "kleines" Problem aber ich find den Fehler im 
System irgendwie nicht richtig. Ich wollte folgendes probieren: Ich 
wollte per UART Daten zum Mikrocontroller (ATMega8) schicken. So diese 
müssten ja im Buffer UDR abgelegt sein. Jetzt wollte ich diesen Wert auf 
das LCD ausgeben aber das einzige was mein LCD anzeigt ist eine 0. Der 
Compiler zeigt auch keine Fehlermeldung und keine Warnings an. Falls es 
noch wichtig ist: Mein LCD hängt an PORTC.

Hier ist mal der Code:
1
void USART_Init(unsigned int ubrr)            //Funktion zum Initialisierung des UARTS
2
{
3
  //Setzen der Baudrate
4
  UBRRH = (unsigned char) (ubrr>>8);
5
  UBRRL = (unsigned char)ubrr;
6
  //Freigabe vom Transmitter und vom Receiver
7
  UCSRB = (1<<RXEN) |(1<<TXEN);
8
  //Setzen des Frame Formates: 8 Daten und 2 Stoppbits
9
  UCSRC = (1<<URSEL)|(1<<USBS)|(1<<UCSZ0);
10
}
11
12
unsigned int USART_Receive(void)            //Funktion zum Empfangen der Daten
13
{
14
  
15
  
16
  while( !(UCSRA &(1<<RXC)) );
17
  
18
  return UDR;
19
  
20
}
21
22
23
24
25
26
int main(void)
27
{  
28
  int data;
29
  char daten_array[11];
30
  
31
32
  lcd_init();
33
  USART_Init(MYUBRR);
34
  USART_Receive();
35
  
36
  
37
  data=UDR;
38
  itoa(data,daten_array,2);
39
  lcd_string(daten_array);
40
    
41
  while(1)
42
  {}
43
}

Die Initialisierung und den Codeschnipsel zum empfangen hab ich aus dem 
Datenblatt.
Ich weiß das hier schon oft Fragen darüber gestellt worden sind, aber 
genau weil mein Compiler keine Fehlermeldungen ausgibt steh ich gerade 
ein wenig auf dem Schlauch. Ich hoffe mir kann jemand helfen.

Danke im voraus!

von Karl H. (kbuchegg)


Lesenswert?

L. J. schrieb:

> wollte per UART Daten zum Mikrocontroller (ATMega8) schicken. So diese
> müssten ja im Buffer UDR abgelegt sein. Jetzt wollte ich diesen Wert auf
> das LCD ausgeben aber das einzige was mein LCD anzeigt ist eine 0. Der
> Compiler zeigt auch keine Fehlermeldung und keine Warnings an.

Das heißt nur, dass dein Programm den Sprachregeln genügt.
"Ich esse das U-Boot" ist auch ein deutscher Satz, der den deutschen 
Grammatikregeln genügt. Trotzdem ist er sinnlos

>   USART_Init(MYUBRR);
>   USART_Receive();

Hier, aus dieser Funktion kriegst du das empfangene Byte heraus

     data = USART_Receive();

Da USART_Receive das UDR ausliest, wird dadurch auch das UDR gelöscht 
...

>   data=UDR;

... daher kannst du hier nicht mehr auf das Zeichen zugreifen.

>   itoa(data,daten_array,2);
>   lcd_string(daten_array);
>
>   while(1)
>   {}

Warum machst du das Empfangen nur 1-mal?
Leg es doch in die Schleife hinein. Dann kannst du deinem µC mehrere 
Zeichen hintereinander senden und jedesmal, wenn der µC ein Zeichen 
kriegt, zeigt er es dir an.

> Ich weiß das hier schon oft Fragen darüber gestellt worden sind, aber
> genau weil mein Compiler keine Fehlermeldungen ausgibt steh ich gerade
> ein wenig auf dem Schlauch.

Nochmal:
Der Compiler kümmert sich nur um die Regeln der Sprache. Die Logik ist 
dein Bier.

von L. J. (luke1)


Lesenswert?

Ah vielen vielen Dank :)

>  data = USART_Receive();

Das war der Fehler? Okay gut zu wissen aber ehrlich zugegeben wär ich da 
erst mal nicht draufgekommen. Wo löscht er denn UDR wieder?
Und was merkwürdig ist: Für die Buchstaben bekomme ich immer dieselbe 
Zahl. Für Zahlen bekomme ich unterschiedliche. Weiß jemand woran das 
liegt?

von Stefan B. (Fedora 12) (Gast)


Lesenswert?

Tipp: Was macht denn die Funktion itoa() (Remember: Das ist eine 
Funktion zum Umwandeln einer Zahl in eine Ziffernfolge) aus einem 
Buchstaben und was aus einer Zahl?

von L. J. (luke1)


Lesenswert?

Ich weiß das itoa aus einem Integer ein Array macht. Das eine Zahl in 
eine Ziffernfolge umgewandelt wird sagtest du ja bereits. Aber was mit 
Buchstaben passiert weiß ich nicht. Die haben ja auch irgendeinen Wert.

von L. J. (luke1)


Lesenswert?

Hi Leute,

Ich bräuchte nochmal eure Hilfe. Und zwar funktioniert das mit dem UART 
ja jetzt super. Ich habe mir eine lookup-table gemacht und wenn ich eine 
Taste drücke steht das alles schön auf dem Display. Nur sobald ich die 
Pfeiltaste drücke passiert nichts.Ich glaube es muss irgendwo an der 
lookup-table liegen.
1
unsigned long lut[12]= {0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x1b/*ESC*/,0x1b1b53f,0x1b1b93f};

Bis esc geht alles super. Die zwei anderen Werte sind von den 
Pfeiltasten. Die funktionieren nicht. Also hab ich diese an der Stelle 
lut[10] einfach mal auslesen lassen und es kam raus: b53f (hex) und 
nicht 1b1b53f. Das heißt die lut lässt 1b1 weg, dass soll sie aber 
nicht. Und ich weiß leider nicht wie ich das mache. Kann mir da noch 
jemand einen Tipp geben?

von L. J. (luke1)


Lesenswert?

Weiß wirklich niemand was da los ist? Es ist ja so, dass bei lut[10] 
nicht alle Bits da sind. Aber vom Datentyp her ist er doch lang genug, 
sprich es ist kein Überlauf möglich oder?

von STK500-Besitzer (Gast)


Lesenswert?

Woher hast du die Werte für die Pfeiltasten?
Wo befinden sich die Pfeiltasten? Im PC?

von L. J. (luke1)


Lesenswert?

Die Werte der Pfeiltasten habe ich ausgelesen.
1
int main(void)
2
{            
3
unsigned long lut[12]= {0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x1b/*ESC*/,0x1b1b53f,0x1b1b93f};
4
unsigned long  data;
5
char daten_array[11];
6
lcd_init();
7
USART_Init(MYUBRR);
8
9
10
  while(1)
11
  {  
12
                  data=USART_Receive();
13
    itoa(data,daten_array,16);
14
    lcd_string(daten_array);
15
  }
16
}
Und wenn ich halt eine Pfeiltaste drücke kommt der Wert.

von STK500-Besitzer (Gast)


Lesenswert?

>Und wenn ich halt eine Pfeiltaste drücke kommt der Wert.

Dir ist klar, dass über die serielle Schnittstelle nur Bytes übertragen 
werden können, oder?
Du wirst irgendwie in deinem Programm herausfinden müssen, dass es sich 
bei diesen Tasten um "Magic-Keys" handelt.

von L. J. (luke1)


Lesenswert?

Hm nein das wusste ich nicht aber danke. Das Problem habe ich aber auch 
bei Buchstaben. Z.B ein u. Das müsste hex. eine 0x75 sein. Aber auch das 
u wird nicht dargestellt.

von L. J. (luke1)


Lesenswert?

Ich habe gerade gesehen das bei Buchstaben auch mehr als 8 Bit ankommen. 
Das ist jetzt richtig mies.

von STK500-Besitzer (Gast)


Lesenswert?

>Ich habe gerade gesehen das bei Buchstaben auch mehr als 8 Bit ankommen.
>Das ist jetzt richtig mies.

Kannn es sein, dass du sowas wie HyperTerm zur Kommunikation benutzt?

von Stefan B. (Gast)


Lesenswert?

1. Beim Drücken der Pfeiltaste werden schnell mehrere Bytes 
hintereinander gesendet. Mit deiner Byte Lesen, Byte umwandeln, Byte 
ausgeben Schleife und Draufkucken wirst du immer nur das letzte 
empfangene Byte sehen!

2. Die Sequenz z.B. 0x1b1b53f für eine Pfeiltaste halte ich für falsch, 
Einmal weil es zwar mit ESC 0x1B beginnt, dann aber die Zahl folgenden 
Bits kein Vielfaches von 8 ergibt.

Du solltest dich mit ANSI Escape Codes befassen. Dort kommt zuerst ein 
Byte <ESC> (0x1B) dann ggf. eine Zählsequenz dann ein Byte für die 
betreffende Pfeiltaste. http://ascii-table.com/ansi-escape-sequences.php

Z.B. in der VT52 Emulation im einfachsten Fall (1x Cursor Up) <ESC>A 
(0x1B 0x41) oder bei mehrfachem Tastendruck <ESC>[/wert/A z.B. dreimal 
Cursor up
(0x1B 0x5B 0x03 0x41)

Zunächst brauchst du eine UART-Empfangsfunktion, die den richtigen 
Datentyp für ein Byte liefert:

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

Dann solltest du die Schleife abändern:

int main(void)
{
  unsigned long data;
  char daten_array[11];

  lcd_init();
  USART_Init(MYUBRR);

  while(1)
  {
    unsigned char byte;

    byte = USART_Receive();
    data = byte;

    // Auf ANSI ESCAPE SEQUENZ prüfen
    if (byte == 0x1B) // ESC?
    {
      data <<= 8; // 0x0000001B => 0x00001B00
      byte = USART_Receive();
      if (byte == '[') // Anzahl angegeben?
      {
        data |= byte; // 0x00001B00 | 0x5B => 0x00001B5B
        data <<= 8;   // 0x00001B5B => 0x001B5B00
        byte = USART_Receive(); // Anzahl einfügen
        data |= byte;
      }
      // z.B. A=Rauf, B=Runter, C=Rechts, D=Links einfügen
      // ohne Kontrolle auf Gültigkeit
      data <<= 8;
      byte = USART_Receive();
      data |= byte;
    }

    itoa(data,daten_array,16);
    lcd_string(daten_array);
  }
}

von L. J. (luke1)


Lesenswert?

Hm nein dein Code funktioniert auch irgendwie nicht. Drücke ich ein u 
kommt 353f an.
>Kannn es sein, dass du sowas wie HyperTerm zur Kommunikation benutzt?

Ja ich benutze das Hyperterminal.

von Stefan B. (Gast)


Lesenswert?

> Hm nein dein Code funktioniert auch irgendwie nicht. Drücke ich ein u
> kommt 353f an.

Meinst du meinen Code?

Ein 'u' ist im ASCII Code 0x75
http://www.torsten-horn.de/techdocs/ascii.htm

Wenn ein 0x353f ankommt sind 2 Sachen falsch:

1. Es sind mehr als 1 Byte (8 Bits)
2. Es sind beides die falschen Bytes

1 kann daran hängen, dass du Reste der vorangegangenen Ausgabe noch auf 
dem LCD stehen hast. Bsp. zuerst 0x35 ausgegeben, anschliessend 0x3F 
ausgegeben.
Du solltest die alte LCD Ausgabe vor der neuen Ausgabe löschen oder 
einen Zeilenvorschub einsetzen.

2 kann daran hängen, dass deine UART Übertragung fehlerhaft ist. Bei 
Abweichungen der Baudrate kommen beim AVR falsche Zeichen an. Gängige 
Fehler und deren Lösungsmöglichkeiten sind in der AVR Checkliste 
beschrieben. In deinem Code sehe ich z.B. nicht, wie du den Wert für 
MYUBRR berechnest und ob du einen externen Quarz (gut) oder den internen 
RC-Oszillator (schlecht) verwendest.

von L. J. (luke1)


Lesenswert?

1
#define F_CPU 8000000UL
2
#define BAUD 9600UL
3
#define MYUBRR (F_CPU/16/(BAUD-1))
Hier die Berechnung der Baudrate etc. Das habe ich auch vom Datenblatt 
übernommen. Die Seite habe ich auch schon gefunden. Deswegen habe ich 
mich gewundert warum bei 'u' 353f angekommen ist und nicht 0x75. Quarz 
ist extern 8MHz.
Einstellungen am Hyperterminal: Baudrate:9600
                                Datenbits: 8
                                Stoppbit:1
                                Flusssteuerung:Kein

Aber wenn ich das jetzt richtig begriffen habe und 353f ankommt müssten 
das doch 2 Bytes sein die ankommen. Oder habe ich da was falsch 
verstanden?

EDIT: Ich habe jetzt hinter der LCD-Ausgabe mal eine Sekunde gewartet. 
Drücke ich jetzt u, so kommen folgende Bits an: 110101 und danach: 
111111.
Das würde die 353f erklären.

von Stefan B. (Gast)


Lesenswert?

> #define MYUBRR (F_CPU/16/(BAUD-1))

// Table 52
#define MYUBRR (F_CPU/(16*BAUD)-1)

von Stefan B. (Gast)


Lesenswert?

>>  //Setzen des Frame Formates: 8 Daten und 2 Stoppbits
                                             ^
>>  UCSRC = (1<<URSEL)|(1<<USBS)|(1<<UCSZ0);


> Einstellungen am Hyperterminal: Baudrate:9600
>                                 Datenbits: 8
>                                 Stoppbit:1

=>  UCSRC = (1<<URSEL)|(0<<USBS)|(1<<UCSZ1)|(1<<UCSZ0);

von Stefan B. (Gast)


Lesenswert?

Du hattest 6-Bit Datenworte und 2 Stoppbits eingestellt... Das passt zu 
"110101 und danach 111111"

von L. J. (luke1)


Lesenswert?

Hm ich habe trotzdem noch immmer dasselbe Problem. Erst kommt die 35 an 
dann die 3f. Würde es nicht gehen, diese beiden Werte in eine Variable 
zu speichern? Und erst dann abzufragen? Weil es scheint ja so als würde 
die Variable data überschrieben werden. Erst die 35 und danach die 3f.

EDIT: Nein das ist ja das lustige. Ich hatte 8 Datenbits nicht 6. Und 
Stoppbits war nur eins. Und selbst wenn es 2 wären würde das letzte doch 
ignoriert werden soweit ich das mal gelesen habe.

von Stefan B. (Gast)


Lesenswert?

Nein. Die UART-Initialisierung stimmt nicht. Bring die in Ordnung, dann 
passt auch der Rest.

von Stefan B. (Gast)


Lesenswert?

Nein. Dein Sourcecode

UCSRC = (1<<URSEL)|(1<<USBS)|(1<<UCSZ0);

Stellt auf dem AVR 2 Stoppbits ein ((1<<USBS)) und 6-Bit Datenworte 
((1<<UCSZ0)). Das passt nicht zur Hyperterminaleinstellung.

von L. J. (luke1)


Lesenswert?

Hm okay. Ich werde mir die nochmals genauer ansehen. Vielen Dank für die 
Hilfe :) Ich melde mich nochmal wenn es funktioniert und berichte wo der 
Fehler lag. Ich melde mich auch wenn es trotzdem nicht funktioniert :)

von L. J. (luke1)


Lesenswert?

Also einen Fehler hab ich. Laut Datenblatt müsste ich UCSZ1 noch setzen. 
Habe ich getan. Jetzt habe ich 7 Datenbits. Ich werd noch weiter suchen 
mal sehen was sich noch finden lässt.

von L. J. (luke1)


Lesenswert?

Hi und so melde ich mich wieder.
Leider ohne großen weiteren Erfolg. Ich hab nochmals das Datenblatt 
durchgeschaut und habe aber keinen Fehler mehr gefunden. Die 
Initialisierung sieht bei mir so aus:
1
#define F_CPU 8000000UL
2
#define BAUD 9600UL
3
#define MYUBRR (F_CPU/(16*BAUD)-1)
4
5
6
void USART_Init(unsigned int ubrr)            //Funktion zum Initialisierung des UARTS
7
{
8
  //Setzen der Baudrate
9
  UBRRH = (unsigned char) (ubrr>>8);
10
  UBRRL = (unsigned char)ubrr;
11
  //Freigabe vom Receiver
12
  UCSRB = (1<<RXEN); 
13
  //Setzen des Frame Formates: 8 Datenbits und 1 Stoppbit
14
  UCSRC = (1<<URSEL) | (1<<UCSZ0) | (1<<UCSZ1) | (0<<USBS);
15
}
16
17
unsigned int USART_Receive(void)            //Funktion zum Empfangen der Daten
18
{
19
  
20
  
21
  while( !(UCSRA &(1<<RXC)) )
22
  ;
23
  
24
  return UDR;
25
  
26
}
Vielleicht kann noch mal jemand drüber schauen. Wenn jemand noch was 
findet kann er/sie mir ja einen Tipp geben (bitte nicht gleich die 
Lösung) wo ungefähr mein Denkfehler bzw. der Programmfehler liegt.Bin 
für jede Hilfe dankbar :)

von L. J. (luke1)


Lesenswert?

Sieht keiner einen Fehler oder sowas in der Art? :(

von STK500-Besitzer (Gast)


Lesenswert?

>unsigned int USART_Receive(

Mach da mal ein unsigned char draus.

von Stefan B. (Gast)


Angehängte Dateien:

Lesenswert?

Mit unsigned char USART_Receive() wie ich es oben bereits vorgeschlagen 
hatte und der richtigen UART Initialisierung funktioniert das Programm 
bei mir. In der Erkennung der Cursortasten war noch ein logischer Bug 
von mir. Hyperterminal sollte auch auf VT52 Emulation eingestellt sein, 
damit dir Cursortasten schön rüberkommen.

Weil ich im Moment einen Atmega8 auf meinem Board habe, habe ich einen 
Attiny2313 zum Testen verwendet. Das betrifft aber nur die Stelle mit 
dem URSEL-Bit (auf dem Attiny2313 nicht vorhanden). Und weil ich kein 
LCD habe , habe ich UART Senden als Ersatzausgabe benutzt.

Sourcecode ist im Anhang.

von L. J. (luke1)


Lesenswert?

Nein das funktioniert auch nicht. Das mekrwürdige ist ja, dass nur 7-Bit 
ankommen obwohl ich laut Datenblatt und nach meiner Initialisierung sage 
das ich 8 empfangen möchte. Also ich seh im Sourcecode keinen Fehler :(

von Stefan B. (Gast)


Lesenswert?

Wie stellst du fest, dass nur 7 Bits ankommen? Bei üblichen Tasten auf 
dem PC ist das 8. Bit 0. Probiere mal öäü, wenn du ein gesetztes 8. Bit 
sehen willst.

von Stefan B. (Gast)


Lesenswert?

Nur zur Sicherheit, wenn du meinen Sourcecode verwendest:

Die Zeilen

  UCSRC = (1<<UCSZ0) | (1<<UCSZ1) | (0<<USBS);           // ### 
Attiny2313 hat kein URSEL ###
  // UCSRC = (1<<URSEL)|(0<<USBS)|(1<<UCSZ1)|(1<<UCSZ0); // ### Atmega8 
hat URSEL ###

hast du auf deinen µC angepasst?
Also // vor die 1. Zeile setzen und das // am Beginn der 2. Zeile 
entfernen!

von L. J. (luke1)


Lesenswert?

Ich benutze einen ATMega8 also gibt's URSEL (steht ja auch im 
Datenblatt).
Recht hast du. Bei ö, ä, ü sind 8-Bit vorhanden. Oder das 8-Bit ist 
gesetzt. Aber wieso wird das 8-Bit bei mir nicht angezeigt wenn es 0 
ist? Wird das nie angezeigt?

von Stefan B. (Gast)


Lesenswert?

Möglich, dass die itoa() die führenden Nullen weglässt. Wenn du die 
sehen willst, solltest du dir eine eigene Funktion basteln. Ist nicht 
schwer.

Ich habe übrigens an der Stelle auch einen Fehler drin:

data ist vom Typ unsigned long, d.h. 32-Bit. itoa nimmt als erstes 
Argument einen 16 Bit Wert, d.h. nicht das komplette data wird 
ausgegeben. Man müsste die Funktion ultoa() verwenden.

Bleiben wir kurz bei itoa... Der Puffer daten_array um die verbleibenden 
16 Bit aufzunehmen müsste 16+1 Zeichen (16 Bits plus Nullbyte) groß 
sein, wenn zur Basis 2 umgewandelt wird und 4+1 Zeichen, wenn zur Basis 
16 umgewandelt wird.

Der vorhandene 11 Zeichen große Puffer ist in deinem Fall zu klein. Du 
schreibst 6 Zeichen über das Ende des Puffers hinaus in die Pampa. 
Möglicherweise funktioniert deshalb einiges anders.

von L. J. (luke1)


Lesenswert?

Ja das könnte natürlich gut möglich sein. Das werde ich gleich morgen 
ausprobieren aber ich geh jetzt erstmal schlafen^^. Für mein weiteres 
Programm was ich noch benutzen werde ist es, so wie es jetzt aussieht, 
auch nicht kritisch ob jetzt vorne die 0 noch angezeigt wird. Ich wollte 
es trotzdem aus reiner Neugier wissen wieso es nicht so funktioniert 
hat. Morgen mal schauen :)

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.