PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : UART überträgt falsche Daten



Lektor
28.07.2006, 09:51
Mein UART überträgt falsche Daten. Woran könnte es liegen und wie kann ich es beheben?

Zur Emulation meiner Solaranlage habe ich ein Programm in meinen µC geschrieben, welches wie die Solaranlage, im Sekundentakt 58 Bytes über die serielle Schnittstelle an den PC senden soll. Damit ich nicht die ganze Zeit im Keller verbringe sollte der µC in gleicher Weise Daten an den PC schicken, wie es auch die Solaranlage tut, damit ich im Büro ein Labviewprogramm erarbeiten kann.

Hier mal der einfache Code des Programms. Am Ende des Codebeispiels habe ich nochmal übersichtlich aufgelistet, welche Bytes gesendet werden sollen und welche Bytes HTerm anzeigt.



.include "m8def.inc"

.def temp = r16
.equ CLOCK = 8000000 ; interner Oszi
.equ BAUD = 9600
.equ UBRRVAL = CLOCK/(BAUD*16)-1

reset: ; Stackpointer initialisieren
ldi temp, LOW(RAMEND)
out SPL, temp
ldi temp, HIGH(RAMEND)
out SPH, temp
;---------------Uart---------------------
; Baudrate einstellen
ldi temp, LOW(UBRRVAL)
out UBRRL, temp
ldi temp, HIGH(UBRRVAL)
out UBRRH, temp

; Frame-Format: 8 Bit
ldi temp, (1<<URSEL)|(1<<USBS)|(3<<UCSZ0)
out UCSRC, temp

sbi UCSRB,TXEN ; TX aktivieren
;--------------/Uart----------------------



loop:

rcall onesekond
;zu sendende Bytefolge (58 Bytes)
;AA 10 00 10 52 10 00 01 08 74 0B 01 77 01 01 7A 06 01 38 22 05 19 5C
;00 00 64 01 3E 00 00 2D 01 00 51 00 00 00 00 00 7F 00 00 01 0D 00 71
;00 00 00 02 00 7D 21 02 21 02 05 34
ldi temp, 0xAA
rcall serout
ldi temp , 0x10
rcall serout
ldi temp , 0x00
rcall serout
ldi temp , 0x10
rcall serout
ldi temp , 0x52
rcall serout
ldi temp , 0x10
rcall serout
ldi temp , 0x00
rcall serout
ldi temp , 0x01
rcall serout
ldi temp , 0x08
rcall serout
ldi temp , 0x74
rcall serout
ldi temp , 0x0B
rcall serout


rjmp loop




serout:
sbis UCSRA,UDRE ; Warten bis UDR für das nächste
; Byte bereit ist
rjmp serout
out UDR, temp
ret ; zurück zum Hauptprogramm

onesekond:
; =============================
; delay loop generator
; 8000000 cycles:
; -----------------------------
; delaying 7999992 cycles:
ldi R17, $48
WGLOOP0: ldi R18, $BC
WGLOOP1: ldi R19, $C4
WGLOOP2: dec R19
brne WGLOOP2
dec R18
brne WGLOOP1
dec R17
brne WGLOOP0
; -----------------------------
; delaying 6 cycles:
ldi R17, $02
WGLOOP3: dec R17
brne WGLOOP3
; -----------------------------
; delaying 2 cycles:
nop
nop
; =============================
ret


;----------------------------------
;gewünscht war
;AA 10 00 10 52 10 00 01 08 74 0B

;Resultat mit HTerm ausgelesen
;AA 90 80 90 D2 90 80 81 88 F4 0B
;AA 10 00 10 D2 90 80 81 88 F4 8B
;AA 90 80 90 D2 90 80 01 08 74 0B
;AA 90 80 10 52 10 00 01 08 74 0B
;AA 10 00 10 52 10 00 01 88 F4 8B
;AA 90 80 90 D2 90 80 81 88 74 0B
;AA 90 80 90 D2 10 00 01 08 74 0B
;AA 10 00 10 52 10 00 01 08 74 0B
;AA 10 00 10 52 10 00 01 08 F4 8B
;AA 90 80 90 D2 90 80 81 88 F4 8B
;-----------------------------------


Das AA am Anfang war komischerweise immer richtig.
Könnte mir folgende Fehlermöglichkeiten vorstellen.
-Störungen auf den Leitungen, da ziemlich provisorisch auf Steckbrett aufgebaut.
-Takt stimmt nicht 100%ig und die 9600 Baut werden nicht eingehalten.

