Thứ Ba, 4 tháng 12, 2018

Giao tiếp với thời gian thực IC DS1307

1.Giới thiệu IC thời gian thực DS1307

1. Giới thiệu:
IC thời gian thực (RTC) DS1307 có thể đếm giờ, phút, giây, thứ, ngày tháng, năm. Giao tiếp với vi điều khiển thông qua chuẩn I2C, và đóng vai trò là slave khi kết nối đến Bus I2C này. Có thể đếm thời gian theo định dạng 24 giờ hoặc 12 giờ với chỉ thị AM/PM. Ngoài ra bên trong chíp có bộ dò phát hiện mất nguồn và tự động chuyển sang sử dụng nguồn Pin dự phòng.
Giao tiếp DS1307
2. Sơ đồ chân:
Giao tiếp DS1307
Trong đó:
ChânTênChức năng
1X1Kết nối đến thạch anh  32.768Khz làm nguồn dao động cho chip
2X2
3VBatKết nối đến cực dương của Pin dự phòng, có điện áp tiêu chuẩn khoảng 3V
4GNDKết nối đến mass
5SDAChân dữ liệu khi kết nối đến bus I2C
6SCLChân nhận xung clock đồng bộ khi kết nối bus I2C
7SQW/OUTNgõ xuất xung vuông, tần số có thể lập trình để thay đổi từ 1Hz, 4Khz, 8 Khz, 32 Khz
8VCCNguồn cấp chính, khoảng 5VDC
 3. Lấy thông tin về thời gian và lịch
Bảng 1 là địa chỉ của các thanh ghi RAM và thanh ghi RTC của DS 1307. Thanh ghi RTC có địa chỉ từ 00-07h. các thanh ghi RAM chiếm địa chỉ từ 08h - 3Fh
Các thông tin về thời gian và lịch thu được bằng cách đọc các byte trong thanh ghi tương ứng. Thời gian và lịch được thiết lập hoặc khởi tạo bằng cách viết các byte thanh ghi thích hợp. Lưu ý dữ liệu lưu thời gian chứa trong thanh ghi đều theo định dạng BCD. Thứ trong tuần thay đổi tại lúc nữa đêm, lưu dưới dạng con số (Ví dụ 1 là Chủ Nhật, 2 là Thứ hai, 3 là thứ 3 ...). Khi lần đầu tiên IC được cấp nguồn các thanh ghi thời gian và lịch reset về 01/01/00 01 00:00:00. (MM/DD/YY DOW HH:MM:SS)
Giao tiếp DS1307
4. Chi tiết các thanh ghi
 Giao tiếp DS1307

