实现功能:
利用51汇编语言实现驱动DS1302芯片,并将显示的时间显示到LCD上
设计思路:
- 给DS1302赋初值。先在51单片机片内RAM开拓一块32字节的空间,用来存储时间数据(本程序是以起始地址60H开始,从60H开始存储秒、分、时、日、月、周、年,共七个字节,剩余字节备用),先给这些地址初值,然后再根据写命令字依次把时间数据写入到DS1302的RAM中
- 初始化LCD显示屏
- 从DS1302的RAM中,根据读命令字依次读出时间数据,存放到第一步开拓的空间
- 将数据显示到LCD屏上
- 延时,然后跳转到第三步进行循环(一定要有延时,否则出BUG)
电路图:
DS1302原理部分
1. 芯片引脚
- X1,X2:接外部时钟
- RST:芯片复位端,0–芯片禁止读写, 1–读写使能。当RST由低到高,启动数据传输。
- SCLK:上升沿将数据写入DS1302芯片,下降沿读出数据
- I/O:数据的传输,双向串行传输
2.芯片读写时序图
3.芯片命令字
4.驱动函数
1.基本宏定义
;******************* 宏定义 ************************
LCDIO EQU P0 ;LCD数据总线连接P0口
RS EQU P2.0 ;Register select 连接P2.0
RW EQU P2.1 ;Read/Write 连接P2.1
E EQU P2.2 ;Enable 连接P2.2
BF EQU P0.7 ;LCD的忙标志位
CLOCKIO EQU P1.0 ;DS1302数据IO
SCLK EQU P1.1 ;DS1302时钟端口
RST EQU P1.2 ;DS1302复位端口
SECOND EQU 60H ;秒地址
MINUTE EQU 61H ;分地址
HOUR EQU 62H ;时地址
YEAR EQU 63H ;日地址
MOUTH EQU 64H ;月地址
WEEK EQU 65H ;周地址
DAY EQU 66H ;年地址
;***************************************************
说明:
- 上边是LCD引脚的宏定义
- 中间是DS1302引脚的宏定义
- 下边是定义的是初始化的时候给DS1302起始时间存放的地址,如第一个秒,表示在单片机片内RAM地址为60H的地方,存放的是DS1302启动的秒数据
2. DS1302写入字节函数
;************** DS1302写入字节函数 ******************
;将B写入DS1302 --传入参数B --无传出参数
INPUT:
MOV R4, #8
INPUT_Rotate:
MOV A, B
RRC A
MOV B, A
MOV CLOCKIO, C
SETB SCLK ;SCLK下降沿写入字节
NOP
CLR SCLK
DJNZ R4, INPUT_Rotate
RET
;***************************************************
3. DS1302读取字节函数
;************** DS1302读出字节函数 ******************
;将DS1302数据读出到A
OUTPUT:
MOV R4, #8
OUTPUT_Rotate:
MOV C, CLOCKIO
RRC A
SETB SCLK ;SCLK下降沿读出字节
NOP
CLR SCLK
DJNZ R4, OUTPUT_Rotate
RET
;***************************************************
4. 定义DS1302起始计时时间函数
;************* 定义DS1302起始计时时间 ***************
;写入 20年 12月 19日 周6 13时 13分 13秒
TIME_SET:
MOV SECOND, #13H ;秒
MOV MINUTE, #13H ;分
MOV HOUR, #13H ;时
MOV DAY, #19H ;日
MOV MOUTH, #12H ;月
MOV WEEK, #06H ;周
MOV YEAR, #20H ;年
RET
;***************************************************
5. DS1302初始化函数
;****************** 初始化DS1302 ********************
CLOCK_INIT:
;留32字节存储从DS1302读取的数据
MOV R0, #60H ;从60H开始,依次增加
MOV R1, #32H ;作为索引,索引32个连续字节
MOV A, #00H ;A起到中间变量,暂时存储00H
CLR_BUF:
MOV @R0, A ;间接寻址,把00H依次写入60H开始的32个字节中
INC R0 ;地址增1
DJNZ R1, CLR_BUF ;跳转,依次赋值
;写入命令字进行初始化
CLR RST ;模拟RST上升沿,启动数据传输(说明启动传输不是代表传输,还需要SCLK的上升沿
CLR SCLK
NOP ; 还需要SCLK的上升沿才能把数据按位依次传输过去)
SETB RST
MOV B, #8EH ;命令字,写保护寄存器,此时不能对寄存器进行写操作了
LCALL INPUT ;把命令字写如DS1302
MOV B, #00H ;WP清零,现在允许外部写入DS1302中数据
LCALL INPUT ;把命令字写如DS1302
LCALL TIME_SET ;设定初始化时间
MOV R0, #SECOND ;把在RAM中地址为60H(存储数据为秒)数据给R0
MOV R7, #7 ;索引,秒、分......送七次
MOV R1, #80H ;命令字。表示写入秒数据,当R2依次增二,表明开始进行写如分,时等数据.(这是规定,写如数据前先给命令字)
WRITE:
CLR RST ;模拟RST上升沿,启动数据传输
CLR SCLK
NOP
SETB RST
MOV B, R1 ;将命令字80H写入DS1302
LCALL INPUT
MOV A,@R0 ;R0存储的秒地址,间接寻址将数据给A
MOV B, A ;必须把数据传给B,因为写入函数(INPUT)传入参数是B
LCALL INPUT
INC R0 ;R0增1表示由秒向分过渡,或者由分向时过渡,依次类推
INC R1 ;R1增2,表示由秒向分的命令字过渡,或者由分向时的命令字过渡,依次类推
INC R1
SETB SCLK
CLR RST
DJNZ R7, WRITE ;循环7次,将秒,分,时,星期,天,月,年都写入
MOV B, #8EH ;写保护寄存器
LCALL INPUT
MOV B, #80H ;WP置1,写保护
LCALL INPUT
SETB SCLK
CLR RST
;***************************************************
6.获取时间函数
;***************** 获取时间函数 *********************
GET_TIME:
MOV R0, #SECOND ;把秒的地址给R0,以便依次读出数据
MOV R7, #7 ;用来循环
MOV R1, #81H ;命令字。表示读出秒数据,当R2依次增二,表明开始进行写如分,时等数据.
GET_TIME_Rotato:
CLR RST ;模拟RST上升沿,表示启动数据传输
CLR SCLK
NOP
SETB RST
MOV B, R1 ;把命令字给B,由B写如DS1302中
LCALL INPUT ;写入命令字
LCALL OUTPUT ;读出数据,读出的数据是保存到A中的
MOV @R0, A ;现在将读出来的值放到秒或者分等的地址中
INC R0 ;地址加1,从而过渡到分,时等
INC R1 ;命令字需要加2才能进行读取
INC R1
SETB SCLK
CLR RST
DJNZ R7, GET_TIME_Rotato ;循环读取
RET
;***************************************************
7.将时间显示再LCD函数
;***************** 显示时间函数 *********************
SHOW_TIME:
;显示小时
MOV A, #84H
LCALL W_CMD
MOV A, HOUR
PUSH Acc
SWAP A
ANL A, #0FH
ORL A, #30H
LCALL W_DAT ;显示小时高位
MOV A, #85H
LCALL W_CMD
POP Acc
ANL A, #0FH
ORL A, #30H
LCALL W_DAT ;显示小时低位
;显示符号-
MOV A, #86H
LCALL W_CMD
MOV A, #2DH
LCALL W_DAT
;显示分钟
MOV A, #87H
LCALL W_CMD
MOV A, MINUTE
PUSH Acc
SWAP A
ANL A, #0FH
ORL A, #30H
LCALL W_DAT ;显示分钟高位
MOV A, #88H
LCALL W_CMD
POP Acc
ANL A, #0FH
ORL A, #30H
LCALL W_DAT ;显示分钟低位
;显示符号-
MOV A, #89H
LCALL W_CMD
MOV A, #2DH
LCALL W_DAT
;显示秒
MOV A, #8AH
LCALL W_CMD
MOV A, SECOND
PUSH Acc
SWAP A
ANL A, #0FH
ORL A, #30H
LCALL W_DAT ;显示秒高位
MOV A, #8BH
LCALL W_CMD
POP Acc
ANL A, #0FH
ORL A, #30H
LCALL W_DAT ;显示秒低位
;显示年
MOV A, #0C3H
LCALL W_CMD
MOV A, YEAR
PUSH Acc
SWAP A
ANL A, #0FH
ORL A, #30H
LCALL W_DAT ;显示年高位
MOV A, #0C4H
LCALL W_CMD
POP Acc
ANL A, #0FH
ORL A, #30H
LCALL W_DAT ;显示年低位
;显示符号-
MOV A, #0C5H
LCALL W_CMD
MOV A, #2DH
LCALL W_DAT
;显示月
MOV A, #0C6H
LCALL W_CMD
MOV A, MOUTH
PUSH Acc
SWAP A
ANL A, #0FH
ORL A, #30H
LCALL W_DAT ;显示月高位
MOV A, #0C7H
LCALL W_CMD
POP Acc
ANL A, #0FH
ORL A, #30H
LCALL W_DAT ;显示月低位
;显示符号-
MOV A, #0C8H
LCALL W_CMD
MOV A, #2DH
LCALL W_DAT
;显示日
MOV A, #0C9H
LCALL W_CMD
MOV A, DAY
PUSH Acc
SWAP A
ANL A, #0FH
ORL A, #30H
LCALL W_DAT ;显示日高位
MOV A, #0CAH
LCALL W_CMD
POP Acc
ANL A, #0FH
ORL A, #30H
LCALL W_DAT ;显示日低位
;显示符号-
MOV A, #0CBH
LCALL W_CMD
MOV A, #2DH
LCALL W_DAT
;显示周
MOV A, #0CCH
LCALL W_CMD
MOV A, WEEK
ANL A, #0FH
ORL A, #30H
LCALL W_DAT ;显示周
RET
;***************************************************
8.延时函数
;****************** T0延时函数 *******************
T0_DELAY:
PUSH Acc
LCALL T0_WAIT
POP Acc
DEC A
JNZ T0_DELAY
RET
T0_WAIT:
XRL DPL, #0FFH
XRL DPH, #0FFH
INC DPTR
T0_1:
MOV TL0, #09CH
MOV TH0, #0FFH
MOV TMOD, #1
SETB TCON.4
T0_2:
JNB TCON.5, T0_2
CLR TCON.4
CLR TCON.5
INC DPTR
MOV A, DPL
MOV A, DPH
JNZ T0_1
RET
;***************************************************
整体程序设计
;******************* 宏定义 ************************
LCDIO EQU P0 ;LCD数据总线连接P0口
RS EQU P2.0 ;Register select 连接P2.0
RW EQU P2.1 ;Read/Write 连接P2.1
E EQU P2.2 ;Enable 连接P2.2
BF EQU P0.7 ;LCD的忙标志位
CLOCKIO EQU P1.0 ;DS1302数据IO
SCLK EQU P1.1 ;DS1302时钟端口
RST EQU P1.2 ;DS1302复位端口
SECOND EQU 60H ;秒地址
MINUTE EQU 61H ;分地址
HOUR EQU 62H ;时地址
YEAR EQU 63H ;日地址
MOUTH EQU 64H ;月地址
WEEK EQU 65H ;周地址
DAY EQU 66H ;年地址
;***************************************************
ORG 0000H
AJMP MAIN
ORG 0100H
;******************** 主函数 ************************
MAIN:
LCALL CLOCK_INIT ;调用DS1602初始化函数
LCALL LCD_INIT ;调用LCD1602初始化函数
LOOP:
LCALL GET_TIME ;调用获取时间函数,存储起始地址60H
LCALL SHOW_TIME ;调用LCD显示时间函数
MOV DPTR, #800 ;调用延时函数
MOV A, #1
LCALL T0_DELAY
AJMP LOOP
;***************************************************
;**************** LCD1602初始化 *********************
LCD_INIT:
MOV A, #01H ;写入清屏命令
ACALL W_CMD
MOV A, #38H ;设置显示模式16*2显示
ACALL W_CMD
MOV A, #0CH ;设置屏幕显示,无光标
ACALL W_CMD
MOV A, #14 ;设置右移
ACALL W_CMD
RET
;***************************************************
;**************** LCD1602忙标志 *********************
WAIT_BUSY:
MOV LCDIO,#0FFH
CLR RS
SETB RW
CLR E
NOP
SETB E
JB BF, WAIT_BUSY
RET
;***************************************************
;*************** LCD1602写入命令函数 ****************
W_CMD:
LCALL WAIT_BUSY
MOV LCDIO, A ;把命令写到IO口处
CLR RS ;清0,选择命令寄存器
CLR RW
SETB E ;模拟下降沿,命令写入LCD中
NOP
CLR E
RET
;***************************************************
;*************** LCD1602写入数据函数 ****************
W_DAT:
LCALL WAIT_BUSY
MOV LCDIO, A
SETB RS ;置1,选择数据寄存器
CLR RW ;清0,为写入,置1,为读取
SETB E ;模拟下降沿
NOP
CLR E
RET
;***************************************************
;************** DS1302写入字节函数 ******************
;将B写入DS1302 --传入参数B --无传出参数
INPUT:
MOV R4, #8
INPUT_Rotate:
MOV A, B
RRC A
MOV B, A
MOV CLOCKIO, C
SETB SCLK ;SCLK下降沿写入字节
NOP
CLR SCLK
DJNZ R4, INPUT_Rotate
RET
;***************************************************
;************** DS1302读出字节函数 ******************
;将DS1302数据读出到A
OUTPUT:
MOV R4, #8
OUTPUT_Rotate:
MOV C, CLOCKIO
RRC A
SETB SCLK ;SCLK下降沿读出字节
NOP
CLR SCLK
DJNZ R4, OUTPUT_Rotate
RET
;***************************************************
;************* 定义DS1302启示计时时间 ***************
;写入 20年 12月 19日 周6 13时 13分 13秒
TIME_SET:
MOV SECOND, #13H ;秒
MOV MINUTE, #13H ;分
MOV HOUR, #13H ;时
MOV DAY, #19H ;日
MOV MOUTH, #12H ;月
MOV WEEK, #06H ;周
MOV YEAR, #20H ;年
RET
;***************************************************
;****************** 初始化DS1302 ********************
CLOCK_INIT:
;留32字节存储从DS1302读取的数据
MOV R0, #60H ;从60H开始,依次增加
MOV R1, #32H ;作为索引,索引32个连续字节
MOV A, #00H ;A起到中间变量,暂时存储00H
CLR_BUF:
MOV @R0, A ;间接寻址,把00H依次写入60H开始的32个字节中
INC R0 ;地址增1
DJNZ R1, CLR_BUF ;跳转,依次赋值
;写入命令字进行初始化
CLR RST ;模拟RST上升沿,启动数据传输(说明启动传输不是代表传输,还需要SCLK的上升沿
CLR SCLK
NOP ; 还需要SCLK的上升沿才能把数据按位依次传输过去)
SETB RST
MOV B, #8EH ;命令字,写保护寄存器,此时不能对寄存器进行写操作了
LCALL INPUT ;把命令字写如DS1302
MOV B, #00H ;WP清零,现在允许外部写入DS1302中数据
LCALL INPUT ;把命令字写如DS1302
LCALL TIME_SET ;设定初始化时间
MOV R0, #SECOND ;把在RAM中地址为60H(存储数据为秒)数据给R0
MOV R7, #7 ;索引,秒、分......送七次
MOV R1, #80H ;命令字。表示写入秒数据,当R2依次增二,表明开始进行写如分,时等数据.(这是规定,写如数据前先给命令字)
WRITE:
CLR RST ;模拟RST上升沿,启动数据传输
CLR SCLK
NOP
SETB RST
MOV B, R1 ;将命令字80H写入DS1302
LCALL INPUT
MOV A,@R0 ;R0存储的秒地址,间接寻址将数据给A
MOV B, A ;必须把数据传给B,因为写入函数(INPUT)传入参数是B
LCALL INPUT
INC R0 ;R0增1表示由秒向分过渡,或者由分向时过渡,依次类推
INC R1 ;R1增2,表示由秒向分的命令字过渡,或者由分向时的命令字过渡,依次类推
INC R1
SETB SCLK
CLR RST
DJNZ R7, WRITE ;循环7次,将秒,分,时,星期,天,月,年都写入
MOV B, #8EH ;写保护寄存器
LCALL INPUT
MOV B, #80H ;WP置1,写保护
LCALL INPUT
SETB SCLK
CLR RST
;***************************************************
;***************** 获取时间函数 *********************
GET_TIME:
MOV R0, #SECOND ;把秒的地址给R0,以便依次读出数据
MOV R7, #7 ;用来循环
MOV R1, #81H ;命令字。表示读出秒数据,当R2依次增二,表明开始进行写如分,时等数据.
GET_TIME_Rotato:
CLR RST ;模拟RST上升沿,表示启动数据传输
CLR SCLK
NOP
SETB RST
MOV B, R1 ;把命令字给B,由B写如DS1302中
LCALL INPUT ;写入命令字
LCALL OUTPUT ;读出数据,读出的数据是保存到A中的
MOV @R0, A ;现在将读出来的值放到秒或者分等的地址中
INC R0 ;地址加1,从而过渡到分,时等
INC R1 ;命令字需要加2才能进行读取
INC R1
SETB SCLK
CLR RST
DJNZ R7, GET_TIME_Rotato ;循环读取
RET
;***************************************************
;***************** 显示时间函数 *********************
SHOW_TIME:
;显示小时
MOV A, #84H
LCALL W_CMD
MOV A, HOUR
PUSH Acc
SWAP A
ANL A, #0FH
ORL A, #30H
LCALL W_DAT ;显示小时高位
MOV A, #85H
LCALL W_CMD
POP Acc
ANL A, #0FH
ORL A, #30H
LCALL W_DAT ;显示小时低位
;显示符号-
MOV A, #86H
LCALL W_CMD
MOV A, #2DH
LCALL W_DAT
;显示分钟
MOV A, #87H
LCALL W_CMD
MOV A, MINUTE
PUSH Acc
SWAP A
ANL A, #0FH
ORL A, #30H
LCALL W_DAT ;显示分钟高位
MOV A, #88H
LCALL W_CMD
POP Acc
ANL A, #0FH
ORL A, #30H
LCALL W_DAT ;显示分钟低位
;显示符号-
MOV A, #89H
LCALL W_CMD
MOV A, #2DH
LCALL W_DAT
;显示秒
MOV A, #8AH
LCALL W_CMD
MOV A, SECOND
PUSH Acc
SWAP A
ANL A, #0FH
ORL A, #30H
LCALL W_DAT ;显示秒高位
MOV A, #8BH
LCALL W_CMD
POP Acc
ANL A, #0FH
ORL A, #30H
LCALL W_DAT ;显示秒低位
;显示年
MOV A, #0C3H
LCALL W_CMD
MOV A, YEAR
PUSH Acc
SWAP A
ANL A, #0FH
ORL A, #30H
LCALL W_DAT ;显示年高位
MOV A, #0C4H
LCALL W_CMD
POP Acc
ANL A, #0FH
ORL A, #30H
LCALL W_DAT ;显示年低位
;显示符号-
MOV A, #0C5H
LCALL W_CMD
MOV A, #2DH
LCALL W_DAT
;显示月
MOV A, #0C6H
LCALL W_CMD
MOV A, MOUTH
PUSH Acc
SWAP A
ANL A, #0FH
ORL A, #30H
LCALL W_DAT ;显示月高位
MOV A, #0C7H
LCALL W_CMD
POP Acc
ANL A, #0FH
ORL A, #30H
LCALL W_DAT ;显示月低位
;显示符号-
MOV A, #0C8H
LCALL W_CMD
MOV A, #2DH
LCALL W_DAT
;显示日
MOV A, #0C9H
LCALL W_CMD
MOV A, DAY
PUSH Acc
SWAP A
ANL A, #0FH
ORL A, #30H
LCALL W_DAT ;显示日高位
MOV A, #0CAH
LCALL W_CMD
POP Acc
ANL A, #0FH
ORL A, #30H
LCALL W_DAT ;显示日低位
;显示符号-
MOV A, #0CBH
LCALL W_CMD
MOV A, #2DH
LCALL W_DAT
;显示周
MOV A, #0CCH
LCALL W_CMD
MOV A, WEEK
ANL A, #0FH
ORL A, #30H
LCALL W_DAT ;显示周
RET
;****************** T0延时函数 *******************
T0_DELAY:
PUSH Acc
LCALL T0_WAIT
POP Acc
DEC A
JNZ T0_DELAY
RET
T0_WAIT:
XRL DPL, #0FFH
XRL DPH, #0FFH
INC DPTR
T0_1:
MOV TL0, #09CH
MOV TH0, #0FFH
MOV TMOD, #1
SETB TCON.4
T0_2:
JNB TCON.5, T0_2
CLR TCON.4
CLR TCON.5
INC DPTR
MOV A, DPL
MOV A, DPH
JNZ T0_1
RET
;***************************************************
END