Software Serial - Giao tiếp giữa Arduino và nhiều mạch Serial khác - Truyền tải trung gian giữa một mạch khác qua giao tiếp Serial

I. Giới thiệu

Có thể nói Serial là một trong những phương thức giao tiếp đơn giản nhất trong môi trường Serial. Vì bạn chỉ cần 2 dây và cách thức truyền dữ liệu của nó lại giống hệt stream trong các ngôn ngữ lập trình. Nhưng thật đáng tiết, con Arduino Uno chỉ có duy nhất một cổng Serial được phần cứng hỗ trợ sẵn (Mega thì 3). Vì vậy, nếu bạn muốn giao tiếp với nhiều module Serial thì đó là một chuyện không thể. Và đó chính là lý do vì sao thư viện Software Serial ra đời. Hôm nay, chúng ta sẽ tìm cách giao tiếp giữa 2 mạch Arduino thông qua Serial và một ví dụ về chuyển tiếp giá trị của một module giao tiếp qua Serial (như module bluetooth) với thư viện này.

II. Giới thiệu về thư viện Software Serial

1. Mục đích ra đời của Software Serial

Giả lập thêm nhiều cổng Serial cho các board Arduino

2. Tải về

Nó đã là một thư viện cứng trong bộ thư viện chuẩn của Arduino, các bạn không cần phải download. Để chắc ăn, các bạn hãy nâng cấp IDE của mình lên bản 1.6.x, có thể tải tại mục Tải về.

3. Phương thức hoạt động

Vì mình không đủ level để hack não được nên bó tay các bạn nhé :D.

4. Hạn chế

Không phải chân nào của Arduino Mega và Arduino Mega 2560 cũng hỗ trợ đổi ngắt, vì vậy chỉ có các chân 10, 11, 12, 13, 50, 51, 52, 53, 62, 64, 65, 66, 67, 68, 69 có thể dùng làm chân RX. Tương tự với mạch Leonardo, cũng chỉ có các chân 8, 9, 10, 11, 14, 15, 16 hỗ trợ để làm chân RX.

Mình thấy cái này cũng không ảnh hưởng gì lắm vì sao? Vì bạn tính thử xem, bạn có bao giờ dùng hết được nó không devil? Liệt kê thử nào, GPS, bluetooth, SIM, điều khiển 1 Uno thì cũng chỉ cần đến 4 cổng Arduino. Như vậy là quá nhiều luôn, đúng không nào?

III. Thực nghiệm với 2 Arduino

1. Mục tiêu

Mục tiêu của mình trong phần này đó là hướng dẫn các bạn dùng Arduino giao tiếp với một một Arduino khác thông qua cổng Serial ảo được  tạo từ Software Serial.

2. Phần cứng cần chuẩn bị

3. Nạp code cho Arduino "thứ 2"

Vì sao lại là Arduino thứ 2 mà không phài thứ nhất? Bởi vì mình sẽ upload một chương trình giao tiếp serial bình thường vào đây trước. Rồi dùng Arduino "thứ 1" với thư viện Software Serial từ đó giao tiếp với Arduino "thứ 2".

int led = 13;
unsigned long time = 0;
unsigned long delayTime = 1000; //Thời gian delay (không dùng hàm delay)

void setup() {
  Serial.begin(9600);
  pinMode(led, OUTPUT);
  digitalWrite(led, LOW); // Tắt led
}


void loop() {
  if (Serial.available()) {
    time = millis(); //cập nhập lại biến time để cho đèn sáng được trong khoảng delayTime
    digitalWrite(led, HIGH); // đèn led sáng
    while (Serial.available()) { //xóa hết bộ đệm
      Serial.read();
      delay(3);
    }
    Serial.println("Da nhan duoc"); //trả về lại cho arduino 1
  }
    
  if (millis() - time > delayTime)
    digitalWrite(led, LOW);
}

Mục đích của đoạn code này rất đơn giản. Khi nào có tín hiệu Serial thì nó sẽ làm đèn 13 nháy sáng lên trong 1 giây và trả về qua Serial (phần cứng) nội dung "Da nhan duoc"! Bạn hãy thử bật Serial Monitor chỉnh baudrate 9600 xem là thấy ngay devil!

Lưu ý: Nếu bạn đã kết nối Arduino thứ 1 và thứ 2 thì hãy tháo kết nối TX và RX giữa chúng thì mới nạp code được nhé.

4. Mạch kết nối giữa Arduino thứ 1 và Arduino thứ 2

Vì phần này đơn giản quá nên mình sẽ đưa vào bảng tóm tắt cho nhanh kiss.

Arduino thứ 1 Arduino thứ 2
GND GND
10 (RX software Serial) TX
11 (TX software Serial) RX

 

Lưu ý: Software Serial sẽ giả lập một công Serial, như vậy bạn sẽ có một cổng TX và cổng RX mới!

Vì vậy ở Arduino thứ 1, board dùng thư viện Software Serial sẽ có một cặp TX và RX ảo từ các chân digital.

5. Nạp code cho Arduino thứ 1

