AVR-UART master slave

#925372
Lesenswert?

hallo,
ich habe ein problem mit den uarts vom mega168 und mega128,
der mega128 ist der master und der mega168 ist der slave soll nur 
empfangen,komunikation erfolgt über rs485.
zeichen hin und her senden zwischen den beiden mc funktioniert

so nun sollten die slaves ihre eigene adresse bekommen im datenblatt 
steht etwas von ""Multi-processor Communication Mode"" aber nirgends 
findet mann ein beispiel

slave mega168:
;uart init
ldi temp, 0
sts UBRR0H, temp
ldi temp, (F_CPU/16+Baudrate/2)/Baudrate-1;
sts UBRR0L, temp
ldi temp, (1<<RXEN0)|(1<<RXCIE0) ; RX aktivieren
sts UCSR0B, temp
;************************
UART_RX_int:
in regsave, sreg
lds tempi, UDR0
inc WPos
mov tempi2, WPos
andi tempi2, RX_Buffer-1
cp tempi2, RPos
breq buffer_full
mov WPos, tempi2
clr tempi2
ldi XL, low(RXBUF)
ldi XH, high(RXBUF)
add XL, WPos
adc XH, tempi2
st X, tempi
buffer_full:
out sreg, regsave
reti

;maaster mega128
;uart1 init
ldi  wl,low((clock/(16*baud1))-1)  ;RS232-1 auf 9600 Baud
sts  ubrr1l,wl    ;Baudratenwert L setzen
ldi  wl,high((clock/(16*baud1))-1) ;einstellen
sts  ubrr1h,wl    ;Baudratenwert H setzen
ldi  wl,(3<<ucsz10)   ;Datenformat 8N1;
sts  ucsr1c,wl    ;Datenformat setzen
ldi  wl,(1<<RXCIE1)|(1<<RXEN1)|(1<<TXEN1);RX mit Interrupt aktivieren
sts  ucsr1b,wl    ;Einstellungen setzen

 ;************************
USART_TX1:
:in wl steht das zeichen was übertragen wird

   lds buffer,  UCSR1A
    sbrs buffer, UDRE1
    rjmp USART_TX1
    sts UDR1, WL
ret




vieleicht könnte einer von euch mir ein bischen weiterhelfen
mfg
kay
Gast #926090
Lesenswert?

Mit dem "Multi-processor Communication Mode" wird nur eine Hilfestellung 
zur automatischen Reaktion auf das 8. Bit (TXB8) bereitgestellt.

Wird ein Zeichen empfangen, bei dem der Sender das 8. Bit gesetzt hat, 
dann werten (per von dir zu schreibender Software) die Slaves dieses 
Zeichen als Adresse und vergleichen diese Adresse mit der eigenen.
Ist sie gleich, dann löscht die Software des betroffenen Slave-uC sein 
MPCM-Bit und kann so die nachfolgenden Daten (mit Bit 8 = 0) empfangen.
Beim erneuten Empfang einer Adresse (mit Bit 8 = 1) geht das Spiel mit 
dem MPCM-Bit wieder von vorne los.


Diese Slave-Adresse ist also nichts, was man einfach in irgendeinem 
Register einstellen kann. Du siehst, da gibt es noch einiges zu 
Programmieren.
#926259
Lesenswert?

hallo,
so habe erstmal versucht den sender richtig einzustellen

könnte das denn einer von euch mal überprüfen

 ldi  temp,low((clock/(16*baud0))-1)   ;RS232-0 auf 9600 Baud;
 out  ubrr0l,temp          ;Baudratenwert L setzen
 ldi  temp,high((clock/(16*baud0))-1)   ;einstellen
 sts  ubrr0h,temp          ;Baudratenwert H setzen

 ldi temp,0    ; "double transmission speed" aus
 out UCSR0A,temp      ; MPCM aus

 ldi temp,0b00001100    ; 9 Bit
 out UCSR0B,temp    ; Sender aktivieren
 ldi temp, 0b10000110  ; Frame-Format: 9 Bit, asyncrone Übertragung
 STS UCSR0C, temp    ; kein Parity, 1 Stopbit


