Du hast geschrieben
> An für sich funktioniert es (wenn die Auskommentierten
> Sachen nicht auskommentiert sind).
Dann sollten sich auch nicht auskommentiert sein, sonst bekomme ich als
Leser einen Knoten im Kopf.
Drücke sich bitte klarer aus:
> Wenn ich jetzt eine uart nachricht mit weniger als 5 zeichen schicke
Wer schickt wohin? Ich nehme an dass du mit dem PC 5 Zeichen + <Enter>
an den Mikrocontroller sendest. Also 6 Zeichen.
> kommt nichts mehr.
Meine Frau "kommt". In diesem technischen Zusammenhang hat das Wort für
mich keine klar Bedeutung. Auch hier muss ich wieder raten, was du
meinst.
Meinst das der Mikrocontroller nichts mehr empfängt, oder dass der PC
nichts mehr empfängt?
> Von wo werden diese gesendet? bzw. Warum?
Ich dachte es kommt nicht mehr. Jetzt doch? Der PC sendet vermutlich
nur, wenn du das Terminalprogramm entsprechend manuell bedienst. Und
beim Mikrocontroller kann es nur mit uart_sendString() zusammenhängen,
denn das ist die einzige Stelle wo uart_transmit() benutzt wird, was
wiederum die einzige Stelle ist, die das UDR Register überschreibt.
Ich sehe in deinem Code eine kritische Race Condition:
1 | if(uart_dataReceived_b)
|
2 | {
|
3 | uart_sendString(&uart_data_c[0]);
|
4 | uart_dataReceived_b = false;
|
5 | }
|
Wenn etwas empfangen wurde, sendest du es und machst dich danach wieder
empfangsbereit. Während dieser Zeit bis zu nicht empfangsbereit.
Deswegen ist mit diesem Code nut Half-Duplex Kommunikation möglich. War
das gewollt?
Das hier ist übrigend von hintern durch die Brust:
> uart_sendString(&uart_data_c[0]);
Schreibe einfach: uart_sendString(uart_data_c);
Da kommt technisch exakt das gleiche bei heraus, der Code wird aber
besser lesbar. Denn so sieht man, dass der String gesendet werden soll,
nicht nur das erste Zeichen, was man beim Anblick deiner Zeile mit dem
[0] vermuten könnte, wenn man nicht aufpasst.
Due bekommst eine Warnung vom Compiler, die du nicht ignorieren
solltest!:
1 | warning: passing argument 1 of ‘uart_sendString’ discards ‘volatile’ qualifier from pointer target type [-Wdiscarded-qualifiers]
|
2 | uart_sendString(&uart_data_c[0]);
|
Du darfst nicht eine volatile Variable an eine Funktion übergeben, die
eine nicht volatile Variable erwartet. Weil dadurch der Sinn von
volatile verloren geht.
Die Zeile
> uart_data_c[UART_MAXSTRLEN + 1] = {0};
war richtig. Du willst einen Puffer anlegen, der ein Byte mehr speichern
kann als die 5 Zeichen, weil dahinter noch Platz für den
String-Terminierer \0 gebraucht wird.
Der Hauptfehler ist hier:
> // && (UART_MAXSTRLEN > uart_dataReceivedLength_u8))
Durch das Auskommentieren dieser Zeile bekommst du einen Pufferüberlauf.
Du schreibst empfangene Zeichen hinter uart_data_c[] ins RAM, wodurch
andere Daten überschrieben werden. Vermutlich trifft es in deinem Fall
als erstes die Variable uart_dataReceived_b.
Ich habe deinen Code mal compiliert, um zu ermitteln, woe genau die
Variablen im Speicher liegen:
1 | avr-gcc -O1 -g -mmcu=atmega328 -Wa,-adhlns test.c
|
2 | ...
|
3 | .bss:0000000000000000 uart_dataReceivedLength_u8.1789
|
4 | .bss:0000000000000001 uart_data_c
|
5 | .bss:0000000000000007 uart_dataReceived_b
|
Hier kann man schön sehen, dass die Variable uart_dataReceived_b im RAM
an Adresse 7 hinter dem Puffer liegt. Wenn du 6 Zeichen (+
String-Terminierer) empfängst, überschreibst du uart_dataReceived_b mit
dem String-Terminierer, der den Wert 0 hat. Wenn du Wenn du 7 Zeichen
empfängst, überschreibst du uart_dataReceived_b mit dem letzten zeichen.
Und weil das >0 ist, wird es als "true" ausgewertet.
Das erklärt, warum die Bedingung
> if(uart_dataReceived_b)
unerwartet erfüllt wurde.