Forum: Mikrocontroller und Digitale Elektronik ein Byte senden aber wie?!


von Michael Kassel (Gast)


Lesenswert?

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

von Hannes L. (hannes)


Lesenswert?

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.

...

von key (Gast)


Lesenswert?

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.

von Sebastian (Gast)


Lesenswert?

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

von Rahul (Gast)


Lesenswert?

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?

von Stefan (Gast)


Lesenswert?

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

von Michael Kassel (Gast)


Lesenswert?

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

von Michael Kassel (Gast)


Lesenswert?

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

von Michael Kassel (Gast)


Lesenswert?

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

von TravelRec. (Gast)


Lesenswert?

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.

von Hannes L. (hannes)


Lesenswert?

Es ist kein Tiny2313 sondern ein AT90S2313.

Aber das kommt davon, wenn man die Bezeichnungen nicht korrekt nennt.
Dann verwechselt man das schnell mal...

...

von Michael Kassel (Gast)


Lesenswert?

Beim AT90S2313 kann ich ja keine Frames und sowas einstellen.
Ich geh mal davon aus dass der immer auf 8-Bit Frames läuft.
Stimmt das?!

von Simon K. (simon) Benutzerseite


Lesenswert?

Stackpointer initialisiert ? Gut wäre es, wenn du mal das ganze Programm
anhängen würdest...

von Simon K. (simon) Benutzerseite


Lesenswert?

Übrigens: wenn du nur zwischen 2 Controllern Daten austauschen willst,
nimm doch SPI. Ist etwas einfacher.

von David W. (Gast)


Lesenswert?

Davon wäre ich jetzt nicht so überzeugt :)

Aber es wäre wirklich mal interessant, wie du denn überhaupt
feststellst, dass das nich läuft :)

von Michael Kassel (Gast)


Lesenswert?

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

von David W. (Gast)


Lesenswert?

[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.

von Michael Kassel (Gast)


Lesenswert?

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?

von Hannes L. (hannes)


Lesenswert?

"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?

...

von Simon K. (simon) Benutzerseite


Lesenswert?

Ich mach in meinr recevie Methode glaub ich das selbe.

Öh ne.

Du führst andauernd einen ret aus!?

von Stefan (Gast)


Lesenswert?

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

von Michael Kassel (Gast)


Lesenswert?

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

von Michael Kassel (Gast)


Lesenswert?

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......

von Hannes L. (hannes)


Lesenswert?

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.

...

von Hannes L. (hannes)


Lesenswert?

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.

...

von Michael Kassel (Gast)


Lesenswert?

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?

von Sebastian (Gast)


Lesenswert?

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

von Sebastian (Gast)


Lesenswert?

Fällt mir gerade ein,

teste doch mal auf frame-Errors, evtl. gibt das Hinweise darauf, was
genau nicht stimmt.

Gruß nochmal,
Sebastian

von Hannes L. (hannes)


Lesenswert?

> 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.

...

von Michael Kassel (Gast)


Lesenswert?

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? :-)

von Hannes L. (hannes)


Lesenswert?

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.

...

von Michael Kassel (Gast)


Lesenswert?

coole sache...
danke für den Tipp ....
Wie teste ich die?
Mit einem Oszyloskop oder gibts da noch andere Möglichkeiten?

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.