*0 luôn luôn đọc là 0
Bảng 1: Các thanh ghi lưu giữ thời gian
Thanh ghi control
Giao tiếp DS1307
Bit 7: Output Control (OUT) thanh ghi điều khiển ngõ ra. Nó ảnh hưởng đến chân số 7 (chân SQW/OUT) . Khi sóng vuông xuất ra chân này bị disable, nếu bit OUT=1 khi đó chân số 7 ở mức cao, ngược lại bit OUT=0 khi đó chân số 7 ở mức thấp
Bit 6: Luôn luôn đọc bằng 0
Bit 5: Luôn luôn đọc bằng 0
Bit 4: Square-Wave Enable (SQWE): khi bit này được thiết lập bằng 1, cho phép xuất ra xung vuông tại chân số 7., Tần số của của xung vuông phụ thuộc vào bit RS0 và RS1. Khi tần số sóng vuông được thiết lập là 1 Hz. Các thanh ghi thời gian được cập nhật tại cạnh xuống của xung vuông. Khi lần đầu khởi tạo cấp nguồn đến thiết bị, bit này bằng 0.
Bits 1 and 0: Lựa chọn tốc độ(RS[1:0]). Những bit này điều khiển tần số của tần số sóng vuông, khi sóng vuông được cho phép .
RS1RS0SÓNG VUÔNG NGÕ RA SQW/OUTSQWEOUT
001Hz1X
014.096kHz1X
108.192kHz1X
1132.768kHz1X
XX000
XX101
Thanh ghi giây (địa chỉ 00h): 4 bit thấp chứa hàng đơn vị, 3 bit cao chứa hàng chục của giây. Ngoài ra bit thứ 7 có tên là CH, nếu bít này được thiết lập bằng 1 thì đồng hồ không hoạt động. Vì vậy phải thiết lập bit này bằng không ngay từ đầu.
Thanh ghi phút (địa chỉ 01h): 4 bit thấp chứa hàng đơn vị, 3 bit cao chứa hàng chục của phút. Ngoài ra bit thứ 7 luôn bằng 0.
Thanh ghi giờ (địa chỉ 02h): 4 bit thấp của thanh ghi này chứa hàng đơn vị của giờ, bit thứ 6 quy định chế độ 12 h (bit6 =1) hoặc 24 h (bit 6=0). Nếu ở chế độ 24h thì bit 4 và bit 5 quy định hàng chục của giờ. Nếu chế độ 12h thì bit 4 quy định hàng chục, bit 5 khi đó quy định (PM: buổi chiều hoặc AM: buổi sáng)
Thanh ghi thứ (địa chỉ 03h): ba bit đầu quy định thứ trong tuần (Ví dụ 1 là Chủ Nhật, 2 là Thứ hai, 3 là thứ 3 ...). Các bit còn lại luôn bằng 0.
Thanh ghi ngày(địa chỉ 04h): 4 bit đầu lưu hàng đơn vị của ngày, bit 4 và bit 5 quy định hàng chục. Bit 6 và bit 7 luôn luôn bằng 0.
Thanh ghi tháng(địa chỉ 05h): 4 bit đầu lưu hàng đơn vị của tháng, bit thứ 4 quy định hàng chục. Các bit còn lại luôn bằng 0.

Thanh ghi năm (địa chỉ 06h): 4 bit thấp lưu hàng đơn vị và 4 bit cao hàng chục của năm (từ 00 - 99).

5. Địa chỉ của DS1307.
DS1307 có 7 bit địa chỉ cố định là 1101000. Tiếp theo là bit quy định hướng truyền dữ liệu. Nếu bit=0, thì byte dữ liệu truyền từ vi đều khiển -> DS1307. Ngược lại bit=1 thì  hướng dữ liệu sẽ là DS1307-> Vi điều khiển.
Ở chế độ ghi dữ liệu:
- Vi điều khiển tạo tín hiệu Start lên bus để báo bắt đầu muốn giao tiếp.
- Vi điều khiển gửi địa chỉ của thiết bị muốn giao tiếp. Ở đây DS 1307 là 1101000 + bit hướng = 0. Do vậy byte được gửi là 11010000.
- DS 1307 tạo tín hiệu ACK.
- Vi điều khiển gửi địa chỉ của thanh ghi muốn viết đến.
- DS 1307 tạo tín hiệu ACK báo đã nhận thành công.
- Tiếp theo vi điều khiển gửi dữ liệu muốn ghi
- Con trỏ địa chỉ của DS 1307 tự tăng lên đến địa chỉ thanh ghi tiếp theo
- Vi khiển gửi dữ liệu muốn ghi đến thanh ghi tiếp theo.
......
- Vi điều khiển muốn kết thúc qua trình truyền dữ liệu bằng cách gửi tín hiệu Stop.

Giao tiếp DS1307
        Chế độ ghi dữ liệu
