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

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!

lên
23 thành viên đã đánh giá bài viết này hữu ích.
Các dự án được truyền cảm hứng

Bộ điều khiển PID - ứng dụng phần 2 - xe dò line dùng thuật toán PID

Tiép nối bài viết về xe dò line cảm ơn Đỗ Hữu Toàn đã viết hộ mình phần 4. hôm nay mình sẽ làm cho chiếc xe dò line đi mượt và có hồn hơn 

lên
34 thành viên đã đánh giá bài viết này hữu ích.
Các bài viết cùng tác giả

Sạc cho nguồn và cấp nguồn cho Arduino - Giải quyết vấn đề năng lượng bằng một bài viết bỏ túi

Đối với các dự án không tiêu thụ nhiều năng lượng, các bạn có thể sử dụng pin AAA hoặc pin 9v. Nhưng với những dự án tiêu thụ nhiều năng lượng bao gồm cả động cơ, màn hình LCD hay âm thanh thì pin 18650 là lựa chọn tối ưu, vừa bền, vừa gọn nhẹ.

lên
21 thành viên đã đánh giá bài viết này hữu ích.

Công cụ vẽ đồ thị trên arduino IDE - Serial Plotter

Bắt đầu từ bản cập nhật arduino IDE 1.6.6, Arduino IDE đã giới thiệu một tính năng mới tuyệt vời. Nó được gọi là Serial Plotter, gọi nôm na là vẽ nối tiếp và bạn có thể tìm thấy nó trong Arduino IDE của bạn dưới menu Tools. Bài viết này mình sẽ giới thiệu với các bạn công cụ Plotter này

lên
15 thành viên đã đánh giá bài viết này hữu ích.