Ausgabe:
 sbis UCSR0A,UDRE0
 rjmp Ausgabe           ; Byte bereit ist

 sbi UCSR0B,TXB80
 out UDR0, adresse       ; senden der Adresse=168
 cbi UCSR0B,TXB80

Ausgabe2:
sbis UCSRA,UDRE       ; Warten bis UDR für das nächste
rjmp Ausgabe2            ; Byte bereit ist
out UDR,temp           ;temp enthält das auszugebende zeichen
ret

mfg
kay
Gast #928405
Lesenswert?

HI

>kann mir denn keiner sagen ob meine initialisierung vom sender her richtig >ist.

Ja. Falsch, siehe oben.

>anscheinend kennt sich wohl niemand mit mpcm mode aus...

Da hast du wahrscheinlich Recht. Ist aber für dich die einmalige 
Gelegenheit das herauszubekommen und es hier kundzutun.

Also was im Datenblatt vom 168 steht, ist doch ziemlich verständlich. Du 
hast ganz oben geschrieben, das die Kommunikation zwischen den AVRs 
funktioniert.
Wo ist jetzt eigentlich das Problem?

MfG Spess
Gast #928438
Lesenswert?

Hi

>nun sollten die slavs ihre eigene adresse bekommen und das haut nicht...

Die Adressen musst du doch den Slaves verpassen.

Der Mastermode macht eigendlich nichts anderes, als erst mal alle 
Kommunikation mit den Slaves zu unterbinden, solange Bit 8 nicht gesetzt 
ist. Wenn das Bit gesetzt ist steht bei allen Slaves die vom Master 
gesendete Adresse im UDR. Das musst du auslesen (bei jedem Slave) und 
jeder Slave muss die Adresse mit seiner eigenen vergleichen. Wenn die 
Adresse nicht stimmt kann der Slave weiter ein Nickerchen machen. Bei 
übereinstimmender Adresse in den Normalmode schalten um die 
nachfolgenden Daten (mit Bit 8=0) empfangen zu können. Nach Ende der 
Übertragung wieder in den Mastermode schalten und die Nachricht 
verarbeiten. Fertig. Diese Erkenntnisse entstammen 2 min Datenblatt.

MfG Spess
#928443
Lesenswert?

Hi


> Die Adressen musst du doch den Slaves verpassen.
das habe ich schon gemacht zb.slave1=155 svlave2=188,in der
RXint-routine vergleiche ich ,
UART_RX_int:
  in regsave, sreg
  lds ADRES, UDR0



 cpi ADRES,168
    breq empfang2
RJMP buffer_full

empfang2:
ldi temp,(0<<MPCM0)    ;
    STS UCSR0A,temp      ; MPCM ein

lds tempi, UDR0
  inc WPos
  mov tempi2, WPos
  andi tempi2, RX_Buffer-1
  cp tempi2, RPos
  breq buffer_full
  mov WPos, tempi2
  clr tempi2
  ldi XL, low(RXBUF)
  ldi XH, high(RXBUF)
  add XL, WPos
  adc XH, tempi2
  st X, tempi
buffer_full:

ldi temp,(1<<MPCM0)    ;
    STS UCSR0A,temp      ; MPCM ein



  out sreg, regsave
reti


so und hier die init vom uart
  ldi temp, 0
  sts UBRR0H, temp

  ldi temp, (F_CPU/16+Baudrate/2)/Baudrate-1;Baudrate berechnen und 
runden
  sts UBRR0L, temp



     ldi  temp,(0<<MPCM0); "double tranmission speed" aus
  sts UCSR0A,temp      ; MPCM aus

     ldi  temp,(7<<ucsz00)    ;Datenformat 9N1  ;
  sts UCSR0C,temp    ; Sender aktivieren


    ldi  temp,(1<<RXCIE0)|(1<<rxen0); RX und TX akti-
    sts  ucsr0b,temp    ;vieren, RX Int einschalten



so hab ich es gemacht

mfg
kay
#928474
Lesenswert?