Ở chế độ đọc dữ liệu:
- Vi điều khiển tạo tín hiệu Start lên bus để báo bắt đầu muốn giao tiếp.
- Vi điều khiển gửi địa chỉ của thiết bị muốn giao tiếp. Ở đây DS 1307 là 1101000 + bit hướng = 1. Do vậy byte là 11010001.
- DS 1307 tạo tín hiệu ACK.
- DS 1307 gửi dữ liệu của thanh ghi đầu tiên
- Vi điều khiển gửi tín hiệu ACK báo nhận thành công.
- DS 1307 gửi dữ liệu của thanh ghi tiếp theo.
      - Vi điều khiển gửi tín hiệu ACK báo nhận thành công.
      ......
      - Vi điều khiển gửi tín hiệu NACK khi không muốn nhận thêm dữ liệu.
      - Vi điều khiển tạo tín hiệu stop để kết thúc truyền nhận và giải phóng Bus I2C
Giao tiếp DS1307
                                                           Chế độ đọc dữ liệu
 6. Mã nhị phân BCD
Mã nhị phân BCD, trong đó mỗi số nguyên của một số thập phân(0-9) được biểu diễn bởi một số nhị phân 4-bit. Như hình dưới:
Giao tiếp DS1307
Do dữ liệu thanh ghi thời gian thực của DS1307 được biểu thị dưới dạng mã BCD . Ví dụ số 59 giây được lưu dưới dạng mã BCD là 01011001
Ta cần lưu ý sự khác biệt của mã BCD và mã nhị phân của một số là khác nhau ví dụ:
Mã nhị phân của số 85 là: 1010101
Mã BCD của số 85 là: 10000101
Đoạn chương trình dưới đây chuyển từ mã BCD -> mã nhị phân:
BYTE bcd2bin(BYTE bcd_value)
{
  BYTE temp;
  temp = bcd_value;
  temp >>= 1;
  temp &= 0x78;
  return(temp + (temp >> 2) + (bcd_value & 0x0f));
}
Đoạn chương trình dưới đây chuyển từ mã nhị phân -> mã BCD:
BYTE bin2bcd(BYTE binary_value)
{
  BYTE temp;
  BYTE retval;
  temp = binary_value;
  retval = 0;
  while(1)
  {
    // Get the tens digit by doing multiple subtraction
    // of 10 from the binary value.
    if(temp >= 10)
    {
      temp -= 10;
      retval += 0x10;
    }
    else // Get the ones digit by adding the remainder.
    {
      retval += temp;
      break;
    }
  }
  return(retval);
}

IC DS1307 + text LCD
 Đoạn chương trình đọc thời gian từ IC DS1307 và hiển thị lên text LCD
#include <16f877a.h>
#device *=16 ADC=10
#FUSES NOWDT, HS, NOPUT, NOPROTECT, NODEBUG, NOBROWNOUT, NOLVP, NOCPD, NOWRT
#use delay(clock=12000000)
#include "ds1307_user.c"
#define LCD_ENABLE_PIN  PIN_E0 
#define LCD_RS_PIN      PIN_E1  
#define LCD_RW_PIN      PIN_E2                               
#define LCD_DATA4       PIN_D4                                    
#define LCD_DATA5       PIN_D5                                
#define LCD_DATA6       PIN_D6                            
#define LCD_DATA7       PIN_D7   
#include <lcd.c>
void main(void)
{
BYTE sec;
BYTE min;
BYTE hrs;
BYTE day;
BYTE month;
BYTE yr;
BYTE dow; 
ds1307_init(); // khởi tạo ic thời gian thực
lcd_init(); //khởi tạo LCD
while(1)
{
ds1307_get_time(hrs,min,sec); // đọc, giờ, phút giây là lưu vào biến
ds1307_get_date(day,month,yr,dow); // đọc thứ, ngày, tháng, năm
lcd_gotoxy(5,1); // di chuyển đến cột 1 hàng 5
lcd_putc((hrs/10)+48);  // chuyển sang mã ASCII bằng cách cộng với 48 
lcd_putc((hrs%10)+48); 
lcd_putc(":");
lcd_putc((min/10)+48);
lcd_putc((min%10)+48);
lcd_putc(":");
lcd_putc(sec/10+48);
lcd_putc(sec%10+48);
lcd_gotoxy(1,2);            // cot 1 hang 2
if(dow==1) //nếu là chủ nhật thì
lcd_putc("ChuNhat ");  // hien thi test lcd
else
{
lcd_putc("Thu");  
lcd_putc(dow +48);
lcd_putc(" ");  

}
lcd_putc((day/10)+48);
lcd_putc((day%10)+48); 
lcd_putc("-");
lcd_putc((month/10)+48);
lcd_putc((month%10)+48);
lcd_putc("-");
lcd_putc(yr/10+48);
lcd_putc(yr%10+48);
delay_ms(500);
}
}
 Giao tiếp DS1307