Ihr habt sicherlich wesentlich mehr Erfahrung mit RS232 und vielleicht könnt ihr mir ja beantworten, wie man dieses Problem vermeidet.

PicNick
28.07.2006, 12:38
Kann das sein, daß du im HTErm eine Parity gesetzt hast ?

Lektor
28.07.2006, 13:42
nein, leider nicht. Parity ist none. Wäre schön, wenn es so einfach wäre. :(

dennisstrehl
28.07.2006, 13:47
Joah, den internen Oszi sollte man als erstes ersetzen, da er oft (aber bei weitem nicht immer) zu ungenau für asynchrone Datenübertragung ist.

Was btw. sehr auffälig ist, ist dass immer das MSB den Fehler macht. Der Fehler ist deshalb immer [...] Edit: Es ist immer +0x80, -0x80 könnte nur beim 0xAA auftreten und da passiert der Fehler nicht. Also nur +0x80.

MfG

PicNick
28.07.2006, 13:51
Dann isses die Baudrate.
Denn: AA geht tadellos, aber aus 10 wird 90 und aus 00 wird 80,
d.h. er nimmt das Stop-Bit als datenbit
(Bei AA passt es, aber bei den anderen isses eben verkehrt)

Bei C isser heikel mit:
UBRRVAL = CLOCK/(BAUD*16)-1
da MUSS man schreiben
UBRRVAL = CLOCK/(BAUD*16L)-1

Probier's mal , wer weiss ?

Lektor
28.07.2006, 14:53
Es sind weitere Zahlreiche versuche gefolgt, ohne großen Erfolg.
Das mit dem "L" funktioniert nicht, weil dann AVR Studio einen fehler ausgibt. ( In Assembler programmiert)

Habe noch reichlich mit Stopbits und Framegröße herumexperimentiert, hat aber auch nichts gebracht.

Dann habe ich noch "Test" hinzugefügt und dort ist mir aufgefallen, dass das erste Byte T auch nicht immer richtig ist.

Muß jetzt erstmal einen Oszi raussuchen und das Programm umschreiben.
Melde mich wieder, wenn ich Neues weiss.

Lektor
28.07.2006, 15:16
Schade. Lag wirklich am internen Takt. Habe einen Oszi angeschlossen und jetzt läuft es ohne Probleme.
Vielleicht ist ja auch das der Grund warum bei mir nie das LCD funktioniert hat, weil der Takt nicht genau genug war.
Schade das ich dadurch zusätzliche Komponenten auf der Platine anbringen muß. Je kompakter, desto besser. Naja Hauptsache es funktioniert jetzt.
Danke für die Unterstützung.

Arexx-Henk
28.07.2006, 15:25
Hallo,

probier einfach 51 (dezimal) in UBRL/UBRH zu chreiben und dann wieder testen.

Vielleicht geht die baudrate dividirung nicht richtig.

ldi temp, (1<<URSEL)|(1<<USBS)|(3<<UCSZ0)
Die USBS generiert 2 (zwei) stopbits, das ware so gemeint?

Gruss

Henk

Lektor
28.07.2006, 18:22
da das Problem mit dem externen Oszi behoben ist, denke ich nicht, dass es an der Berechnung von UBRRL liegt. Aber danke für den Tipp. Werde ich trotzdem mal ausprobieren, wenn ich den Oszi abgeklemmt habe.

NACHTRAG: hier noch einen interessanten Nachtrag für alle, die auf über die Suche auf diesen Beitrag gestoßen sind und ein ähnliches Problem haben.

Habe ich bei mikrocontroller.net gefunden.

" UART/USART: Übertragungsprobleme wegen falschem Takt?

* der interne Oszillator ist nicht temperaturstabil. Daher kann die Umgebungstemperatur auch den USART-Takt verändern. Für schnelle serielle Kommunikation sollte man deshalb immer einen Quarz(oszillator) verwenden. Falls doch der interne Oszillator verwendet wird, wurde er für die richtige Frequenz kalibriert?

* Nicht mit allen Quarzen kann man alle Baudraten exakt erzeugen; deswegen gibt es Quarze mit so "krummen" Frequenzen wie 3,6864 MHz. Näheres steht im Datenblatt. "

http://www.mikrocontroller.net/articles/AVR_Checkliste