spess53 wrote:
> Hi
>
> Indikator ist das RXB8n im UCSR0B. Wenn gesetzt -> Adresse, wenn 0
> Datenbyte.
> Also die Adresse nur überprüfen, wenn gesetzt.


müsste ich das in der init so initialisieren
   ldi  temp,(1<<RXCIE0)|(1<<rxen0)|(1<<rxb80); ; RX und TX akti-
    sts  ucsr0b,temp    ;vieren, RX Int einschalten

entschuldige bitte wenn ich nochmal frage,
> Also die Adresse nur überprüfen, wenn gesetzt.
das praktisch so umzusetzen habe ich probleme

mfg
kay
Gast #928496
Lesenswert?

Hi


>müsste ich das in der init so initialisieren..
Nein, das wird vom Master mitgesendet.


UART_RX_int:
            in regsave, sreg

            lds temp,UCSR0B
            sbrs tmp, 1<<RXB8n
            rjmp empfang2        ; wenn Datenbyte

            lds ADRES, UDR0      ; Adresse
            cpi ADRES,168        ; vergleichen
            brne ende            ; wenn kein Adresse->ende

            lds tmp, UCSR0A      ; Normalmode einstellen
            cbr tmp,1<<MPCM0
            sts UCSR0A.temp
            rjmp ende


empfang2:   ....


ende:       out sreg, regsave
            reti


Sollte in etwa so gehen.

MfG Spess
#928515
Lesenswert?

hallo ,

erstmal danke für die geduld,
so jetzt habe ich noch eine frage bezüglich des senders master

uart init
   ldi  temp,low((clock/(16*baud0))-1)  ;RS232-1 auf 9600 Baud;;
  out  ubrr0l,temp    ;Baudratenwert L setzen
   ldi  temp,high((clock/(16*baud0))-1) ;einstellen
  sts  ubrr0h,temp    ;Baudratenwert H setzen


ldi  temp,(0<<MPCM0); "double tranmission speed" aus
  out UCSR0A,temp      ; MPCM aus

    ldi  temp,(7<<ucsz00)    ;Datenformat 9N1
  sts UCSR0C,temp      ; Sender aktivieren


    ldi  temp,(1<<RXCIE0)|(1<<rxen0)|(1<<txen0); RX und TX akti-
    out  ucsr0b,temp    ;vieren, RX Int einschalten



daten senden:
sbis UCSR0A,UDRE0       ; Warten bis UDR für das nächste
rjmp daten senden           ; Byte bereit ist

sbi UCSR0B,TXB80
out UDR0, adress      ; senden der Adresse 168

cbi UCSR0B,TXB80

ausgabe2:
  sbis UCSR0A,UDRE0       ; Warten bis UDR für das nächste
  rjmp Ausgabe2           ; Byte bereit ist
  out UDR0,temp
ret

wäre dies so korrekt

mfg
kay
Gast #928539
Lesenswert?

Hi

Zum 3.Mal: Nein

Beim laden von 16-Bit-Registern MUSS erst das High-Byte und DANACH das 
Low-Byte geschrieben werden (UBRR0)

>ldi  temp,(0<<MPCM0); "double tranmission speed" aus    ????????

Gewöhne dir bitte von Anfang an an, nur die Bits zu verändern, die 
geändert werden müssen. Mit dem vorherigen Befehl und

>out UCSR0A,temp      ; MPCM aus

überschreibst du das ganze Register mit $00, egal was vorher drin war. 
Also erst Einlesen, Bit(s) ändern und wieder ausgeben.
Deine Codeschnipsel sehen erst mal OK aus. Aber sortiere erst mal deine 
Kommentare.

MfG Spess
#929394
Lesenswert?

hallo,

hier die uart sende und init vom master,
vielleicht wäre es möglich ob sich einer von euch das mal anschauen kann
obs soweit in ordnung ist.


mfg kay

uart init
ldi  wl,low((clock/(16*baud0))-1)  ;RS232-1 auf 9600 Baud;;
out  ubrr0l,wl    ;Baudratenwert L setzen
ldi  wl,high((clock/(16*baud0))-1) ;einstellen
sts  ubrr0h,wl    ;Baudratenwert H setzen