Đoạn code dưới đây mình sưu tầm từ diễn đàn CCS. Giúp các bạn giao tiếp với IC DS1307 được dễ dàng hơn.
Đoạn code driver, bạn lưu với tên là DS1307_USER.C
//////////////////////////////////////////////////////////////////////////////// 
///                               DS1307_USER.C                                   /// 
///                     Driver for Real Time Clock                           /// 
///                                                                          /// 
/// ds1307_init() - Enable oscillator without clearing the seconds register -/// 
///                 used when PIC loses power and DS1307 run from 3V BAT     /// 
///               - Disable squarewave output                                /// 
///                                                                          /// 
/// ds1307_set_date_time(day,mth,year,dow,hour,min,sec)  Set the date/time   /// 
///                                                                          /// 
/// ds1307_get_date(day,mth,year,dow)               Get the date             /// 
///                                                                          /// 
/// ds1307_get_time(hr,min,sec)                     Get the time             /// 
///                                                                          /// 
//////////////////////////////////////////////////////////////////////////////// 

#define RTC_SDA  PIN_C4 
#define RTC_SCL  PIN_C3 

#use i2c(master, sda=RTC_SDA, scl=RTC_SCL) 

BYTE bin2bcd(BYTE binary_value); 
BYTE bcd2bin(BYTE bcd_value); 

void ds1307_init(void) 

   BYTE seconds = 0; 

   i2c_start(); 
   i2c_write(0xD0);      // WR to RTC 
   i2c_write(0x00);      // REG 0 
   i2c_start(); 
   i2c_write(0xD1);      // RD from RTC 
   seconds = bcd2bin(i2c_read(0)); // Read current "seconds" in DS1307 
   i2c_stop(); 
   seconds &= 0x7F; 

   delay_us(3); 

   i2c_start(); 
   i2c_write(0xD0);      // WR to RTC 
   i2c_write(0x00);      // REG 0 
   i2c_write(bin2bcd(seconds));     // Start oscillator with current "seconds value 
   i2c_start(); 
   i2c_write(0xD0);      // WR to RTC 
   i2c_write(0x07);      // Control Register 
   i2c_write(0x80);     // Disable squarewave output pin 
   i2c_stop(); 



void ds1307_set_date_time(BYTE day, BYTE mth, BYTE year, BYTE dow, BYTE hr, BYTE min, BYTE sec) 

  sec &= 0x7F; 
  hr &= 0x3F; 

  i2c_start(); 
  i2c_write(0xD0);            // I2C write address 
  i2c_write(0x00);            // Start at REG 0 - Seconds 
  i2c_write(bin2bcd(sec));      // REG 0 
  i2c_write(bin2bcd(min));      // REG 1 
  i2c_write(bin2bcd(hr));      // REG 2 
  i2c_write(bin2bcd(dow));      // REG 3 
  i2c_write(bin2bcd(day));      // REG 4 
  i2c_write(bin2bcd(mth));      // REG 5 
  i2c_write(bin2bcd(year));      // REG 6 
  i2c_write(0x80);            // REG 7 - Disable squarewave output pin 
  i2c_stop(); 


