Forum: Mikrocontroller und Digitale Elektronik Attiny2313 USART Baudrate stimmt nicht


von StePo (Gast)


Lesenswert?

Guten Tag allerseits

Ich möchte mich ein wenig in USART einarbeiten.
Ich habe:

Attiny2313
AVR Studio 4
STK500
HyperTerminal

Ich möchte vom Attiny aus Zeichen an den pc senden. Das ganze 
funktioniert aber nicht. Der HyperTerminal verhält sich recht seltsam, 
manchmal bekomme ich einfach nur datenschrott ( willkührliche 
zeichenketten ), manchmal macht mein Hyperterminal lauter leerzeichen 
und manchmal blinkt der curser vom hyperterminal einfach nur hektisch, 
wenn ich den attiny anschalte.

Vorab mal der quellcode:
1
.include "C:\Programme\Atmel\AVR Tools\AvrAssembler\Appnotes\2313def_manipuliert.inc"
2
3
;Register deffintion
4
5
.def zeichen = R17
6
7
;Baudrate berechnen
8
.equ F_CPU = 3686400                           ; Systemtakt in Hz
9
.equ BAUD  = 2400                              ; Baudrate
10
 
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
20
;Stackpointer initialisieren
21
22
ldi     R16, LOW(RAMEND)
23
out     SPL, R16
24
25
;Prescaler auf Faktor 1 setzen
26
sbr R16,CLKPCE
27
out CLKPR,R16
28
29
ldi R16,0
30
out CLKPR,R16
31
32
; Baudrate setzen
33
34
ldi R16,HIGH(UBRR_VAL)
35
out UBRRH,R16
36
ldi R16,LOW(UBRR_VAL)
37
out UBRRL,R16
38
39
;UART anschalten
40
41
ldi R16,0
42
sbr R16,UCSZ1
43
SBR R16,UCSZ0
44
;sbr R16,UMSEL
45
46
out UCSRC,R16
47
48
sbi UCSRB,TXEN
49
50
loop:
51
    ldi     zeichen, 'T'
52
    rcall   serout                      ; Unterprogramm aufrufen
53
    ldi     zeichen, 'e'
54
    rcall   serout                      ; Unterprogramm aufrufen
55
    ldi     zeichen, 's'
56
    rcall   serout                      ; ...
57
    ldi     zeichen, 't'
58
    rcall   serout
59
    ldi     zeichen, '!'
60
    rcall   serout
61
    ldi     zeichen, 10
62
    rcall   serout
63
    ldi     zeichen, 13
64
    rcall   serout
65
    rcall   sync                        
66
    rjmp    loop
67
 
68
serout:
69
    sbis    UCSRA,UDRE                  ; Warten bis UDR für das nächste
70
                                        ; Byte bereit ist
71
    rjmp    serout
72
    out     UDR, zeichen
73
    ret                                 ; zurück zum Hauptprogramm
74
 
75
; kleine Pause zum Synchronisieren des Empfängers, falls zwischenzeitlich
76
; das Kabel getrennt wurde
77
                                    
78
sync:
79
    ldi     r16,0
80
sync_1:
81
    ldi     r17,0
82
sync_loop:
83
    dec     r17
84
    brne    sync_loop
85
    dec     r16
86
    brne    sync_1  
87
    ret


Da sich der hyperterminal so seltsam verhält, nehme ich an das der 
Fehler irgendwie bei der Baudrate liegt. Es kommt ja auch ein signal aus 
dem controler heraus. Ich habe im simulator überprüft ob der 
Präprozessor den richtigen Wert für das UBRR Register errechnet.

Bei 2400 BAUD = 0x5F = 95
ich habe "zu fuss" den wert 95,5 errechnet

Bei 9600 Baud =  0x17 = 23
zu fuss: 24,5

ich hab das UBRR register auch schon mit allen werten (auf und 
abgerundet) gefüttert, half aber alles nichts.

Ich habe volgende Fehlerquellen schon ausgeschlossen:

-Controler wird vom auf dem STK500 integriertem oszilator mit 3686400 Hz 
gespeist.
-Fuses stehen auf External Clock mit 65ms Start-up time
-CKDIV8 Fuse ist nicht gesetzt
-interner Vorteiler steht auf faktor 1 (siehe quellcode)
-Das programm scheint im Simulator zu laufen (daten werden ins UDR 
Register transportiert)
-Signal kommt aus dem Attiny heraus ( mit osziloskop geprüft )
-Hyperterminal einstellungen überprüft ( 2400 bzw 9600 BAUD 8bit  1 
stoppbit )

so langsam gehen mit die Ideen und die schokolade aus. Währe über etwas 
hilfe sehr erfreut.

mfg Steffen

von Stefan E. (sternst)


Lesenswert?

1
;Prescaler auf Faktor 1 setzen
2
sbr R16,CLKPCE
3
out CLKPR,R16
In R16 steht nicht das, was richtig wäre, schließlich war R16 vor dieser 
Operation nicht leer.