; RX und TX aktivieren, RX Int einschalten txb80 p.Bit einschalten
ldi  wl,(1<<RXCIE0)|(1<<rxen0)|(1<<txen0)|(1<<txb80)
out  ucsr0b,wl

;datenformat 9n1;; 3<<ucsz00=8n1
ldi  wl,(7<<ucsz00)
sts  UCSR0C,wl


uart send

sbis UCSR0A,UDRE0 ;warte bis udre0 bereit zum senden ist
rjmp uart send
cbi UCSR0B,TXB80
sbrc WL,0
sbi UCSR0B,TXB80
out UDR0,adress        ;adresse die übertragen wird 168

USART_TX00:
 sbis UCSR0A,UDRE0                ; Warten bis UDR für das Byte bereit 
ist
 rjmp USART_TX00
  OUT UDR0, wl                     ;in wl steht das zeichen welches 
übertragen wird
Gast #929648
Lesenswert?

Hi

Zum 4.mal nein!

>ldi  wl,low((clock/(16*baud0))-1)  ;RS232-1 auf 9600 Baud;;
>out  ubrr0l,wl    ;Baudratenwert L setzen
>ldi  wl,high((clock/(16*baud0))-1) ;einstellen
>sts  ubrr0h,wl    ;Baudratenwert H setzen

Irgendwie scheinst du etwas lernresistend zu sein. Da ist zum Beispiel 
der gleiche Fehler drin, auf den ich dich mindesten drei mal hingewiesen 
habe.

>ldi  wl,(7<<ucsz00)
>sts  UCSR0C,wl

Das Gleiche. Gedankenloses Überschreiben eines Registers. Siehe oben.

Warum testest du das nicht im Simulator. Im Einzelschrittbetrieb kannst 
du genau verfolgen, was in den Registern passiert. Du schreibst ein 
kleines Programm, in dem du die notwendigen Register lädst und dann 
deine Routine aufrufst.
Ich helfe eigentlich ganz gern. Aber das sollte als Hilfe zur 
Selbsthilfe verstanden werden.

MfG Spess
#929657
Lesenswert?

HALLO,

das hatte ich vorhin aus meiner alten datei
ldi  wl,high((clock/(16*baud0))-1) ;einstellen
sts  ubrr0h,wl    ;Baudratenwert H setzen

ldi  wl,low((clock/(16*baud0))-1)  ;RS232-1 auf 9600 Baud;;
out  ubrr0l,wl    ;Baudratenwert L setzen

so nun hab ich die bits so wie im datenblatt beschrieben
ldi wl,0b00001100      ;9bit
out UCSR0B,wl      ; Sender aktivieren

ldi wl, 0b10000110   ; Frame-Format: 9 Bit,
sts UCSR0C, wl   ; 9n1

ich wollte niemanden auf die palme bringen
mfg
kay
#929680
Lesenswert?

Hallo,

was Spess meinte, war, dass du mit diesen Nullen mögliche gesetzte Bits 
im Register überschreibst. Dessen musst du dir bewusst sein. Wenn du nur 
einzelne Bits setzen möchtest, und den Rest lässt, wie er ist, dann 
brauchst du sowas:
1
in wl, UCSR0B
2
ori wl,0b00001100
3
out UCSR0B,wl
(nur als Beispiel, habe jetzt nicht lang über Sinn oder Unsinn von 
diesem konkreten Fall nachgedacht)

also zuerst einlesen und dann per bitweisem Oder nur diejenigen Bits 
setzen, die du möchtest. Der Rest bleibt wie ausgelesen und wird auch 
genau so wieder zurückgeschrieben.

Für das Löschen = auf Null setzen bestimmter Bits nimmt man dann ein 
bitweises Und, wie

andi r16, ~(1 << Bit) ; z.B. wenn Bit = 1, ergibt das 0b11111101

das setzt das "Bit" auf 0, alles andere bleibt wie vorher.
Gast #929707
Lesenswert?

Hi

Du hast mich noch nicht auf der Palme gesehen.

