Hallooo liebe Leute,
Ich hab hier ein Problem mit dem UART.
Das Empfangen einzelner Zeichen und das senden einzelnder Zeichen und
Strings geht einwandfrei aaaaaber das empfangen von Strings geht mal
überhaupt nicht.
Da kommt erst nach 50 mal was schreiben und Enter drücken irgendwas
zurück.
Habe die Funktionen nur kopiert die Funktion für das Empfangen von
Strings hab ich hier aus dem AVR GCC Tutorial.
Es handelt sich um den ATMEGA168.
Als Serial Terminal verwende ich Picocom mit Folgenden einstellungen:
picocom -p 2 -b 19200 /dev/ttyS0
Als Programmierumgebung Nutze ich:
Eclipse IDE for C/C++ Developers
Version: Mars.1 Release (4.5.1)
Hier die Source:
1
#include <avr/io.h>
2
#include <util/delay.h>
3
#include <stdint.h>
4
/*
5
*
6
* Kerkos am Quartz fehlen noch
7
*
8
* */
9
10
11
12
void USART_Init( unsigned int ubrr){ /* USART Allgemein Aktivieren */
13
14
UBRR0H = (unsigned char)(ubrr>>8); /* Set baud rate */
15
UBRR0L = (unsigned char)ubrr;
16
UCSR0B = (1<<RXEN0)|(1<<TXEN0); /* Enable receiver and transmitter */
17
UCSR0C = (1<<USBS0)|(3<<UCSZ00); /* Set frame format: 8data, 2stop bit */
18
}
19
20
int USART_Transmit_Char( unsigned char data ){ /* Sende einzelne zeichen */
21
22
while ( !( UCSR0A & (1<<UDRE0)) ); /* Wait for empty transmit buffer */
23
UDR0 = data; /* Put data into buffer, sends the data */
NextChar = USART_Get_Char(); // Warte auf und empfange das nächste Zeichen
49
50
while( NextChar != '\n' && StringLen < MaxLen - 1 ) { // Sammle solange Zeichen, bis: entweder das String Ende Zeichen kam oder das aufnehmende Array voll ist
51
*Buffer++ = NextChar;
52
StringLen++;
53
NextChar = USART_Get_Char();
54
}
55
56
*Buffer = '\0'; // Noch ein '\0' anhängen um einen Standard C-String daraus zu machen
57
58
}
59
60
int main(void)
61
{
62
USART_Init(31); /* Baudrate berechnet anhand der defines angaben im datenblatt vom µC (mit webseite rechner)*/
63
64
while (1) {
65
66
67
char Line[40]; // String mit maximal 39 zeichen
68
69
USART_Get_String( Line, sizeof( Line ) / sizeof( Line[0] ) );
NextChar=USART_Get_Char();// Warte auf und empfange das nächste Zeichen
7
8
while(NextChar!='\n'&&StringLen<MaxLen-1){// Sammle solange Zeichen, bis: entweder das String Ende Zeichen kam oder das aufnehmende Array voll ist
9
*Buffer++=NextChar;
10
StringLen++;
11
NextChar=USART_Get_Char();
12
}
13
14
*Buffer='\0';// Noch ein '\0' anhängen um einen Standard C-String daraus zu machen
15
16
}
jeweils nach dem UART_Get_Char einen Aufruf von USART_Transmit_Char mit
dem gerade erhaltenen Zeichen einbaust, damit du im Terminal unmittelbar
nach jedem Tastendruck siehst, was der µC verstanden hat.
USART_Init(31);/* Baudrate berechnet anhand der defines angaben im datenblatt vom µC (mit webseite rechner)*/
4
5
...
gleich mal einen String ausgeben zu lassen. Ebenfalls damit du siehst,
ob die Sache mit der Baudrate wirklich in Ordnung ist.
(Denn wenn ich so fixe Zahlenwerte im Programm sehe, anstatt sie aus der
Taktfrequenz und der gewünschten Baudrate vom Compiler ausrechnen zu
lassen, dann werde ich nervös)
Karl H. schrieb:> jeweils nach dem UART_Get_Char einen Aufruf von USART_Transmit_Char mit> dem gerade erhaltenen Zeichen einbaust, damit du im Terminal unmittelbar> nach jedem Tastendruck siehst, was der µC verstanden hat.
Weiß zwar nicht was du mir jetzt mit "nicht Verboten" aber ich hab
zuerst das ganze mit nur einzelnen Chars gemacht mit get char zeichen
empfangen lassen und mit transmit char das gleiche zurückschicken.
das lief einwandfrei deswegn hab ich mich dann der String Version
gewidmet.
Karl H. schrieb:> Auch ist es eine gute Idee, hierint main(void)> {> USART_Init(31); /* Baudrate berechnet anhand der defines angaben im> datenblatt vom µC (mit webseite rechner)*/>> ...> gleich mal einen String ausgeben zu lassen. Ebenfalls damit du siehst,> ob die Sache mit der Baudrate wirklich in Ordnung ist.> (Denn wenn ich so fixe Zahlenwerte im Programm sehe, anstatt sie aus der> Taktfrequenz und der gewünschten Baudrate vom Compiler ausrechnen zu> lassen, dann werde ich nervös)
Die Baudrate ist in ordnung wie ich im Anfangspost auch geschrieben
hatte kann ich Strings ohne Probleme zum PC schicken.
nur eben der Empfang klappt nicht...
Holger K. schrieb:> Versuchs mal mit einer tieferen Baudrate.
Könnte man ausprobieren wobei ICH mir nicht erklären kann wieso das
senden Senden zum pc einwandfrei klappt.
Franky schrieb:> Karl H. schrieb:>> jeweils nach dem UART_Get_Char einen Aufruf von USART_Transmit_Char mit>> dem gerade erhaltenen Zeichen einbaust, damit du im Terminal unmittelbar>> nach jedem Tastendruck siehst, was der µC verstanden hat.>> Weiß zwar nicht was du mir jetzt mit "nicht Verboten" aber
was ich damit meine ist:
Warum zum Teufel tust du das nicht?
1
voidUSART_Get_String(char*Buffer,uint8_tMaxLen)
2
{
3
uint8_tNextChar;
4
uint8_tStringLen=0;
5
6
NextChar=USART_Get_Char();// Warte auf und empfange das nächste Zeichen
7
USART_Transmit_Char(NextChar);
8
9
....
10
11
selbigesweiteruntennochmal
> ich hab> zuerst das ganze mit nur einzelnen Chars gemacht mit get char zeichen> empfangen lassen und mit transmit char das gleiche zurückschicken.> das lief einwandfrei deswegn hab ich mich dann der String Version> gewidmet.
Ja, ist ja schön. Aber offenbar geht ja irgendetwas schief.
Du hast eine UART, die nach deiner Aussage auvch funktioniert. Dann
benutze sie auch, um dir selbst einen Überblick darüber zu geben was da
schief geht.
Karl H. schrieb:> Franky schrieb:>> Karl H. schrieb:>>> jeweils nach dem UART_Get_Char einen Aufruf von USART_Transmit_Char mit>>> dem gerade erhaltenen Zeichen einbaust, damit du im Terminal unmittelbar>>> nach jedem Tastendruck siehst, was der µC verstanden hat.>>>> Weiß zwar nicht was du mir jetzt mit "nicht Verboten" aber>> was ich damit meine ist:>> Warum zum Teufel tust du das nicht?void USART_Get_String( char* Buffer,> uint8_t MaxLen )> {> uint8_t NextChar;> uint8_t StringLen = 0;>> NextChar = USART_Get_Char(); // Warte auf und empfange das> nächste Zeichen> USART_Transmit_Char( NextChar );>> ....>
Weil das 2 getrennte Funktionen sein sollen Einmal String Empfangen und
einmal Sting senden.
Ich will die Strings später auch auswerten können und nicht nur sinnlos
per Echo zurückschicken.
Die sollen Zuerst in eine Variable.
In dem Jetztigen Programm geht es schlicht um das Testen der Funktionen.
> selbiges weiter unten nochmal>>> ich hab>> zuerst das ganze mit nur einzelnen Chars gemacht mit get char zeichen>> empfangen lassen und mit transmit char das gleiche zurückschicken.>> das lief einwandfrei deswegn hab ich mich dann der String Version>> gewidmet.>> Ja, ist ja schön. Aber offenbar geht ja irgendetwas schief.> Du hast eine UART, die nach deiner Aussage auvch funktioniert. Dann> benutze sie auch, um dir selbst einen Überblick darüber zu geben was da> schief geht.
Nun ich bin jetzt davon ausgegangen das hier jemand das in kurzfassung
sagen kann was da schief läuft ohne das ich lange den code rumtesten
muss zudem der 1 zu 1 aus dem Tutorial von hier kopiert wurde.
Ich habe nur die Namen der Funktionen geändert.
http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial/Der_UART#Empfang_von_Zeichenketten_.28Strings.29
Franky schrieb:> Weil das 2 getrennte Funktionen sein sollen Einmal String Empfangen und> einmal Sting senden.
Ja. Später einmal.
Aber im Moment funktioniert es nicht, und du hast keinen blassen
schimmer warum nicht.
Genauso wie es nicht verboten ist, sich jetzt Code hinzuzufügen, mit dem
man rauskriegen könnte, was da los ist, genausowenig ist es verboten
diesen Code dann wieder zu entfernen, WENN dann das Problem behoben ist.
Du scheinst unter der Prämisse gefangen zu sein, dass einmal
geschriebener Code nie wieder geändert werden darf.
Franky schrieb:> sagen kann was da schief läuft ohne das ich lange den code rumtesten> muss zudem der 1 zu 1 aus dem Tutorial von hier kopiert wurde.
Schön.
Trotzdem gibt es hundertausend Dinge die schief gehen können. Letzten
Endes kann dir dein µC weiter helfen rauszufinden, was schief geht. Du
musst nur die Möglichkeiten nutzen, die du verfügbar hast.
Letzten Endes musst du lernen dir selbst zu helfen. Wenn nicht jetzt,
wann dann?
Dacht immer Foren sind dafür da damit man Leuten hilft aber wenn du
sagst Foren sind nutzlos alles klar.
Mal wieder nur Profis hier im Forum.
Ich werd hier die Lösung des Problems trotzdem noch reinschreiben damit
andere hilfesuchende Menschen sich da nicht auf euch verlassen müssen.
Schönen Tag noch.
Franky schrieb:> Dacht immer Foren sind dafür da damit man Leuten hilft
Ich hätte es sp gemacht, wie Karl Heinz vorschlägt. Dieser Vorgang nennt
sich "debuggen"...
> aber wenn du sagst Foren sind nutzlos
Das ist dann auch sicher ein Grund, warum er seine Freizeit hier als
Ratgeber und Moderator verplempert.
> Ich werd hier die Lösung des Problems trotzdem> noch reinschreiben
Gut.
> damit andere hilfesuchende Menschen sich da nicht> auf euch verlassen müssen.
Halten dich andere Menschen manchmal für arrogant?
Lothar M. schrieb:>> aber wenn du sagst Foren sind nutzlos> Das ist dann auch sicher ein Grund, warum er seine Freizeit hier als> Ratgeber und Moderator verplempert.
:-)
Du String-Empfangsroutine die er 'zitiert' stammt von mir.
Es ist auch leicht zu sehen, dass die korrekt ist. Wenn er also einen
Nonsense-String kriegt, dann ist sein Character Empfang schon schlecht.
Das wiederrum liegt nicht an der Funktion sondern sehr wahrscheinlich an
irgendetwas, was hier nicht zu sehen ist.
Tja. Wenn er die Debug-Tips beherzigen würde, hätte er es schon längst
gesehen. Da er sich aber weigert, und statt dessen lieber den
Überbringer der Nachricht anmault .....
>> damit andere hilfesuchende Menschen sich da nicht>> auf euch verlassen müssen.> Halten dich andere Menschen manchmal für arrogant?
Nein.
Karl H. schrieb:> Du String-Empfangsroutine die er 'zitiert' stammt von mir.> Es ist auch leicht zu sehen, dass die korrekt ist. Wenn er also einen> Nonsense-String kriegt, dann ist sein Character Empfang schon schlecht.> Das wiederrum liegt nicht an der Funktion sondern sehr wahrscheinlich an> irgendetwas, was hier nicht zu sehen ist.>
Schön das dies auch mal jemand sagt.
Wäre ja schon sehr hilfreich gewesen.
> Tja. Wenn er die Debug-Tips beherzigen würde, hätte er es schon längst> gesehen. Da er sich aber weigert, und statt dessen lieber den> Überbringer der Nachricht anmault .....
Bin bisher nicht dazu gekommen.
Hab das auch nicht als Debug erkannt wegen deinem komischen Art dich
auszudrücken.
Dacht du wolltest nur das ich meinen Code änder damit ich wunderbar die
ganze Zeit n Echo bekomme.
Was ja völlig uninteresannt ist.
Wie gesagt ich werde Mitteilen worans lag.
Franky schrieb:> Hier die Source:> #include <avr/io.h>> #include <util/delay.h>> #include <stdint.h>> /*> *> * Kerkos am Quartz fehlen noch> *> * */
Du hast echt keine Kondensatoren am Quarz?
Tom schrieb:> Du hast echt keine Kondensatoren am Quarz?
Nein, die fehlen laut Kommentar am Quar-t-z...
Franky schrieb:> Dacht du wolltest nur das ich meinen Code änder damit ich wunderbar die> ganze Zeit n Echo bekomme.> Was ja völlig uninteresannt ist.
Ich fände das wie gesagt unheimlich inreressant, zu sehen, was der UART
empfängt, wenn ich weiß, dass die Sendereotuine geht...
Das Debuggen einer seriellen Schnittstelle läuft immer gleich ab: es
werden Brücken gebaut.
Die erste Brücke wird gleich mal direkt am RS232-Anschluss (oder am
USB-Adapter) des PCs zwischen RXD und TXD. Dann wird kontrolliert, ob
die Zeichen, die vom Terminalprogramm ausgegeben werden genauso wieder
empfangen werden.
Dann wird diese Brücke wieder aufgetrennt und der RS232 Anschluss an den
uC angeschlossen. Dort wird dann auf der Platine zwischen RX und TX eine
Brücke gemacht, der Controller in den Reset gesetzt oder ausgesteckt.
Und dann wird kontrolliert ob die Zeichen, die vom Terminalprogramm
ausgegeben werden genauso wieder empfangen werden.
Dann wird diese Brücke wieder aufgetrennt und eine Brücke in die
Software gemacht, indem jedes empfangene Zeichen sofort wieder
zurückgeschickt wird. Und dann wird kontrolliert ob die Zeichen, die vom
Terminalprogramm ausgegeben werden genauso wieder empfangen werden.
Franky schrieb:> Weiß zwar nicht was du mir jetzt mit "nicht Verboten" aber ich hab> zuerst das ganze mit nur einzelnen Chars gemacht mit get char zeichen> empfangen lassen und mit transmit char das gleiche zurückschicken.> das lief einwandfrei deswegn hab ich mich dann der String Version> gewidmet.
Gut, dann geht das ja schon mal...
Franky schrieb:> Da kommt erst nach 50 mal was schreiben und Enter drücken irgendwas> zurück.
Und WAS genau? Du sendest also genau 50 Zeichen und ein Enter, und
dann kommt was zurück? Oder könnte könnte es dann sein, dass du schon
nach 40mal was schreiben und Enter drücken was empfängst? Sendet dein
Terminal auch tatsächlich ein '\n' beim Drücken der Enter-Taste? Oder
sendet es ein '\r'?
Probier mal sowas:
Franky schrieb:>> Du String-Empfangsroutine die er 'zitiert' stammt von mir.>> Es ist auch leicht zu sehen, dass die korrekt ist. Wenn er also einen>> Nonsense-String kriegt, dann ist sein Character Empfang schon schlecht.>> Das wiederrum liegt nicht an der Funktion sondern sehr wahrscheinlich an>> irgendetwas, was hier nicht zu sehen ist.>>>> Schön das dies auch mal jemand sagt.> Wäre ja schon sehr hilfreich gewesen.
Wenn es in den Tutorialsfunktionen einen Fehler gegeben hätte (was
durchaus auch schon vorgekommen ist), dann hätte ich sicherlich was
gesagt.
Oder was glaubst du, warum ich im allerersten Posting diesen Satz
benutzt habe
> jeweils nach dem UART_Get_Char einen Aufruf von USART_Transmit_Char mit> dem gerade erhaltenen Zeichen einbaust, damit du im Terminal unmittelbar> nach jedem Tastendruck siehst, was der µC verstanden hat.
Ich mach das doch nicht aus Jux und Tollerei, dir beizubringen wie man
Licht ins Dunkel bringt. Du hat etwas, an dem du ausgeben kannst? Dann
benutze es, um dir aus dem Programm selbst heraus Informationen ausgeben
zu lassen, um einen Einblick zu kriegen, was denn eigentlich wirklich
schief geht.
Das ist ganz normale Debug-Strategie. Debugen wiederum fängt vorne an:
wenn hinten etwas Unerwartetes rauskommt (in deinem Fall ein String),
dann sieht man sich sinnigerweise als erstes das an was ganz am Anfang
reinkommt. Bei dir ist der String aus unsinnigen Zeichen aufgebaut? Dann
sieh dir erst mal die Zeichen an, so wie sie rein kommen. Sind die schon
falsch, dann ist klar, dass da hinten nichts richtiges rauskommen kann.
Sind die in Ordnung, dann liegt das Problem irgendwo im Zusammenbau.
Ganz normale Debug Strategie - welche Fehlermöglichkeiten gibt es? Wie
kann ich sie ausschliessen bzw. kontrollieren das eines davon NICHT der
Fall ist? Nichts wird als korrekt angenommen, solange es nicht
kontrolliert wurde.
Im übrigen ist ein Echo auch im regulären Betrieb der Normafall. Denn
wenn ich auf der Tastatur rumhämmere, und ich sehe nichts am Monitor
weil kein Echo kommt, dann ist das ein starkes Indiz, dass irgendetwas
nicht stimmt. Das kann etwas ganz Banales sein, wie ein Stecker, der
nicht in seiner Buchse steckt oder ein Kabelbruch oder ....
Oder aber ich kriege zwar ein Echo, aber es stimmt nicht mit dem
überein, welche Taste ich gedrückt habe. Das wiederrum ist ein starkes
Indiz dafür, dass die Baudrate nicht stimmt.
Ein Echo ist also keineswegs 'komplett uninteressant'.
Franky schrieb:> Hallooo liebe Leute,>> aaaaaber das empfangen von Strings geht mal überhaupt nicht.> Da kommt erst nach 50 mal was schreiben und Enter drücken irgendwas> zurück.
Ich wette dass dein PC den Text erst schickt nachdem du ENTER gedruckt
hast...
Man sollte sich fuer Kommunikationsanwendungen von den nullterminierten
Strings loesen, und zuerst die Laenge des Strings senden. Dann kann der
Receiver herunterzaehlen. Sonst hat er ein Problem, wenn das Null
verschwindet, resp nicht kommt.
Oder D. schrieb:> Man sollte sich fuer Kommunikationsanwendungen von den nullterminierten> Strings loesen
Das tut ja hier auch keiner...
> und zuerst die Laenge des Strings senden. Dann kann der Receiver> herunterzaehlen. Sonst hat er ein Problem, wenn das Null verschwindet,> resp nicht kommt.
Und was, wenn die Übertragung der Länge fehlerhaft ist?
Ich übertrage auf der seriellen Schnitte soweit möglich alles in ASCII
und terminiert mit '\n'. Auch und besonders Zahlen. Dann kann ich mit
jedem handelsüblichen Terminalprogramm mithören und die Kommunikation
mitprotokollieren.
Bestenfalls zum Download von großen Datenmengen wie z.B. Firmware kann
mal ein binäres Protokoll eingesetzt werden...
Robin R. schrieb:> Eine fehlerhafte Übertragung erkennt man mit Fehlererkennung. Bspw. Via> crc oder parity-byte über die Bytes des Längenfeldes.
Und das hilft dir jetzt genau wie, wenn das erste Byte der Übertragung
die Längenangabe des weitern ist und da anstelle von 5 die Zahl 252
daherkommt? D.h. sofern du überhaupt soweit synchron bist, dass
wenigstens absolut sicher ist, dass das nächste Byte die Längenangabe
ist und du nicht irgendein Datenbyte aus der vorhergehenden Übertragung
fälschlicherweise als Längenbyte ansiehst.
Bei einem gut gemachten UART Protokoll, kann die Putzfrau während der
Übertragung den Stecker ziehen und wieder einstecken und die Übertragung
synchronisiert sich wieder selber.
Framing/Synchronisation und Fehlererkennung sind doch orthogonale
Konzepte? DU fragtest was man macht wenn die Länge fehlerhaft ist.
Das alleine eine Übertragung der Länge kein zuverlässiges (für bestimmte
Bedeutungen von Zuverlässig) Protokoll ergibt, sollte selbstverständlich
sein.
So Problem ist gelöst eine änderung von
while( NextChar != '\n' && StringLen < MaxLen - 1 )
in
while( NextChar != '\r' && StringLen < MaxLen - 1 )
löst das Problem.
Soviel zum Thema der String-Empfangsroutine ist korrekt.
Franky schrieb:> So Problem ist gelöst eine änderung von>> while( NextChar != '\n' && StringLen < MaxLen - 1 )>> in>> while( NextChar != '\r' && StringLen < MaxLen - 1 )>> löst das Problem.>> Soviel zum Thema der String-Empfangsroutine ist korrekt.
Die Empfangsroutine ist korrekt. Was nicht korrekt ist, das ist deine
Terminaleinstellung, das bei einem Return offenbar kein \n schickt,
sondern lediglich ein \r.
1
\n Line Feed
2
\r Carriage Return
Das Mischmasch zwischen all den Möglichkeiten ist legendär. Die Frage
dreht sich allerdings meistens nur um die beiden Möglichkeiten, ob ein
Terminal ein \n schickt, oder doch ein \r\n. Ein einzelnes \r ist zwar
bei manchen Terminals möglich, ist allerdings auch eher unüblich und ist
mir zu Zeiten, als es noch eigenständige Terminals gab, nie
untergekommen.
Im übrigen passt diese Modifikation nicht als Erklärung für
> Da kommt erst nach 50 mal was schreiben und Enter drücken irgendwas zurück.
Wenn das die einzige Modifikation ist, dann ist es zwar erklärbar, dass
der Code das Drücken von Return nicht mitkriegt, aber nach 40
übertragenen Zeichen hättest du ein Echo kriegen müssen. Und das Echo
ist auch nicht 'irgendwas', sondern das ist genau der Text, den du
getippt hast, nur dass er eben nicht mit einem Return als abgeschlossen
erkannt wurde sondern auch die nachfolgenden Tastendrücke mit in den
String aufgenommen wurden.
Den Unterschied zwischen "Ich bekomme irgendetwas als Antwort" und "Ich
bekomme zwar das Getippte aber ein Return führt nicht zur Beendigung der
Eingabe" als Fehlerbeschreibung solltest mitlerweile erkannt haben.