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

DS1337 là IC Real-Time Clock (RTC) đếm giây, phút, giờ, ngày, tháng, năm chính xác với tính năng bù năm nhuận tự động. Giao thức giao tiếp chuẩn I2C với 2 đường tín hiệu SCL và SDA.

2. Sơ đồ kết nối phần cứng với AT89

Đường SCL nối vào chân P1.0, đường SDA nối vào chân P1.1 của vi điều khiển AT89S52. Cần gắn trở kéo lên 4.7kΩ cho cả hai đường SDA và SCL.

3. Mã nguồn hợp ngữ ASM nguyên bản từ phòng LAB PCTCO

#include <sfr52.inc>

sda bit P1.0
scl bit P1.1

i2c_ack_in equ 0       ; flag bit on RAM bit area at 20h
i2c_ack_out equ 1  
    
sec equ 21h
min equ 22h
hour equ 23h
dow equ 24h
date equ 25h
month equ 26h
year equ 27h
mode equ 28h
led1 equ 30h
led2 equ 31h
led3 equ 32h
led4 equ 33h
led5 equ 34h
led6 equ 35h

org 0
ljmp main

org 0030h
main:
    setb i2c_ack_in
    setb i2c_ack_out
    mov dptr,#maled7
    clr a
    acall init_time
    mov r5,#5
    mov mode,#0
loop:
    acall delay
    acall delay
    djnz r5,loop
    acall update_time
main_loop:
    acall read_time
    acall delay
    acall display
    acall keyscan
    sjmp main_loop

init_time:
    acall i2c_start        ;/* The following Enables the Oscillator */
    mov a,#0D0h
    acall i2c_write        ;  /* address the part to write */
    mov a,#00h
    acall i2c_write;  /* position the address pointer to 0 */
    mov a,#0
    acall   i2c_write;     /* write 0 to the seconds register, clear the CH bit */
    mov a,#55h
    acall i2c_write;  /* write slave address + write */
    mov a,#52h
    acall i2c_write;  /* hour = 101 0010  12h mode - time =12  */
    mov a,#07h
    acall i2c_write;  //Day of week. 1=sun, 2=mon...
    mov a,#03h
    acall i2c_write;
    mov a,#11h
    acall   i2c_write;
    mov a,#05h
    acall   i2c_write;
    acall i2c_stop;

    acall i2c_start;     // Write control and status register
    mov a,#0d0h
    acall i2c_write; // write slave address + write */
    mov a,#0eh
    acall i2c_write; // write register address, control register */
    mov a,#00000011b
    acall i2c_write; /* enable osc, bbsqi */
    mov a,#00h
    acall i2c_write;
    acall i2c_stop;
    ret
keyscan:
    mov p1,#0ffh    ; All are input
    nop
    mov a,P1
    jnb acc.0,mode_key
    jnb acc.1,change_key
    jnb acc.2,clear_key
    jnb acc.3,alarm_key
    nop
mode_key:
    inc mode
    ret
change_key:
    mov a,mode
    cjne a,#1,next1
    acall setmin
    ret
next1:
    cjne a,#2,next2
    acall sethour
    ret
next2:
    cjne a,#3,next3
    acall setdate
    ret
next3:
    cjne a,#4,exit
    acall setmonth
exit:
    cjne a,#5,thoat
    mov mode,#0
thoat:
    ret
clear_key:
    acall i2c_start;
    mov a,#0D0h
    acall i2c_write;  /* address the part to write */
    mov a,#0Fh
    acall i2c_write;  /* position the address pointer to 0 */
    mov a,#00h
    acall i2c_write;
    acall i2c_stop;
    ret
alarm_key:
    ret
; END of key scan

setmin: 
    inc min
    mov a,min
    cjne a,#0Ah,next4
    mov min,#10h
next4:
    cjne a,#1Ah,next5
    mov min,#20h
next5:
    cjne a,#2Ah,next6
    mov min,#30h
next6:
    cjne a,#3Ah,next7
    mov min,#40h
next7:
    cjne a,#4Ah,next8
    mov min,#50h
next8:
    cjne a,#5Ah,next9
    mov min,#00h
next9:
    mov led3,min
    mov led4,min
    anl led3,#0Fh
    anl led4,#0F0h
    mov a,led4
    swap a
    mov led4,a
    ret
sethour:
    inc hour
    mov a,hour
    cjne a,#0Ah,next10
    mov hour,#10h
next10:
    cjne a,#13h,next11
    mov hour,#01h
next11:
    mov led5,hour
    mov led6,hour
    anl led5,#0Fh
    anl led6,#0F0h
    mov a,led6
    swap a
    mov led6,a
    ret
setdate:
    inc date
    ret
setmonth:
    inc month
    ret
setyear:
    inc year
    ret
