Forum: Mikrocontroller und Digitale Elektronik Modbus Pegel


von SK (Gast)


Lesenswert?

Hallo zusammen,

ich arbeite gerade das erste mal mit dem Modbus. Das Ganze ist wie Folgt 
aufgebaut:

ATTiny (Rx/Tx) -> Uart0 -> MAX481 -> Modbus (A/B)

Ausserdem ibt es noch ein Pin am Attiny womit man zwichen 
lesen/schreiben umschalten kann.

Wiederstände am Ausgang sehen so aus:

  VCC
  |
  |
  R1 390 Ohm
  |
  ------ Modbus A
  |
  R2 120 Ohm
  |
  ------ Modbus B
  |
  R3 390 Ohm
  |
  |
 GND


Ich habe mir ein kleines Testprogramm programmiert, womit ich ein Paar 
Bytes über den Uart0 sende. Dann kann ich am Tx Pin vom ATTiny mit 
meinen Oszi diese Signal sehen, wobei dieses erwartungsgemäss einen 
Pegel von ~4,5V hat.
Wenn ich jetzt mit den 2ten Kanal des Oszi, Modbus A/B abgreife, sehe 
ich das Signal nur wenn ich auf 100mV umschalte. Das Signal sieht dem 
vom Uart sehr Ähnlich, aber der Pegel Unterschied (Pegel < 100mV) 
scheint mir sehr seltsam zu sein.

Wie müßte ein korrekter Pegel beim Modbus RTU sein?

von Helge A. (besupreme)


Lesenswert?

Falsche Widerstände, Kurzschluß, enable vergessen?

Ich würde >2V Differenzspannung zwischen den Buspins erwarten.

von RS485 (Gast)


Lesenswert?

Modbus basiert auf RS485. Scha dir mal die Spezifikationen für die RS485 
Treiber an. das ist ein differentieller Bus. R1 und R3 sind 
BIAS-Widerstände, die in Ruhe den Bus auf ein Potential vorspannen. 390 
Ohm ist hier viel zu niederohmig. Versuch mal 3,9k Ohm.

von SK (Gast)


Lesenswert?

Helge A. schrieb:
> enable vergessen?

Wie schon von mir beschrieben gibt es da am ATTiny einen Ausgang mit dem 
ich zwischen lesen und schreiben umschalten kann. Dieser ist mit dem DE 
und !RE Pin des Max841 verbunden. Ich habe den in meinm Testprogamm auf 
High gesetzt.
Den habe ich natürlich auch schon Testweise mal auf Low gesetzt, dadurch 
sehe ich nur einen Offset im Pegel, aber immer noch im Bereich <100mV.

Wenn der Pegel >2V sein muß ist irgendwas am Max841 nicht in Ordnung.

von SK (Gast)


Lesenswert?

RS485 schrieb:
> Modbus basiert auf RS485. Scha dir mal die Spezifikationen für die RS485
> Treiber an. das ist ein differentieller Bus. R1 und R3 sind
> BIAS-Widerstände, die in Ruhe den Bus auf ein Potential vorspannen. 390
> Ohm ist hier viel zu niederohmig. Versuch mal 3,9k Ohm.

Leider hab ich gerade keine Wiederstände da, muß also bis Montag warten.
Danke für den Tipp.

von Alex W. (a20q90)


Lesenswert?

Hallo SK,

zeig mal bitte deine Schaltung! Wir haben auch einen RS485 mit den 
gleichen Widerständen und 5V als VCC

von Gerhard O. (gerhard_)


Lesenswert?

Falls es in diesem Zusamenhang indirekt von Interesse ist, möchte ich 
vollständigerweise auf einen frei erhältlichen Modbus Stack hinweisen 
mit dem ich auf einem STM32 sehr gute Erfahrungen machte. Es gibt Builds 
für die meisten gängigen MCUs. Rs wird RTU, ASCII, UND TCPIP 
unterstützt.

http://www.freemodbus.org

von Alex W. (a20q90)


Lesenswert?

Nachtrag:
Die 390R werden so auch beim ProfiBus gemacht.

von SK (Gast)


Lesenswert?

Alex W. schrieb:
> Hallo SK,
>
> zeig mal bitte deine Schaltung! Wir haben auch einen RS485 mit den
> gleichen Widerständen und 5V als VCC



                                     VCC 5V
                                     |
