Forum: Mikrocontroller und Digitale Elektronik UART ATmega644


von LDer (Gast)


Lesenswert?

Moin!

Ich habe folgenden Code im 
http://www.mikrocontroller.net/articles/AVR-Tutorial:_UART gefunden:
1
.def temp    = r16                              ; Register für kleinere Arbeiten
2
.def zeichen = r17                              ; in diesem Register wird das Zeichen an die
3
                                                ; Ausgabefunktion übergeben
4
 
5
.equ F_CPU = 4000000                            ; Systemtakt in Hz
6
.equ BAUD  = 9600                               ; Baudrate
7
 
8
; Berechnungen
9
.equ UBRR_VAL   = ((F_CPU+BAUD*8)/(BAUD*16)-1)  ; clever runden
10
.equ BAUD_REAL  = (F_CPU/(16*(UBRR_VAL+1)))      ; Reale Baudrate
11
.equ BAUD_ERROR = ((BAUD_REAL*1000)/BAUD-1000)  ; Fehler in Promille
12
 
13
.if ((BAUD_ERROR>10) || (BAUD_ERROR<-10))       ; max. +/-10 Promille Fehler
14
  .error "Systematischer Fehler der Baudrate grösser 1 Prozent und damit zu hoch!"
15
.endif
16
 
17
    ; Stackpointer initialisieren
18
 
19
    ldi     temp, HIGH(RAMEND)
20
    out     SPH, temp
21
    ldi     temp, LOW(RAMEND)
22
    out     SPL, temp
23
 
24
    ; Baudrate einstellen
25
 
26
    ldi     temp, HIGH(UBRR_VAL)
27
    out     UBRRH, temp
28
    ldi     temp, LOW(UBRR_VAL)
29
    out     UBRRL, temp
30
 
31
    ; Frame-Format: 8 Bit
32
 
33
    ldi     temp, (1<<URSEL)|(1<<UCSZ1)|(1<<UCSZ0)
34
    out     UCSRC, temp
35
 
36
    sbi     UCSRB,TXEN                  ; TX aktivieren
37
    ;(einige Sende-Tests)

Fand ich interessant und kam auf die Idee, diesen Code für den Mega8 auf 
meinen Mega644 zuzuschneiden. Also Datenblatt her...

Das ist dabei rausgekommen:
1
.def temp    = r16                              ; Register für kleinere Arbeiten
2
.def zeichen = r17                              ; in diesem Register wird das Zeichen an die
3
                                                ; Ausgabefunktion übergeben
4
 
5
.equ F_CPU = 16000000                           ; Systemtakt in Hz
6
.equ BAUD  = 9600                               ; Baudrate
7
 
8
; Berechnungen
9
.equ UBRR_VAL   = ((F_CPU+BAUD*8)/(BAUD*16)-1)  ; clever runden
10
.equ BAUD_REAL  = (F_CPU/(16*(UBRR_VAL+1)))      ; Reale Baudrate
11
.equ BAUD_ERROR = ((BAUD_REAL*1000)/BAUD-1000)  ; Fehler in Promille
12
 
13
.if ((BAUD_ERROR>10) || (BAUD_ERROR<-10))       ; max. +/-10 Promille Fehler
14
  .error "Systematischer Fehler der Baudrate grösser 1 Prozent und damit zu hoch!"
15
.endif
16
 
17
    ; Stackpointer initialisieren
18
 
19
    lds     temp, HIGH(RAMEND)
20
    sts     SPH, temp
21
    lds     temp, LOW(RAMEND)
22
    sts     SPL, temp
23
 
24
    ; Baudrate einstellen
25
 
26
    lds     temp, HIGH(UBRR_VAL)
27
    sts     UBRR0H, temp
28
    lds     temp, LOW(UBRR_VAL)
29
    sts     UBRR0L, temp
30
 
31
    ; Frame-Format: 8 Bit
32
 
33
    lds     temp, (1<<UCSZ01)|(1<<UCSZ00)
34
    sts     UCSR0C, temp
35
 
36
    lds    temp,UCSR0B
37
    sbr    temp,TXEN0
