Cách kết nối hai bo mạch Arduino bằng I2C
Trong khi một Arduino duy nhất có thể hoàn thành nhiều tác vụ, một số dự án có thể yêu cầu sử dụng nhiều hơn một bảng để xử lý các chức năng khác nhau. Vì vậy, để cho phép truyền dữ liệu giữa hai bộ vi điều khiển, một giao thức truyền thông như CAN, SPI, I2C hoặc UART phải được thiết lập.
Trong hướng dẫn này, chúng tôi sẽ đề cập đến những điều cơ bản về cách thức hoạt động của I2C, các kết nối phần cứng và triển khai phần mềm cần thiết để thiết lập hai bo mạch Arduino làm thiết bị chủ và phụ I2C.
Mục Lục
I2C là gì?
Inter-Integrated Circuit (I2C) là một giao thức truyền thông được sử dụng rộng rãi trong các hệ thống nhúng và bộ vi điều khiển để cho phép truyền dữ liệu giữa các thiết bị điện tử. Không giống như SPI (Giao diện ngoại vi nối tiếp), I2C cho phép bạn kết nối nhiều thiết bị chính với một xe buýt có một hoặc nhiều thiết bị phụ. Nó lần đầu tiên được sử dụng bởi Philips và còn được gọi là giao thức truyền thông Giao diện hai dây (TWI).
Giao tiếp I2C hoạt động như thế nào?
I2C sử dụng hai đường truyền hai chiều: Dữ liệu nối tiếp (SDA) và Đồng hồ nối tiếp (SCL) để truyền dữ liệu và đồng bộ hóa giao tiếp giữa các thiết bị. Mỗi thiết bị được kết nối với bus I2C có một địa chỉ duy nhất xác định nó trong quá trình liên lạc. Giao thức I2C cho phép nhiều thiết bị chia sẻ cùng một bus và mỗi thiết bị có thể đóng vai trò là chủ hoặc phụ.
Giao tiếp được bắt đầu bởi thiết bị chính và việc định địa chỉ không chính xác của thiết bị phụ có thể gây ra lỗi khi truyền. Hãy xem hướng dẫn chuyên sâu của chúng tôi về cách hoạt động của giao tiếp nối tiếp UART, SPI và I2C để cung cấp cho bạn một số ngữ cảnh.
Một ưu điểm chính của giao tiếp I2C đáng chú ý là tính linh hoạt mà nó mang lại khi quản lý năng lượng. Các thiết bị hoạt động ở các mức điện áp khác nhau vẫn có thể giao tiếp hiệu quả với sự trợ giúp của bộ chuyển đổi điện áp. Điều này có nghĩa là các thiết bị hoạt động ở mức 3,3V cần có bộ chuyển đổi điện áp để kết nối với bus I2C 5V.
thư viện dây
Thư viện Wire là thư viện Arduino tích hợp cung cấp các chức năng để giao tiếp qua I2C. Nó sử dụng hai chân—SDA và SCL—trên bo mạch Arduino để giao tiếp I2C.
Chân I2C trên Arduino Uno:
Chân Arduino Nano I2C:
Để sử dụng thư viện, bạn phải bao gồm Dây.h tệp tiêu đề ở đầu bản phác thảo Arduino của bạn.
#include <Wire.h>
Thư viện Wire cung cấp các chức năng để bắt đầu giao tiếp với thiết bị I2C, gửi dữ liệu và nhận dữ liệu. Một số chức năng quan trọng bạn nên biết bao gồm:
- Dây.bắt đầu(): được sử dụng để tham gia bus I2C và bắt đầu giao tiếp.
- Wire.beginTransmission(): được sử dụng để chỉ định địa chỉ nô lệ và bắt đầu truyền.
- Wire.write(): dùng để gửi dữ liệu đến thiết bị I2C.
- Wire.endTransmission(): dùng để kết thúc quá trình truyền và kiểm tra lỗi.
- Wire.requestFrom(): được sử dụng để yêu cầu dữ liệu từ thiết bị I2C.
- Dây.có sẵn (): được sử dụng để kiểm tra xem dữ liệu có sẵn để đọc từ thiết bị I2C hay không.
- Wire.read(): dùng để đọc dữ liệu từ thiết bị I2C.
Sử dụng Wire.beginTransmission() chức năng đặt địa chỉ của cảm biến, được chèn làm đối số. Ví dụ: nếu địa chỉ của cảm biến là 0x68bạn sẽ sử dụng:
Wire.beginTransmission(0x68);
Cài đặt phần cứng Arduino I2C
Để kết nối hai bo mạch Arduino bằng I2C, bạn sẽ cần các thành phần phần cứng sau:
- Hai bảng Arduino (chính và nô lệ)
- bánh mì
- dây nhảy
- Hai điện trở kéo lên 4,7kΩ
Kết nối SDA Và SCL chân của cả hai bảng Arduino vào bảng mạch. Kết nối các điện trở kéo lên giữa SDA Và SCL ghim và 5V đường ray điện trên breadboard. Cuối cùng, kết nối hai breadboard với nhau bằng dây nhảy.
Mạch Arduino Uno
Mạch Arduino Nano
Thiết lập bảng Arduino làm thiết bị I2C Master và Slave
Sử dụng Wire.requestFrom() có chức năng chỉ định địa chỉ của thiết bị nô lệ mà chúng ta muốn giao tiếp. Sau đó sử dụng Wire.read() chức năng lấy dữ liệu từ thiết bị phụ.
Mã thiết bị chính:
#include <Wire.h>
void setup() {
Wire.begin();
Serial.begin(9600);
}
void receiveData() {
int address = 8;
int bytesToRead = 6;
Wire.requestFrom(address, bytesToRead);
while (Wire.available()) {
char data = Wire.read();
Serial.print(data);
}
delay(500);
}
void loop() {
receiveData();
}
Các Wire.onReceive() chức năng được sử dụng để chỉ định những việc cần làm khi thiết bị phụ nhận dữ liệu từ thiết bị chính. Trong đoạn mã trên, Dây.có sẵn () chức năng kiểm tra nếu dữ liệu có sẵn, và Wire.read() chức năng đọc dữ liệu được gửi bởi thiết bị chính.
Mã thiết bị phụ:
#include <Wire.h>
void setup() {
Wire.begin(8);
Wire.onReceive(receiveEvent);
}
void loop() {
delay(100);
}
void receiveEvent(int bytes) {
Wire.write("hello ");
}
Gửi và nhận dữ liệu bằng I2C
Trong ví dụ này, hãy đọc nhiệt độ từ cảm biến nhiệt độ DHT11 giao tiếp với Arduino phụ và in nó trên màn hình nối tiếp của Arduino chính.
Hãy sửa đổi mã mà chúng ta đã viết trước đó để bao gồm phép đo nhiệt độ mà sau đó chúng ta sẽ gửi đến bo mạch chủ qua bus I2C. Sau đó, bảng chính có thể đọc giá trị mà chúng tôi đã gửi, sau đó hiển thị giá trị đó trên màn hình nối tiếp.
Mã thiết bị chính:
#include <Wire.h>
void setup() {
Wire.begin();
Serial.begin(9600);
Serial.println("Master Initialized!");
}
void loop() {
Wire.requestFrom(8, 1);
if (Wire.available()) {
byte temperature = Wire.read();
Serial.print("Temperature: ");
Serial.print(temperature);
Serial.println(" °C");
}
delay(2000);
}
Mã thiết bị phụ:
#include <Wire.h>
#include <DHT.h>#define DHTPIN 4
#define DHTTYPE DHT11
DHT dht(DHTPIN, DHTTYPE);
byte temperature;
void setup() {
Wire.begin(8);
Wire.onRequest(requestEvent);
dht.begin();
}
void loop() {
delay(2000);
temperature = dht.readTemperature();
}
void requestEvent() {
Wire.write(temperature);
}
Bạn có thể tùy chỉnh mã này để phù hợp với bất kỳ cảm biến nào bạn có thể có trong dự án của mình hoặc thậm chí hiển thị các giá trị cảm biến trên mô-đun hiển thị để tạo nhiệt kế và máy đo độ ẩm trong phòng của riêng bạn.
Định địa chỉ nô lệ với I2C trên Arduino
Để đọc các giá trị từ các thành phần được thêm vào bus I2C trong một dự án như vậy, điều quan trọng là bạn phải bao gồm địa chỉ nô lệ chính xác khi mã hóa. May mắn thay, Arduino cung cấp một thư viện máy quét giúp đơn giản hóa quá trình xác định địa chỉ nô lệ, loại bỏ nhu cầu sàng lọc các bảng dữ liệu cảm biến dài và tài liệu trực tuyến khó hiểu.
Sử dụng đoạn mã sau để xác định địa chỉ của bất kỳ thiết bị nô lệ nào có trên xe buýt I2C.
#include <Wire.h> // Include the Wire library for I2C communicationvoid setup() {
Wire.begin();
Serial.begin(9600);
while (!Serial);
Serial.println("nI2C Scanner");
}
void loop() {
byte error, address;
int nDevices;
Serial.println("Scanning...");
nDevices = 0;
for (address = 1; address < 127; address++) {
Wire.beginTransmission(address);
error = Wire.endTransmission();
if (error == 0) {
Serial.print("I2C device found at address 0x");
if (address < 16) Serial.print("0");
Serial.print(address, HEX);
Serial.println(" !");
nDevices++;
}
else if (error == 4) {
Serial.print("Unknown error at address 0x");
if (address < 16) Serial.print("0");
Serial.println(address, HEX);
}
}
if (nDevices == 0) {
Serial.println("No I2C devices foundn");
}
else {
Serial.println("donen");
}
delay(5000);
}
Mở rộng dự án của bạn ngay hôm nay
Giao tiếp hai bảng Arduino bằng giao thức truyền thông I2C mang đến một cách linh hoạt và hiệu quả để đạt được các tác vụ phức tạp mà một bảng duy nhất không thể xử lý được. Với sự trợ giúp của thư viện Wire, việc giao tiếp giữa hai bảng sử dụng I2C trở nên dễ dàng, cho phép bạn thêm nhiều thành phần hơn vào dự án của mình.