ATTiny           MAX481              R1 390 Ohm
---------    ------------  A         |
|       |    |          --------------
|    PA0 ---- DE/!RE    |            |
|(TX)PA1 ---- D         |            R2 120 Ohm
|(RX)PA2 ---- R         | !B         |
|       |    |          --------------
---------    ------------            |
                                     R3 390 Ohm
                                     |
                                     GND

Ich hoffe mal das reicht, ich habe die Hardware nicht gemacht, deshalb 
habe ich auch keinen richtigen Schaltplan.

von Helge A. (besupreme)


Lesenswert?

Widerstände hängen von Länge und Art der Leitung ab. 120-220Ω zwischen 
den beiden Adern und 390-470Ω um das Ruhepotential festzulegen paßt 
schon. Das kommt an beide Enden der Leitung. Schwierig (mit Oszi ansehen 
sinnvoll) wirds nur bei langer oder schlechter Leitung oder vielen 
Teilnehmern.

von Alex W. (a20q90)


Lesenswert?

Kann es sein das beim Umschalten bei DE/!RE eventuell der Ausgang 
floatet?
Also das die internen PullUps nicht funktionieren und daher eines der 
beiden Pegel nicht sauber sind?

von SK (Gast)


Lesenswert?

Es gibt nur einen Teilnehmer, die Leitungen sind ca. 20cm lang 
(mehraderig Kupfer).
Gemessen mit den Oszi habe ich direkt an den Wiederständen, über die 
Leitungen habe ich auch mal gemessen sah genauso aus.

Wenn ich den Modbus Client anschließe regiert dieser auf das Signal 
nicht.
als Library habe ich folgende benutzt:
https://github.com/angeloc/simplemodbusng

von Alex W. (a20q90)


Lesenswert?

Jetzt bitte ein Foto vom Aufbau machen und den Code posten!
Zusätzlich mal einen PullUp mit 1-10k an DE/!RE gegen VCC

: Bearbeitet durch User
von Gerhard O. (gerhard_)


Lesenswert?

Möchte noch auf eine Kleinigkeit hinweisen. Man soll auf alle Fälle dem 
Rx Eingang beim MCU als Pull-Up ausführen oder einen Widerstand nach Vdd 
hin spendieren damit der Rx beim senden nicht frei herumschwebt. Das 
kann sonst zu unerwarteten Interrupts beim Empfang führen, die dann 
komische, unerklärliche UART Fehler(Framing, Oberrun) vortäuschen. Wenn 
man RE/DE zusammenschließt wird der Empfangerausgang, während DE/RE Im 
Sende Modus ist, des Transceivers High Impedance und dann hat dieser Pin 
keinen Bezugspunkt mehr.

von SK (Gast)


Lesenswert?

Alex W. schrieb:
> Kann es sein das beim Umschalten bei DE/!RE eventuell der Ausgang
> floatet?
> Also das die internen PullUps nicht funktionieren und daher eines der
> beiden Pegel nicht sauber sind?

Bei Attiny ist der Pin PA0 als Ausgang definiert.
DE uns !RE sind zwei Eingangs Pins des MAX481, welche gebrückt sind.
Programmieren kann ich nur den Attiny, was meinst du mit Ausgang 
floaten?

von Alex W. (a20q90)


Lesenswert?

Mit "floaten" meine ich das entweder der Pin zwar richtig gegen VCC 
oder GND gezogen wird, aber beim "umschalten" in der Luft hängt und 
somit macht was er will.

von SK (Gast)


Angehängte Dateien:

Lesenswert?

Hier das Bild vom Oszi Ch1 ist Modbus und Ch2 Uart0 Tx

