Hallo!
Ich möchte ein Byte von einem AT90S2313 zu einem ATMEGA8535 schicken.
Es gelingt mir aber leider nicht. Ich bin mir sehr sicher dass die
Hardware korrekt verdrahtet ist. Ich möchte das Byte vom 8535 zum 2313
schicken und habe deshalb TxD vom 8535 mit RxD vom 2313 verbunden.
Wenn das stimmt glaub ich ist die initialisierug des Uart bzw Usart
falsch.
Ich würde gerne 8-bit Frames verwenden.
Wäre echt nett wenn sich mal jemand meine init methoden ankuken
könnte.
Ich stell sie hier mal rein.
AT90S2313:
-------------------------------------------
.equ CLOCK = 10000000 ;10 Mhz
.equ BAUD = 4882 ; UBRR ca. 128
.equ UBRRVAL = CLOCK/(BAUD*16)-1 ; ==> Baudrate 4882,87
.def temp = r21
.def RData = r22
;**********************************************************
;*** Methode die das UART zum empfangen initialisiert ***
;*** und die Baudrate einstellt ***
;**********************************************************
init_UART:
push temp
ldi temp, UBRRVAL ; Baudrate einstellen
out UBRR, temp
sbi UCR, RXEN ; RX (Empfang) aktivieren
pop temp
ret
-------------------------------------------
Jetzt der Code auf dem 8535:
----------------------------
;.equ CLOCK = 16000000 ;16 Mhz
;.equ BAUD = 4882 ; UBRR ca. 203
;.equ UBRRVAL = CLOCK/(BAUD*16)-1 ; ==> Baudrate 4882,87
.equ CLOCK = 10000000 ;10 Mhz
.equ BAUD = 4882 ; UBRR ca. 128
.equ UBRRVAL = CLOCK/(BAUD*16)-1 ; ==> Baudrate 4882,87
;***********************************************************************
**************
;*** Diese Methode Initialisert das Uart zum Senden mit einer Bausrate
vo ca 4882 ***
;***********************************************************************
**************
init_UART:
push temp
; Baudrate einstellen
ldi temp, 0x00
out UBRRH, temp
ldi temp, LOW(UBRRVAL)
out UBRRL, temp
; Frame-Format: 8 Bit
ldi TEMP, (1<<URSEL)|(1<<UCSZ0)|(1<<UCSZ1)
out UCSRC, temp
sbi UCSRB,TXEN ; TX aktivieren
pop temp
ret
----------------------------
Wäre sehr nett wenn sich jemand die Mühe machen würd und sich das mal
anschaut. Vielen dank im Vorraus :-)
Stimmt die Hardware?
Ich glaube mich zu erinnern, irgendwo hier mal gelesen zu haben, dass
man eine der RS232-Leitungen invertieren müsste, falls man keine
MAX232-ICs benutzt. Ist aber jetzt reine Spekulation.
...
kann es sein, dass Du TxD und RxD verwechselt hast?
Invertiert werden muss nix bei uC zu uC. Nur wenn ein Partner RS232
Pegel verwendet, also +-12V, dann wird logisch '1' zu -12V, was dann
mit einer Primitiv-Empfangsschaltung (z.B. Zenerdiode) halt invertiert
ist.
Wer sagt denn hier was von RS232? Da war doch gar nicht die Rede von.
Nee, nee. Nicht verwirren lassen.
TxD vom Sender an RxD vom Empfänger ist goldrichtig. Dann kommuniziert
man eben mit 5V-Pegeln. Geht. Ganz klar. Eventuell aber ein 10k
Pull-Down, ich hatte da mal Probleme, allerdings mit wesentlich höheren
Baud-Raten.
Zu Deinem Code kann ich leider nix sagen, ich programmiere in C.
Bestimmt wird Dir hier noch geholfen.
Gruß,
Sebastian
lässt du den 8535 jetzt mit 10 oder 16MHz laufen?
Irgendwie stehen da zwei ".equ"-Anweisungen.
Wie wäre es denn, wenn die Controller duplex verbindest, sprich: beide
TXD-Leitungen mit beiden RXD-Leitungen verbinden?
Hallo,
also meiner meinung nach müssten deine inits auf beiden avrs gleich
sein. Auch würde ich vermeiden nur einzelne bits zu setzen ohne vorher
das register komplett zu initialisieren.
sbi UCSRB,TXEN ; TX aktivieren
so was z.B, du weist ja nie ob vorher wirklich alle low waren. Auch
sind deine registerbezeichnungen teilweise komisch, das UCSRB heißt
doch auch UCR ??? Und das UCBRR ist nur ein 8 Bit register. Da brauchts
kein high() und low()
mfg
Stefan
Hallo!
Also ich bin mir sehr sicher dass ich TxD mit RxD verbunden habe. Ich
habs eben nochmal nachgschaut. Den 8535 hatte ich mal mit 16 Mhz und
hab gedacht es könnte evtl daran liegen dass es nicht geht. Ich hab ihn
dann an einen 10Mhz Quarz gehängt und gehofft dass es dann geht. Hat
aber nichts geholfen. Das mit den 16Mhz ist auskommentiert. Hab ich
vergssen wegzumachen g
Wo sollte ich den 10k Widerstand hinmachen?
Ich weiß zwar in etwa was Pull-down heißt aber ich
hab ehrlich gesgat keine Ahung wo der Widerstand da
jetzt hin sollte :-)
Was hätte ich den davon wenn ich beide Leitungen verbinde?
Das Problem daran wäre dass ich die Beiden anderen Pins schon benutze.
Ich müßte also nochmal an die Hardware ran. Ich würd das gern vermeiden
wenns geht. Ich kann doch asynchron senden und empfangen
dacht ich.
Die bezeichnungen für die Register hab ich aus dem Tutorial bzw aus dem
Datenblatt des 2313 übernommen. Das Low() ist da quatsch das stimmt :-)
Ich werd jetzt mal testen was passiert wenn ich die register vorher mit
0x00 beschreibe. Ich hab das Programm mit dem
Softwaredebugger vom AVR-Studio getstet. Da ist beim aufruf natürlich
alles null. g
vielen Dank für die Tipps. :-)
Hallo.
Da fällt mir grade nochwas ein.
Wie ist das mit dem URSEL-bit?
Soweit ich das verstanden hab aus dem Datenblatt kann ich damit regeln
in welches Register ich schreibe. Entweder nach UBRRH oder UCSRC. Beim
AVR-Studio werden aber IMMER beide Register geschrieben. Liegt das an
meinem Programm oder ist das ein Fehler im AVR-Studio?
danke :-)
Hallo!
Ich hab die Initmethoden jetzt verändert.
Was haltet ihr davon?
AT90S2313:
init_UART:
push temp
ldi temp, UBRRVAL ; Baudrate einstellen
out UBRR, temp
ldi temp, 0x10
out UCR, temp ; RX (Empfang) aktivieren
pop temp
ret
ATMEGA8535:
init_UART:
push temp
; Baudrate einstellen
ldi temp, 0x00
out UBRRH, temp
ldi temp, UBRRVAL
out UBRRL, temp
; Frame-Format: 8 Bit
ldi temp, 0x00
out UCSRC, temp
ldi TEMP, (1<<URSEL)|(1<<UCSZ0)|(1<<UCSZ1)
out UCSRC, temp
ldi temp, 0x08
out UCSRB,temp ; TX aktivieren
pop temp
ret
Es geht übrigens trotzdem nicht :-)
Deine Init im tiny2313 ist unvollständig, Du gibst keine
Frame-Informationen (Bytelänge, Stop, Parity...) an. Außerdem gibt es
Low- und High-Register für die Baudrate. Lies Dir mal das Datenblatt
durch ab Seite 110, da steht, wie´s gemacht wird.
Es ist kein Tiny2313 sondern ein AT90S2313.
Aber das kommt davon, wenn man die Bezeichnungen nicht korrekt nennt.
Dann verwechselt man das schnell mal...
...
Hi!
Ich möchte wirklich nur ein Byte senden ....
Das restliche Programm ist recht groß und unübersichtlich. Es ist eine
Steuerung für einen 6 beinigen Laufroboter.
Das einzige was nicht funktioniert ist die Komunikation zwischen den
controllern. Ich zeige euch gerne noch die sende Methode. Wenn ihr
wirklich wollt stelle ich auch das ganze Programm rein. Aber ich glaub
das bringt nichts. Also dann hier mal die Methode zum senden
;*******************************************************************
;*** Diese Methode versucht ein Byte über das UART zu senden. ***
;*** Sie klemmt das Programm solange fest bei das Byte weg ist. ***
;*******************************************************************
send_Data_UART:
sbis UCSRA,UDRE
rjmp send_Data_UART
ldi send_Data, 0x03
out UDR, send_Data
ret
und hier die Methode zum empfangen...
;**********************************************************
;*** Methode zum empfangen eines Datums über das Uart ***
;*** Falls ein neues Datum vorhanden ist dann wird ***
;*** der neue Bewegungsmodus festgelegt. ***
;*** (es findest keine Überprüfung auf Framfehler ***
;*** oder Overflow statt!!) ***
;**********************************************************
receive_DATA:
sbis USR, RXC
ret
push RData
in RData, UDR
ldi MovementMode, 0x00
ADD MovementMode, RData
pop RData
ret
Ansonsten benutze ich nur noch das Register Movementmode außerhalb
dieser Routinen. Ich denk mal dass es dann daran liegen muß wie ich
sende oder Empfange.
SPI möchte ich nicht benutzen weil ich noch nciht weiß ob ich später
irgendwann noch mehr Controller anhängen möchte.
Also wenn jemand eine Idee hat wäre ich für Voschläge dankbar :-)
[aussem Tutorial übernommen]
receive_loop:
sbis UCS[RA], RXC ; warten bis ein Byte angekommen ist
rjmp receive_loop
in temp, UDR ; empfangenes Byte nach temp kopieren
out PORTD, temp ; ... und an Port D ausgeben.
Einmal reinspringen und dann warten :) vielleicht ja endlos..
Oder richte mal nen IRQ für RXC ein, wäre vielleicht sogar sicherer.
IRQ? :-)
Ich mach in meinr recevie Methode glaub ich das selbe.
Ich warte nur nicht endlos, sondern wenn nix da ist sprioge ich aus der
Methode wieder raus. Ich seh sonst keinen UNterschied. Ich habs übrigens
auch aus dem Tutorial g
was ist denn ein IRQ?
"was ist denn ein IRQ?"
Nee...?
Ein IRQ ist ein Interrupt-Request. Kann von einem Timer oder einem
anderen Ereignis (siehe Datenblatt, Interruptquellen) ausgelöst werden
und verzweigt über die am Programmanfang stehende
Interrupt-Sprungtabelle...
So machst du das doch, oder willst du etwa behaupten, dass du solch
komplexe Steuerungen wie einen 6-beinigen Laufroboter ohne Interrupts
machst?
...
Hallo,
also ich finde das sieht eigendlich sehr gut aus. Probier mal
.equ UBRRVAL = 128
eventuell kommt dein Assembler ja nicht mit dem rechnen klar. Der Init,
das senden und empfangen sollte so funktionieren, zumindest beim 2313.
Hast du den TxD Pin als Ausgang mit Pull-Up definiert und den RxD am
anderen Prozzi als Eingang? Ich mach das zumindest immer, ich weis
nicht obs auch ohne geht.
mfg
Stefan
HI!
Ja stimmt ich mach das mit interrupts.
Ich wußte nur nicht dass das IRQ heißt :-)
Ich weiß ich führe ret aus. Wenn ich es so wie im tutorial mache dann
muß ich evtl ewig warten. So wie ich es mache springt er wieder raus
wenn er nix empfangen hat. Ich fand das so besser.
Im Datenblatt steht dass es egal ist ob man den PIN als Engang oder
ausgang definiert sobald man das UART eingeschaltet hat. Ich hab das
auch mal getestet. Es hat sich nix geändert. Das mit dem 128 probier
ich mal aus. Ich würd dann allerdings nicht vertsehen warum es geht...
g
Wie ich das teste dass es nicht geht?
ganz einfach g
Die beiden Programme auf den beiden contollern machen genau das was sie
sollen wenn ich die werte die ich vom uart bekommen soll einfach fest
einspeichere. Sobald die Werte mit dem UART eingelesen werden sollen
geht nixmehr. Daraus schließe ich dass es an der komunikation liegen
muss. Das ist ja das einzige was ich ändere......
Jetzt "zerpflück" ich mal deine Routine:
;**********************************************************
;*** Methode zum empfangen eines Datums über das Uart ***
;*** Falls ein neues Datum vorhanden ist dann wird ***
;*** der neue Bewegungsmodus festgelegt. ***
;*** (es findest keine Überprüfung auf Framfehler ***
;*** oder Overflow statt!!) ***
;**********************************************************
receive_DATA:
sbis USR, RXC
ret
push RData
in RData, UDR
ldi MovementMode, 0x00
ADD MovementMode, RData
pop RData
ret
Die Routine wird alsp mit (r)call aufgerufen.
Wenn das Interrupt-Flag RXC in USR nicht gesetzt wurde, dann wird
sofort zurückgesprungen. Das ist erstmal richtig, obwohl das Überprüfen
dieses Flags in der Mainloop "billiger" wäre, also jede Menge (r)call
und ret ersparen würde, die ja nicht gerade wenig Takte verbrauchen.
Nun kommt push & pop von RData. Wäre richtig, wenn man RData brauchen
würde. Braucht man aber nicht. Denn du könntest die Daten auch sofort
in das Register MovementMode einlesen, denn der Umweg über Löschen und
Addieren kommt aufs Selbe raus.
Statt
push RData
in RData, UDR
ldi MovementMode, 0x00
ADD MovementMode, RData
pop RData
ret
würde also
in MovementMode,UDR
ret
völlig reichen.
Noch sparsamer wäre es in der Mainloop:
mainloop:
;irgendwelche anderen Jobs...
sbis usr,rxc ;Byte empfangen? ja...
rjmp mainloop1 ;nein, weg hier...
in MovementMode,udr ;ja, Byte übernehmen
mainloop1:
;weitere Jobs der Mainloop
rjmp mainloop ;nochmal...
Du sparst bei gleicher Funktionalität einen UP-Aufruf (7 Takte), der ja
länger dauert als die eigentliche Arbeit.
...
Und andersherum wird es noch billiger:
;andere Mainloop-Jobs
sbic usr,rxc ;neues Byte empfangen?
in MovementMode,udr ;ja, Byte übernehmen
;weitere Mainloop-Jobs
Diese 2 Zeilen kosten dich ganze 2 Takte Rechenzeit und bewirken das
Selbe wie deine Routine.
Hat aber den Nachteil, dass man keine weiteren Programmzeilen einfügen
kann, z.B. das Setzen eines Flags, um andere Programmteile zu
informieren, dass sich etwas geändert hat.
...
also wenn ich das reichtig verstadanden hab ich das so wie ich es
geschrieben hab sehr umständlich aber es sollte funktionieren? :-)
bzw du siehts keinen Grund warum es nciht gehen soll?
Hallo,
Den Pull-down zwischen die TxD-RxD-Verbindung und GND.
Aber daran muss es nicht liegen.
Grundsätzlich solltest Du überprüfen:
a) identische Baudrate eingestellt?
b) externe Takte (Quarze oder Quarzoszillatoren) verwenden! Die
internen Oszillatoren in den AVRs sind zu ungenau.
c) gleiche Frames (z.B. 1 Startbit, 8 Datenbits, 2 Stoppbits)?
Deine beiden AVRs laufen aber an, oder? Nicht, dass einer der Beiden
aus irgendwelchen Gründen gar nicht arbeitet?
Ansonsten kann ich mich meinen Vorrednern nur anschließen: In den
Datenblättern sind Beispiele, wie man die USART auch in Assembler
initialisiert und programmiert. Das soll kein RTFM sein, die können das
nur besser erklären als ich ;-)
Weiterhin viel Erfolg.
Gruß,
Sebastian
> 0,54 euro porto können nie schadn
Für jedes Bit oder jedes Byte?
Ich habe übrigens nicht geschrieben, dass es funktionieren müsste, nur
dass es dasselbe tut wie deine Routine.
Um Aussagen zur Funktion machen zu können bräuchte ich das gesamte
Programm, viel Zeit und ein Motiv, warum ich mir diese Arbeit aufhalsen
sollte. Denn woher soll ich wissen, ob diese Routine auch jemals
aufgerufen wird?
Ansonsten schließe ich mich Sebastian an.
...
Ich benutze externe osilatoren und abe die selbe baudrate eingestellt.
Es könnte natürlich an unterschiedlichen frmes liegn. Ich hab aber
leider im Tutorial vom AT90S2313 nix dazu gefunden was für frames er
sendet! Ich dachte deshalb dass er wohl 8 Bit frames sendet. Ist das
falsch? Wie bekomme ich das raus? :-)
Hmmm...
Also ich hatte kürzlich das Problem, dass ein 3,6864MHz-Quarz (mit
22pF-Kondensatoren) an einem Mega8535 mit dreifachem Tempo rannte. Da
ging die serielle Verbindung mit dem PC auch nicht. Erst Kondensatoren
von 330pF am Quarz brachten Abhilfe. Warum das so ist, weiß ich nicht,
die Quarze stammen aus einem Sortiment von Pollin.
Es wäre also nicht schlecht, wenn du die Taktfrequenz mal überprüfen
würdest.
...