Với đoạn chương trình dưới đây, thực ra, nó cũng rất đơn giản. Mình sẽ bật 2 cổng Serial: Serial - hardware ở baudrate 9600, mySerial ở baudrate 9600 luôn, 2 cổng Serial này không nhất thiết phải khác nhau về mức baudrate, sau đó sẽ có 2 nhóm chương trình. Nhóm thứ nhất sẽ nhận dữ liệu từ máy tính và chuyển lại cho Arduino thứ 2, nhóm thứ hai sẽ nhận dữ liệu từ Arduino thứ 2 và xuất ra màn hình Serial monitor (máy tính).

#include <SoftwareSerial.h>

SoftwareSerial mySerial(10, 11); // RX, TX

void setup() {
  Serial.begin(9600);

  Serial.println("Da san sang");

  mySerial.begin(9600);
}

void loop() {
  // Khi máy tính gửi dữ liệu cho mình
  if (Serial.available() > 0) {
    Serial.print("May tinh gui: ");
    while (Serial.available() > 0) {// in hết nội dung mà máy tính gửi cho mình, đồng thời gửi cho arduino thứ 2  
      char ch = Serial.read(); //đọc ký tự đầu tiên trogn buffer
      Serial.write(ch); //xuất ra monitor máy tính
      mySerial.write(ch); //gửi dữ liệu cho Arduino thứ 2
      //delay(3);
    }    
    Serial.println();
  }
  
  if (mySerial.available() > 0) {
    Serial.println("Serial thu 2 gui gia tri: ");
    //đọc giá trị từ Arduino nếu có
    delay(20);
    while (mySerial.available() > 0) {
      char ch = mySerial.read(); //đọc
      Serial.write(ch); //xuất ra monitor
      delay(3);
    }
    Serial.println();
  }
}

Và khi bạn gõ một chuỗi gì đó qua Serial monitor thì nó sẽ chuyển hết chuỗi đó qua Arduino thứ 2, Arduino thứ 2 nhận được biết là có tín hiệu => làm đèn 13 (của arduino thứ 2) sáng trong 1 giây và trả lời nội dung là "Da nhan duoc".

Kết quả qua Serial Monitor máy tính

Mô hình hoạt động của Arduino và thư viện Serial với những module khác nhau (Click vào để xem to hơn)

6. Rút kinh nghiệm

Như vậy, ta đã giả lập được giao tiếp Serial và khi nạp code cho Arduino thứ 1 ta không cần phải tháo TX và RX ra nữa :). Thật tiện lợi phải không nào? Nói thì nói vậy thôi nhưng bạn phải thử thì mới biết cái khó của nó. Nếu bạn có một con mắt tinh tế thì sẽ nhận thấy ở các đoạn code Arduino thứ 1 và thứ 2, mình có để vài làm delay trong vài mili giây? Vì sao mình phải làm vậy nhỉ? Bởi vì, khi nhận dữ liệu Serial qua Software Serial thì lâu lâu nó sẽ bị lỗi mất dữ liệu => làm dữ liệu sai lệch vì tốc độ gửi dữ liệu quá nhanh phần mềm xử lý không kịp. Vì vậy để chắc ăn, bạn hãy dùng thư viện SerialCommand để giao tiếp giữa 2 mạch Arduino nhé.

7. Ví dụ về cách dùng với thư viện Serial Command

Trên cộng đồng của chúng ta đã có bài viết về thư viện Serial Command rồi, nên mình sẽ dùng ví dụ trong bài viết đó luôn. Vì vậy, các bạn nên vào bài viết đó và lắp mạch test trước rồi quay lại đây nhé heart.

Ở đây CLIENT là Arduino thứ 2, HOST là Client thứ 1. Code của CLIENT khôn thay đổi và chỉ thay đổi code của HOST. Vì sao? Vì CLIENT vẫn dùng serial chuẩn của hắn chứ có cần giao tiếp với máy tính làm gì đâu haha.

Các bạn lưu ý là phải nối RX và TX như mình hướng dẫn ở mục 4 nhé.

Code host sẽ thay đổi như sau.

#include <SoftwareSerial.h>

SoftwareSerial mySerial(10, 11); // RX, TX
void setup() {
  mySerial.begin(9600);// Bạn khởi tạo một cổng Serial tại baudrate 9600. Ở Client, bạn cũng phải mở một cổng Serial cùng Baudrate với HOST
}

int Step = 0;

void loop() {
  if (Step == 0) {
    mySerial.println("LED_RED 1"); // Đèn đỏ sáng. 1 == HIGH
  } else if (Step == 1) {
    mySerial.println("LED_RED 0"); // Đèn đỏ tắt . 0 == LOW
  } else if (Step == 2) {
    mySerial.println("LED_BLUE 1");// Đèn xanh sáng
  } else if (Step == 3) {
    mySerial.println("LED_BLUE 0");// Đèn xanh tắt
  }
  
  Step = (Step + 1) % 4; //Step sẽ tuần tự tuần hoàn các giá trị trong khoảng từ 0 --> 3
  
  delay(1000);// Dừng một giây giữa các lần gửi
}

