Hallo an alle, ich versuche mich gerade in die Programmierung eines Microcontrollers mit C. Dabei möchte ich zunächst den USART initalisieren und mir gesendete Zeichen am PC anzeigen lassen. Zum Programmieren und Flashen des Controllers verwende ich die Software AtmelStudio, zum auslesen des USART die Software hterm. Der Microcontroller wird mit einem externen 12 Mhz Quarz betrieben, die Fusebits sind entsprechend gesetzt: High:0xDF Low 0x3F. Mein Problem: Die richtigen Zeichen werden gesendet und empfangen. Allerdings scheint es so als ob Zeichen übersprungen werden. In dem Angehangenen Programm soll schlicht "Hallo" in einer Endlosschleife ausgegeben werden. hterm Empfängt aber folgendes: loHal HloHal Hlo aloHlo aloHll aloHll aloHal HloHal Hlo aloHlo aloHll aloHll aloHal HloHal Hlo aloHlo aloHll Vielleicht kann mir hier jemand auf die Sprünge helfen. Gruß, Practical
Hallo, versuch mal nach jedem Senden des Strings eine Pause zu machen. Wenn Deine Baudrateneinstellungen passen, könnte es sein, das Dein µC den PC zuwirft und dieser nicht hinterherkommt. Zweite Möglichkeit ist, das Dein Takt nicht genau genug ist. Verwendest Du einen externen Quarz? Bei Kommunikation zwingend nötig! Berechne mal Deine BER (Bit Error Rate) ev. ist Deine ausgewählte Baudrate zu ungenau. Teiler anpassen! Gruß Florian
Hi, wenn ich zwischen dem Senden von jedem Zeichen eine Pause von 100ms mache dann funktioniert es. In meinem Code frage ich das Register UCSRA ab um dort zu erfahren ob das Zeichen gesendet wurde, erst dann sende ich das nächste Zeichen. Diese Lösung finde ich flexibler. Daher frage ich mich, warum die von mir verwendete Abfrage nicht den selben Effekt hat:
1 | while( !( UCSRA & (1<<UDRE)) ); |
Ich verwende einen externen Quarz.
Stefan Harney schrieb: > In meinem Code frage ich das Register UCSRA ab um dort zu erfahren ob > das Zeichen gesendet wurde, erst dann sende ich das nächste Zeichen. Das ist auch ok so. > Diese Lösung finde ich flexibler. Daher frage ich mich, warum die von > mir verwendete Abfrage nicht den selben Effekt hat: Mach die Pause mal nach DEM STRING als ganzes, nicht nach jedem Zeichen.
@ Stefan Harney (practical) >wenn ich zwischen dem Senden von jedem Zeichen eine Pause von 100ms >mache dann funktioniert es. Soviel braucht man gar nicht. Es reicht, EINMALIG am Anfang des Sendens eine kleine Pause zu machen, um dem Empfänger, hier dem PC, die Möglichkeit zur Synchronisation zu geben. Das Thema ist alt. Siehe UART. >In meinem Code frage ich das Register UCSRA ab um dort zu erfahren ob >das Zeichen gesendet wurde, erst dann sende ich das nächste Zeichen. >Diese Lösung finde ich flexibler. Das ist auch OK so. >Daher frage ich mich, warum die von >mir verwendete Abfrage nicht den selben Effekt hat: Beitrag "Unnachvollziehbares Verhalten von AVR mit UART" Beitrag "Woran erkennt ein UART eigentlich das Startbit?" Beitrag "Das A und O des UART- Puffers"
Bei 12MHz und einer Baudrate von 9600 hast du einen Fehler von 0,993%. Laut Datenblatt kannst Du ab 0,5% Fehler Probleme bei bei kontinuierlicher Übertragung bekommen. Mögliche Korrekturen: - Baudratenquarz benutzen - eine Baudrate finden, bei der der Fehler unter 0,5% liegt - Pausen zwischen der Übertragung des Arrays einfügen
Okay ich habe mein Hauptprogramm jetzt etwas angepasst: ___________________________________________________________________
1 | /*
|
2 | * usart_test.c
|
3 | *
|
4 | * Created: 18.07.2013 11:11:28
|
5 | * Author: Practical
|
6 | */
|
7 | |
8 | #ifndef F_CPU
|
9 | #define F_CPU 12000000UL // 12 MHz
|
10 | #endif
|
11 | #ifndef BAUD
|
12 | #define BAUD 9600UL//UART mit 9600 Baud
|
13 | #endif
|
14 | |
15 | #define UBRR_VAL ((F_CPU+BAUD*8)/(BAUD*16)-1) // clever runden
|
16 | #define BAUD_REAL (F_CPU/(16*(UBRR_VAL+1))) // Reale Baudrate
|
17 | #define BAUD_ERROR ((BAUD_REAL*1000)/BAUD) // Fehler in Promille, 1000 = kein Fehler.
|
18 | |
19 | #if ((BAUD_ERROR<990) || (BAUD_ERROR>1010))
|
20 | #error Systematischer Fehler der Baudrate grösser 1% und damit zu hoch!
|
21 | #endif
|
22 | |
23 | |
24 | #include <avr/io.h> |
25 | #include "usart.h" |
26 | #include <util/delay.h> |
27 | |
28 | char ausgabe[]={'H','a','l','l','o', '\r','\0'}; |
29 | |
30 | int main(void) |
31 | {
|
32 | usart_init(UBRR_VAL); |
33 | _delay_ms(3); |
34 | usart_write_str(ausgabe); |
35 | while(1) |
36 | {
|
37 | }
|
38 | }
|
___________________________________________________________________ Ich warte nach der initialisierung des USART 3ms, dann Sende ich den String einmal. Jetzt werden die ersten drei Zeichen korrekt übertragen. Die hterm-Ausgabe sieht so aus (mehrmaliges Reseten des Controllers bei aktiver Verbindung mit hterm): Hal Hall Hall Hal Hall Hall Halo Hall Hall Hall Hal Hal Halo Hall Hall
Ich weigere mich, daran zu glauben, dass man einen PC mit 9600 Baud und Stringlängen_am_Stück von 7 Bytes überfahren kann. Aber genau so siehts aus. Entweder das, oder der Mega hat einen Schuss.
Haben deine UART Funktionen IMMER schon so ausgesehen, oder hast du irgendwann mal drann gebastelt? Zb. mal ein vergessenes ! ergänzt? Geh mal in Windows ins AVR-Projekt Verzeichnis und lösche alle *.o Files, die dort liegen. Das müssten bei dir 2 sein. Geh auch in die Subverzeichnisse rein und lösch dort die *.o Files. Und dann bau im AVR-Studio das Projekt neu. Achte drauf, dass auch wirklich alle beiden C-Files kompiliert werden. Sieh dir die Pfade im Output Fenster bei den Compiler-Aufrufen an, ob das auch wirklich die richtigen Files sind.
@ Stefan Harney (practical) >Okay ich habe mein Hauptprogramm jetzt etwas angepasst: Wie sieht deine Senderoutine usart_write_str(ausgabe) aus? >char ausgabe[]={'H','a','l','l','o', '\r','\0'}; Schon mal ein C-Buch von innen betrachtet? char ausgabe[]={"Hallo\r"}; ist deutlich einfacher einzugeben und der Compiler ist sogar so nett, die Null zur Stringterminierung automatisch anzufügen.
Wo wir schon mal dabei sind: Wie ist die Hardware aufgebaut? (Schaltplan und Bild vom Aufbau). Welchen Pegelwandler verwendest Du, was für Kondensatoren, etc.
O.T. Vielleicht ist der Kontroller bei dem Wetter ja eher geneigt, statt "Hallo" lieber "Aloha heja" auszugeben, jedenfalls hat man an Hand der Ausgabe den Eindruck. http://www.youtube.com/watch?v=44ZF_B5ijfo ;-) MfG Paul
Ich errechne eine recht hohe Baudratenfehler - das würde das Problem
auch erklären.
> char ausgabe[]={'H','a','l','l','o', '\r','\0'};
geht auch einfacher:
char ausgabe[]={'Hallo\r'};
@ Falk Brunner (falk) Ich bin gerade dabei mir ein Buch über C zu betrachten, hatte es bisher nur mit so gutmütigen Sprachen wie Matlab und Python zu tun. Der Code von mir mag etwas umstandlich sein, aber da es sich hier nur um ein Test-Projekt handelt, spielt das ja eigentlich keine Rolle. @ Toff (Gast) Ich verwende ein Experimentierboard, welches einen AVR-CDC Wandler an Bord hat. http://www.recursion.jp/avrcdc/. Ob dieser Wandler wirklich korrekt funktioniert, kann ich nicht sagen. @ Karl Heinz Buchegger (kbuchegg) Ich habe dieses Projekt nur angelegt um mein Problem zu schildern. Dafür habe ich die include und C-Files aus meinem eigentlichen Projekt einfach kopiert. Dass der Atmega vlt einen Schaden hat ist natürlich nie auszuschließen. Ich werde mich etwas mit dem Baudratenfehler beschäftigen.
Stefan Harney schrieb: > Ich habe dieses Projekt nur angelegt um mein Problem zu schildern. > Dafür habe ich die include und C-Files aus meinem eigentlichen Projekt > einfach Ist schon klar. Und ist auch gut so. Wichtig ist nur, dass sicher gestellt ist, dass auch TATSÄCHLICH der Code den du herzeigst, auf dem µC läuft. Das soll schon passiert sein, dass auf dem µC eine ältere Version gelaufen ist, die noch fehlerhaft war. > Ob dieser Wandler wirklich korrekt funktioniert, kann ich nicht sagen. Hast du irgendeine Möglichkeit, alter PC oder altes Notebook, ohne diesen Umsetzer auszukommen?
Ich weiß jetzt nicht, welchen genauen Wandler Du einsetzt. Manche scheinen von Werk her auf maximal 4800 Baud eingestellt zu sein. Versuche mal eine geringere Baudrate.
@ Karl Heinz Buchegger (kbuchegg) Ich habe mir, um von dem Experimentierboard unabhäniger werden zu können, einen Wandler bestellt: http://www.ebay.de/itm/USB-2-0-to-UART-TTL-6PIN-Connector-Module-Serial-Converter-CP2102-New-/190685792376 Allerdings lässt die Lieferung aus Fern Ost noch auf sich warten. ______________________________________________________________________ __ Um die Ergebnisse hier zusammenzufassen: - Pausenloses Senden über den UART ist keine Gute Idee - Mein verwendeter Code sollte sonst Grundsätzlich funktionieren Da ich keinen alternativen Rechner mit einer alten Seriellen-Schnittstelle zur Verfügung habe, werde ich wohl auf den Neuen Wandler warten. Weiter kann ich den Atmega8A durch einen neuen ersetzen und sehen was dann passiert. Die gute Resonanz in diesem Forum ist echt überwältigend, Danke an alle!!
@ Stefan H. (practical) >- Pausenloses Senden über den UART ist keine Gute Idee Jain. Man kann schon SEHR lange Datenströme ohne Pause senden, ehe der UART ein Problem kriegt, so in der Größenordnung 100++. >- Mein verwendeter Code sollte sonst Grundsätzlich funktionieren Wir sehen deinen COde nicht vollständig. >Weiter kann ich den Atmega8A durch einen neuen ersetzen und sehen was >dann passiert. Nicht sinnvoll.
Stefan H. schrieb: > @ Karl Heinz Buchegger (kbuchegg) > > können, einen Wandler bestellt: > http://www.ebay.de/itm/USB-2-0-to-UART-TTL-6PIN-Connector-Module-Serial-Converter-CP2102-New-/190685792376 Bei deinem bisher verwendeten Wandler steht auf der WEbsite, dass du, wenn du eine zuverlässige Verbindung haben willst, lieber einen FTDI-Chip nehmen sollst, weil das alles noch sehr 'experimental' ist. Sehr vertrauenerweckend ist das nicht gerade. Zumal es ja augenfällig ist, dass ausgerechnet jedes 2. Zeichen fehlt (im wesentlichen) aber das, was durch kommt, korrekt ist. Wenn die Baudrate fehlerhaft wäre, dann würde da Zeichensalat auftauchen. Aber das tut es bei dir nicht. > - Pausenloses Senden über den UART ist keine Gute Idee In dieser Allgemeinheit kann man das so nicht sagen. Die Synchronisierung wird bei jedem Byte neu hergestellt, von daher kannst du in einer Wurscht dahinsenden (Handshake mal ausgenommen). Das Problem ist das erste Zeichen! Genauer gesagt: Wenn der Sender mit Senden beginnt und der Empfänger aber noch nicht bereit ist. Dann verpasst er die ersten Flanken vom Byte und steigt quer in die Übertragung ein. Ohne eine Pause kann sich der Empfänger nie auf einen korrekten Byteanfang synchronisieren. Sobald die Synchronisation da ist, ist alles in Butter. Dann gehts dahin. Wobei: kein reales Programm sendet pausenlos. Was soll es denn auch senden? Irgendwann muss ja mal auch was berechnet werden, damit man was zum Senden hat. > - Mein verwendeter Code sollte sonst Grundsätzlich funktionieren Jep.
Habe den neuen Wandler erhalten. Mit diesem Wandler funktioniert das ganze Fehlerfrei!!! Danke für die schnelle Hilfe hier im Forum.
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.