von (prx) A. K. (prx)


Lesenswert?

Dazu kommt, dass
  sbi port,1
Bit 1 setzt, aber
  sbr reg,1
Bit 0 setzt.

von Norbert (Gast)


Lesenswert?

>> Zitat:
>> In R16 steht nicht das, was richtig wäre,
>> schließlich war R16 vor dieser Operation nicht leer.

 ;Prescaler auf Faktor 1 setzen
 sbr R16,CLKPCE
 out CLKPR,R16

 ldi R16,0
 out CLKPR,R16

Die ersten beiden Befehle sind redundant, da sie von den nächsten zwei 
Befehlen komplett ersetzt werden.

Versuch mal kontinuierlich 0xff zu senden, das ergibt ein Startbit (Low) 
und dann neun High Bits.

Man kann dann prima mit dem Oszilloskop die Periode messen und mit dem 
avisierten Ziel vergleichen.

von Stefan E. (sternst)


Lesenswert?

Norbert schrieb:
>>> Zitat:
>>> In R16 steht nicht das, was richtig wäre,
>>> schließlich war R16 vor dieser Operation nicht leer.
>
>  ;Prescaler auf Faktor 1 setzen
>  sbr R16,CLKPCE
>  out CLKPR,R16
>
>  ldi R16,0
>  out CLKPR,R16
>
> Die ersten beiden Befehle sind redundant, da sie von den nächsten zwei
> Befehlen komplett ersetzt werden.

Nein. CLKPR benötigt eine spezielle Zugriffssequenz. Und weil beim 
ersten Zugriff nicht das richtige geschrieben wird, wird CLKPR hier gar 
nicht verändert.

von Norbert (Gast)


Lesenswert?

Stefan Ernst schrieb:
> Nein. CLKPR benötigt eine spezielle Zugriffssequenz. Und weil beim
> ersten Zugriff nicht das richtige geschrieben wird, wird CLKPR hier gar
> nicht verändert.

Da CKDIV8 nicht gesetzt ist, gilt laut Handbuch:

>If CKDIV8 is unprogrammed, the CLKPS bits will be reset to “0000”.

damit ist der Divisor der Taktfrequenz 1.

Da der Teiler sowieso auf 1 gesetzt werden soll gilt:

- da RAM Größe = 128Byte müsste RAMEND <= 0x7f sein.

>> ldi     R16, LOW(RAMEND)

  Damit ist das MSB in R16 nicht gesetzt und es wird beim späteren 
Schreiben auch nicht das CLKPCE Bit gesetzt.

Also haben die beiden out Befehle keine Wirkung.

von Norbert (Gast)


Lesenswert?

Stop, alles zurück.

>> ;Prescaler auf Faktor 1 setzen
>> sbr R16,CLKPCE
>> out CLKPR,R16

Der hier schlägt fehl, weil noch andere Bits ausser CLKPCE gesetzt sind.
Überbleibsel von RAMEND in R16.
(Anmerkung an mich selbst: RTFM) ;-)

Somit werden die hier nicht funktionieren:
>> ldi R16,0
>> out CLKPR,R16

Asche auf mein Haupt!


Aber im Ergebnis bleibt der ClockPrescaler auf 1 stehen und sollte daher 
mit dem ursprünglichen Problem nichts zu tun haben.

von Stefan E. (sternst)


Lesenswert?

Norbert schrieb:

> Da CKDIV8 nicht gesetzt ist,

Sorry, aber auf solche Aussagen vertraue ich nicht blind. Schon gar 
nicht nach Betrachten des Codes. Würde er den Code diesbezüglich 
korrigieren, wäre es schlicht egal, was CKDIV8 für einen Status hat.

>>> ldi     R16, LOW(RAMEND)
>
>   Damit ist das MSB in R16 nicht gesetzt und es wird beim späteren
> Schreiben auch nicht das CLKPCE Bit gesetzt.

Das MSB alleine ist es nicht. Auch wenn er das MSB später setzen würde, 
würde es nicht gehen, weil der Rest dann nicht Null ist.
EDIT: wie du inzwischen ja auch selbst festgestellt hast. ;-)

> Also haben die beiden out Befehle keine Wirkung.

Sag ich ja. ;-)

von Norbert (Gast)


Lesenswert?

OK, helfen wir noch mal ein bischen...

Versuch mal folgendes:
  ;UART anschalten
  ldi R16,(1<<UCSZ1)|(1<<UCSZ0)
  out UCSRC,R16
  ldi R16,(1<<TXEN)|(1<<RXEN)
  out UCSRB,R16


(aber erst das Prescaler Zeuch aufräumen ;-)

von spess53 (Gast)


Lesenswert?

Hi

>Controler wird vom auf dem STK500 integriertem oszilator mit 3686400 Hz
>gespeist.

