找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 6828|回复: 0
打印 上一主题 下一主题
收起左侧

DS1302实时时钟实验程序 带详细注释

[复制链接]
跳转到指定楼层
楼主
ID:71259 发表于 2014-12-30 01:44 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
  1. #include<reg52.h>        //包含单片机寄存器的头文件
  2. #include<intrins.h>       //包含_nop_()的头文件
  3. sbit RS=P2^0;            //LCD读写选择位
  4. sbit RW=P2^1;    //LCD读写选择位
  5. sbit E=P2^2;  //LCD使能端
  6. sbit BF=P0^7;        //忙信号
  7. sbit SCLK=P1^0;    //1302时钟输出端
  8. sbit DATA=P1^1;    //1302数据端
  9. sbit RST=P1^2;    //1302复位端
  10. unsigned char code digit[]="0123456789";
  11. /***************************
  12. 1ms基准延时
  13. ***************************/
  14. void delay1ms(unsigned int n)      
  15. {
  16. unsigned char i;
  17. while(n--)
  18.   for(i=0;i<115;i++);
  19. }
  20. /***************************
  21. 以下是DS1302模块
  22. ***************************/

  23. /**************************
  24. 向1302写一个字节
  25. **************************/
  26. void Write1302(unsigned char dat)
  27. {
  28. unsigned char i;

  29. SCLK=0;       //确保写数据前SCLK为低电平
  30. _nop_();
  31. _nop_(); //给硬件反应时间
  32. for(i=0;i<8;i++){
  33.   DATA=dat&0x01; //取数据的最低位  低位在前,高位在后
  34.   _nop_();
  35.   _nop_();  //给硬件反应时间
  36.   SCLK=1;  //正跳变写数据
  37.   _nop_();
  38.   _nop_();  //给硬件反应时间
  39.   SCLK=0;  //重新拉低SCLK,形成脉冲
  40.   dat>>=1;   //dat右移,为写入下位数据做准备
  41. }
  42. }
  43. /**************************
  44. 根据命令字,向1302写一个字节
  45. **************************/

  46. void WriteSet1302(unsigned char cmd, unsigned char dat)
  47. {
  48.   RST=0;          //禁止数据传输   .!!!这条很重要
  49.   SCLK=0;      //确保写数据前SCLK为低电平
  50.   RST=1;  //开启数据传输        
  51.   _nop_();
  52.   _nop_();
  53.   Write1302(cmd);
  54.   Write1302(dat);
  55.   SCLK=1;   // 将时钟电平置于高电平状态 ,处于已知状态
  56.   RST=0;
  57. }
  58. /**************************
  59. 向1302读一个字节
  60. **************************/

  61. unsigned char Read1302()
  62. {
  63. unsigned char i,dat=0;
  64. for(i=0;i<8;i++){
  65.   dat>>=1;
  66.   if(DATA==1)  //如果读出的数据是1
  67.    dat|=0x80;   //将1取出,写在dat的最高位
  68.   SCLK=1;      //将SCLK置于高电平,为下降沿读出
  69.   _nop_();
  70.   _nop_();
  71.   SCLK=0;   //拉低SCLK,形成脉冲下降沿
  72. }
  73. return dat;
  74. }

  75. /**************************
  76. 根据命令字.向1302读一个字节
  77. **************************/

  78. unsigned char ReadSet1302(unsigned char cmd)
  79. {
  80. unsigned char dat;
  81.     RST=0;    //这条很重要
  82. SCLK=0;   //确保写数居前SCLK被拉低
  83. RST=1;    //启动数据传输
  84. _nop_();
  85. _nop_();
  86. Write1302(cmd);  //写入命令字
  87. dat=Read1302();   //读出数据
  88. SCLK=1;     //将时钟电平置于已知状态
  89. RST=0;      //禁止数据传递
  90. return dat;    //将读出的数据返回
  91. }
  92. /**************************
  93. 初始化1302
  94. **************************/

  95. void DS1302_Int()
  96. {

  97. WriteSet1302(0x8E,0x00);                 //根据写状态寄存器命令字,写入不保护指令
  98.     WriteSet1302(0x80,((55/10)<<4|(55%10)));   //根据写秒寄存器命令字,写入秒的初始值
  99. WriteSet1302(0x82,((59/10)<<4|(59%10)));   //根据写分寄存器命令字,写入分的初始值
  100. WriteSet1302(0x84,((23/10)<<4|(23%10))); //根据写小时寄存器命令字,写入小时的初始值
  101. WriteSet1302(0x86,((18/10)<<4|(18%10))); //根据写日寄存器命令字,写入日的初始值
  102. WriteSet1302(0x88,((6/10)<<4|(6%10))); //根据写月寄存器命令字,写入月的初始值
  103. WriteSet1302(0x8c,((9/10)<<4|(9%10)));   //根据写年寄存器命令字,写入年的初始值
  104. WriteSet1302(0x90,0xa5);                //打开充电功能 选择2K电阻充电方式
  105. WriteSet1302(0x8E,0x80);              //根据写状态寄存器命令字,写入保护指令
  106. }




  107. /***************************
  108. 以下是液晶模块
  109. ***************************/

  110. /***************************
  111. 忙信号检测
  112. ***************************/

  113. bit BusyTest()
  114. {
  115. bit result;
  116. RS=0;   //根据规定,RS为低电平,RW为高电平时,可以读状态
  117. RW=1;
  118. E=1;
  119. _nop_();
  120. _nop_();
  121. result=BF;     //将忙碌标志电平赋给result
  122. E=0;     //将E恢复低电平
  123. _nop_();
  124. _nop_();
  125. return result;

  126. }

  127. /***************************
  128. 将模式设置指令或显示地址送入LCD
  129. ***************************/

  130. void WriteInstruction(unsigned char dictate)
  131. {
  132. while(BusyTest()==1);     //如果忙就等待
  133. RS=0;      //根据规定,RS和R/W同时为低电平时,可以写入指令
  134. RW=0;
  135. E=0;       //E置低电平(写指令时,E为高脉冲,
  136.                            // 就是让E从0到1发生正跳变,所以应先置"0"
  137. _nop_();
  138. _nop_();
  139. P0=dictate;
  140. _nop_();
  141. _nop_();
  142. _nop_();
  143. _nop_();
  144. E=1;     //E置高电平
  145. _nop_();
  146. _nop_();
  147. _nop_();
  148. _nop_();
  149. E=0;       //当E由高电平跳变成低电平时,液晶模块开始执行命令
  150. }


  151. /***************************
  152. 设定字符显示位置
  153. ***************************/

  154. void WriteAddress(unsigned char x)
  155. {
  156.      WriteInstruction(x|0x80); //显示位置的确定方法规定为"80H+地址码x"
  157. }
  158. /***************************
  159. 向LCD写数据
  160. ***************************/

  161. void WriteData(unsigned char dat)
  162. {
  163. while(BusyTest()==1);    //如果忙就等待
  164. RS=1;        //RS为高电平,RW为低电平时,可以写入数据
  165. RW=0;
  166. E=0;        //E置低电平(写指令时,E为高脉冲,
  167.                      // 就是让E从0到1发生正跳变,所以应先置"0"
  168. _nop_();
  169. _nop_();
  170. P0=dat;     //将数据送入P0口,即将数据写入液晶模块
  171. _nop_();
  172. _nop_();
  173. _nop_();
  174. _nop_();
  175. E=1;       //E置高电平
  176. _nop_();
  177. _nop_();
  178. _nop_();
  179. _nop_();
  180. E=0;   //当E由高电平跳变成低电平时,液晶模块开始执行命令
  181. }


  182. /***************************
  183. 初始化LCD
  184. ***************************/

  185. void LCD_Int()
  186. {
  187. delay1ms(15);      //延时15ms,首次写指令时应给LCD一段较长的反应时间
  188. WriteInstruction(0x38);     //显示模式设置:16×2显示,5×7点阵,8位数据接口
  189. delay1ms(5);
  190. WriteInstruction(0x38);
  191. delay1ms(5);
  192. WriteInstruction(0x38);
  193. delay1ms(5);     //连续三次,确保初始化成功
  194. WriteInstruction(0x0c);  //显示模式设置:显示开,无光标,光标不闪烁
  195. delay1ms(5);
  196. WriteInstruction(0x06);    //显示模式设置:光标右移,字符不移
  197. delay1ms(5);
  198. WriteInstruction(0x01);     //清屏幕指令,将以前的显示内容清除
  199. delay1ms(5);
  200. }


  201. /***************************
  202. 以下是1302的显示程序
  203. ***************************/

  204. void DisplaySecond(unsigned char x)
  205. {
  206. unsigned char i,j;   //i,j分别储存十位和个位
  207.     i=x/10;
  208. j=x%10;
  209. WriteAddress(0x49);
  210. WriteData(digit[i]);
  211. WriteData(digit[j]);
  212. delay1ms(15);
  213. }

  214. void DisplayMinute(unsigned char x)
  215. {
  216. unsigned char i,j;
  217.     i=x/10;
  218. j=x%10;
  219. WriteAddress(0x46);
  220. WriteData(digit[i]);
  221. WriteData(digit[j]);
  222. delay1ms(15);
  223. }

  224. void DisplayHour(unsigned char x)
  225. {
  226. unsigned char i,j;
  227.     i=x/10;
  228. j=x%10;
  229. WriteAddress(0x43);
  230. WriteData(digit[i]);
  231. WriteData(digit[j]);
  232. delay1ms(15);
  233. }

  234. void DisplayDay(unsigned char x)
  235. {
  236. unsigned char i,j;
  237.     i=x/10;
  238. j=x%10;
  239. WriteAddress(0x0c);
  240. WriteData(digit[i]);
  241. WriteData(digit[j]);
  242. delay1ms(15);
  243. }

  244. void DisplayMonth(unsigned char x)
  245. {
  246. unsigned char i,j;
  247.     i=x/10;
  248. j=x%10;
  249. WriteAddress(0x09);
  250. WriteData(digit[i]);
  251. WriteData(digit[j]);
  252. delay1ms(15);
  253. }

  254. void DisplayYear(unsigned char x)
  255. {
  256. unsigned char i,j;
  257.     i=x/10;
  258. j=x%10;
  259. WriteAddress(0x06);
  260. WriteData(digit[i]);
  261. WriteData(digit[j]);
  262. delay1ms(15);
  263. }

  264. /*******************************
  265. 主函数
  266. *******************************/

  267. void main()
  268. {
  269. unsigned char second,minute,hour,day,month,year;     //分别储存苗、分、小时,日,月,年
  270. unsigned char ReadValue;        //储存从1302读取的数据
  271. LCD_Int();     //将液晶初始化
  272. WriteAddress(0x01);   //写Date的显示地址,将在第1行第2列开始显示
  273. WriteData('D');
  274. WriteData('a');
  275. WriteData('t');
  276. WriteData('e');
  277. WriteData(':');
  278. WriteAddress(0x08);
  279. WriteData('-');
  280. WriteAddress(0x0b);
  281. WriteData('-');
  282. WriteAddress(0x45);
  283. WriteData(':');
  284. WriteAddress(0x48);
  285. WriteData(':');
  286. DS1302_Int();            //将1302初始化
  287. while(1){
  288.   ReadValue = ReadSet1302(0x81);   //从秒寄存器读数据
  289.         second=((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F);//将读出数据转化
  290.      DisplaySecond(second);          //显示秒
  291.      ReadValue = ReadSet1302(0x83);  //从分寄存器读
  292.         minute=((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F); //将读出数据转化
  293.      DisplayMinute(minute);        //显示分
  294.         ReadValue = ReadSet1302(0x85);  //从分寄存器读
  295.         hour=((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F); //将读出数据转化
  296.      DisplayHour(hour);              //显示小时
  297.         ReadValue = ReadSet1302(0x87);  //从分寄存器读
  298.         day=((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F); //将读出数据转化
  299.      DisplayDay(day);                //显示日
  300.      ReadValue = ReadSet1302(0x89);  //从分寄存器读
  301.         month=((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F); //将读出数据转化
  302.      DisplayMonth(month);            //显示月
  303.      ReadValue = ReadSet1302(0x8d);  //从分寄存器读
  304.         year=((ReadValue&0xf0)>>4)*10 + (ReadValue&0x0F); //将读出数据转化
  305.      DisplayYear(year);              //显示年
  306. }
  307. }

复制代码


分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏3 分享淘帖 顶 踩
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表