Skip to content

Arduino – Chuẩn giao tiếp truyền nhận dữ liệu SPI

Arduino – Chuẩn giao tiếp truyền nhận dữ liệu SPI

Chương này chúng ta sẽ tìm hiểu về một chuẩn giao tiếp khá thông dụng trong truyền nhận dữ liệu, đó là chuẩn giao tiếp truyền nhận SPI. Điểm qua 1 số nội dung sẽ tìm hiểu ở chương này:

  • Giới thiệu về chuẩn SPI, lịch sử hình thành và nguyên lí hoạt động.

  • Một số ví dụ sử dụng SPI trong truyền, nhận dữ liệu như điều khiển LED matrix và đọc giá trị nhiệt độ, áp suất, độ cao bằng cảm biến BMP280 hiển thị giá trị lên màn hình OLED.

Giao thức SPI

Giới thiệu

Với tốc độ phát triển của công nghệ ngày nay thì việc truyền dữ liệu qua các chuẩn truyền I2C, UART chưa đáp ứng được đối với các dự án cần truyền dữ liệu với tốc độ cao, để đáp ứng điều đó hãng Motorola đã đề xuất ra chuẩn truyền SPI.

SPI là chữ viết tắt của Serial Peripheral Interface, chuẩn giao tiếp nối tiếp đồng bộ tốc độ cao do hãng Motorola đề xuất được sử dụng cho truyền thông khoảng cách ngắn, chủ yếu là trong các hệ thống nhúng. Giao diện được Motorola phát triển vào giữa những năm 1980 và đã trở thành tiêu chuẩn trong thực tế. Các ứng dụng điển hình như Secure Digital cards (các loại thẻ nhớ SD ví dụ: miniSD, microSD cards) và liquid crystal displays (màn hình tinh thể lỏng).

Đôi khi SPI còn được gọi là chuẩn truyền thông “4 dây” vì nó có 4 đường giao tiếp là SCK (Serial Clock), MISO (Master Input/Slave Output), MOSI (Master Output/Slave Input) và SS(Slave Select).

  • SCK (Serial Clock): Là đường xung giữ nhịp cho chuẩn SPI, là chân output từ master, do chuẩn SPI là giao tiếp đồng bộ nên phải cần dùng một đường giữ nhịp. Đây là sự khác biệt giữa truyền thông đồng bộ và truyền thông không đồng bộ như chuẩn giao tiếp UART. SCK giúp chuẩn SPI có tốc độ truyền/nhận dữ liệu cao và ít xảy ra lỗi trong quá trình truyền/nhận dữ liệu.

  • MISO (Master Input/Slave Output): Với master thì MISO là chân input và với slave là chân output, 2 chân MISO của master và slave nối trực tiếp với nhau.

  • MOSI (Master Output/Slave Input): Với chip master thì MOSI là chân output và với chip slave là chân input, 2 đường MOSI của master và slave nối trực tiếp với nhau.

  • SS (Slave Select): Là chân chọn thiết bị slave cần giao tiếp, trên thiết bị slave sẽ có một chân slave kết nối với chân SS của master và trên thiết bị master sẽ có nhiều chân SS điều khiển thiết bị slave. Chân SS trên các chip slave sẽ ở mức cao khi không giao tiếp, nếu chip master kéo đường SS của một slave nào đó xuống mức thấp thì master sẽ giao tiếp với slave đó.

Chuẩn truyền SPI sử dụng kiểu truyền thông master-slave, với một master có thể điều khiển nhiều slave thông qua việc lựa chọn các đường SS (Slave Select), muốn điều khiển slave nào thì chỉ cần chọn SS của slave đó. Các thiết bị sử dụng chuẩn truyền SPI sẽ truyền dữ liệu song công (duplex communication) là truyền và nhận dữ liệu cùng lúc, master có thể gửi dữ liệu đến slave và nhận dữ liệu từ slave cùng một thời điểm.

master slave
Hình 1. Hình ảnh cách kết nối các thiết bị trong giao thức SPI (Nguồn en.wikipedia.org)

SPI, ưu và nhược điểm

Ưu điểm

  • Chuẩn truyền thông nối tiếp SPI có tốc độ truyền dữ liệu và ít lỗi phát sinh trong quá trình truyền/nhận dữ liệu hơn các chuẩn truyền nối tiếp khác.

  • Hỗ trợ truyền thông song công (duplex communication) là dữ liệu có thể truyền và nhận cùng một thời điểm.

  • Có giao diện phần cứng khá đơn giản.

  • Không giới hạn tốc độ xung clock, cho phép truyền dữ liệu với tốc độ cao.

  • Hỗ trợ điều khiển nhiều slave.

Nhược điểm:

  • Tốn năng lượng.

  • Chỉ hỗ trợ một master.

  • Không có giao thức kiểm tra lỗi.

  • SPI đòi hỏi các slave có một đường SS (slave Select) riêng biệt, vì thế nếu cần nhiều slave thì sẽ cần nhiều đường SS sẽ làm tốn chân của chip master và nhiều dây sẽ gây rối.

