Hallo Forum,
ich versuche gerade mein USART mit einem Atmega88 in Assembler ans
Laufen zu bringen. Der Empfang läuft bereits. Der Atmega88 sendet leider
nicht korrekt. Hat jemand ein Beispiel zur Hand?
Meinen Code habe ich dem Usart Artikel entnommen und von Atmega8 nach
Atmega88 transferiert. Hat wohl nur teilweise geklappt.
Ich hänge ihn unten an, da es relativ lang ist. Den Code habe ich nur
infomäßig angefügt. Ich benötige nur ein Beispiel und erwarte keine
Korrektur.
Vielen herzlichsten Dank schon jetzt
Valentin
Ich definiere Makros zum Setzen und Löschen von bits.
Hallo,
erst mal Danke für die unmittelbare Antwort.
Deine Bemerkung zu meiner Platzverschwendung verstehe ich. Ich bin
AVR-Assembler Anfänger und versuche meinen Code für mich lesbarer zu
gestalten ohne Rücksicht auf den Flash. Ist ja genug da. Sollte ich in
Schwierigkeiten kommen, kann ich den Code eindampfen. Ich hoffe ich
benötige dann solche Krücken nicht mehr.
Nun zum USART: Ja ich versuche mit Polling zu senden. Die USART
Programmierung habe ich noch nicht richtig verstanden und ich hatte
gehofft wenigstens den Teil mit Beispielen erschlagen zu können.
Schließlich betrete ich überall Neuland. Habe nun den ganzen Sonntag
damit verbracht mir einen TTL nach Seriell Wandler zu bauen und den
USART zu programmieren. Trotz intensiver Suche und Lesen der Atmega88
Doku gelingt mir das Senden nicht. Übrigens scheinen da Fehler im
Atmega48 Atmega88 Atmega168 zu sein: Dort werden die out Befehle
benutzt die aber den Bereich der USART Register gar nicht erreichen
können. Man braucht offensichtlich sts.
Kann ich bitte ein Beispiel haben um das Senden mit Polling auch zu
erreichen? Senden tu ich wohl mit Polling wie folgt:
Im Anschluss zur Unterhaltung noch zwei Makros, da ich ständig bei push
und pop das SREG vergessen hatte. Ist als Anfänger einfach
betriebssicherer.
Nochmals vielen Dank!
Gruß
Valentin
ZuBlödFürTouch schrieb:> Was genau spricht gegen sbr und cbr?
Es geht halt nicht jeder Befehl mit jedem Register.
Man kann sich Makros schreiben, um das zu umgehen oder man kann sich
damit arrangieren und Für Operationen, bei denen in einem Register
einzelne Bits behandelt werden sollen, einfach Register nehmen, mit
denen das geht.
Da ich (ebenfalls noch nicht so lange dabei) auch noch nicht im Kopf
habe, welcher Befehl mit welchen Registern geht, habe ich mir ein
Word-Dokument (Anlage) gemacht, in dem die Register mit den möglichen
Befehlen tabellarisch aufgelistet sind. Da trage ich bei einem Projekt
jeweils die Variablen ein, und bekomme so eine Übersicht, welche sehr
häufig verwendeten Variablen ich in welche Register packen kann und was
in den SRAM muss.
Hallo zusammen,
erst mal Danke für die lebhafte Diskussion. Leider finden meine Makros
mehr Beachtung als meine Frage. Phillip hat völlig recht, mit seiner
Annahme, dass ich mir mit den Makros einiges Erleichtern will. Danke für
das Dokument Phillip!
Seid doch bitte so nett und geht auf meine eigentliche Frage ein. Sie
lautete: Hat jemand ein Beispiel für das Senden von einem Atmega48,
Atmega88 oder Atmega168 zum PC zur Hand? Das Senden soll wie oben
erklärt ablaufen. Stefan hat die von mir gewünschte Methode als Polling
bezeichnet. Empfangen klappt übrigens schon.
Viele Grüße
Reinhard
Hi
>ZuBlödFürTouch schrieb:>> Was genau spricht gegen sbr und cbr?>Es geht halt nicht jeder Befehl mit jedem Register.
Ein kurzer Blick ins Instruction Set sagt jedem, das 'sbr/cbr' auf jedes
Register anwendbar sind. Also kann man das Macro 'setbit' auf
MACRO setbit
sbr @0, 1<<@1
endmacro
eindampfen. Gilt analog für clrbit.
@Reinhard J. (rvj
Du schreibst:
>Nun zum USART: Ja ich versuche mit Polling zu senden.
Warum gibst du dann sämtliche Interrupts der UART frei?
MfG Spess
Danke für die Antwort.
Die Interrupts gebe ich wohl aus Unkenntnis frei.
Was möchte ich tun?
Ich benutze ein AVR-Net-IO und sende ein Startbyte (0x7E) vom PC zum
Controller, falls das zweite Byte 0xFE enthält werden vier Register Div1
bis Div4 vom Controller an den PC zurückgesendet. Ist das nicht der Fall
werden die Register mit den folgenden vier Bytes die vom PC kommen
gefüllt.
Wozu das ganze? Ich kann dann die Register setzen und abfragen.
Setzen der Register klappt einwandfrei. Nur weiß ich nicht wie ich das
mit dem Senden der Register zum PC bewerkstelligen muss. Die
Dokumentation habe cih leider bis jetzt noch nicht verstanden. Ich hoffe
mit einem Beispiel durchzublicken.
Viele Grüße
Reinhard
Hi
Empfängt dein PC überhaupt etwas?
Wenn du Probleme mit der UART hast dann schreibe dir ein kleins
Testprogramm das nur aus Initialisierung und einer Schleife, die ein
Zeichen sendet, besteht.
MfG Spess
Hallo,
ja mein PC empfängt was. Nur leider statt Startsignal (0x7E), Div1,
Div2, Div3, Div4, Endesignal (0x7F) stehen da sechsmal 0x02. Nutze
HTerm.exe ein freies Terminal, das wirklich Klasse ist. Der restliche
Code ist so simpel, dass ich meinen USART verdächtige nicht richtig
programmiert zu sein. Hast Du ein Beispiel? Das ist das was mir helfen
würde. Ich habe wirklich vieles probiert bevor ich mich ans Forum
wendete.
Gruß Reinhard
Hi
Probiere mal das Programm im Anhang. Mit HTerm solltest du 'A'
empfangen. UBRR muss natürlich angepasst werden.
Welche Taktfrequenz/Baudrate benutzt du?
MfG Spess
Vielen Dank Spess,
bin jetzt nicht mehr zu Hause und kann es erst morgen Abend
ausprobieren. Ich habe einen von 18,4320 MHz eingebaut. Die Frequenz und
baudrate gebe ich so mit
1
.equ clockmaster = 18432000 ; a baud rate quarz for the master
2
.equ baudrate = 9600
und schiebe dann den Wert in UBRR0H
1
; set baudrate
2
ldi temp0, high( clockmaster/(baudrate*16)-1)
3
sts UBRR0H, temp0
4
ldi temp0, low( clockmaster/(baudrate*16)-1)
5
sts UBRR0L, temp0
Das scheint richtig zu sein denn mit Deiner baudrate errechne ich
(11059200 / (9600 * 16) ) - 1 = 71 = 0x47
Mir fehlt aber
1
ldi r16,3<<UCSZ00
2
sts UCSR0C,r16
Ich werde mir das mit Register UCSR0C nochmal durchlesen, testen und
spätestens Mittwoch berichten. Wenn ich das Handbuch richtig verstehe
kann ich mir das eigentlich sparen, denn der default im UCSR0C ist
UCSZ00=1 und UCSZ01=1. Im Register UCSR0B ist der default für UCSZ02=0
und wir arbeiten darum mit 8-bit character size. Falls Dein code
funktioniert muss ich den Fehler woanders suchen.
Herzlichsten Dank
Valentin
PS: Ich muss mir das mit den Bitmanipulatoren vergegenwärtigen. Mit
meiner Makroakrobatik und dem Nacheinander setzen der Bits hatte ich
mich davor gedrückt. So wie Du das schreibst sieht das deutlich kürzer
aus. Gibt es da ein Tutorial für die Landbevölkerung?
spess53 schrieb:> Ein kurzer Blick ins Instruction Set sagt jedem, das 'sbr/cbr' auf jedes> Register anwendbar sind.
Dann bin ich mal wieder zu deppert, Doku richtig zu lesen.
Da steht:
CBR – Clear Bits in Register
Description:
Clears the specified bits in register Rd. Performs the logical AND
between the contents of register Rd and the complement
of the constant mask K. The result will be placed in register Rd.
Operation:
(i) Rd ← Rd • ($FF - K)
Syntax: Operands: Program Counter:
(i) CBR Rd,K 16 ≤ d ≤ 31, 0 ≤ K ≤ 255 PC ← PC + 1
16-bit Opcode: (see ANDI with K complemented)
Ich dachte bisher immer, das "d" in "Rd" stünde für die Nummer des
Registers also r.B. r16 für d=16 und das "16 ≤ d ≤ 31" gäbe an, welche
Nummern dür "d" genommen werden können.
Vielleicht kannst Du spess53 mir erklären, wie es richtig zu
interpretieren ist?
Hi
>Ich muss mir das mit den Bitmanipulatoren vergegenwärtigen. Mit>meiner Makroakrobatik und dem Nacheinander setzen der Bits hatte ich>mich davor gedrückt.
Das bringt wirklich mehr.
>Gibt es da ein Tutorial für die Landbevölkerung?
Wüsste ich aus dem Hut für Assembler nicht. Mir hat eigentlich die
AVR-Studio-Hilfe: AVR Assembler->User's Guide->Expressions gereicht.
Ansonsten must du mal in C-Hilfen wildern. Die sind identisch.
MfG Spess
Hi
@Philipp Klostermann (ag999)
>Vielleicht kannst Du spess53 mir erklären, wie es richtig zu>interpretieren ist?
Mein Fehler. Du hast Recht. Ich bin wahrscheinlich in der Schnelle bei
cbi oder sbi gelandet und habe das '0 ≤ A ≤ 31' falsch interpretiert.
MfG Spess
Ich geb mal zu, auch meine erste Frage hätte sich auf die Bitsetzerei
gestürzt. cbr/sbr funktioniert (also, sofern mir nicht jemand etwas
anderes zeigt) für alle general purpose register, cbi/sbi funktioniert
nicht bei allen I/O Registern wegen der Adressierung, soweit richtig.
Aber zum Thema:
Schau ins Tutorial hier auf der Seite, gibt's 'n ganzes Kapitel nur zum
Thema UART mit ASM (links oben auf der Seite, im Punkt AVR). Was danach
an Fragen bliebt bitte noch posten.
Hallo
im instruction set manual steht
CBR Rd,K 16 ≤ d ≤ 31, 0 ≤ K ≤ 255
SBR Rd,K 16 ≤ d ≤ 31, 0 ≤ K ≤ 255
und ich vermute, dass r0 bis r15 nicht funktionieren werden.
Dann besteht da noch die Schwierigkeit, dass wegen 3=0b00000011
1
sbr r16,3 ; Set bits 0 and 1 in r16
bits 0 und 1 setzt, während dessen
1
sbi DDRC, 3 ; Port C.3 output - LCD Data/command
nur bit 3 setzt. Für mich war das ein beliebter Fehler und wenn mein
Projekt wieder einige Wochen ruhte, lief ich prompt wieder in die selbe
Falle. Daher die Makros.
Vielen Dank für den Hinweis mit dem Tutorial. Ich habe es sehr sehr oft
konsultiert. Es st einfach Klasse. Vielleicht liest das ja einer der
Autoren. Ihnen herzlichsten Dank.
Ich kann leider erst morgen Abend weiter machen. ich werde das Programm
von spess laufen lassen und dann mal die überflüssigen Interrupts
entfernen. Diese habe ich auch nicht in der Interrupt Vektortabelle mit
ISRs versorgt. Das könnte der Grund sein. Falls es so ist beschreibe ich
es hier.
Vielen Dank für das rege Interesse an diesem thread.
Valentin
Vielleicht sollte man sich diese Fake-Opcodes gar nicht erst angewöhnen.
Habe auch schon öfters diesen sbi/sbr-Denkfehler mit der Bitmaske
gemacht und lange den Fehler gesucht.
Wenn man daran denkt, dass es eigentlich gar kein SBR gibt oder direkt
ORI verwendet oder gedanklich berücksichtigt, passiert das nicht.bei CBR
geht das auch mit ANDI reg,!mask sind nur zwei Zeichen mehr zu tippen.
Mark
Hallo zusammen!
Erst mal vielen Dank an alle! Nachdem ich mit spess53's Hilfe gesehen
habe, dass der USART funktioniert, habe ich den Fehler eliminieren
können. Hier mein Analyseweg und mein Fehler:
1. Ich habe das Programm von spess53 laufen lassen und 'A's ohne Ende
gekriegt (vergleiche Eintrag vom Datum: 18.03.2012 22:13). Speziellen
Dank an spess53
2. Danach habe ich die überflüssigen Interrupts rausgehauen (vergleiche
Eintrag vom Datum: 18.03.2012 22:13 und Tipp in Eintrag Datum:
18.03.2012 22:35) Danke Stefan.
1
; This interrupt is dropped due to the the discussion
2
; on microcontroller.net
3
; USART Interrupt if send-register empty
4
; lds temp0, UCSR0B
5
; setbit temp0, UDRIE0, temp2
6
; sts UCSR0B, temp0
7
; This interrupt is dropped due to the the discussion
8
; on microcontroller.net
9
; USART Interrupt bei Sendevorgang beendet
10
; lds temp0, UCSR0B
11
; setbit temp0, TXCIE0, temp2
12
; sts UCSR0B, temp0
Leider kein Erfolg. Ich empfange weiterhin nur 0x02.
3. Und jetzt kommts: Ich habe den Fehler! Mein Makro sichert immer alle
named register temp0 bis temp4. Dann speichere ich das SREG in temp0 und
haue auch dieses auf den stack. Da ich aber das zu übermittelnde Byte in
temp0 ablegte bevor ich USARTSEND rufe stand nach dem Sichern des SREG
das SREG in temp0 und das enthielt zufällig 0x02.
Was mir passiert ist im code ohne Makros:
Ich stelle das zu übermittelnde Byte nach temp0 und rufe USARTSEND
1
mov temp0, DIV1
2
rcall USARTSEND
und das sieht so aus
1
USARTSEND:
2
push temp0 ; save temp0
3
push temp1 ; save temp1
4
in temp0, SREG ; save SREG !!! hier geht Byte in ...
5
; ... temp0 kaputt !!! Es ...
6
push temp0 ; ... steht jetzt das SREG in temp0
7
;
8
UDR0EmptyOrNot:
9
lds temp1, UCSR0A
10
sbrs temp1, UDRE0 ; Loop until UDR0 in UCSR0A is empty
11
rjmp UDR0EmptyOrNot
12
sts UDR0, temp0 ; Gib temp0 nach seriell
13
;
14
pop temp0 ; restore SREG,
15
out SREG, temp0
16
pop temp1 ; restore temp1
17
pop temp0 ; restore temp0
18
;
19
ret
Ich denke das war ein Anfängerfehler.
Lehre: Falls das SREG in einem Register gespeichert wird um es auf den
stack zu legen, dann kann dieses Register nicht zum Parametertransport
genutzt werden.
Nochmals vielen Dank.
Gruß Valentin
PS. Ich werde noch zum USART Fan. Damit kann ich mir beim Programmieren
Registerinhalte anzeigen lassen.
Reinhard J. schrieb:> Ich denke das war ein Anfängerfehler.
Es war vor allen Dingen ein Fehler, weil du in deinem Registerchaos die
Übersicht verloren hast. Alle Register irgendwie tempxx zu nennen trägt
dann auch nicht dazu bei, die Übersicht zu behalten.
Wenn dir ein Register so wichtig ist, dass du ihm einen Namen geben
willst, dann gib ihm einen guten Namen, der auch etwas ob die
beabsichtigte Nutzung des Registers etwas aussagt. Einfach alles temp zu
nennen ... da kannst du es auch gleich bleiben lassen. Das wär sogar
noch besser.