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
voidUSART_Init(unsignedintubrr)//Funktion zum Initialisierung des UARTS
2
{
3
//Setzen der Baudrate
4
UBRRH=(unsignedchar)(ubrr>>8);
5
UBRRL=(unsignedchar)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
unsignedintUSART_Receive(void)//Funktion zum Empfangen der Daten
13
{
14
15
16
while(!(UCSRA&(1<<RXC)));
17
18
returnUDR;
19
20
}
21
22
23
24
25
26
intmain(void)
27
{
28
intdata;
29
chardaten_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!
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.
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?
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?
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.
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.
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?
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?
>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.
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.
>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?
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);
}
}
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.
> 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.
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.
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.
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.
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 :)
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.
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
voidUSART_Init(unsignedintubrr)//Funktion zum Initialisierung des UARTS
7
{
8
//Setzen der Baudrate
9
UBRRH=(unsignedchar)(ubrr>>8);
10
UBRRL=(unsignedchar)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
unsignedintUSART_Receive(void)//Funktion zum Empfangen der Daten
18
{
19
20
21
while(!(UCSRA&(1<<RXC)))
22
;
23
24
returnUDR;
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 :)
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.
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 :(
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.
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!
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?
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.
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 :)