1 /*********************************************************************************
2 * 【编写时间】: 2016年02月15日
3 * 【作 者】: 清翔电子:03
4 * 【版 本】: 1.0
5 * 【网 站】: http://www.qxmcu.com/
6 * 【淘宝店铺】: http://qxmcu.taobao.com/
7 * 【实验平台】: QX-MCS51 单片机开发板
8 * 【外部晶振】: 11.0592mhz
9 * 【主控芯片】: STC89C52
10 * 【编译环境】: Keil μVisio3
11 * 【程序功能】: LCD1602液晶显示DS1302时钟日历
12 * 【使用说明】: 试验前请用杜邦线分别把j5排针根据背面丝印相应接到P10、P11、P12
13 并接上LCD1602液晶调节好对比度再下载此程序
14
15 * 说明:免费开源,不提供源代码分析.
16 **********************************************************************************/
17
18 //调用1602显示驱动,在此文件内已包含51头文件和定义数据类型
19 #include "LCD1602.h"
20 /*====================================
21 IO接口定义
22 ====================================*/
23 sbit TSCLK = P1^0; //时钟
24 sbit TIO = P1^1; //数据
25 sbit TRST = P1^2; //使能
26
27 #define MAIN_Fosc 11059200UL //宏定义主时钟HZ
28 #define DS1302_W_ADDR 0x80 //写时钟日历寄存器起始地址
29 #define DS1302_R_ADDR 0x81 //读时钟日历寄存器起始地址
30
31 //时钟日历暂存数组,秒、分、时、日、月、周、年 初值为= 16年2月15日 周1 23:58:50
32 uchar TimeData[7]={50, 58, 23, 15, 2, 1, 16};
33
34 /*=================================================
35 *函数名称:Delay_Ms
36 *函数功能:12T 51单片机自适应主时钟毫秒级延时函数
37 *说明:需定义MAIN_Fosc(晶振主频单位HZ)
38 *输入:ms:要延时的毫秒
39 =================================================*/
40 void Delay_Ms(INT16U ms)
41 {
42 INT16U i;
43 do{
44 i = MAIN_Fosc / 96000;
45 while(--i); //96T per loop
46 }while(--ms);
47 }
48 /*=================================================
49 *函数名称:DS1302_W_Byte
50 *函数功能:DS1302写一字节数据
51 *输入:dat:要写入的数据
52 =================================================*/
53 void DS1302_W_Byte(uchar dat)
54 {
55 uchar i;
56 for(i = 0; i < 8; i++) //每次写1bit,写8次
57 {
58 TSCLK = 0; //拉低时钟总线
59 TIO = dat & 0x01; //从一字节最低位开始写
60 TSCLK = 1; //拉高时钟总线,DS1302把数据读走
61 dat >>= 1; //数据右移一位
62 }
63 }
64 /*=================================================
65 *函数名称:DS1302_R_Byte
66 *函数功能:DS1302读一字节
67 *输出:dat:读取的数据
68 =================================================*/
69 uchar DS1302_R_Byte()
70 {
71 uchar i, dat;
72 for(i = 0; i < 8; i++) //每次写1bit,写8次
73 {
74 TSCLK = 0; //拉低时钟总线,DS1302把数据放到数据总线上
75 dat >>= 1; //数据右移一位,数据从最低位开始读
76 if(TIO) dat |= 0x80;//读取数据
77 TSCLK = 1; //拉高时钟总线
78 }
79 return dat; //返回读取的数据
80 }
81 /*=================================================
82 *函数名称:DS1302_W_DAT
83 *函数功能:写DS1302数据一次写2个字节
84 *说明:先写命令后写数据
85 *调用:DS1302_W_Byte()
86 *输入:cmd:需要写的命令 ,dat:需要些的数据
87 =================================================*/
88 void DS1302_W_DAT(uchar cmd, uchar dat)
89 {
90 TRST = 0; //拉低使能端
91 TSCLK = 0; //拉低数据总线
92 TRST = 1; //拉高使能端,开始写数据
93 DS1302_W_Byte(cmd); //写命令
94 DS1302_W_Byte(dat); //写数据
95 }
96 /*=================================================
97 *函数名称:DS1302_R_DAT
98 *函数功能:读DS1302数据
99 *说明:先写入命令字节后读出对应数据
100 *调用: DS1302_W_Byte();DS1302_R_Byte();
101 *输入: cmd:需要写的命令
102 *输出: dat:读出的数据
103 =================================================*/
104 uchar DS1302_R_DAT(uchar cmd)
105 {
106 uchar dat;
107 TRST = 0; //拉低使能端
108 TSCLK = 0; //拉低数据总线
109 TRST = 1; //拉高使能端,开始写数据
110 DS1302_W_Byte(cmd); //写命令
111 dat = DS1302_R_Byte(); //读出数据
112 return dat; //返回读出数据
113 }
114
115 /*=================================================
116 *函数名称:DS1302_Clear_WP
117 *函数功能:清除DS1302写保护
118 *说明:先写入命令0x8e(写控制寄存器)接着向该寄存器写0
119 *调用:DS1302_W_DAT()
120 =================================================*/
121 void DS1302_Clear_WP()
122 {
123 DS1302_W_DAT(0x8e,0x00); //把控制寄存器WP位置0
124 }
125 /*=================================================
126 *函数名称:DS1302_Clear_WP
127 *函数功能:设置DS1302写保护
128 *说明:先写入命令0x8e(写控制寄存器)接着向该寄存器写0x80
129 *调用:DS1302_W_DAT()
130 =================================================*/
131 void DS1302_Set_WP()
132 {
133 DS1302_W_DAT(0x8e,0x80); //把控制寄存器WP位置1
134 TRST = 0; //拉低使能端
135 TSCLK = 0; //拉低数据总线
136 }
137 /*=================================================
138 *函数名称:Set_DS1302_Time
139 *函数功能:设置DS1302时钟日历数据
140 *说明:把时钟日历暂存数组TimeData数据转换为BCD码并
141 写入到DS1302时钟日历寄存器中
142 *调用:DS1302_Clear_WP();DS1302_W_DAT();DS1302_Set_WP();
143 *输入:addr:需要写入寄存器的地址 ,TimeData数组:时钟日历初始值
144 =================================================*/
145 void Set_DS1302_Time(uchar addr)
146 {
147 uchar i, j;
148 DS1302_Clear_WP(); //清除写保护
149 for(i = 0; i < 7; i++) //写入7个字节的时钟初始值
150 {
151 j = TimeData[i]/10; //BCD码转换
152 TimeData[i] %= 10; //BCD码转换
153 TimeData[i] += j*16; //BCD码转换
154 DS1302_W_DAT(addr, TimeData[i]); //先写DS1302时钟日历起始地址,再写数据
155 addr += 2; //时钟日历寄存器地址+2转向下一个寄存器
156 }
157 DS1302_Set_WP(); //开起写保护
158 }
159 /*=================================================
160 *函数名称:Read_DS1302_Time
161 *函数功能:读取DS1302时钟数据
162 *说明: 读取DS1302时钟数据 返回数据存入时钟日历暂存
163 数组TimeData(数据格式BCD码)
164 *调用:DS1302_Clear_WP();DS1302_R_DAT();DS1302_Set_WP();
165 *输入: addr:需要读取时钟日历寄存器的起始地址
166 =================================================*/
167 void Read_DS1302_Time(uchar addr)
168 {
169 uchar i;
170 DS1302_Clear_WP(); //清楚些保护
171 for(i = 0; i < 7; i++) //从DS1302读取7个字节的时钟日历数据
172 {
173 TimeData[i] = DS1302_R_DAT(addr);//先写入要读取数据的寄存器起始地址,再读出数据存入TimeData数组
174 addr += 2; //时钟日历寄存器地址+2转向下一个寄存器
175 }
176 DS1302_Set_WP(); //开起写保护
177 }
178 /*=================================================
179 *函数名称:main
180 *函数功能:主函数 1602液晶显示DS1302数据
181 Date:年-月-日-星期
182 Time:时:分:秒
183 =================================================*/
184 void main()
185 {
186 InitLcd1602(); //1602初始化
187 Set_DS1302_Time(DS1302_W_ADDR); //先写入时钟日历寄存器起始地址再设置时钟日历初值
188 LcdShowStr(0,0,"Date:"); //1602显示字符串
189 LcdShowStr(0,1,"Time:"); //1602显示字符串
190 while(1)
191 {
192 Read_DS1302_Time(DS1302_R_ADDR); //先写入时钟日历寄存器起始地址再读出时钟日历写入到TimeData数组中
193 DisplayOneStr (5,0,TimeData[6]); //年
194 DisplayOneChar (7,0,\'-\'); //-
195 DisplayOneStr (8,0,TimeData[4]); //月
196 DisplayOneChar (10,0,\'-\'); //-
197 DisplayOneStr (11,0,TimeData[3]);//日
198 DisplayOneChar (13,0,\'-\'); //-
199 DisplayOneStr (14,0,TimeData[5]);//星期
200
201 DisplayOneStr (6,1,TimeData[2]); //时
202 DisplayOneChar (8,1,\':\'); //:
203 DisplayOneStr (9,1,TimeData[1]); //分
204 DisplayOneChar (11,1,\':\'); //:
205 DisplayOneStr (12,1,TimeData[0]);//秒
206 Delay_Ms(1000); //延时1秒
207 }
208 }