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 sử dụng cảm biến nhiệt độ TMP36 - Khoảng đo từ -40 đến 125 độ C

Mình thấy cảm biến nhiệt độ LM35 rất rẻ và hoạt động cũng tương đối chính xác. Tuy nhiên, độ bền của nó không cao vì mình thấy mình chỉ dùng cảm biến LM35 trong khoảng thời gian 3 tháng, sau đó phải thay cảm biến khác (để đo nhiệt độ luộc gà). Bản thân mình không thích điều đó nên thử dùng một cảm biến khác cũng có chức năng tương tự là TMP36 và thấy nó hoạt động bền hơn (đã đến tháng thứ 4 nhưng chưa hư). Mình xin chia sẻ với các bạn nhé. Loại này hơi khó tìm và không thông dụng, nhưng nó bền hơn hẳn LM35 các bạn nhé.

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

Hướng dẫn điều khiển động cơ bước với thư viện Accel Stepper và driver điều khiển động cơ bước A4988 hoặc DRV8825

Mình thấy có nhiều bạn hỏi về stepper và cách điều khiển nó. Đồng thời thấy vấn đề điều khiển động cơ bước là một vấn đề kinh điển nhưng lại chưa có trên Cộng đồng. Ngoài ra, vì chức năng điểm cộng đồng khá hay và mình cũng muốn có quà nên hôm nay mình sẽ hướng dẫn rất kỹ với các bạn! Thư viện mình dùng là thư viện AccelStepper chứ không phải thư viện stepper mặc định của Arduino nên có thể điều khiển đồng thời nhiều stepper và kết hợp với các thư viện bất đồng bộ khác.

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