Hallo, ich versuche bei einem Atmega128 Zeichen über die UART-Schnittstelle zu senden, es werden Zeichen auf dem Hyperterminal angezeigt (richtige Anzahl), aber leider nicht die richtigen. An was kann das liegen? #ifndef F_CPU #define F_CPU 10000000 #endif /* UART baud rate */ #define UART_BAUD 9600 int main (void){ //2 Stopbits, 8 bit Daten, Parity: No UCSR0C |= (1<<USBS)|(1<<UCSZ01)|(1<<UCSZ00)|(0<<UPM01)|(0<<UPM00); UBRR0L =64; //Baudrate 9600 bei 10 MHz UCSR0B |= (1<<TXEN1); for(;;){ USART_transmit('a'); _delay_ms(500); USART_transmit('b'); _delay_ms(500); USART_transmit('c'); _delay_ms(500); } } void USART_transmit(unsigned char a){ while(!(UCSR0A &(1<<UDRE0))){} UDR0 = a; } Gruß Angelika
"falsche Zeichen" sind ein eindeutiger Hinweis auf falsche Parametrierung der seriellen Schnittstelle, meistens verursacht durch unstimmige Baudraten. Überprüfmal ob der Systemtakt 10Mhz und der UBRR0L-Wert korrekt ist. Ausserdem solltest du UBRR0H auch initialisieren. Zudem kommt mir jedoch der Parameter "2 Stoppbits" merkwürdig, weil unüblich vor. Eine "normale" serielle Parametrierung sieht meistens "8,N,1" vor. (8 Datenbits,No Parity, 1Stoppbit)
#ifndef F_CPU #define F_CPU 10000000 #endif /* UART baud rate */ #define UART_BAUD 9600 Das ist ja alles recht schön - allerdings solltest du dann auch die Werte für das Baudratenregister daraus berechnen, sonst macht es wenig sind. Bleibt als weitere Fehlerquelle zu dem schon gesagten noch, ob der Chip wirklich mit dem 10MHz-Quarz getaktet wird oder noch mit dem internen Clock läuft.
_delay_ms(500) geht mit 10 MHz nicht. Mit der Frequenz gehen max. 26,2 ms. Schau mal in die libc-Doku. Baudrate checken, Takt checken, Einstellungen im Terminal checken... An den zwei Stopbits kann es jedenfalls eigentlich nicht liegen.
Hi, ein Oszi hilft ungemein, damit kannst Du leicht überprüfen, ob der Fehler bei Hypereterm liegt (z.B. falsches Frameformat eingestellt) oder bei deinem µC (z.B. falsches Baudrate). Vllt. kennst Du ja jemanden, der Dir eines leihen kann. Es ist auf jeden Fall empfehlenswert, weil es Grübelzeit spart. ;-) Solltest Du ein Ozsi haben, danke daran, dass das kleinste Bit zuerst übertragen wird und daher auf dem Oszi ganz rechts zu sehen ist, während das 128er-Bit z.B. ganz links steht. Ansonsten: * Probier' es doch mal mit einer anderen Baudrate, z.B. 2400Bd * Vllt. haben einige Register nocht falsche Werte? Schreib' doch mal explizit noch UBRR0H = 0 oder das U2X0-Bit auf 0. * Stimmt das Frameformat und die Baudrate bei Hyperterm. * Welche Zeichen kommen denn an. Schick' doch mal Zeichen von 0x00-0xff vllt. bildet sich ein Schema, durch das Du auf den Fehler schliessen kannst. * Atmel bietet zu einigen Controllern auch Bibliotheken, darunter auch UART. Vergleich doch mal die Atmel-Sourcen mit Deinen. Ich hatte ähnliche Probleme und habe dazu auch schon einige Forenbeiträge gelesen und irgendwie lag es IMMER an der Baudrate ;-) Grüße mef PS: Ich hatte gestern 2 Stunden mal wider an meinen UART-Sourcen herumdebuggt, weil sie "plötzlich" nicht mehr gingen. Irgendwann fiehl mir dann auf, daß ich anstelle von uart_putchar('A') ausversehen uart_putchar("A") geschrieben hatte... SMILEY_DER_SEINEN_KOPF_AUF_DEN_TISCH_HAUT So, das musste ich jetzt unbedingt noch loswerden ;-)
@Niels Hüsken: Die Stopbits dürften eigentlich keine Probleme machen. Wenn der µC die Frames mit so langen Pausen schickt, kann der Empfänger nicht unterscheiden, ob nun 1 oder 2 Stopbits verwendet werden. Macht auch in diesem Fall kein Unterschied, weil die Bits sich vom Idle-Pegel nicht unterscheiden. Grüße mef
Ich sagte ja auch lediglich, daß die Verwendung zweier Stoppbits unüblich ist. Problematisch wirds auf jeden Fall, wenn der Empfänger zwei Stoppbits erwartet, aber nur Eines kommt. Auf jeden Fall möchte ich nochmal hervorheben, daß die initialisierung des UBRR0H-Registers fehlt. Das wäre äusserst wichtig, daß das passiert. Das delay_ms() falsch parametriert ist, interessiert hier nen Toten.
@Nils mal eine Frage wie kann ich den Systemtakt feststellen? Ich habe hier ein begonnenes Projekt übernommen, im Datenblatt ist ein Takt von 16 MHz angegeben Stopbit habe ich auf 1 geändert UCSR0C |= (0<<USBS0)|(1<<UCSZ01)|(1<<UCSZ00)|(0<<UPM01)|(0<<UPM00); UBRR0H = 0 beschrieben @mef habe leider kein Oszi unterschiedliche Baudraten habe ich auch ausprobiert
@Angelika: Das "e" ist kein Tippfehler. Mein Name ist "Niels" :) Um den Systemtakt festzustellen gibt es mehrere Möglichkeiten: Fusebits auslesen und schauen, was konfiguriert ist. Ist ein externer Taktgeber konfiguriert, müsste also ein Quarz oder ein Ozillator angeschlossen sein, auf dem die Taktfrequenz draufsteht. Ist über die Fuses ein interner Taktgeber konfiguriert, müsste hier beistehen, wie schnell der klappert. In diesem Fall ist häufig jedoch die Taktfrequenztolleranz ausserhalb die der für seriellen Übertragung nötigen präzision. Ein externer Taktgeber ist auf jeden Fall von nöten. Bitte schau auch bezüglich des UBRR0H-Registers in die Dokumentation des Mega128. Die Reihenfolge in der man die UBRR0H und UBRR0L beschreibt ist wichtig. Ich habe sie nur gerade nicht im Kopf.
Ich hätte jetzt einfach auf den Quarz geschaut und überprüft, ob die Fuses richtig gesetzt sind. Es gibt IMO eine Fuse, die angibt, ob die interne oder externe Taktquelle verwendet werden soll. Ich habe gelesen, daß die Interne Taktquelle nicht für UART geeignet ist, weil zu ungenau (temperaturabhängig, usw.). Apropos Fuses, vllt. ist bei Dir auch die Fuse für die Kompatiblität zum ATMega103 gesetzt. Vielleicht macht das auch Probleme. Grüße aus Ulm
mef wrote: > (temperaturabhängig, usw.). Apropos Fuses, vllt. ist bei Dir auch die > Fuse für die Kompatiblität zum ATMega103 gesetzt. Vielleicht macht das > auch Probleme. Eher unwahrscheinlich. Wenn die 103-Fuse falsch steht, stürzt der Prozessor beim ersten Funktionsaufruf ab, weil der Stack nicht dort liegt wo er sollte. Das Wahrschinlichste ist immer noch Takt und daher die Baudrate. Wenn man mit den Fuses nicht klarkommt, kann man auch folgendes machen: Mittels _delay_ms einfach mal eine LED im Sekundentakt blinken lassen. Den Unterschied zwischen 10Mhz und 1Mhz internem Takt kann man deutlich sehen.
@ Niels ;-) also auf der Platine ist ein Quartz auf dem steht 16.000H6D ich nehme an 16 Mhz das mit zuerst UBRR0H und dann UBRR0L beschreiben ist richtig was die Fusebits betrifft, die habe ich gestern auf alle möglichen Arten versucht auszulesen. Das Problem: Ponyprog kann ich nicht verwenden, mein Spi-Adapter ist über die Parallele Schnittstelle(stk200), das wird nicht unterstützt. Mit Averdude GUIscheint zwar irgendetwas gelesen zu werden ... reading efuse memory.. ...writing outputfile "con" nur das outputfile kann ich nicht finden was nun? Gruß Angelika
Angelika Voß wrote: > @ Niels ;-) > also auf der Platine ist ein Quartz auf dem steht 16.000H6D > ich nehme an 16 Mhz Das heist noch lange nicht, dass der auch verwendet wird. Einfacher Test: Mittels _delay_ms (welches den delay aus der angegebenen Taktfrequenz F_CPU berechnet) eine Blinkschleife bauen und nachsehen ob die Zeiten stimmen können. Einfach 100 mal _delay_ms(10) aufrufen und LED umschalten. Ist der Wert für F_CPU korrekt, dann blinkt deine LED alle 1 Sekunde. Läuft der interne Oszillator dann blinkt sie alle 16 Sekunden. Ist deutlich unterscheidbar. Aber ich muss mich schon wundern. Wenn du einen 16Mhz Quarz hast, dann solltest du nicht lügen und hier #ifndef F_CPU #define F_CPU 10000000 #endif 10Mhz angeben. Sicher ist sicher. Solche Zahlen sollten immer stimmen (auch wenn die tatsächliche Frequenz zb. im AVR-Studio noch mal eingegeben werden kann). Das hat zwar jetzt keine Auswirkungen auf deine UART (weil da momentan die Baudrate nicht von der F_CPU abgeleitet wird), aber es geht ums Prinzip.
@ Karl heinz Buchegger (kbuchegg) >machen: Mittels _delay_ms einfach mal eine LED im Sekundentakt >blinken lassen. Den Unterschied zwischen 10Mhz und 1Mhz internem >Takt kann man deutlich sehen. Ja, aber auch nur, wenn man es richtig macht. http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial#Warteschleifen_.28delay.h.29 MFG Falk
@Angelika
Vergiss die gui. Die macht desöfteren schonmal probleme. Geh auf
Kommandozeile und starte avrdude im interactive-mode.
> avrdude -p m128 -c stk200 -t -F
und dann kannst du mit "read lfuse" und "read hfuse" die Fuses auslesen.
Den Hexadizimalcode musst du in Binär umwandeln (Windows-Taschenrechner)
und kannst dann Anhand der Fuses-Tabelle in der Atmel-Doku die einzelnen
Flags bestimmen. Wichtig für die Taktangabe sind die flags für CKSEL und
CKOPT.
Eine "1" als "High" bedeutet übrigens "unprogrammed"
@ Karl heinz Buchegger ich habe hier 2 Boards und konnte mit der Wartefunktion (danke @Falk) herausfinden: Board1 blinkt bei F_CPU von 16 MHz im Sekundentakt Board2 ist langsamer @ Niels na dann werd ich mich mal an das Auslesen der Fuses machen
Sollte Dein µC doch nicht mit 10Mhz laufen, dann stimmen die Werte im UBRR-Register nicht mehr. Im Datenblatt stehen meistens Tabellen mit passenden Werten, Baudraten und Fehlerraten. Ich würde das gleich mal anpassen und schauen ob's jetzt geht, vielleicht war das schon der Fehler und Du sparst Dir das mit den Fuses. Für 16Mhz und 2400bd bei 0% Fehler: UBBRxH = 3 und UBBRxL = 64 UBBR berechnet man so: F_OSC / (16*Baudrate) - 1 * Der Faktor 16, weil die UART 16-fach sampled (sagt man das so?). * - 1 weil IMO bis 0 runtergezählt wird.aDo je nach Prozessortakt keine ganzen Zahlen herauskommen hat man einen gewissen Fehler, der 0.2% nicht überschreiten sollte. Grüße mef
@mef das habe ich schon versucht, leider kein Erfolg @Niels bei den zwei Atmega128-Boards mit verschiedener Einstellung hat das Auslesen der Fusebits hat fogendes ergeben: Low Fuse Byte: High Fuse Byte: Extendet Fuse Byte: Board1 00000100 11011001 11111111 Board2 11101110 10000001 11111111 nun werde ich mal das Datenblatt studieren
Ich werd' aus dem Datenblatt nicht schlau, nun habe ich aber getestet von Board2 über serielle Schnittstelle Daten an den Rechner zu schicken Einstellungen: CPU-Takt: 16MHz Baudrate: 9600 8N1 Fusebits wie oben beschrieben, es funktioniert!! macht es nun Sinn die EInstellungen der Fusebits von Board2 auf Board1 zu übertragen? @Niels lautet der Befehl für das Schreiben z.B. write hfuse?
@Angelika
> write hfuse 0 <byte>
für <byte> beispielsweise 0xa0... Die '0' bedeutet, das offset 0 von der
basis beschrieben werden soll.
Board1 hat CKSEL 0100 CKOPT 1
und Board2 CKSEL 1110 CKOPT 0
Bei Board 1 bedeutet das laut Tabelle 6 auf Seite 37/38, daß interne
Resonator auf 8Mhz (tabelle 13) schwingt.
Bei Board 2 ist der externe Crystal-Resonator ab 1Mhz aufwärts
selektiert (Tabelle 8) und konfiguriert.
Wenn die Boards auf den externen 16Mhz laufen soll, solltest du auf
Board1 die Einstellungen von Board2 übernehmen.... sowohl lfuse, als
auch hfuse
Angelika Voß wrote:
> Ich werd' aus dem Datenblatt nicht schlau,
Datenblatt, Seite 288
Fuse Low Byte
Name Bit Default
-----------------------------
BODLEVEL 7 1
BODEN 6 1
SUT1 5 1
SUT0 4 0
CKSEL3 3 0
CKSEL2 2 0
CKSEL1 1 0
CKSEL0 0 1
Board1 00000100
Board2 11101110
Bei deinem Board1 sind die CKSEL Bits also so 0100.
Laut Tabelle 6 auf Seite 38, bedeutet dies, dass der
interne RC-Oszillator aktiv ist.
Bei deinem Board2 sind die CKSEL Bits 1110
Laut derselben Tabelle heist das, das dort ein externer
Quarz (external Crystal) verwendet wird.
Die Einstellung external Crystal ist die, die du haben willst.
Kein Wunder dass dein Board1 nicht die vorgegebene Baudrate
erreicht. Der Prozessor arbeitet nicht mit dem Quarz, sondern
läuft immer noch auf dem internen Oszillator.
Karl heiz Buchegger vielen Dank es wird mir klarer, wenn ich nun auch die Einstellung für SUT1..0 von Board2, also laut Datenblatt bei CKSEL0 auf 0 somit auf "Chystal Oscillator, fast rising power", übernehmen würde, wäre ich damit wahrscheinlich im grünen Bereich. Brownout(Spannungseinbruch)-Detektor ist bei Board2 ausgeschaltet. d.h. ich kann die Einstellung für Fuse Low Byte (11101110) von Board2 übernehmen. ich hoffe das stimmt so, nun noch eins, wie kann ich das im Interaktive Terminal Mode von Avrdude eingeben?
Angelika Voß wrote: > nun noch eins, wie kann ich das im Interaktive Terminal Mode von Avrdude > eingeben? Die Antwort auf diese Frage hatte ich bereits ein Post vor Herrn Bucheggers Posting gegeben.
ist das dann so ok? averdude -p m128 -u -c stk200 -t -F und dann: averdude> d lfuse averdude> w lfuse 0 0xee
Angelika Voß wrote:
> averdude> w lfuse 0 0xee
sollte passen. Die hfuse nicht vergessen! Die beinhaltet nämlich CKOPT.
Niels Hüsken wrote:
> vor Herrn Bucheggers Posting gegeben.
Einfach nur 'Karl Heinz' oder noch einfacher 'Heinz'.
Herr Buchegger, das ist mein Vater :-)
ist klar, ich habe hfuse und lfuse geändert, und das Testprogramm laufen lassen, dass Daten über serielle Schnittstelle an den Rechner sendet. Es funktioniert auf beiden Boards!! Die Werte werden korrekt auf dem Hyperterminal angezeigt. Ich danke euch allen für euren freundlichen Rat. Angelika
Karl heinz Buchegger wrote: > Einfach nur 'Karl Heinz' oder noch einfacher 'Heinz'. > Herr Buchegger, das ist mein Vater :-) Ist schon klar. Die Nettiquette sagt eindeutig "Im de-Usenet duzt man sich". Deshalb gehe ich eigentlich auch immer davon aus, daß das "du" okey ist. Das hier sollte sich allerdings absichtlich etwas "literarisch" anhören.... mache ich in R/L mit meinen Freunden auch öfter so :)
Herr Niels ;) ich hoffe ich bin Ihnen da nicht über den großen Zehen geschlappt auf jeden Fall viele Grüsse
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.