void ds1307_get_date(BYTE &day, BYTE &mth, BYTE &year, BYTE &dow) 

  i2c_start(); 
  i2c_write(0xD0); 
  i2c_write(0x03);            // Start at REG 3 - Day of week 
  i2c_start(); 
  i2c_write(0xD1); 
  dow  = bcd2bin(i2c_read() & 0x7f);   // REG 3 
  day  = bcd2bin(i2c_read() & 0x3f);   // REG 4 
  mth  = bcd2bin(i2c_read() & 0x1f);   // REG 5 
  year = bcd2bin(i2c_read(0));            // REG 6 
  i2c_stop(); 


void ds1307_get_time(BYTE &hr, BYTE &min, BYTE &sec) 

  i2c_start(); 
  i2c_write(0xD0); 
  i2c_write(0x00);            // Start at REG 0 - Seconds 
  i2c_start(); 
  i2c_write(0xD1); 
  sec = bcd2bin(i2c_read() & 0x7f); 
  min = bcd2bin(i2c_read() & 0x7f); 
  hr  = bcd2bin(i2c_read(0) & 0x3f); 
  i2c_stop(); 



BYTE bin2bcd(BYTE binary_value) 

  BYTE temp; 
  BYTE retval; 

  temp = binary_value; 
  retval = 0; 

  while(1) 
  { 
    // Get the tens digit by doing multiple subtraction 
    // of 10 from the binary value. 
    if(temp >= 10) 
    { 
      temp -= 10; 
      retval += 0x10; 
    } 
    else // Get the ones digit by adding the remainder. 
    { 
      retval += temp; 
      break; 
    } 
  } 

  return(retval); 



// Input range - 00 to 99. 
BYTE bcd2bin(BYTE bcd_value) 

  BYTE temp; 

  temp = bcd_value; 
  // Shifting upper digit right by 1 is same as multiplying by 8. 
  temp >>= 1; 
  // Isolate the bits for the upper digit. 
  temp &= 0x78; 

  // Now return: (Tens * 8) + (Tens * 2) + Ones 

  return(temp + (temp >> 2) + (bcd_value & 0x0f)); 
}
Đoạn chương trình chính hiển thị giờ phút giây ra led 7 đoạn, bao gồm 1 nút nhấn để điều chỉnh thời gian
#include <18F452.h> 
#device adc=8 
#fuses NOWDT,WDT128,HS, NOPROTECT, NOOSCSEN, BROWNOUT, BORV20, NOPUT, STVREN, NODEBUG, NOLVP, NOWRT, NOWRTD, NOWRTB, NOWRTC, NOCPD, NOCPB, NOEBTR, NOEBTRB 
#use delay(clock=20000000,RESTART_WDT) 
#use rs232(baud=9600,parity=N,xmit=PIN_C6,rcv=PIN_C7,bits=8,stream=PC,errors) 
#include <ds1307_user.c> 

void main() 

  BYTE sec; 
  BYTE min; 
  BYTE hrs; 
  BYTE day; 
  BYTE month; 
  BYTE yr; 
  BYTE dow; 
  
  ds1307_init(); 
  
  // Set date for -> 15 June 2005 Tuesday 
  // Set time for -> 15:20:55 
  ds1307_set_date_time(15,6,5,2,15,20,55); 
  
  while(1) 
  { 
    delay_ms(1000); 
    
    ds1307_get_date(day,month,yr,dow); 
    ds1307_get_time(hrs,min,sec); 
      
    printf("\f\%02d/\%02d/\%02d\r\n",day,month,yr); 
    printf("\%02d:\%02d:\%02d", hrs,min,sec); 
  } 
}



Link File nguồn và chương trình mô phỏng

Không có nhận xét nào:

Đăng nhận xét

Bài đăng mới nhất

Valdes Fernando - Microcontrollers Applications With Pic

Bài đăng phổ biến