Hallo allerseits,
ich nutze hier einen ATmega16 mit externem Quarz (14.7456 MHz).
Für UART habe ich einen USB-Serial-Wandler aus dem nur noch RX und TX
raus/reinführen.
Nach dem Löten prüfe ich den UART immer mit einem C-Programm, welches
die empfangenen Bytes wieder zurücksendet. Das funktioniert hier, die
Einstellungen sind: 115200 Baud, 1 Stop, keine Parity.
Nun wollte ich ein Programm in Assembler schreiben, und damit ich da
halbwegs debuggen kann, wollte ich von dort den UART nutzen, um Daten
zurückzusenden.
Da keine Daten zurückkamen, habe ich mein C-Programm auf ASM übersetzt
und das eingespielt. Nun kommen zwar Bytes zurück, aber nie genau die
die man sendet. Sende ich 0 kommt 0xFF, sende ich 0xAA kommt 0xAB
(manchmal kommt auch was ganz anderes, weswegen ich glaube, dass es
irgendwie mit dem UART-Timing zusammenhängt).
Die beiden Programm sind hier: (C-Programm, funktioniert)
1
#include<avr/io.h>
2
#include<inttypes.h>
3
#include<avr/interrupt.h>
4
5
// Baudrate, das L am Ende ist wichtig, NICHT UL verwenden!
6
7
#define FR_CPU 14745600L
8
#define BAUD 115200L
9
10
// Berechnungen
11
// clever runden
12
#define UBRR_VAL ((FR_CPU+BAUD*8)/(BAUD*16)-1)
13
// Reale Baudrate
14
#define BAUD_REAL (FR_CPU/(16*(UBRR_VAL+1)))
15
// Fehler in Promille
16
#define BAUD_ERROR ((BAUD_REAL*1000)/BAUD-1000)
17
18
#if ((BAUD_ERROR > 10) || (BAUD_ERROR < -10))
19
#error Systematischer Fehler der Baudrate grösser 1% und damit zu hoch!
Hm, das stimmt wohl, aber unter 'USART Initialization' im gleichen
Datenblatt steht das Codebeispiel (fast genau) wie bei mir.
Sehr sonderbar alles, zumal das C-Programm ja funktioniert.
Die Reihenfolge der Register-Eintragungen habe ich mal im ASM der des
C-Programms angegleichen, das Verhalten ändert sich aber trotzdem nicht.
Meiermann schrieb:> Kann es sein, dass der Fehler über die Baud-Ratenformel kommt?
Hast du einfach mal nachgerechnet?
Was kommt raus, wenn du die Werte "hart" einträgst?
Hi
In deinem ASM-Pprogramm ist ein gravierender Fehler:
> ldi var1 , HIGH(UBRR_VAL)> sts UBRRH , var1> ldi var1 , LOW(UBRR_VAL)> sts UBRRL , var1
Die Adressen von UBRRH und UBRRL sind für IO-Adressen. Die kannst du
nicht mit sts/lds verwenden.
MfG Spess
Tatsache, out statt sts und schon geht alles :).
Wäre mir im Leben nicht aufgefallen, da viele Programmbeispiele von out
auf sts geändert werden müssen, wegen der Reichweite...
Danke!
Ich hab sonst schon jede Zeite 3 mal neu
geschrieben/geändert/umgruppiert.
spess53 schrieb:> Die Adressen von UBRRH und UBRRL sind für IO-Adressen. Die kannst du> nicht mit sts/lds verwenden.
Vermutlich ursprünglich für einen der neueren AVRs unsauber
programmiert.
In jedem Fall richtig wäre es so: