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?
Falsche Widerstände, Kurzschluß, enable vergessen? Ich würde >2V Differenzspannung zwischen den Buspins erwarten.
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.
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.
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.
Hallo SK, zeig mal bitte deine Schaltung! Wir haben auch einen RS485 mit den gleichen Widerständen und 5V als VCC
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
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.
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.
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?
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
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
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.
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?
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.
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 | } |
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.
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 | } |
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.
Das sieht aber merkwürdig aus! A und B müssen invertiert sein! hast Du auch den GND rüber verbunden?
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.
ich schrieb: > Wie hast du dein Oszi angeschlossen? Die Masse vom Tastkopf an GND und Messspitze an Modbus A oder B.
Analog dazu natürlich auch die Messung am Tx Pin. Masse an GND und Messspitze an den Tx-Pin.
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.