Viet Dev

Cover image for Arduino - Chuẩn giao tiếp truyền nhận dữ liệu SPI
Tuan for Unicloud Group

Posted on

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.

Hình ảnh cách kết nối các thiết bị trong giao thức SPI (Nguồn<br>
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".

Quá trình truyền nhận dữ liệu trong giao thức SPI (Nguồn<br>
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ữ.

Hình ảnh module LED<br>
matrix

LED matrix 8x8 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 8x8 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.

LED matrix Board Arduino Uno
VCC 5V
GND GND
DIN D11 (MOSI )
CLK D13 (SCK)
CS D10 (SS)

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

Hình ảnh kết nối module LED matrix với board Arduino<br>
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:

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();
  }
}
Enter fullscreen mode Exit fullscreen mode

Đọ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

Hình ảnh module cảm biến áp suất<br>
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.

BMP280 Arduino Uno
VCC 3.3V
GND GND
SDI D11 (MOSI )
SCK D13 (SCK)
CSE D10 (SS)
SDO D12(MISO)

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

Hình ảnh kết nối module cảm biến áp suất BMP280 với board Arduino<br>
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.

OLED Arduino Uno
VCC 3.3V
GND GND
SDA SDA(hoặc A4)
SCL SCL(hoặc A5)

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

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);
}
Enter fullscreen mode Exit fullscreen mode

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.

Latest comments (0)