38
    sts     UCSR0B,temp                  ; TX aktivieren
39
    ;(einige Sende-Tests)

Nur leider sendet der µC nach dem Flashen... rein gar nichts!

Woran liegt das? Habe ich ein Bit falsch gesetzt oder Schwachsinn mit 
den Registern angestellt? Ich finde den Fehler jedenfalls nicht mehr 
allein :(

Hoffe, dass mal jemand reinschaut ;)

Gruß,
euer LDer

von nmbx (Gast)


Lesenswert?

ist das der komplette Code? Wenn ja: Da wird bisher noch nix gesendet. 
Schreib mal irgendwas in das UDR Register

von LDer (Gast)


Lesenswert?

ADD: Ich nehm auch gern C; es muss nicht zwingend Assembler sein ;)

von LDer (Gast)


Lesenswert?

@nmbx, nein, danach folgt noch der (Original-)code aus dem Tutorial, wie 
ich mit dem ";(einige Sende-Tests)" versucht habe, anzudeuten, das in 
beiden Codeblöcken am Ende steht.

Für Leute, die das Tut nun nicht auskramen wollen:
1
loop:
2
    ldi     zeichen, 'T'
3
    rcall   serout                      ; Unterprogramm aufrufen
4
    ldi     zeichen, 'e'
5
    rcall   serout                      ; Unterprogramm aufrufen
6
    ldi     zeichen, 's'
7
    rcall   serout                      ; ...
8
    ldi     zeichen, 't'
9
    rcall   serout
10
    ldi     zeichen, '!'
11
    rcall   serout
12
    ldi     zeichen, 10
13
    rcall   serout
14
    ldi     zeichen, 13
15
    rcall   serout
16
    rcall   sync                        
17
    rjmp    loop

Gruß,
LDer

von LDer (Gast)


Lesenswert?

hrmpf...
sorry, fehlt immernoch was:
1
serout:  
2
  lds    temp,UCSR0A
3
    sbrs    temp,UDRE0                ; Warten bis UDR für das nächste
4
                                        ; Byte bereit ist
5
    rjmp    serout
6
    sts     UDR0, zeichen
7
    ret                                 ; zurück zum Hauptprogramm
8
 
9
; kleine Pause zum Synchronisieren des Empfängers, falls zwischenzeitlich
10
; das Kabel getrennt wurde
11
                                    
12
sync:
13
    ldi     r16,0
14
sync_1:
15
    ldi     r17,0
16
sync_loop:
17
    dec     r17
18
    brne    sync_loop
19
    dec     r16
20
    brne    sync_1  
21
    ret

wenn ich euch jetzt noch die Anfangszeile '.include "m644def.inc"' mit 
dazuschreibe, habt ihr die komplette Datei :-D

Gruß,
LDer

von Spess53 (Gast)


Lesenswert?

Hi

Warum nimmst du nicht einfach die Initialisierung aus dem Datenblatt? 
Die passt.

MfG Spess

von LDer (Gast)


Lesenswert?

Hm, wo finde ich die?
Also das Datenblatt ist ja LANG und ich habe ehrlich gesagt keine große 
Lust, es komplett durchzulesen. Passt auch gerade nicht in mein 
Köpfchen...

Also welcher Punkt?

Gruß,
LDer

von Spess53 (Gast)


Lesenswert?

Hi

Wahrscheinlich unter ADC, Timer oder so.

MfG spess

von Peter D. (peda)


Lesenswert?

LDer schrieb:
> Also das Datenblatt ist ja LANG

Wie wärs mit dem Inhaltsverzeichnis?


> Also welcher Punkt?

Wie wärs mit: "16.6 USART Initialization"


Peter

von LDer (Gast)


Lesenswert?

Peter Dannegger schrieb:
>> Also welcher Punkt?
>
> Wie wärs mit: "16.6 USART Initialization"

Oh, danke. Also Blindheit meinserseits. Auch gut^^

