I.GIỚI THIỆU VỀ CHUẨN GIAO TIẾP I2C
I2C là viết tắt của “Inter-Integrated Circuit”, một chuẩn giao tiếp được phát minh bởi Philips’ semiconductor division (giờ là NXP) nhằm đơn giản hóa việc trao đổi dữ liệu giữa các ICs. Đôi khi nó cũng được gọi là Two Wire Interface (TWI) vì chỉ sử dụng 2 kết nối để truyền tải dữ liệu, 2 kết nối của giao tiếp I2C gồm: SDA (Serial Data Line) và SCL (Serial Clock Line).
Có hàng ngàn thiết bị sử dụng giao tiếp I2C, chẳng hạn như real-time clocks, digital potentiometers, temperature sensors, digital compasses, memory chips, FM radio circuits, I/O expanders, LCD controllers, amplifiers,…Board Arduino của chúng ta có thể kiểm soát tất cả và số lượng tối đa trong một thời điểm lên đến 112 thiết bị I2C.
Trên board Arduino UNO, SDA là chân analog D2, SCL là chân analog D1.
Trên I2C bus, sẽ có một thiết bị được coi là “Master”, và trong hầu hết các trường hợp, Arduino là một “Master”, mỗi IC được gắn trên I2C bus là một “Slave”. Mỗi “slave” có một địa chỉ riêng ở dạng HEX (thập lục phân) để NODEMCU (“Master”) có thể giao tiếp với nó.
Để I2C bus có thể hoạt động, chúng ta cần 2 điện trở pull-up như trong hình, 4.7k hoặc 10k là hợp lý. Tuy nhiên, nếu chỉ có một thiết bị I2C, chúng ta có thể bỏ qua điện trở pull-up vì trong MCU ATmega328 của Arduino UNO đã có sẵn 20k build-in resisters.
Lưu ý: vì Arduino UNO sử dụng điện áp 5V, do đó các thiết bị I2C cũng phải hoạt động ở 5V.
II.SỬ DỤNG I2C TRÊN NODEMCU
Đế sử dụng I2C bus trên Arduino, chúng ta sẽ cần sử dụng thư viện Wire.h (đây là built-in library của Arduino).
Mình sẽ giới thiệu một số hàm trong thư viện Wire.h:
- begin(address (optional));
- Khởi tạo thư viện Wire.h và tham gia vào I2C bus.
- address: 7-bit địa chỉ của thiết bị “Slave” (optional); nếu không có địa chỉ thì coi như “Master”.
- beginTransmission(address);
- Bắt đầu truyền dữ liệu đến thiết bị “Slave” với address đã có.
- endTransmission();
- Kết thúc truyền dữ liệu đến thiết bị “Slave” đã được bắt đầu bởi Wire.beginTransmission(address).
- write(value);
- Ghi dữ liệu lên thiết bị “Slave”, được gọi giữa beginTransmission() và endTransmission().
- read();
- Đọc dữ liệu được truyền từ thiết bị “Slave” đến Arduino, được gọi sau requestFrom().
- requestFrom(address, quantity);
- Được sử dụng bởi thiết bị “Master” để yêu cầu dữ liệu từ thiết bị “Slave”.
- address: là địa chỉ của thiết bị “Slave”.
- quantity: số lượng bytes yêu cầu.
Code mẫu cho các bạn tham khảo:
#include <Wire.h> const byte DS1307 = 0x68; const byte NumberOfFields = 7; int second, minute, hour, day, wday, month, year; void setup() { Wire.begin(); setTime(1, 00, 00, 1, 1, 1, 18); // 1:00:00 1-1-2018 Serial.begin(9600); } void loop() { readDS1307(); digitalClockDisplay(); delay(1000); } void readDS1307() { Wire.beginTransmission(DS1307); Wire.write((byte)0x00); Wire.endTransmission(); Wire.requestFrom(DS1307, NumberOfFields); second = bcd2dec(Wire.read() & 0x7f); minute = bcd2dec(Wire.read() ); hour = bcd2dec(Wire.read() & 0x3f); wday = bcd2dec(Wire.read() ); day = bcd2dec(Wire.read() ); month = bcd2dec(Wire.read() ); year = bcd2dec(Wire.read() ); year += 2000; } int bcd2dec(byte num) { return ((num/16 * 10) + (num % 16)); } int dec2bcd(byte num) { return ((num/10 * 16) + (num % 10)); } void digitalClockDisplay(){ Serial.print(hour); printDigits(minute); printDigits(second); Serial.print(" "); Serial.print(day); Serial.print(" "); Serial.print(month); Serial.print(" "); Serial.print(year); Serial.println(); } void printDigits(int digits){ Serial.print(":"); if(digits < 10) Serial.print('0'); Serial.print(digits); } void setTime(byte hr, byte min, byte sec, byte wd, byte d, byte mth, byte yr) { Wire.beginTransmission(DS1307); Wire.write(byte(0x00)); Wire.write(dec2bcd(sec)); Wire.write(dec2bcd(min)); Wire.write(dec2bcd(hr)); Wire.write(dec2bcd(wd)); Wire.write(dec2bcd(d)); Wire.write(dec2bcd(mth)); Wire.write(dec2bcd(yr)); Wire.endTransmission(); }