Các bạn đã thấy sự vi diệu chưa! Phần mở rộng mà tôi muốn các bạn làm đó là hãy điều khiển CLIENT từ máy tính của mình, và tôi se gợi ý ở mục IV!

IV. Biến Arduino trở thành một USB to Serial

1. Mục tiêu

Mục tiêu của mình là không chỉ nói đến Arduino Uno, vì với mạch Arduino Uno bạn chỉ việc tháo con Atmega328p ra và nó đã trở thành một mạch USB to Serial 5V mất rồi! Ở đây, mình hướng đến việc, biến mọi con Arduino bình thường trở thành một mạch USB to Serial.

2. Bài toán đặt ra

Giao tiếp giữa máy tính và một module bluetooth khác sử dụng mạch Arduino bất kỳ.

Mâu thuẫn

Khi sử dụng cổng Serial hardware (chân digital 0 1) thì bạn không thể nào giao tiếp được với máy tính. Như vậy không thể dùng cổng Serial hardware để giao tiếp với module bluetooth từ đó xem giá trị truyền qua Serial được. Nhưng module bluetooth thì chỉ có thể giao tiếp qua giao tiếp Serial. Vậy giờ phải làm sao?

3. Giải pháp

Chúng ta sẽ giả lập một cổng Serial bằng thư viện Software Serial và từ đó biến Arduino trở thành một nơi trung chuyển dư liệuheart. Nghĩa là khi Arduino nhận gì từ máy tính thì nó đẩy hết qua software Serial và khi software serial nhận được dữ liệu thì lại đẩy hết về máy tính.

4. Ví dụ

Arduino
Bluetooth
GND
GND
10 (RX software Serial)
TX
11 (TX software Serial)
RX
5V 5V
#include <SoftwareSerial.h>

SoftwareSerial mySerial(10, 11); // RX, TX

void setup() {
  Serial.begin(115200); //serial hardware kết nối với serial monitor của máy tính

  mySerial.begin(9600); //software serial kết nối với module sử dụng serial để giao tiếp (ở ví dụ này là bluetooth HC-06)
}

void loop() { 
  if (mySerial.available()) //khi software serial có dữ liệu
    Serial.write(mySerial.read()); //viết ra monitor

  if (Serial.available()) // khi hardware serial có dữ liệu
    mySerial.write(Serial.read()); //viết lại qua module bluetooth (software serial)

}

Rồi, bây giờ bạn hãy thử các câu lệnh AT của module bluetooth đi là sẽ thấy ngay thôi mà, hoặc là dùng điện thoại kết nối với module bluetooth rồi thử gửi lệnh qua là sẽ thấy ngay thôi mà!

5. Nhược điểm

Không như một mạch USB to Serial bình thường, để chuyển đổi giữa mức baudrate nhằm giao tiếp với thiết bị khác ta chỉ việc chỉnh option trong máy tính. Với cách tiếp cận này bạn phải nạp lại code mới cho nó để chỉnh lại baudrate! Nhưng được một cái là, ta không cần phải mua một mạch USB to Serial nếu dự án của ta chỉ là một dự án nhỏ!

V. Kết luận

Như vậy thì các bạn đã biết cách sử dụng thư viện Software Serial phải không nào? Hãy chia sẻ những dự án hay với nó nhé. Và nhớ hãy đọc từ trên xuống dưới đừng nên đọc lướt vì mình có để vài "Lưu ý" trong bài viết đấy!

lên
25 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

Select any filter and click on Apply to see results

Các bài viết cùng tác giả

Hướng dẫn điều khiển stepper 28BYJ-48 bằng mạch điều khiển động cơ bước ULN2003

Động cơ bước 28BYJ-48 có đến 5 dây chứ không phải thuộc loại 4 dây hoặc 6 dây như ta thường thấy. Nhưng thật may mắn, chúng ta lại có board điều khiển động cơ bước ULN2003 với 5 giây vừa khít với con động cơ bước này luôn. Vì vậy, bộ động cơ bước + stepper driver này thường được dùng trong các dự án DIY. Hôm nay, mình sẽ chỉ các bạn cách sử dụng thư viện để sử dụng bộ combo này cho dễ nhé.

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

Một cách tiếp cận khác với sóng vô tuyến 315 hay 433Mhz

Yeah, cộng đồng Arduino Việt Nam chúng ta đã có một bài viết về sóng vô tuyến rất hay của NTP_PRO phải không nào! Tuy nhiên, mình thấy một số ý kiến về sự đụng độ thư viện VirtualWire và Servo (của Arduino). Vì vậy, qua cách tiếp cận này của mình sẽ giúp các bạn giải quyết vấn đề trên nhé. Ngoài ra, qua bài viết, mình muốn chia sẻ cho các bạn cách "hack" những thiết bị vô tuyến hiện có như xe điều khiển từ xa. Từ đó, tự các bạn chế ra những bộ remote của riêng mình. heart

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