Nguyên lý hoạt động

Thiết bị master và slave mỗi thiết bị có thanh ghi dữ liệu 8 bit. Khi đường SCK của master tạo ra một xung nhịp thì một bit trong thanh ghi dữ liệu của master truyền qua slave trên đường MOSI, và ngược lại một bit dữ liệu từ slave sẽ truyền qua master trên đường MISO, do 2 dữ liệu được truyền cùng một lúc trên một nhịp xung nên quá trình truyền dữ liệu này gọi là truyền dữ liệu “song công”.

send spi
Hình 2. Quá trình truyền nhận dữ liệu trong giao thức SPI (Nguồn learn.sparkfun.com)

SPI, các ví dụ mẫu

Hiển thị chữ trên LED matrix

Yêu cầu

Đây là một ví dụ cơ bản của chuẩn giao tiếp nối tiếp SPI. Vi điều khiển giao tiếp với module LED matrix để hiển thị chữ.

module led matrix
Hình 3. Hình ảnh module LED matrix

LED matrix 8×8 MAX7219 dùng IC 7219 để điều LED matrix 1 cách dễ dàng và đơn giản hơn, dùng 3 dây dữ liệu để truyền dữ liệu và 2 dây nguồn. Module 8×8 LED matrix sử dụng khá đơn giản, có thể điều chỉnh độ sáng của LED ngay trên phần mềm.

Linh kiện cần dùng

  • Board Arduino Uno

  • Module LED matrix MAX7219

  • Dây kết nối

Kết nối Arduino Uno với LED matrix

Board Arduino Uno sẽ là master và LED matrix sẽ là slave.

  • Master sẽ gửi dữ liệu ra từ chân D11 (MOSI) và slave sẽ nhận dữ liệu bằng chân DIN.

  • Chân D13 (SCK) của master sẽ tạo xung clock qua chân CLK của slave mỗi nhịp sẽ gửi 1bit dữ liệu qua slave.

  • Chân D10 (SS) của master nối với chân CS của slave khi muốn giao tiếp với slave thì chân D10 (SS) của master sẽ kéo chân CS của slave xuống mức thấp.

Bảng 1. Bảng kết nối LED matrix và board Arduino Uno
LED matrix Board Arduino Uno

VCC

5V

GND

GND

DIN

D11 (MOSI )

CLK

D13 (SCK)

CS

D10 (SS)

module led matrix8x8
Hình 4. Hình ảnh kết nối module LED matrix với board Arduino Uno

Thư viện cần dùng:

Với những thư viện không có sẵn trong trình biên dịch Arduino IDE thì cần phải clone (dùng với git) hoặc Download về máy và add vào chương trình. Các thư viện cần dùng cho ứng dụng được kiệt kê bên dưới:

  • Thư viện “SPI.h” là thư viện đã có sẵn trong trình biên dịch Arduino IDE.

  • Thư viện bitBangedSPI.

  • Thư viện MAX7219_Dot_Matrix.

Source code

#include <SPI.h>
#include <bitBangedSPI.h>
#include <MAX7219_Dot_Matrix.h>

MAX7219_Dot_Matrix display (chips, 10); // Chân D10 là chân SS của board Iotmaker Uno X

const byte chips = 1;                   // Số chip MAX7219 được sử dụng
const char message [] = "IOT MAKER VN"; // Nội dung được hiển thị
unsigned long lastMoved = 0;
unsigned long MOVE_INTERVAL = 40;       // Thời gian chạy chữ đơn vị (ms)
int  messageOffset;

void updateDisplay ()
{
  //  Hiển thị chữ của mảng message, bắt đầu từ pixel mesageOffset
  display.sendSmooth (message, messageOffset);

  // Mỗi thời gian hiển thị một pixel từ phải qua trái
  if (messageOffset++ >= (int) (strlen (message) * 8))
    messageOffset = -chips * 8;
}

void setup ()
{
  display.begin ();                       // Khởi tạo hiển thị
}

void loop ()
{
  //  Nội dung được hiển thị lại sau khi chạy
  if (millis() - lastMoved >= MOVE_INTERVAL) {
    updateDisplay ();
    lastMoved = millis();
  }
}

Đọc dữ liệu từ cảm biến BMP280, hiển thị trên OLED

Yêu cầu

Ứng dụng này giúp chúng ta đọc dữ liệu từ cảm biến áp suất và hiển thị giá trị lên màn hình OLED.

Module cảm biến áp suất BMP280

cam bien ap suat bmp 280
Hình 5. Hình ảnh module cảm biến áp suất BMP280

BPM280 là cảm biến nâng cấp thế hệ tiếp theo cho BMP085/BMP180/BMP183. Với chi phí thấp, độ chính xác cao. Module có chức năng đo áp suất khí quyển và nhiệt độ. Chúng ta cũng có thể sử dụng nó như một module đo độ cao (sai số ± 1m) bởi mối liên hệ giữa áp suất và độ cao.

