Forum: Mikrocontroller und Digitale Elektronik Multiprocessor Communication and Automatic Address Recognition 8051


von Lucas W. (micline)


Lesenswert?

Hallo,

Ich versuche eine Multiprozessor Kommunikation mit automatischer 
Adresserkennung auf einem 8051 Derivat zu implementieren.
Der genaue uC den ich Verwende ist der MG82FE/L564 (datasheet: 
https://datasheetspdf.com/pdf-file/1098335/Megawin/MG82FL564/1).

Unten findet ihr meinen master und Slave Code.

Mein Problem: So wie es aussieht kann ich die einzelnen Slaves 
ansprechen (bei Falscher Adresse reagiert der Slave garnicht. LED1 
schaltet nicht), jedoch werden nicht die übertragenen Daten in SBUF 
geschrieben sondern die Adresse.
Mit dem Oszi sehe ich, dass sowohl Adresse als auch Daten richtig 
übertragen werden. Jetzt frage ich mich ob ich die automatische 
Adresserkennung richtig verstanden habe. Ich dachte, das Funktioniert 
alles auf Hardwareebene (außer das Setzten von Bit 9) und der Serial 
interrupt wird nur ausgelöst wenn die gesendete Adresse mit der Slave 
Adresse übereinstimmt. Oder muss ich zuerst auf Softwareebene die 
Adressen vergleichen und dann die Daten in SBUF schreiben?
Außerdem ist mir nicht ganz klar ob ich SM2 im SCON register in der 
Software zurücksetzten muss oder das auch auf Hardwareebene passiert? 
(Siehe Note unter Figure 12-9 auf Seite 68 im Datasheet).

Kann es sein, dass ich falsch initialisiere, oder einen Fehler in der 
RxData() Funktion habe ?
Hat jemand zufällig funktionierenden Beispielcode in C ?
Ich bin dankbar um jede Hilfe!


MASTER CODE:
1
#include <reg51.h> 
2
void Tx_data(char dat){
3
  
4
    TB8 = 0;        // 9th bit = 0 for data tx
5
    SBUF = dat;     // load the data to be transmitted
6
    while(TI==0);   // wait till the data is trasmitted  
7
    TI = 0;  // clear the Tx flag for next cycle.
8
        
9
}
10
11
void Tx_addr(char addr){
12
  
13
    TB8 = 1;        // 9th bit = 1 for address tx
14
    
15
    SBUF = addr;
16
    while(TI==0);   // Wait till the data is trasmitted
17
    TI = 0;         //Clear the Tx flag for next cycle.    
18
}
19
20
void main(){
21
  
22
    PCON = 0x80;    // SMOD bit is set / 0x80 = 1000 0000
23
    SCON = 0xB0;     // Mode3 9-Bit UART / 0xB0 = 1011 0000
24
    TMOD = 0x21;
25
    TH1  = 0xFA;    // TH1 = 256-(11.0592*10^6)/(192 * 9600) = 250 
26
    TR1  = 1;      // Turn ON the timer for Baud rate generation
27
    IE = 0x90;
28
29
while(1){
30
31
if(SWIN==0){       // if push button pressed send data to address 0xFF
32
    Tx_addr(0xFF);
33
    Tx_data(0x0F);
34
    }
35
  }
36
}

SLAVE CODE:
1
#include <reg51.h>
2
3
#define LED1 P2_7
4
5
unsigned char mybuf;
6
7
8
void RxData() interrupt 4
9
{  
10
      while(RI==0);
11
      RI=0;
12
      mybuf = SBUF;
13
      LED1=0; // LED1 indicates if Slave interrupts and jumps into RXData function
14
}
15
16
void main(){
17
  
18
    PCON = 0x80;    // SMOD bit is set / 0x80 = 1000 0000
19
    SCON = 0xB0;     // Mode3 9-Bit UART / 0xB0 = 1011 0000
20
21
    TMOD = 0x21;    // 0x21 = 0010 0001
22
    TH1  = 0xFA;      // TH1 = 256-(11.0592*10^6)/(192 * 9600) = 250 
23
    TR1  = 1;        // Turn ON the timer for Baud rate generation
24
  
25
    SADDR = 0xFA;    // Slave Address
26
    SADEN = 0xFF;    // Mask
27
  
28
    IE = 0x90;          // Interrupt enable
29
    
30
  
31
  
32
  while(1){
33
    
34
    if(mybuf == 0x0F){ // if Data is 0x0F switch LED1 on and LED8 off
35
      LED1 = 0;
36
      LED8 = 1;
37
      
38
    }else { 
39
      LED1 = 1;
40
      LED8 = 0;
41
    }
42
  
43
  }
44
45
}

von Peter D. (peda)


Lesenswert?

Lucas W. schrieb:
> Außerdem ist mir nicht ganz klar ob ich SM2 im SCON register in der
> Software zurücksetzten muss oder das auch auf Hardwareebene passiert?

SM2 muß nach Empfang der Adresse zurück gesetzt werden, um auch die 
Daten zu empfangen.

von Lucas W. (micline)


Lesenswert?

Danke. Funktioniert jetzt.

Hier der geupdatete Code:
1
void RxData() interrupt 4
2
{  
3
      while(RI==0); // wait for receiving address 
4
      RI=0;
5
  
6
      SM2=0;        // reset SM2 for receiving data
7
  
8
      while(RI==0); 
9
      RI=0;
10
      mybuf = SBUF; // write data in mybuf
11
  
12
      SM2=1;        // set SM2 
13
}

von Elias K. (elik)


Lesenswert?

Aus dem Datenblatt:
1
Modes 2 and 3 have a special provision for multiprocessor communications as shown in 304HFigure 13-8. In these two modes, 9 data bits are received. The 9th bit goes into RB80. Then comes a stop bit. The port can be programmed such that when the stop bit is received, the serial port interrupt will be activated only if RB80=1. This feature is enabled by setting bit SM20 (in SCON0 register). A way to use this feature in multiprocessor systems is
2
as follows: 
3
When the master processor wants to transmit a block of data to one of several slaves, it first sends out an address byte which identifies the target slave. An address byte differs from a data byte in that the 9th bit is 1 in an address byte and 0 in a data byte. With SM20=1, no slave will be interrupted by a data byte. An address byte, however, will interrupt all slaves, so that each slave can examine the received byte and check if it is being addressed. The addressed slave will clear its SM20 bit and prepare to receive the data bytes that will be coming.
4
The slaves that weren‘t being addressed leave their SM20 set and go on about their business, ignoring the coming data bytes.

In anderen Worten: Alle Pakete ohne gesetztes Adressbit werden von allen 
Slaves ignoriert. Dann kommt ein Paket mit gesetztem Bit. Alle Slaves 
gehen in den Interrupt. Im Interrupt musst du prüfen, ob die Adresse auf 
dem Device übereinstimmt. Bei allen, wo die Adresse nicht stimmt, wird 
nichts gemacht. Bei dem, wo die Adresse stimmt, muss die UART vom 
Programm so umkonfiguriert werden, dass es die nun folgenden Pakete auch 
annimmt. (Quasi wieder auf 8-Bit UART zurück setzen. "clear its SM20 
bit") Wenn der Slave alle Daten empfangen hat, muss er wieder zurück auf 
"Warte auf Adresse", bzw. SM20 Bit setzen.

Edit: Hat sich mit dem Update überschnitten. Damit hinfällig.

: Bearbeitet durch User
von Jim M. (turboj)


Lesenswert?

Lucas W. schrieb:
> Hier der geupdatete Code:

Der wartet im Interrupt auf das 2. Frame. Das wird in nicht-trivialen 
Fällen praktisch immer stören und sollte anders gelöst werden.

von Lucas W. (micline)


Lesenswert?

Ja stimmt. Ich hab auch vergessen die Adresse auszuwerten. Jetzt wartet 
er nur auf das zweite Frame wenn die gesendete Adresse mit der 
Slave-Adresse übereinstimmt.
Oder was genau meinst du mit nicht-trivialen fällen?
1
  
2
void RxData() interrupt 4
3
{  
4
      while(RI==0); // wait for receiving address 
5
      RI=0;
6
  
7
  if(SBUF==SADDR){
8
      SM2=0;        // reset SM2 for receiving data
9
      while(RI==0); 
10
      RI=0;
11
      mybuf = SBUF; // write data in mybuf
12
      SM2=1;        // set SM2
13
  }   
14
}

von Jim M. (turboj)


Lesenswert?

Lucas W. schrieb:
> Oder was genau meinst du mit nicht-trivialen fällen?

In allen Fällen wo die Zeit zwischen 2 UART Frames zu lang ist, weil 
main() noch was anderes zu tun hat.

Du müsstest auch ein Bit haben wo drin steht das ein Address Frame im 
Empfangsregister steht. Wenn der Master mal rebootet, könnten ja auch 
z.B. mal 2 Adressen hintereinander kommen.

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.