In deinem Code sehe erst mal keine Fehler. Allerdings habe das nicht mit 
dem Datenbatt verglichen.

Die Frage zum Simulator hast du aber auch nicht beantwortet.

Du solltest dir angewöhnen, dein Programm in überschaubare 'Häppchen' 
aufzuteilen. In deinem Fall z.B.:

Initialisierung UART
Sende Adresse
Sende Datenbyte
Sende eine bestimmte Anzahl Datenbytes
...

Diese Funktionen packst du in Unterprogramme. Die notwendigen Register 
werden vor dem Aufruf geladen. Im Unterprogramm, alle verwendeten 
Register, die nicht verändert werden dürfen mit 'push' sichern und mit 
'pop' rekonstruieren.
Die Unterprogramme ausgiebig testen (z.B. Simulator). Wenn du sicher 
bist, das es funktioniert kannst du das nächste Problem angehen. Damit 
vermeidest du es, mehrere Baustellen zu haben und überhaupt keinen Plan 
zu haben, wo ein Fehler sein könnte.

MfG Spess
Gast #929733
Lesenswert?

Hi

>es gibt ja nicht mal ein tutorial wo dieser mpcm mode ausführlich  >beschrieben 
wird.

Alles, was es da zu wissen gibt, steht im Datenblatt.

>die normale uart übertragung funktioniert tadellos...

Hast du den Code dazu selbst geschrieben?

Und zum jetzt dritten und letzten mal: Hast du deinen Code schon mal im 
Simulator laufen lassen?

MfG Spess
#930277
Lesenswert?

spess53 wrote:
> Hi
>
>>die normale uart übertragung funktioniert tadellos...
>
> Hast du den Code dazu selbst geschrieben?

also amega128 uart1 hängt eine weiter platine mit mega8 4MHz zum 
Temperratur messen über den uart das hab ich selber gemacht



> Und zum jetzt dritten und letzten mal: Hast du deinen Code schon mal im
> Simulator laufen lassen?
ja hab ich
onhne fehler
mfg
kay
Gast #934592
Lesenswert?

Im Datenblatt gibt's ein Kapitel "Using MPCM", da ist sogar eine Liste, 
was du machen sollst (wenn Englisch das Problem ist, sag es wir können 
dir notfalls übersetzen helfen).

(Hab mir nur die "mcpm mode senden.asm" angeschaut:)
Was ist z.B. DAS hier?
> ldi  temp,(9<<ucsz00) ;Datenformat 9N1;
(Es gibt nur drei UCSZnm-Bits, aber auf zwei Register verteilt)

Auch da ist ein subtiler Fehler drin:
1
  ldi temp, high((clock/(16*baud1))-1)  ;RS232-1 auf 9600 Baud
2
  sts ubrr1l, temp    ;Baudratenwert L setzen
3
  ldi temp, low((clock/(16*baud1))-1) ;einstellen
4
  sts ubrr1h, temp    ;Baudratenwert H setzen
Es gibt die Direktive ".equ", um das besser lesbar zu machen:
1
  .equ UBRR_VAL=(clock/(16*baud1))-1
2

3
  ldi temp, high(UBRR_VAL)
4
  sts UBRR1H, temp
5
  ldi temp, low(UBRR_VAL)
6
  sts UBRR1L, temp
Um im MCPM-Mode eine Addresse zu schicken musst du das 9. Bit setzen, 
genau anders als du es gerade machst.

hth. Jörg
ps.: der AVR-Studio assembler versteht macros:
1
.macro set_sram_bit
2
  lds @1, @0
3
  sbr @1, @2
4
  sts @0, @1
5
.endmacro
6
.macro clr_sram_bit
7
  lds @1, @0
8
  clr @1, @2
9
  sts @0, @1
10
.endmacro
11
; wird wie folgt benutzt:
12
  set_sram_bit UCSR1B, temp, (1<<TXB81)
13
; ...
14
  clr_sram_bit UCSR1B, temp, (1<<TXB81)
pps: Es schadet Niemandem, wenn du den Code einheitlich formatierst...
Gast #934772
Lesenswert?