Da steht folgendes:
1
USART_Init:
2
; Set baud rate
3
out UBRRHn, r17
4
out UBRRLn, r16
5
; Enable receiver and transmitter
6
ldi r16, (1<<RXENn)|(1<<TXENn)
7
out UCSRnB,r16
8
; Set frame format: 8data, 2stop bit
9
ldi r16, (1<<USBSn)|(3<<UCSZn0)
10
out UCSRnC,r16
11
ret

nur dumm, dass der out-Befehl nicht auf Register wie UBRRnH bzw konkret 
UBRR0H anwendbar ist. und es eben nicht UBRRHn wie im Datenblatt, 
sondern vielmehr UBRRnH ist. Kann man aber auch noch mit leben.
Zu allem Überfluss steht da doch nichts anderes, als das was ich gemacht 
habe. Oder doch?
Jedenfalls bringt auch die Änderung meines Codes auf Folgendes nichts:
1
 
2
    ; Frame-Format: 8 Bit
3
 
4
    lds    temp, (1<<USBS0)|(3<<UCSZ00)
5
    sts    UCSR0C, temp
6
 
7
    lds     temp,UCSR0B
8
    sbr     temp,TXEN0
9
    sbr    temp,RXEN0
10
    sts    UCSR0B,temp                  ; TX aktivieren
Wobei ich jetzt nur den relevanten Teil poste.

Gruß,
LDer

von ersthelfer (Gast)


Lesenswert?

>    lds     temp, HIGH(RAMEND)
>    sts     SPH, temp
>    lds     temp, LOW(RAMEND)
>    sts     SPL, temp

Was soll denn LDS hier??
Das ist wohl ein bisschen zu viel des Guten.

> Also das Datenblatt ist ja LANG und ich habe ehrlich gesagt keine große
> Lust, es komplett durchzulesen.

Eigentlich habe ich aber auch keine Lust, dir zu helfen. Warum sollte 
ich?

von Sascha W. (sascha_w)


Lesenswert?

... und
1
sbr     temp,TXEN0
2
sbr    temp,RXEN0
setzt nicht etwa die Bits TXEN0 und RXEN0, da der Befehl sbr eine 
Bitmaske und keine Bitnummern haben möchte!
1
sbr   temp,(1<<TXEN0) | (1<<RXEN0)
sollte da schon eher angebracht sein!

Sascha

von J-M M. (ldericher)


Lesenswert?

Sascha Weber schrieb:
> setzt nicht etwa die Bits TXEN0 und RXEN0, da der Befehl sbr eine
> Bitmaske und keine Bitnummern haben möchte!
> sbr   temp,(1<<TXEN0) | (1<<RXEN0)
> sollte da schon eher angebracht sein!

cool, danke, ich habe eine Ausgabe!
Also falsch gesetzte Bits. Jetzt habe ich allerdings das Problem, dass 
ich nur Müll empfange, statt "T" bzw. 01010100 (hab es gekürzt, sodass 
nur das T übertragen wird) kommt immer "ô" bzw. 11110100 an... :(
Anscheinend werden die ersten vier Bits (von MSB an gesehen) als 1, 
dafür die letzten Bits korrekt übertragen.

ersthelfer schrieb:
> Was soll denn LDS hier??
> Das ist wohl ein bisschen zu viel des Guten.

Dann sag mir doch, wie ich es besser machen kann :)

ersthelfer schrieb:
> Eigentlich habe ich aber auch keine Lust, dir zu helfen. Warum sollte
> ich?

1. hast du es doch bereits getan, indem du mich auf lds hingewiesen 
hast.
2. Warum versucht du es dann? Niemand zwingt dich.

Gruß,
LDer

ADD: mein derzeitiger Code:
1
    ; Stackpointer initialisieren
2
 
3
    lds     temp, HIGH(RAMEND)
4
    sts     SPH, temp
5
    lds     temp, LOW(RAMEND)
6
    sts     SPL, temp
7
 
8
    ; Baudrate einstellen
9
 
10
    lds     temp, HIGH(UBRR_VAL)
11
    sts     UBRR0H, temp
12
    lds     temp, LOW(UBRR_VAL)
13
    sts     UBRR0L, temp
14
 
15
    ; Frame-Format: 8 Bit
16
17
    lds     temp, (1<<UCSZ00)
