Hallo, ich habe folgendes Problem. Wenn ich einen String z.B. 1234567 an den µC (atmega8) schicke erhalte ich auf dem Display nur die ersten drei zeichen und das letzte also 1237. Bis 4 Zeichen funktioniert alles. Hat jemand Rat warum er die zwischen Zeichen "verschluckt"??? Als Anhang mein C Programm. Über eine Hilfe wäre ich sehr dankbar. Gruß Denis
Hat der ATmega8 überhaupt einen Empfangsbuffer? Wenn ja, wie gross?
1 | do{ |
2 | string[i]=UDR; |
3 | // UDR=0;
|
4 | // while (UCSRA&32);
|
5 | wait_ms (100); // Damit alle Zeichen im Buffer angekommen sind |
6 | //lcd_write(UDR);
|
7 | i++; |
8 | }
|
9 | while(UCSRA&128); |
Das wait_ms() ist nicht sehr geschickt, lieber warten, bis ein Zeichen empfangen wurde und es dann sofort auslesen. So wie im obigen Code könnte ja ein Zeichen verpasst werden. Leider kenne ich mich mit AVRs nicht so gut aus, aber die Flags für die Register sollten doch auch symbolisch definiert sein, oder? UCSRA&128 und so ist mühsam zum Lesen.
In deinem Programm ist einiges verbockt. Ein grundsätzlicher Programmaufbau sieht so aus int main() { initialisiere die Hardware schalte Ports richtig initialisiere was auch immer das Programm onst noch so braucht, zb UART oder ADC while( 1 ) { arbeite mit der Hardware } } Es gibt (zumindest in deinem Programm) keinen Grund, die Hardware (in deinem Fall die UART) innerhalb der Hauptschleife immer wieder neu zu initialisieren. Ganz im Gegenteil, das kann auch kontraproduktiv sein. Was denkst du wird wohl passieren, wenn die UART gerade ein Zeichen empfängt und dein Code initialisiert die UART neu. do{ string[i]=UDR; // UDR=0; // while (UCSRA&32); wait_ms (100); // Damit alle Zeichen im Buffer angekommen sind //lcd_write(UDR); i++; } Woher weist du, wenn du das UDR Register ausliest, dass die UART überhaupt ein Zeichen empfangen hat? Antwort: Du kannst es nicht wissen. Aber die UART zeigt es dir mit einem speziellen Bit an. Du musst nur solange warten, bis dieses Bit den Empfang signalisiert. Aber: Zuerst auf das Signal warten und dann das Zeichen holen! while (!(UCSRA & (1<<RXC))) // warten bis Zeichen verfuegbar ; string[i] = UDR; Das mit dem Warten ist Unsinn, du weist nicht wie schnell dein Benutzer tippt! http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial#Der_UART
Ich würde die UART Initialisierung vor die While-Schleife ziehen, also diesen Abschnitt:
1 | //sprintf(str,"A:%d",UCSRA&32);
|
2 | //lcd_write1(str);
|
3 | //lcd_write1("A1");
|
4 | while(!(UCSRA&128)); |
5 | |
6 | UCSRB |= (1<<TXEN); // UART TX einschalten |
7 | UCSRB |= (1<<RXEN); // UART RX einschalten |
8 | UCSRC |= (1<<URSEL)|(3<<UCSZ0); // Asynchron 8N1 |
z.B. in initUART() machen. Und ich würde vor dem Abholen von Zeichen beim UART prüfen, ob Zeichen vorhanden sind, also diesen Block umstellen
1 | do{ |
2 | string[i]=UDR; |
3 | // UDR=0;
|
4 | // while (UCSRA&32);
|
5 | wait_ms (100); // Damit alle Zeichen im Buffer angekommen sind |
6 | //lcd_write(UDR);
|
7 | i++; |
8 | }
|
9 | while(UCSRA&128); |
zu
1 | while(UCSRA & 128) |
2 | {
|
3 | string[i] = UDR; |
4 | i++; |
5 | |
6 | // Jetzt die Übertragungszeit für ca. 1-2 Zeichen warten
|
7 | // in der Hoffnung, dass der Sender das nächste Zeichen
|
8 | // auf den Weg gegeben hat und die Bedingung der while
|
9 | // schleife wieder erfüllt ist (Übertragung nicht zuende)
|
10 | // oder nicht erfüllt ist (alle Zeichen gesendet und empfangen)
|
11 | //
|
12 | // Die Wartezeit ist kritisch, weil bei zu langer Wartezeit
|
13 | // Zeichen verloren gehen. 100 ms wie im Originalcode halte
|
14 | // ich für deutlich zuviel. Bei 9600 Baud 8N1 liegt die
|
15 | // Übetragungszeit bei
|
16 | // 1 / 9600 Bit_pro_Sekunde / (1+8+1) Bit_pro_Zeichen
|
17 | // = ca. 1.04 ms
|
18 | //
|
19 | // Sehr stabil wird ein solcher Code mit diesem Quasi-Timeout
|
20 | // aber nicht.
|
21 | |
22 | wait_ms (2); |
23 | }
|
Oder besser die bereits vorhandene Funktion getchar() benutzen
1 | string[i++] = getchar(); |
Allerdings brauchst du dann auch noch einen Weg um festzustellen, ob alle Zeichen empfangen wurden. Welcher Weg das ist, hängt vom Sender ab z.B. feste Anzahl Zeichen oder bekanntes Endezeichen oder feste Sendedauer...
Hallo, habe mein Programm etwas umgestaltet aber immer noch kein Erfolg. Mein String den ich vom PC an den µC Sende z.B. 123456 erhalte ich auf dem LCD Display 1236. Die ersten drei Zeichen sind ok und dann schneidet er 45 raus und hängt das letzte an. Hingegen wenn mein String nur aus max. 4 Zeichen besteht ist alles OK. z.B. 1234 Hat jemand Rat??? Als Anhang nochmals das C Programm Gruß Denis
Du solltest nur dann warten, wenn es nötig ist, d.h. wenn kein Zeichen an UART anliegt. Also statt:
1 | while( !( UCSRA & (1<<RXC)) );; |
2 | |
3 | i=0; |
4 | do{ |
5 | string[i]=UDR; |
6 | i++; |
7 | wait_ms(2); |
8 | }
|
9 | while(UCSRA&128); |
diesen Code
1 | // Max. Anzahl der 1ms Warteschleifen auf ein Zeichen an UART
|
2 | #define MAX_TIMEOUT 10
|
3 | #define ZEICHEN_IST_AN_UART_VORHANDEN() (UCSRA & (1<<RXC))
|
4 | |
5 | // Die Empfangsschleife wird verlassen, wenn der Sender
|
6 | // MAX_TIMEOUT * 1ms lang nichts sendet.
|
7 | |
8 | {
|
9 | unsigned char timeout = MAX_TIMEOUT; |
10 | i = 0; |
11 | |
12 | do
|
13 | {
|
14 | // getchar() ist eine wartende Funktion und das warten
|
15 | // stört den vorgesehenen Programmablauf (da Anzahl der
|
16 | // Zeichen ist unklar & Endezeichen ist nicht definiert)
|
17 | //
|
18 | // Deshalb vor dem Aufruf zuerst prüfen, ob ein Zeichen
|
19 | // empfangen wurde.
|
20 | |
21 | if (ZEICHEN_IST_AN_UART_VORHANDEN()) |
22 | {
|
23 | // UDR auslesen
|
24 | char c = UDR; |
25 | |
26 | // Wenn Puffer noch nicht voll, dann Zeichen speichern
|
27 | if (i < (32-1)) |
28 | string[i++] = c; |
29 | |
30 | // Das nächste Zeichen erhält wieder die Chance
|
31 | // auf die komplette Wartezeit
|
32 | |
33 | timeout = MAX_TIMEOUT; |
34 | }
|
35 | else
|
36 | {
|
37 | // Im Moment ist Kein Zeichen in UDR vorhanden
|
38 | // Jetzt eine kleine Zeitspanne warten und dann
|
39 | // neuer Versuch
|
40 | |
41 | // #include <util/delay.h> muss vorhanden sein
|
42 | // F_CPU muss definiert sein
|
43 | // Es muss mit Optimierung kompiliert werden
|
44 | |
45 | _delay_ms(1); |
46 | |
47 | // Nicht bis zum Nimmerleinstag warten, sondern
|
48 | // max. eine vorher festgelegte Anzahl (Zeit) lang
|
49 | |
50 | timeout--; |
51 | }
|
52 | |
53 | } while (timeout); |
54 | }
|
Aber z.B. bei 115200 Baud könnte es sein, dass mehrere Bytes innerhalb der Millisekunde ankommen, die du wartest...
David Madl wrote: > Aber z.B. bei 115200 Baud könnte es sein, dass mehrere Bytes innerhalb > der Millisekunde ankommen, die du wartest... Stimmt. Und wie könnte man das berücksichtigen? Mir würde dazu einfallen, dass die Wartefunktion nicht nur trödelt, sondern auch den Status der UART überwacht und vorzeitig das Trödeln abbricht, wenn ein Zeichen angekommen ist.
Stefan "stefb" B. wrote: > David Madl wrote: >> Aber z.B. bei 115200 Baud könnte es sein, dass mehrere Bytes innerhalb >> der Millisekunde ankommen, die du wartest... > > Stimmt. Und wie könnte man das berücksichtigen? Wie eigentlich immer, wenn es um eine zeitlich begrenzte Warterei geht und gleichzeitig etwas überwacht werden muss: * Timer aufsetzen, der die Zeit runterzählt. * In der Warteschleife neben dem zu überwachenden Signal auch noch abprüfen, ob der Timer angeschlagen hat.
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.