1
  ldi  temp, (1<<UCSZ11)|(1<<UCSZ10)
2
    sts  UCSR1C, temp
3

4
  ldi  temp, (1<<RXEN1)|(1<<TXEN1)|(1<<UCSZ12)
5
                                            ^^^^^^^^^^^
6
    sts  UCSR1B, temp
Im Datenblatt ist hinten das "register summary" drin, (spätestens) da, 
kann man (auch du) nachschauen, WO bestimmte Bits zu finden sind.

Ich gebe mich geschlagen (keine rtfm! Hinweise mehr von mir) :(
hth. Jörg
Gast #934963
Lesenswert?

Hi

Ich habe dir mal beide Programme in ein File kopiert. Einen ATMEGA128 
hatte ich nicht da. Deswegen der 1281.
Das Programm für den ATMEGA1281 sendet abwechselnd die Adresse $55 und 
16 ungerade Zahlen und Adresse $56 gefolgt von 16 geraden Zahlen. 
Wichtig für dich sind die Unterprogramme 'send_address' und 'send_data'. 
Im Register r18 wird jeweils die Adresse bzw. das Datenbyte übergeben.

Im Programm für den ATMEGA88 werden die Daten empfangen und in 'buffer' 
gespeichert.In 'USART_RXC' wird ein empfangenes Datenbyte in 'data' 
gespeichert und 'data_valid' gesetzt. Das Hauptprogramm speichert das 
Byte dann im Puffer. Nach 16 Bytes wird der ATMega88 wieder in den 
Slavemode gesetzt.

Was wichtig ist: Im 9Bit-Modus MUSS RXB81/TXB81 VOR UDR gelesen bzw 
geschrieben werden.

Die Programme sind mit 11.059MHz und 9600Baud getestet 
(AVR-Dragon/JTAJ-ICE  MKII).

MfG Spess
Angehängte Dateien:
#935108
Lesenswert?

hallo spess,
erstmal vielen dank und vorallem für die gedult,

ich sende zu den slaves test!,die slaves sind lcdcontroller
1.slave ohne adresse 2.slave mit adresse $55
beim 1.slave wirds richtig angezeigt beim 2.slave wird nur ein T 
angezeigt.
wäre es denn möglich mal drüberzuschauen wenn möglich
über eine antwort würde ich nich sehr freuen

nfg
kay
Angehängte Dateien:
Gast #935152
Lesenswert?

Hi

Die Routine kommt mir etwas suspekt vor:

uart_getchar:
  cp WPos, RPos
  breq uart_getchar
  movw YSaveL, YL
  inc RPos
  mov RX, RPos
  andi RX, RX_Buffer-1
  mov RPos, RX
  clr RX
  ldi YL, low(RXBUF)
  ldi YH, high(RXBUF)
  add YL, RPos
  adc YH, RX
  ld RX, Y
  movw YL, YSaveL

   lds temp,UCSR0A
   sbr temp,1<<MPCM0
   sts UCSR0A,temp             ; Mastermode setzen
  ret

Ich nehme an, das du damit ein Zeichen einliest.

1.  uart_getchar:
  cp WPos, RPos
  breq uart_getchar
birgt die Gefahr, daß sich das Programm aufhängt.

2.      mov RX, RPos
  andi RX, RX_Buffer-1
  mov RPos, RX

Reicht eine Zeile: andi RPos, RX_Buffer-1
Verstehe ich aber trotzdem nicht.

3. movw YSaveL, YL
   movw YL, YSaveL

Hast du eigentlich etwas gegen PUSH und POP

4.    lds temp,UCSR0A
      sbr temp,1<<MPCM0
      sts UCSR0A,temp             ; Mastermode setzen

Nach jedem Zeichen?

Mein Beispielcode basiert der Einfachheit halber au einer festen 
Datenlänge. Wenn du mit wechselnden Datenlängen arbeitest, solltest du 
ein Zeichen für das Ende der Übertragung vereinbaren. Beispielsweise 
'EOT' (ASCII $04 : End of Transmission). und danach in den Mastermode 
zurückschalten.

MfG Spess

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren