Hải Đăng PPK gửi vào
- 59597 lượt xem
Khi một mạng cần phải chuyển các khối nhỏ thông tin trên một khoảng cách dài, RS-485 thường là chuẩn giao tiếp được lựa chọn. Các nút mạng có thể là máy tính cá nhân, vi điều khiển, hoặc bất kỳ thiết bị có khả năng truyền thông nối tiếp không đồng bộ. So với Ethernet và giao diện mạng khác, phần cứng và giao thức yêu cầu của RS-485 đơn giản hơn và rẻ hơn
I. RS485 LÀ GÌ
Năm 1983, Hiệp hội công nghiệp điện tử (EIA) đã phê duyệt một tiêu chuẩn truyền cân bằng mới gọi là RS-485. Đã được chấp nhận rộng rãi và sử dụng trong công nghiệp, y tế, và dân dụng. Có thể coi chuẩn RS485 là một phát triển của RS232 trong việc truyền dữ liệu nối tiếp. Những bộ chuyển đổi RS232/RS485 cho phép người dùng giao tiếp với bất kỳ thiết bị mà sử dụng liên kết nối tiếp RS232 thông qua RS485. Liên kết RS485 được hình thành cho việc thu nhận dữ liệu ở khoảng cách xa và điều khiển cho những ứng dụng. Những đặc điểm nổi trội của RS485 là nó có thể hỗ trợ một mạng lên tới 32 trạm thu phát trên cùng một đường truyền, tốc độ baud có thể lên tới 115.200 cho một khoảng cách là 4000feet (1200m).
Với kiểu truyền cân bằng và các dây được xoắn lại với nhau nên khi nhiễu xảy ra ở dây này thì cũng xảy ra ở dây kia, tức là hai dây cùng nhiễu giống nhau. Điều này làm cho điện áp sai biệt giữa hai dây thay đổi không đáng kể nên tại nơi thu vẫn nhận được tín hiệu đúng nhờ tính năng đặc biệt của bộ thu đã loại bỏ nhiễu. Liên kết RS485 được sử dụng rất rộng rãi trong công nghiệp, nơi mà môi trường nhiễu khá cao và sự tin tưởng vào tính ổn định của hệ thống là điều quan trọng. Bên cạnh đó khả năng truyền thông qua khoảng cách xa ở tốc độ cao cũng rất được quan tâm, đặc biệt là tại những nơi mà có nhiều trạm giao tiếp được trải ra trên diện rộng.
Để nghiên cứu sâu về chuẩn giao tiếp RS-485 thì thực tế mà nói kiến thức của mình không đủ để giới thiệu tới các bạn. Bài viết này chỉ xin đề cập đến Module TTL To RS485.
Module này giúp cho việc truyền dữ liệu đi xa đến 1KM, tốc độ truyền lên đến 20Mbps, và có thể sử dụng trong môi trường đó nhiễu cao, trong môi trường công nghiệp.Trong một mạng RS485 ở tại mọi thời điểm chỉ có 1 thiết bị truyền được.Điều này gần tương tự như các dạng giao tiếp khác. Tức là sau khi truyền dữ liệu xong cho 1 module, đóng cửa, sau đó mở cửa giao tiếp với 1 module khác.
Module RS485 sử dụng điện áp là 5V, có thể kết nối nhiều module trong cùng 1 đường truyền, thông thường để truyền được đi xa cần sử dụng cáp xoắn.Như chính tên gọi của nó, cặp dây xoắn (Twisted-pair wire) đơn giản chỉ là cặp dây có chiều dài bằng nhau và được xoắn lại với nhau. Sử dụng cặp dây xoắn sẽ giảm thiểu được nhiễu, nhất là khi truyền ở khoảng cách xa và với tốc độ cao.
II. SƠ ĐỒ KẾT NỐI
Các chân của module gồm có:
DI- DATA IN (Dữ liệu vào) PIN 1
RO - RECEIVE OUT (Tín hiệu nhận đầu ra) PIN 0
DE- DATA ENABLE; RE RECEIVE ENABLE (Cho phép dữ liệu vào và cho phép được nhận) 2 chân này thường để nối liền với nhau và kết nối với Pin 2
VCC nối với +5v
GND nối với GND, GND của 2 arduino có thể dùng cáp để nối hoặc cần được nối đất tại chỗ
A nối với A; B nối với B thông qua cáp cặp xoắn
III. CODE
Ví dụ dưới đây sẽ sử dụng Serial Monitor để truyền dữ liệu từ Arduino Master thông qua module RS485 đến arduino ở xa (Remote) và arduino(remote) đó sẽ nhận dữ liệu, gửi ngược lại cho arduino Master và hiển thị dữ liệu lên serial monitor
Master Arduino Sketch:
#include <SoftwareSerial.h> /*-----( Khai báo hằng số và Pin )-----*/ #define SSerialRX 0 //Serial Receive pin #define SSerialTX 1 //Serial Transmit pin #define SSerialTxControl 2 //Kiểm soát hướng cho rs485 #define RS485Transmit HIGH #define RS485Receive LOW #define Pin13LED 13 /*-----( Khai báo đối tượng )-----*/ SoftwareSerial RS485Serial(SSerialRX, SSerialTX); // RX, TX /*-----( Khai báo biến )-----*/ int byteReceived; int byteSend; void setup() /****** SETUP ******/ { Serial.begin(9600); Serial.println("Arduino.vn"); Serial.println("Su dung Serial Monitor, go vao cua so phia tren, ENTER"); pinMode(Pin13LED, OUTPUT); pinMode(SSerialTxControl, OUTPUT); digitalWrite(SSerialTxControl, RS485Receive); // bật chế độ thu phát // Khởi động kết nối tới thiest bị khác RS485Serial.begin(4800); // cài đặt tốc độ truyền dữ liệu }//--(end setup )--- void loop() /****** LOOP ******/ { digitalWrite(Pin13LED, HIGH); if (Serial.available()) // Nếu có tín hiệu { byteReceived = Serial.read(); digitalWrite(SSerialTxControl, RS485Transmit); // Cho phép rs485 nhận dữ liệu RS485Serial.write(byteReceived); // gửi byte cho arudino thu digitalWrite(Pin13LED, LOW); delay(10); digitalWrite(SSerialTxControl, RS485Receive); // Vô hiệu hóa quá trình nhận dữ liệu } if (RS485Serial.available()) //tìm dữ liệu từ thiết bị khác truyền về { digitalWrite(Pin13LED, HIGH); byteReceived = RS485Serial.read(); // đọc byte nhận được Serial.write(byteReceived); // hiển thị lên Serial Monitor delay(10); digitalWrite(Pin13LED, LOW); } } Remote Arduino Sketch:
#include <SoftwareSerial.h> /*-----( Khai báo hằng số và pin )-----*/ #define SSerialRX 0 //Serial Receive pin #define SSerialTX 1 //Serial Transmit pin #define SSerialTxControl 2 //RS485 Direction control #define RS485Transmit HIGH #define RS485Receive LOW #define Pin13LED 13 SoftwareSerial RS485Serial(SSerialRX, SSerialTX); // RX, TX int byteReceived; int byteSend; void setup() { Serial.begin(9600); pinMode(Pin13LED, OUTPUT); pinMode(SSerialTxControl, OUTPUT); digitalWrite(SSerialTxControl, RS485Receive); // bật chế độ thu phát // đặt tốc độ truyền RS485Serial.begin(4800); } void loop() { //Sao chép dữ liệu đầu vào ra đầu ra if (RS485Serial.available()) { byteSend = RS485Serial.read(); // đọc dữ liệu digitalWrite(Pin13LED, HIGH); delay(10); digitalWrite(Pin13LED, LOW); digitalWrite(SSerialTxControl, RS485Transmit); // cho phép truyền RS485Serial.write(byteSend); // gửi dữ liệu ngược lại delay(10); digitalWrite(SSerialTxControl, RS485Receive); // Không cho phép truyền delay(100); } }
IV. CÁC VẤN ĐỀ XẢY RA
Các bạn có thể sẽ đặt câu hỏi rằng tại sao không sử dụng module RF?
Trong 1 số môi trường và 1 số trường hợp việc sử dụng module bằng sóng RF là không khả thi, 1 số môi trường có quá nhiều động cơ điện, các tín hiệu điện có thể gây nhiễu và cản trở đến tín hiệu truyền dẫn thì việc sử dụng giao thức rs485 là khả thi. Và thậm chí cũng là để đảm bảo bí mật về thông tin, chúng ta sẽ không sử dụng sóng vô tuyến để truyền dẫn. Tuy nhiên RS485 cũng sẽ vẫn gặp phải các vấn đề về nhiễu trên đường truyền. Như nhiễu trên đường dây, hoặc thậm chí 1 thiết bị hoặc 1 số thiết bị được kết nối lại ngắt kết nối, điều đó dẫn đến thiết bị còn lại hiểu nhầm giữa mức cao và mức thấp. Đọc đến đây, các bạn hãy nhớ rằng việc giao tiếp giữa 2 thiết bị qua rs485 chỉ cần 2 dây, 1 đầu sẽ ở mức cao, đầu còn lại sẽ ở mức thấp. Và khi 1 đầu bị ngắt kết nối, đầu kia sẽ nhầm lẫn giữa việc Mức cao chuyển thành mức thấp (5V về 0V). Do đó có 1 thư viện hỗ trợ xử lý lỗi này. Các bạn có thể down ở đây . Các bạn chỉ việc include vào thư viện. Tiếp sau đây sẽ là ví dụ minh họa về việc điều khiển bóng đèn bằng triết áp
Master code
#include "RS485_protocol.h" #include <SoftwareSerial.h> const byte ENABLE_PIN = 4; const byte LED_PIN = 13; SoftwareSerial rs485 (0, 1); // rx,tx void fWrite (const byte what) { rs485.write (what); } int fAvailable () { return rs485.available (); } int fRead () { return rs485.read (); } void setup() { rs485.begin (28800); pinMode (ENABLE_PIN, OUTPUT); // cho phép truyền pinMode (LED_PIN, OUTPUT); } // end of setup byte old_level = 0; void loop() { // đọc giá trị triết áp byte level = analogRead (0) / 4; // nếu không thay đổi thì bỏ qua if (level == old_level) return; // gửi byte msg [] = { 1, // thiết bị 1 2, // bật đèn sáng level // mức mấy }; // gửi đến slave digitalWrite (ENABLE_PIN, HIGH); // cho phép gửi sendMsg (fWrite, msg, sizeof msg); digitalWrite (ENABLE_PIN, LOW); // không cho phép gửi // nhận phản hồi byte buf [10]; byte received = recvMsg (fAvailable, fRead, buf, sizeof buf); digitalWrite (LED_PIN, received == 0); // turn on LED if error // chỉ gửi 1 lần cho 1 lần thay đổi if (received) old_level = level; }
Slave code
#include <SoftwareSerial.h> #include "RS485_protocol.h" SoftwareSerial rs485 (0, 1); // rx,tx const byte ENABLE_PIN = 2; void fWrite (const byte what) { rs485.write (what); } int fAvailable () { return rs485.available (); } int fRead () { return rs485.read (); } void setup() { rs485.begin (28800); pinMode (ENABLE_PIN, OUTPUT); // cho phép truyền } void loop() { byte buf [10]; byte received = recvMsg (fAvailable, fRead, buf, sizeof (buf)); if (received) { if (buf [0] != 1) return; // Không phải thiết bị trong hệ thống if (buf [1] != 2) return; // không hiểu tín hiệu byte msg [] = { 0, // thiết bị 0 (master) 3, // Bật đèn sáng khi lệnh nhận được }; delay (1); // Cung cấp cho master 1 chút thời gian để nhận tín hiệu digitalWrite (ENABLE_PIN, HIGH); // Cho phép gửi sendMsg (fWrite, msg, sizeof msg); digitalWrite (ENABLE_PIN, LOW); // Không cho phép gửi analogWrite (11, buf [2]); // Đặt mức đèn sáng } }
Các thiết bị nhận đơn giản chỉ là liên tục tìm kiếm dữ liệu đến. Thư viện sẽ hỗ trợ trả về dữ liệu nếu nó hợp lệ. Sau đó, các thiết bị nhận sẽ kiểm tra địa chỉ (byte đầu tiên của tin nhắn) để xem có phải là gửi cho nó không (chứ không phải là gửi cho 1 thiết bị khác). Nếu không, nó bỏ qua các tin nhắn. nếu kiểm tra mà hợp lệ (ví dụ. 2 = bật đèn sáng). Nếu không, nó sẽ qua. Cuối cùng nếu tín hiệu nhận được vượt qua những kiểm tra này, thiết bị nhận sẽ gửi lại một phản ứng đến thiết bị gửi. thêm 1 mS được chèn vào thời gian tổng thể để chuẩn bị cho lệnh phản ứng lại thiết bị gửi. Bằng cách đó các thiết bị gửi biết được rằng thiết bị nhận vẫn đang hoạt động bình thường
Chúc các bạn thành công!