Giao tiếp I2C và sử dụng module Realtime clock DS1307 (module RTC)

Xin chào các bạn, bài viết này của mình sẽ giới thiệu về giao tiếp I2C trên Arduino và sử dụng module Realtime clock DS1307.

NỘI DUNG

  • Giới thiệu về chuẩn giao tiếp I2C.
  • Giao tiếp I2C trên Arduino.
  • Cách sử dụng module Realtime Clock DS1307.

CHUẨN BỊ 

  1. 1x board Arduino UNO R3.
  2. 1x module Realtime Clock DS1307 + datasheet DS1307
  3. Dây cắm breadboard

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 4, SCL là chân analog 5.

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) để Arduino ("Master") có thể giao tiếp với nó. Để biết địa chỉ I2C bus của IC, các bạn có thể tra datasheet hoặc google nhé.

Để 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.

SỬ DỤNG I2C TRÊN ARDUINO

Đế 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:

  1. Wire.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".
  2. Wire.beginTransmission(address);
    • Bắt đầu truyền dữ liệu đến thiết bị "Slave" với address đã có.
  3. Wire.endTransmission();
    • Kết thúc truyền dữ liệu đến thiết bị "Slave" đã được bắt đầu bởi Wire.beginTransmission(address). 
  4. Wire.write(value);
    • Ghi dữ liệu lên thiết bị "Slave", được gọi giữa beginTransmission() và endTransmission().
  5. Wire.read();
    • Đọc dữ liệu được truyền từ thiết bị "Slave" đến Arduino, được gọi sau requestFrom().
  6. Wire.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.

Các bạn có thể tham khảo chi tiết hơn ở link sau: http://arduino.cc/en/Reference/Wire

SỬ DỤNG MODULE REAL TIME CLOCK DS1307

Chúng ta sẽ lắp module Real time clock với Arduino như sau: (trong module real time clock đã có sẵn 2 điện trở pull-up 3.3k)

Đây là các Timekeeper registers của DS1307, chúng ta sẽ dựa vào bảng này để read/write IC  DS1307 qua I2C.

LẬP TRÌNH

#include <Wire.h> 

/* Địa chỉ của DS1307 */
const byte DS1307 = 0x68;
/* Số byte dữ liệu sẽ đọc từ DS1307 */
const byte NumberOfFields = 7;

/* khai báo các biến thời gian */
int second, minute, hour, day, wday, month, year;

void setup()
{
  Wire.begin();
  /* cài đặt thời gian cho module */
  setTime(12, 30, 45, 1, 8, 2, 15); // 12:30:45 CN 08-02-2015
  Serial.begin(9600);
}

void loop()
{
  /* Đọc dữ liệu của DS1307 */
  readDS1307();
  /* Hiển thị thời gian ra Serial monitor */
  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); // chế độ 24h.
        wday   = bcd2dec(Wire.read() );
        day    = bcd2dec(Wire.read() );
        month  = bcd2dec(Wire.read() );
        year   = bcd2dec(Wire.read() );
        year += 2000;    
}
/* Chuyển từ format BCD (Binary-Coded Decimal) sang Decimal */
int bcd2dec(byte num)
{
        return ((num/16 * 10) + (num % 16));
}
/* Chuyển từ Decimal sang BCD */
int dec2bcd(byte num)
{
        return ((num/10 * 16) + (num % 10));
}

void digitalClockDisplay(){
    // digital clock display of the time
    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){
    // các thành phần thời gian được ngăn chách bằng dấu :
    Serial.print(":");
        
    if(digits < 10)
        Serial.print('0');
    Serial.print(digits);
}

/* cài đặt thời gian cho DS1307 */
void setTime(byte hr, byte min, byte sec, byte wd, byte d, byte mth, byte yr)
{
        Wire.beginTransmission(DS1307);
        Wire.write(byte(0x00)); // đặt lại pointer
        Wire.write(dec2bcd(sec));
        Wire.write(dec2bcd(min));
        Wire.write(dec2bcd(hr));
        Wire.write(dec2bcd(wd)); // day of week: Sunday = 1, Saturday = 7
        Wire.write(dec2bcd(d)); 
        Wire.write(dec2bcd(mth));
        Wire.write(dec2bcd(yr));
        Wire.endTransmission();
}

GIẢI THÍCH

  • Những hàm của thư viện Wire.h được sử dụng trong bài mình đã giới thiệu ở trên.
  • Để chuyển sang chế độ 12h, các bạn tham khảo datasheet và bảng Timekeeper registers nhé!
  • second = bcd2dec(Wire.read() & 0x7f); : dựa vào bảng Timekeeper registers, chúng ta sẽ thấy thanh ghi second có bit 7 CH (dùng để tạm dừng dao động), chúng ta sẽ không đọc bit này nên sẽ cần biểu thức Wire.read() & 0x7f để loại đi bit 7 này.
  • hour   = bcd2dec(Wire.read() & 0x3f); :thanh ghi hour có bit 6 để chọn chế độ 12/24h, nếu bit 6 = 1, chế độ 12h sẽ được chọn. Chúng ta sẽ không đọc bit 6 nên cần biểu thức Wire.read() & 0x3f để loại bit 6 này.
  • Để hiểu chi tiết hơn về cách write/read DS1307, các bạn tham khảo datasheet trang 8, 9 nhé!
  • Các hàm bcd2dec() và dec2bcd() dùng để chuyển định dạng, vì IC DS1307 sử dụng định dạng BCD. VD: số 23 khi chuyển sang BCD sẽ có dạng 0b001000112 (0x2316).

LỜI KẾT

Với module realtime này, mình đã làm một chiếc Binary Clock với các chức năng: Điều chỉnh thời gian, Alarm (bật/tắt thiết bị điện). Các bạn hãy sáng tạo cho mình một sản phẩm thật cool nhé!

Cảm ơn các bạn đã theo dõi bài viết. Chúc các bạn thành công.

lên
37 thành viên đã đánh giá bài viết này hữu ích.
Hướng dẫn sử dụng các loại module

Nếu bạn đang muốn thực hiện hóa ý tưởng của mình mà không biết dùng loại module nào? Hãy tham khảo các module trong danh sách sau

Các dự án được truyền cảm hứng

Bộ điều khiển PID - ứng dụng phần 2 - xe dò line dùng thuật toán PID

Tiép nối bài viết về xe dò line cảm ơn Đỗ Hữu Toàn đã viết hộ mình phần 4. hôm nay mình sẽ làm cho chiếc xe dò line đi mượt và có hồn hơn 

lên
34 thành viên đã đánh giá bài viết này hữu ích.
Các bài viết cùng tác giả

Timer/Counter trên AVR/Arduino

Như các bạn đã biết, Arduino là một nền tảng hướng tới sự đơn giản, giúp cho việc hiện thực hóa các ý tưởng dễ dàng hơn rất nhiều, nhưng cũng vì thế mà chúng ta sẽ không thể khai thác hết được sức mạnh của vi điều khiển nằm trên board Arduino. Điều mà mình cảm thấy tiếc nhất là sự thiếu sót của các Interrupt Vector trong môi trường Arduino (Arduino hiện chỉ có built-in function hỗ trợ External Interrupts).

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

Sử dụng cảm biến khoảng cách HC-SR04

Xin chào, hôm nay mình sẽ giới thiệu về cách sử dụng cảm biến khoảng cách HC-SR04. Chúng ta sẽ cùng nhau tìm hiểu về nguyên lý hoạt động của HC-SR04. và cách sử dụng với Arduino.

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