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.

Giao tiếp giữa 2 boad Arduino ở cự li xa 1000m bằng chuẩn giao tiếp RS-485

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

Giao tiếp giữa 2 boad Arduino ở cự li xa 1000m bằng chuẩn giao tiếp RS-485

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:

  1.  
  2. #include <SoftwareSerial.h>
  3. /*—–( Khai báo hằng số và Pin )—–*/
  4. #define SSerialRX 0 //Serial Receive pin
  5. #define SSerialTX 1 //Serial Transmit pin
  6.  
  7. #define SSerialTxControl 2 //Kiểm soát hướng cho rs485
  8.  
  9. #define RS485Transmit HIGH
  10. #define RS485Receive LOW
  11.  
  12. #define Pin13LED 13
  13.  
  14. /*—–( Khai báo đối tượng )—–*/
  15. SoftwareSerial RS485Serial(SSerialRX, SSerialTX); // RX, TX
  16.  
  17. /*—–( Khai báo biến )—–*/
  18. int byteReceived;
  19. int byteSend;
  20.  
  21. void setup() /****** SETUP ******/
  22. {
  23. Serial.begin(9600);
  24. Serial.println(“Arduino.vn”);
  25. Serial.println(“Su dung Serial Monitor, go vao cua so phia tren, ENTER”);
  26. pinMode(Pin13LED, OUTPUT);
  27. pinMode(SSerialTxControl, OUTPUT);
  28. digitalWrite(SSerialTxControl, RS485Receive); // bật chế độ thu phát
  29. // Khởi động kết nối tới thiest bị khác
  30. RS485Serial.begin(4800); // cài đặt tốc độ truyền dữ liệu
  31.  
  32. }//–(end setup )—
  33.  
  34.  
  35. void loop() /****** LOOP ******/
  36. {
  37. digitalWrite(Pin13LED, HIGH);
  38. if (Serial.available()) // Nếu có tín hiệu
  39. {
  40. byteReceived = Serial.read();
  41. digitalWrite(SSerialTxControl, RS485Transmit); // Cho phép rs485 nhận dữ liệu
  42. RS485Serial.write(byteReceived); // gửi byte cho arudino thu
  43. digitalWrite(Pin13LED, LOW);
  44. delay(10);
  45. digitalWrite(SSerialTxControl, RS485Receive); // Vô hiệu hóa quá trình nhận dữ liệu
  46. }
  47. if (RS485Serial.available()) //tìm dữ liệu từ thiết bị khác truyền về
  48. {
  49. digitalWrite(Pin13LED, HIGH);
  50. byteReceived = RS485Serial.read(); // đọc byte nhận được
  51. Serial.write(byteReceived); // hiển thị lên Serial Monitor
  52. delay(10);
  53. digitalWrite(Pin13LED, LOW);
  54. }
  55.  
  56. }
  57. Remote Arduino Sketch:
  1. #include <SoftwareSerial.h>
  2. /*—–( Khai báo hằng số và pin )—–*/
  3. #define SSerialRX 0 //Serial Receive pin
  4. #define SSerialTX 1 //Serial Transmit pin
  5.  
  6. #define SSerialTxControl 2 //RS485 Direction control
  7. #define RS485Transmit HIGH
  8. #define RS485Receive LOW
  9.  
  10. #define Pin13LED 13
  11.  
  12. SoftwareSerial RS485Serial(SSerialRX, SSerialTX); // RX, TX
  13.  
  14. int byteReceived;
  15. int byteSend;
  16.  
  17. void setup()
  18. {
  19. Serial.begin(9600);
  20. pinMode(Pin13LED, OUTPUT);
  21. pinMode(SSerialTxControl, OUTPUT);
  22. digitalWrite(SSerialTxControl, RS485Receive); // bật chế độ thu phát
  23. // đặt tốc độ truyền
  24. RS485Serial.begin(4800);
  25. }
  26.  
  27.  
  28. void loop()
  29. {
  30. //Sao chép dữ liệu đầu vào ra đầu ra
  31. if (RS485Serial.available())
  32. {
  33. byteSend = RS485Serial.read(); // đọc dữ liệu
  34. digitalWrite(Pin13LED, HIGH);
  35. delay(10);
  36. digitalWrite(Pin13LED, LOW);
  37. digitalWrite(SSerialTxControl, RS485Transmit); // cho phép truyền
  38. RS485Serial.write(byteSend); // gửi dữ liệu ngược lại
  39. delay(10);
  40. digitalWrite(SSerialTxControl, RS485Receive); // Không cho phép truyền
  41. delay(100);
  42. }
  43. }

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

  1. #include “RS485_protocol.h”
  2. #include <SoftwareSerial.h>
  3.  
  4. const byte ENABLE_PIN = 4;
  5. const byte LED_PIN = 13;
  6.  
  7. SoftwareSerial rs485 (0, 1); // rx,tx
  8.  
  9. void fWrite (const byte what)
  10. {
  11. rs485.write (what);
  12. }
  13.  
  14. int fAvailable ()
  15. {
  16. return rs485.available ();
  17. }
  18.  
  19. int fRead ()
  20. {
  21. return rs485.read ();
  22. }
  23.  
  24. void setup()
  25. {
  26. rs485.begin (28800);
  27. pinMode (ENABLE_PIN, OUTPUT); // cho phép truyền
  28. pinMode (LED_PIN, OUTPUT);
  29. } // end of setup
  30.  
  31. byte old_level = 0;
  32.  
  33. void loop()
  34. {
  35. // đọc giá trị triết áp
  36. byte level = analogRead (0) / 4;
  37.  
  38. // nếu không thay đổi thì bỏ qua
  39. if (level == old_level)
  40. return;
  41.  
  42. // gửi
  43. byte msg [] = {
  44. 1, // thiết bị 1
  45. 2, // bật đèn sáng
  46. level // mức mấy
  47. };
  48.  
  49. // gửi đến slave
  50. digitalWrite (ENABLE_PIN, HIGH); // cho phép gửi
  51. sendMsg (fWrite, msg, sizeof msg);
  52. digitalWrite (ENABLE_PIN, LOW); // không cho phép gửi
  53.  
  54. // nhận phản hồi
  55. byte buf [10];
  56. byte received = recvMsg (fAvailable, fRead, buf, sizeof buf);
  57. digitalWrite (LED_PIN, received == 0); // turn on LED if error
  58. // chỉ gửi 1 lần cho 1 lần thay đổi
  59. if (received)
  60. old_level = level;
  61.  
  62. }