Der Quellcode vom Testprogramm:
1
int main(void)
2
{  
3
  uint32_t debug_tx_counter = 500000UL;
4
5
  Timers_Init();  
6
  Uart0_Init(19200);
7
  
8
  sei();  
9
  
10
    while(1)
11
    {                      
12
    if(debug_tx_counter++ >= 200000UL)
13
    {
14
      debug_tx_counter = 0;
15
      MODBUS_ENABLED_WRITE();    
16
      Uart0_Write(0xFF);
17
      Uart0_Write(0x00);
18
      Uart0_Write(0xAA);                     
19
      Uart0_Write(0x0A);            
20
    }    
21
    }
22
}
23
24
void Uart0_Init(unsigned long baud)
25
{
26
  uint16_t _baud;
27
  
28
  // Standard Einstellungen vom IFC 050
29
  // Baudrate    19200
30
  // Daten bits  8
31
  // Parity      even
32
  // Stop bits   1
33
  
34
  // Berechent aus der Baudrate den Register wert für die Baudrate
35
  _baud = (F_CPU / 8 / baud - 1) / 2;
36
  
37
  // Setzt die Baudrate
38
  UBRR0 = _baud;
39
  
40
  UCSR0B |= (1 << RXEN0);    // Receiver Enable
41
  UCSR0B |= (1 << TXEN0);    // Transmitter Enable
42
  UCSR0B |= (1 << RXCIE0);   // RX Complete Interrupt Enable
43
  //UCSR0B |= (1 << TXCIE0);   // TX Complete Interrupt Enable
44
  UCSR0B |= (1 << UDRIE0);   // USART Data Register Empty Interrupt Enable
45
  
46
  // USART Mode of Operation
47
  // ==========================================
48
  // | UMSEL01 | UMSEL00 | Mode               |
49
  // ==========================================
50
  // |    0    |    0    | Asynchronous USART |
51
  // |    0    |    1    | Synchronous USART  |
52
  // |    1    |    0    | Reserved           |
53
  // |    1    |    1    | Master SPI         |
54
  // ==========================================
55
  // Register Bits von: UCSR0C
56
  // Quelle: Datenblatt ATtiny441/841 Seite 184
57
  // SUSART Mode = Asynchronous
58
  
59
  
60
  // Daten bits
61
  // ================================================
62
  // | UCSZ02  | UCSZ01  | UCSZ00  | Character Size |
63
  // ================================================
64
  // |    0    |    0    |    0    | 5-bit          |
65
  // |    0    |    0    |    1    | 6-bit          |
66
  // |    0    |    1    |    0    | 7-bit          |
67
  // |    0    |    1    |    1    | 8-bit          |
68
  // |    1    |    0    |    0    | Reserved       |
69
  // |    1    |    0    |    1    | Reserved       |
70
  // |    1    |    1    |    0    | Reserved       |
71
  // |    1    |    1    |    1    | 9-bit          |
72
  // ================================================
73
  // Register Bits von: UCSR0C
74
  // Quelle: Datenblatt ATtiny441/841 Seite 184
75
  // Setzt  Daten bits = 8-bit.
76
  UCSR0C |= ((1 << UCSZ01) | (1 << UCSZ00));
77
  
78
  // Parity
79
  // =========================================
80
  // | UPM01 | UPM00 | Parity Mode           |
81
  // =========================================
82
  // |   0   |   0   | Disabled              |
83
  // |   0   |   1   | Reserved              |
84
  // |   1   |   0   | Enabled, Even Parity  |
85
  // |   1   |   1   | Enabled, Odd Parity   |
86
  // =========================================
87
  // Register Bits von: UCSR0C
88
  // Quelle: Datenblatt ATtiny441/841 Seite 184
89
  // Setzt Parity = Even.
90
  UCSR0C |= (1 << UPM01);
91
  
92
  // Stop bits
93
  // ========================
94
  // | USBS0 | Stop Bit(s)  |
95
  // ========================
96
  // |   0   | 1-bit        |
97
  // |   1   | 2-bit        | 
98
  // ========================
99
  // Register Bits von: UCSR0C
100
  // Quelle: Datenblatt ATtiny441/841 Seite 184
101
  // Setzt Stop bits = 1-bit
102
  
103
  // Clock Polarity Settings
104
  // =============================================================
105
  // | UCPOL | Transmitted Data Changed  | Received Data Sampled |
106
  // |       | (Output of TxDn Pin)      | (Input on RxDn Pin)   |
107
  // =============================================================
108
  // |   0   | Rising XCK Edge           | Falling XCK Edge      |
109
  // |   1   | Falling XCK Edge          | Rising XCK Edge       |
110
  // =============================================================
111
  // Register Bits von: UCSR0C
112
  // Quelle: Datenblatt ATtiny441/841 Seite 185
113
  // Clock Polarity := Tx=Rising XCK Edge, Rx=Falling XCK Edge
114
}

von SK (Gast)


Lesenswert?

Alex W. schrieb:
> Mit "floaten" meine ich das entweder der Pin zwar richtig gegen VCC
> oder GND gezogen wird, aber beim "umschalten" in der Luft hängt und
> somit macht was er will.

Ok das mit dem Pins und den Pull-Up werde ich prüfen.

von SK (Gast)


Lesenswert?