Vergiss es. Nimm einen Quarz.

MfG Spess

von (prx) A. K. (prx)


Lesenswert?

spess53 schrieb:

> Vergiss es. Nimm einen Quarz.

Wo ist da das Problem? der STK500 Taktgenerator ist ebenfalls 
quarzbasiert.

von spess53 (Gast)


Lesenswert?

Hi

>Wo ist da das Problem? der STK500 Taktgenerator ist ebenfalls
>quarzbasiert.

Ich habe das vor längerer Zeit mal nachgemessen und merkliche 
Unterschiede zwischen angezeigter und 'wahrer' Frequenz festgestellt.

MfG Spess

von StePo (Gast)


Lesenswert?

Erstmal danke für die vielen tipps.
Also das mit dem
1
sbr R16,CLKPCE
2
out CLKPR,R16
3
4
ldi R16,0
5
out CLKPR,R16

war natürlich käse, hätte mir schon in der simulation auffallen sollen. 
Mann muss übrigens erst das CLKPCE bit setzen damit man man den wert in 
CLKPR ändern kann. Das fusebit sollte den wert beim fusen zwar auch auf 
0000 bzw 0011 ändern, allerdings kann der Wert immer noch über CLKPR 
geändert werden ohne das das einfluss aufs fusebit hat. Deshalb hab ich 
vorsichtshalber manuell auf 0000 gesetzt.
1
ldi R16,0
2
sbr R16,UCSZ1
3
SBR R16,UCSZ0

hat auch nicht funktioniert. Das hab ich jetzt wie von Norbert 
vorgeschlagen abgeändert.

Außerdem ist mir aufgefallen das hyperterminal noch auf "Flussteuerung: 
Hardware" stand. Ich hab jetzt auf keine umgestellt. Funktionieren tuts 
aber trozdem nicht.
Ich muss mal schauen ob hier irgendwo noch ein quarz durch die gegend 
diffundiert. Wenn ich mein (tast)kopf wiedergefunden hab werd ich das 
signal mal oszillographieren.

Was mich aber wundert ist: warum
1
ldi R16,0
2
sbr R16,UCSZ1
3
SBR R16,UCSZ0
nicht funktioniert sbr ist doch der befehl um einzelne bits in einem 
Register zu setzen. Also syntaxmäßig: R16 Register,Bitnummer aber 
scheinbar übernimmt der den ganzen wert der hinter dem Komma steht ins 
Register, anstadt das entsprechende bit zu setzen.

von Stefan E. (sternst)


Lesenswert?

StePo schrieb:

> Was mich aber wundert ist: warum
>
1
> ldi R16,0
2
> sbr R16,UCSZ1
3
> SBR R16,UCSZ0
4
>
> nicht funktioniert sbr ist doch der befehl um einzelne bits in einem
> Register zu setzen. Also syntaxmäßig: R16 Register,Bitnummer aber
> scheinbar übernimmt der den ganzen wert der hinter dem Komma steht ins
> Register, anstadt das entsprechende bit zu setzen.

Nein, es ist eben nicht der Befehl um ein einzelnes Bit zu setzen, 
sondern um mehrere Bits zu setzten. Der zweite Parameter ist daher 
auch keine Bitnummer, sondern eine Maske.
sbr Rxx,0x81 : Bits 0 und 7 setzen
sbr Rxx,(1<<UCSZ0) : Bit UCSZ0 setzen
sbr Rxx,(1<<UCSZ0)|(1<<UCSZ1) : Bits UCSZ0 und UCSZ1 setzen

So nebenbei: "sbr" ist nur ein Alias für "ori".

PS: Außerdem kannst du dir dieses Schreiben nach UCSRC auch gleich ganz 
sparen. Du schreibst da nur rein, was da sowieso schon drin steht.

von StePo (Gast)


Lesenswert?

Ahhh, danke das erklährt natürlich einiges. Vielleicht sollt ich mir 
doch nochmal das instruction set zu gemüte führen.

Wie auch immer, die programmierfehler sind behoben und ich habe 
inzwischen meinen Tastkopf wiedergefunden :D und folgende seltsame 
enteckung gemacht:
Auf den hinweis von norbert hin habe lasse ich den attiny jetzt nur 0xFF 
senden, sodas ich nur das Start bit habe. Das Start bit ist aber nur 
etwa 20ms lang, was einer Frequenz, bzw bitrate von 50Hz entspricht. Wie 
kann das sein?
Der Attiny bekommt am XTAL1 eingang seine 3,68 MHz, wie genau die sind 
kann ich nicht sagen, mein oszi ist schon etwas älter ;)

von StePo (Gast)


Lesenswert?

Ok, ich habe den Fehler gefunden xD Meine include datei war 
unvollständig und ich hab sie manuel vervollständigt. Dabei hab ich das 
UBRRH und UBRRL Register vertauscht x/ Trozdem danke für die viele 
Hilfe.

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.