18
    sts     UCSR0C, temp
19
 
20
    lds     temp,UCSR0B
21
    sbr     temp,(1<<TXEN0)
22
    sts     UCSR0B,temp                  ; TX aktivieren
23
 
24
loop:
25
    ldi     zeichen, 0b01010100
26
    rcall   serout                      ; Unterprogramm aufrufen
27
    rcall   sync                        
28
    rjmp    loop

von J-M M. (ldericher)


Lesenswert?

Gut, durch Nachdenken bin ich selbst drauf gekommen. Musste ja doch an 
dem LDS liegen ;) Danke @ersthelfer!

Fürs Protokoll:
1
.include "m644def.inc"
2
 
3
.def temp    = r16                              ; Register für kleinere Arbeiten
4
.def zeichen = r17                              ; in diesem Register wird das Zeichen an die
5
                                                ; Ausgabefunktion übergeben
6
 
7
.equ F_CPU = 16000000                           ; Systemtakt in Hz
8
.equ BAUD  = 38400                              ; Baudrate
9
 
10
; Berechnungen
11
.equ UBRR_VAL   = ((F_CPU+BAUD*8)/(BAUD*16)-1)  ; clever runden
12
.equ BAUD_REAL  = (F_CPU/(16*(UBRR_VAL+1)))      ; Reale Baudrate
13
.equ BAUD_ERROR = ((BAUD_REAL*1000)/BAUD-1000)  ; Fehler in Promille
14
 
15
.if ((BAUD_ERROR>10) || (BAUD_ERROR<-10))       ; max. +/-10 Promille Fehler
16
  .error "Systematischer Fehler der Baudrate grösser 1 Prozent und damit zu hoch!"
17
.endif
18
 
19
    ; Stackpointer initialisieren
20
 
21
    ldi     temp, HIGH(RAMEND)
22
    sts     SPH, temp
23
    ldi     temp, LOW(RAMEND)
24
    sts     SPL, temp
25
 
26
    ; Baudrate einstellen
27
 
28
    ldi     temp, HIGH(UBRR_VAL)
29
    sts     UBRR0H, temp
30
    ldi     temp, LOW(UBRR_VAL)
31
    sts     UBRR0L, temp
32
 
33
    ; Frame-Format: 8 Bit
34
35
    ldi     temp, (3<<UCSZ00)
36
    sts     UCSR0C, temp
37
 
38
    lds     temp,UCSR0B
39
    sbr     temp,(1<<TXEN0)
40
    sts     UCSR0B,temp                  ; TX aktivieren
41
 
42
loop:
43
    ldi     zeichen, 'T'
44
    rcall   serout                      ; Unterprogramm aufrufen
45
    ldi     zeichen, 'e'
46
    rcall   serout                      ; Unterprogramm aufrufen
47
    ldi     zeichen, 's'
48
    rcall   serout                      ; ...
49
    ldi     zeichen, 't'
50
    rcall   serout
51
    rcall   sync                        
52
    rjmp    loop
53
 
54
serout:  
55
  lds    temp,UCSR0A
56
    sbrs    temp,UDRE0                ; Warten bis UDR für das nächste
57
                                        ; Byte bereit ist
58
    rjmp    serout
59
    sts     UDR0, zeichen
60
    ret                                 ; zurück zum Hauptprogramm
61
 
62
; kleine Pause zum Synchronisieren des Empfängers, falls zwischenzeitlich
63
; das Kabel getrennt wurde
64
                                    
65
sync:
66
    ldi     r16,0
67
sync_1:
68
    ldi     r17,0
69
sync_loop:
70
    dec     r17
71
    brne    sync_loop
72
    dec     r16
73
    brne    sync_1  
74
    ret
Funktioniert blendend!

Grüße,
euer LDer

von ersthelfer (Gast)


Lesenswert?

> Funktioniert blendend!

... und überhaupt, seit wann kann man SPL und SPH nicht mehr über out 
erreichen?

rumpöbeln hilft hier eben nicht weiter, sondern nachdenken wie du 
gemerkt hast

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
Noch kein Account? Hier anmelden.