Sorry bein Testprogramm fehlte noch was hier nochmal komplett:
1
#define MODBUS_ENABLED_DDR      DDRA
2
#define MODBUS_ENABLED_PORT     PORTA
3
#define MODBUS_ENABLED          PA0
4
#define MODBUS_ENABLED_Output() MODBUS_ENABLED_DDR |= (1 << MODBUS_ENABLED)
5
#define MODBUS_ENABLED_HIGH()   (MODBUS_ENABLED_PORT |= (1 << MODBUS_ENABLED))
6
#define MODBUS_ENABLED_LOW()    (MODBUS_ENABLED_PORT &= ~(1 << MODBUS_ENABLED))
7
#define MODBUS_ENABLED_READ()   MODBUS_ENABLED_LOW()
8
#define MODBUS_ENABLED_WRITE()  MODBUS_ENABLED_HIGH()
9
10
11
int main(void)
12
{  
13
  uint32_t debug_tx_counter = 500000UL;
14
15
  //Timers_Init();  // Wird im Testprogramm nicht benutzt
16
  Uart0_Init(19200);
17
  MODBUS_ENABLED_Output();
18
  MODBUS_ENABLED_READ();
19
  
20
  sei();  
21
  
22
    while(1)
23
    {                      
24
    if(debug_tx_counter++ >= 200000UL)
25
    {
26
      debug_tx_counter = 0;
27
      MODBUS_ENABLED_WRITE();    
28
      Uart0_Write(0xFF);
29
      Uart0_Write(0x00);
30
      Uart0_Write(0xAA);                     
31
      Uart0_Write(0x0A);            
32
    }    
33
    }
34
}
35
36
void Uart0_Init(unsigned long baud)
37
{
38
  uint16_t _baud;
39
  
40
  // Standard Einstellungen vom IFC 050
41
  // Baudrate    19200
42
  // Daten bits  8
43
  // Parity      even
44
  // Stop bits   1
45
  
46
  // Berechent aus der Baudrate den Register wert für die Baudrate
47
  _baud = (F_CPU / 8 / baud - 1) / 2;
48
  
49
  // Setzt die Baudrate
50
  UBRR0 = _baud;
51
  
52
  UCSR0B |= (1 << RXEN0);    // Receiver Enable
53
  UCSR0B |= (1 << TXEN0);    // Transmitter Enable
54
  UCSR0B |= (1 << RXCIE0);   // RX Complete Interrupt Enable
55
  //UCSR0B |= (1 << TXCIE0);   // TX Complete Interrupt Enable
56
  UCSR0B |= (1 << UDRIE0);   // USART Data Register Empty Interrupt Enable
57
  
58
  // USART Mode of Operation
59
  // ==========================================
60
  // | UMSEL01 | UMSEL00 | Mode               |
61
  // ==========================================
62
  // |    0    |    0    | Asynchronous USART |
63
  // |    0    |    1    | Synchronous USART  |
64
  // |    1    |    0    | Reserved           |
65
  // |    1    |    1    | Master SPI         |
66
  // ==========================================
67
  // Register Bits von: UCSR0C
68
  // Quelle: Datenblatt ATtiny441/841 Seite 184
69
  // SUSART Mode = Asynchronous
70
  
71
  
72
  // Daten bits
73
  // ================================================
74
  // | UCSZ02  | UCSZ01  | UCSZ00  | Character Size |
75
  // ================================================
76
  // |    0    |    0    |    0    | 5-bit          |
77
  // |    0    |    0    |    1    | 6-bit          |
78
  // |    0    |    1    |    0    | 7-bit          |
79
  // |    0    |    1    |    1    | 8-bit          |
80
  // |    1    |    0    |    0    | Reserved       |
81
  // |    1    |    0    |    1    | Reserved       |
82
  // |    1    |    1    |    0    | Reserved       |
83
  // |    1    |    1    |    1    | 9-bit          |
84
  // ================================================
85
  // Register Bits von: UCSR0C
86
  // Quelle: Datenblatt ATtiny441/841 Seite 184
87
  // Setzt  Daten bits = 8-bit.
88
  UCSR0C |= ((1 << UCSZ01) | (1 << UCSZ00));
89
  
90
  // Parity
91
  // =========================================
92
  // | UPM01 | UPM00 | Parity Mode           |
93
  // =========================================
94
  // |   0   |   0   | Disabled              |
95
  // |   0   |   1   | Reserved              |
96
  // |   1   |   0   | Enabled, Even Parity  |
97
  // |   1   |   1   | Enabled, Odd Parity   |
98
  // =========================================
99
  // Register Bits von: UCSR0C
100
  // Quelle: Datenblatt ATtiny441/841 Seite 184
101
  // Setzt Parity = Even.
102
  UCSR0C |= (1 << UPM01);
103
  
104
  // Stop bits
105
  // ========================
106
  // | USBS0 | Stop Bit(s)  |
107
  // ========================
108
  // |   0   | 1-bit        |
109
  // |   1   | 2-bit        | 
110
  // ========================
111
  // Register Bits von: UCSR0C
112
  // Quelle: Datenblatt ATtiny441/841 Seite 184
113
  // Setzt Stop bits = 1-bit
114
  
115
  // Clock Polarity Settings
116
  // =============================================================
117
  // | UCPOL | Transmitted Data Changed  | Received Data Sampled |
118
  // |       | (Output of TxDn Pin)      | (Input on RxDn Pin)   |
119
  // =============================================================
120
  // |   0   | Rising XCK Edge           | Falling XCK Edge      |
121
  // |   1   | Falling XCK Edge          | Rising XCK Edge       |
122
  // =============================================================
123
  // Register Bits von: UCSR0C
124
  // Quelle: Datenblatt ATtiny441/841 Seite 185
125
  // Clock Polarity := Tx=Rising XCK Edge, Rx=Falling XCK Edge
126
}