display:
    mov a,led1
    movc a,@a+dptr
    mov p2,a
    clr p0.0
    acall delay
    setb p0.0

    mov a,led2
    movc a,@a+dptr
    mov p2,a
    clr p0.1
    acall delay
    setb p0.1

    mov a,led3
    movc a,@a+dptr
    mov p2,a
    clr p0.2
    acall delay
    setb p0.2

    mov a,led4
    movc a,@a+dptr
    mov p2,a
    clr p0.3
    acall delay
    setb p0.3

    mov a,led5
    movc a,@a+dptr
    mov p2,a
    clr p0.4
    acall delay
    setb p0.4

    mov a,led6
    movc a,@a+dptr
    mov p2,a
    clr p0.5
    acall delay
    setb p0.5
    ret
    
read_time:
    acall i2c_start        ;/* The following Enables the Oscillator */
    mov a,#0D0h
    acall i2c_write        ;  /* address the part to write */
    mov a,#00h
    acall i2c_write;  /* position the address pointer to 0 */
    acall i2c_start
    mov a,#0D1h
    acall   i2c_write;     /* write 0 to the seconds register, clear the CH bit */
    clr i2c_ack_out   ; no ACK
    acall i2c_read
    mov sec,a
    setb i2c_ack_out
    acall i2c_read
    mov min,a
    acall i2c_stop;
    mov a,sec
    jz update_time
next:
    mov led1,sec
    mov led2,sec
    anl led1,#0Fh
    anl led2,#0F0h
    mov a,led2
    swap a
    mov led2,a
    ret

update_time:
    acall i2c_start
    mov a,#0D0h
    acall i2c_write
    mov a,#0
    acall i2c_write
    acall i2c_start
    mov a,#0D1h
    acall i2c_write
    clr i2c_ack_out
    acall i2c_read
    mov sec,a
    acall i2c_read
    mov min,a
    setb i2c_ack_out
    acall i2c_read
    mov hour,a
    acall i2c_stop

    mov led1,sec
    mov led2,sec
    anl led1,#00001111b
    anl led2,#11110000b
    mov a,led2
    swap a
    mov led2,a

    mov led3,min
    mov led4,min
    anl led3,#0Fh
    anl led4,#0F0h
    mov a,led4
    swap a
    mov led4,a

    anl hour,#3Fh
    mov led5,hour
    mov led6,hour
    anl led5,#0Fh
    anl led6,#0F0h
    mov a,led6
    swap a
    mov led6,a
    ret

;i2c_start:
;    setb sda    ;sda =1
;    setb scl    ;sc=1
;   clr sda     ;sda=0
;    ret
;i2c_stop:
;    clr sda
;    setb scl
;   setb sda
;    ret
i2c_start:                 ; I2C Startbedingung
       setb sda
       nop
       setb scl
       acall i2c_wait;
       clr sda             ; Data auf 0 (Start)
       nop
       clr scl             ; Clock auf 0
       ret
i2c_stop:                  ; I2C Stopbedingung
      ;clr sda
       setb scl            ; Clock auf 1
       nop
       setb sda            ; Data auf 1 (Stop)
       ret
i2c_write:                 ; send 1 data byte (Accu) via I2C
       push 3
       mov r3,#8
i2c_sloop:
       rlc a
       mov sda,c
       nop
       setb scl
       ;acall i2c_wait
       clr scl
       djnz r3,i2c_sloop
       nop
       setb sda
       nop
       setb scl
       ;acall i2c_wait           
       mov c,sda            ; read Acknowledge-bit
       mov i2c_ack_in,c
       clr scl
       nop
       clr sda
       pop 3
       ret

i2c_read:                   ; receive 1 data byte via I2C (Accu)
       push 3
       mov r3,#8
       clr a
       setb sda
i2c_rloop:
       ;acall i2c_wait
       setb scl
       nop
       mov c,sda
       rlc a
       nop
       clr scl
       djnz r3,i2c_rloop

       mov c,i2c_ack_out   ; send Acknowledge-bit
       mov sda,c
       nop
       setb scl
       ;acall i2c_wait
       clr scl
       nop
       clr sda
       pop 3
       ret
delay:
    mov r7,#2
dl1:
    mov r6,#255
here:
    nop
    nop
    djnz r6,here
    djnz r7,dl1
    ret
i2c_wait:               ; Verzoegerung fuer I2C (CALL + RET -> 4us bei 12MHz)
       ret
maled7:
        DB     0C0H,0F9H,0A4H,0B0H,99H,92H,82H,0F8H,80H,90H    ;90h LAM CHO SO 9 TREN SEG-7 LA 6 GACH
        DB     88H,0C6H,86H,8EH,82H,89H
        END
end

4. Lưu ý khi cấu hình & nạp ROM

Thạch anh 32.768kHz cho DS1337 cần đặt thật sát chân chip để tránh nhiễu xung dao động.