Slave code

  1. #include <SoftwareSerial.h>
  2. #include “RS485_protocol.h”
  3.  
  4. SoftwareSerial rs485 (0, 1); // rx,tx
  5. const byte ENABLE_PIN = 2;
  6.  
  7. void fWrite (const byte what)
  8. {
  9. rs485.write (what);
  10. }
  11. int fAvailable ()
  12. {
  13. return rs485.available ();
  14. }
  15.  
  16. int fRead ()
  17. {
  18. return rs485.read ();
  19. }
  20. void setup()
  21. {
  22. rs485.begin (28800);
  23. pinMode (ENABLE_PIN, OUTPUT); // cho phép truyền
  24. }
  25.  
  26. void loop()
  27. {
  28. byte buf [10];
  29. byte received = recvMsg (fAvailable, fRead, buf, sizeof (buf));
  30. if (received)
  31. {
  32. if (buf [0] != 1)
  33. return; // Không phải thiết bị trong hệ thống
  34. if (buf [1] != 2)
  35. return; // không hiểu tín hiệu
  36. byte msg [] = {
  37. 0, // thiết bị 0 (master)
  38. 3, // Bật đèn sáng khi lệnh nhận được
  39. };
  40. delay (1); // Cung cấp cho master 1 chút thời gian để nhận tín hiệu
  41. digitalWrite (ENABLE_PIN, HIGH); // Cho phép gửi
  42. sendMsg (fWrite, msg, sizeof msg);
  43. digitalWrite (ENABLE_PIN, LOW); // Không cho phép gửi
  44. analogWrite (11, buf [2]); // Đặt mức đèn sáng
  45. }
  46. }

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!