von ich (Gast)


Lesenswert?

Du hat mit Sicherheit ein Masseproblem. Klemm mal den Tastkopf am Tiny 
ab, auch die Masse. Wenn das Netzteil deiner Elektronik erdfrei ist 
kannst du mit deinem anderen Tastkopf, angeschlossen an RS485 A/B dann 
knapp 10V Vpp messen.

von ogol (Gast)


Lesenswert?

Das sieht aber merkwürdig aus!

A und B müssen invertiert sein!

hast Du auch den GND rüber verbunden?

von SK (Gast)


Lesenswert?

ogol schrieb:
> Das sieht aber merkwürdig aus!
>
> A und B müssen invertiert sein!
>
> hast Du auch den GND rüber verbunden?

Ja GND ist dabei.

von ich (Gast)


Lesenswert?

Wie hast du dein Oszi angeschlossen?

von SK (Gast)


Lesenswert?

ich schrieb:
> Wie hast du dein Oszi angeschlossen?

Die Masse vom Tastkopf an GND und Messspitze an Modbus A oder B.

von SK (Gast)


Lesenswert?

Analog dazu natürlich auch die Messung am Tx Pin.
Masse an GND und Messspitze an den Tx-Pin.

von Joachim R. (bastelbaer)


Lesenswert?

Schau mal unter
http://www.saia-pcd.com/uploads/tx_srcfiles/A-2FehlersucheinSeriellenNetzen_LAH.pdf

Da wird beschrieben wie man mit einem Oszilloskop den 485-Bus checkt. 
RS485 basiert auf Differnzialübertragung. Da ist GND normalerweise gar 
nicht nötig. Hab hier 20 Zähler via 50m Modbus, Zweidraht und einfacher 
120 Ohm-Terminierung am Laufen, ohne Probleme. Ein einzelner Teilnehmer, 
20cm vom Sender funktioniert sogar ohne Terminierung.

Und zum Testen würde ich einfach mal ein Telegramm von Hand 
zusammenbasteln und via Atmel senden. Ohne gross ne lib zu benutzen.

Was macht denn dein Slave, MODBUS-ASC oder MODBUS-RTU?

Nur als Tip USB-RS485-Wandler gibts in der Bucht zwischen fünf und 
sieben Euronen. Haben mir schon viel zusammen mit HTerm bei der 
Fehlersuche geholfen. Und die, die ich habe, haben sogar nur zwei 
Anschlüsse, keine Masse.

Uart0_Write(0xFF);
Uart0_Write(0x00);
Uart0_Write(0xAA);
Uart0_Write(0x0A);
Das ergibt auch nix sinnvolles in MODBUS. Ein Telegramm sind 
normalerweise mindestens 8 Bytes incl. CRC. Es sei denn die LIB macht 
was anderes daraus.

Gibt hier auch ne gute Info über Modbus-Grundlagen:
http://www.camillebauer.com/src/download/Modbus_Grundlagen.pdf

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.