Linh kiện cần dùng

  • Board Arduino Uno

  • Module cảm biến áp suất BPM280

  • Màn hình OLED

  • Dây kết nối

Kết nối :

  • Arduino sẽ là master và cảm biến BMP280 sẽ là slave, slave sẽ gửi dữ liệu qua đường SDI.

  • Mỗi nhịp xung clock từ chân SCK (D13) của master tạo ra sẽ ứng với 1bit dữ liệu được truyền.

  • Chân D10 (SS) của master nối với chân CS của slave khi muốn giao tiếp với slave thì chân D10 (SS) của master sẽ kéo chân CS của slave xuống mức thấp.

Bảng 2. Bảng đấu nối cảm biến BMP280 và board Arduino Uno
BMP280 Arduino Uno

VCC

3.3V

GND

GND

SDI

D11 (MOSI )

SCK

D13 (SCK)

CSE

D10 (SS)

SDO

D12(MISO)

oled bmp280
Hình 6. Hình ảnh kết nối module cảm biến áp suất BMP280 với board Arduino Uno

Kết nối board Arduino Uno với OLED

Xem chương I2C để hiểu hơn về giao tiếp Arduino giao tiếp với OLED, chúng ta có thể cắm trực tiếp OLED vào header đã được thiết kế sẵn trên board Arduino Uno hoặc kết nối theo hướng dẫn bên dưới.

Bảng 3. Bảng đấu nối OLED với board Arduino Uno
OLED Arduino Uno

VCC

3.3V

GND

GND

SDA

SDA(hoặc A4)

SCL

SCL(hoặc A5)

Thư viện cần dùng:

Source code

#include <SPI.h>
#include <Wire.h>
#include <Adafruit_SSD1306.h>
#include <Adafruit_GFX.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_BMP280.h>

#define BMP_SCK     13
#define BMP_MISO    12
#define BMP_MOSI    11
#define BMP_CS      10
#define OLED_RESET  4

Adafruit_SSD1306 display(OLED_RESET);
//  Chọn giao tiếp SPI (BMP280 có 2 chuẩn giao tiếp SPI và I2C)
Adafruit_BMP280 bmp(BMP_CS, BMP_MOSI, BMP_MISO,  BMP_SCK);

void setup()
{
  Serial.begin(9600);
  display.begin(SSD1306_SWITCHCAPVCC, 0x3C);  //  Lấy  địa chỉ I2C của oled
  display.clearDisplay();                     //  Lệnh xóa màn hình hiển thị
  display.setTextColor(WHITE);                //  Chọn màu chữ
  display.setTextSize(1);                     //  Chọn kích thước chữ
  display.setCursor(15, 15);                  //  Chọn vị trí của chữ
  Serial.println(F("BMP280 test"));

  if (!bmp.begin()) {                         //  In ra thông báo nếu kết nối thất bại
    Serial.println(F("Could not find a valid BMP280 sensor, check wiring!"));
    while (1);
  } else
    Serial.println("BMP280 OK");              //  Hiển thị "BMP280 OK" khi kết nối thành công
}

void loop()
{
  display.clearDisplay();
  display.setTextSize(1);
  display.setCursor(0, 0);
  display.print("Temperature:");
  display.print(bmp.readTemperature());          // Lấy giá trị nhiệt độ
  display.print("*C");
  //  Hiển thị giá trị nhiệt độ trên serial monitor
  Serial.print("Temperature:");
  Serial.print(bmp.readTemperature());          //  Lấy giá trị nhiệt độ
  Serial.println("*C");

  display.setCursor(0, 10);
  display.print("Pressure:");
  display.print(bmp.readPressure());            //  Lấy giá trị áp suất
  display.print("Pa");
  //  Hiển thị giá trị áp suất trên serial monitor
  Serial.print("Pressure:");
  Serial.print(bmp.readPressure());             //  Lấy giá trị áp suất
  Serial.println("Pa");

  display.setCursor(0, 20);
  display.print("h:");
  display.print(bmp.readAltitude());            //  Lấy giá trị độ cao
  display.print("m");
  //  Hiển thị giá trị độ cao trên serial monitor
  Serial.print("h:");
  Serial.print(bmp.readAltitude());             //  Lấy giá trị độ cao
  Serial.println("m");

  display.display();
  delay(2000);
}

Tổng kết

Qua phần này, bạn đã tìm hiểu được những khái niệm quan trọng trong giao tiếp SPI, các chân giao tiếp theo chuẩn SPI là SCK, MISO, MOSI, SS. Cách chọn slave để giao tiếp của master và SPI hoạt động theo kiểu truyền song công là như thế nào. Từ đó, chúng ta có thể dễ dàng xây dựng các ứng dụng có hỗ trợ giao tiếp SPI.

Để lại một bình luận

Email của bạn sẽ không được hiển thị công khai. Các trường bắt buộc được đánh dấu *