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:
.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
>> 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.
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.
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.
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.
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. ;-)
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 ;-)
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
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.
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.
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 ;)
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.