找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 10205|回复: 20
收起左侧

DS1307实时时钟万年历proteus仿真与源码

  [复制链接]
ID:136050 发表于 2017-11-17 10:55 | 显示全部楼层 |阅读模式
LCD1602液晶屏显示的万年历,DS1307还有很多功能可以添加小白一个
仿真原理图如下(proteus仿真工程文件可到本帖附件中下载)

protues仿真图

protues仿真图
0.png

单片机源程序如下:
  1. /****************************************************

  2. 电路图说明:
  3.         将单片机P2.7和P1.0分别与RTC(实时时钟)的时钟信号SCL端
  4. 和数据信号SDA端相连, RTC的sout引脚与单片机P3.2相连,RTC的
  5. 地址是11010000.独立键盘k0~K3接P1.1~P1.3
  6. 程序功能:
  7.           使用时钟芯片ds1307制作一个实时时钟
  8. ******************************************************/
  9. #include <reg52.h>
  10. #include<intrins.h>
  11. #define uchar unsigned char
  12. #define uint unsigned int
  13. //实时时钟两信号线
  14. sbit scl=P2^7;
  15. sbit sda=P1^0;
  16. //独立键盘扫描位
  17. sbit k0=P1^1;
  18. sbit k1=P1^2;
  19. sbit k2=P1^3;
  20. //液晶显示器控制位
  21. sbit lcd_rs=P3^4;
  22. sbit lcd_e=P3^5;
  23. //数码管和led锁存器选通位
  24. sbit duan=P2^0;
  25. sbit wei=P2^1;
  26. sbit led=P2^2;
  27. void init();//初始化IIC总线,使总线处于备用状态,
  28.                         //初始化lcd并显示上面table1和table2的值,初始化定时器0,初始化变量时分秒


  29. /****************IIC总线控制函数***************************/
  30. void IIC_start();//IIC通信开始信号
  31. void IIC_stop();//IIC通信停止信号
  32. void IIC_un_ack();//单片机发送非应答位
  33. //void IIC_ack();//单片机发送应答位
  34. void IIC_check_ack();//单片机检查应答位
  35. void IIC_write_byte(uchar);//发送一字节数据
  36. uchar IIC_read_byte();//接收一字节数据
  37. void nop();//5us空操作延迟
  38. /**********************************/
  39. /**********ds1307读写函数*******************/
  40. void ds1307_write_date(uchar ,uchar ,uchar);//向指定器件写一字节数据
  41.                                                                         //参数1器件地址,参数2要存的数据存放位置8位地址
  42.                                                                         //参数3要写的数据

  43. uchar ds1307_read_date(uchar ,uchar );//从指定器件读一字节数据,
  44.                                                                 //参数1被通信器件地址,参数2要读的数据存放位置8位地址
  45.                                                                 //函数返回读取的数据。
  46. void delay(uint);//基数1ms延迟程序
  47. /***********************************/



  48. /**************LCD操作函数**************************/

  49. uchar hour,minute,second,k0_num;//时分秒变量,菜单键k0第几次按下计数,ds1307跟新标志
  50. //时钟初显示
  51. uchar code table1[]="2017-11-16 THUR";
  52. uchar code table2[]="    23:59:55 ";



  53. void lcd_write_com(uchar);//向液晶显示器写指令设置其显示的格式
  54. void lcd_write_date(uchar);//向液晶显示器写显示的数据

  55. /**********************************************/

  56. /**************时钟函数*******************/
  57. void lcd_write_second(uchar);//向lcd写秒
  58. void lcd_write_minute(uchar);//向lcd写分
  59. void lcd_write_hour(uchar);//向lcd写时
  60. void run_time();//时钟走动显示
  61. void keyscan();//菜单键扫描
  62. /****************************************/

  63. /*********十进值与BCD码之间互换**********/
  64. uchar b_second,b_minute,b_hour;
  65. uchar dectobcd(uchar);//十进值转bcd码
  66. uchar bcdtodec(uchar);//bcd码转十进值
  67. /****************************************/

  68. void main()
  69. {
  70.         init();
  71.         while(1)
  72.         {
  73.                 keyscan();
  74.         }
  75. }

  76. void nop()
  77. {
  78.         _nop_();_nop_();_nop_();
  79.         _nop_();_nop_();_nop_();
  80. }

  81. void init()
  82. {
  83.         uchar i;
  84.         //将数据线和时钟线拉高,处于备用状态即非忙
  85.         sda=1;
  86.         nop();
  87.         scl=1;
  88.         nop();
  89.         
  90.         //关数码管显示和8个LED显示
  91.         duan=0;
  92.         wei=0;
  93.         led=0;
  94.         lcd_e=0;

  95.         
  96.         //初始化写入LCD的时分秒
  97.         second=55;
  98.         minute=59;
  99.         hour=23;
  100.         //初始化ds1307
  101.         ds1307_write_date(0xd0,0x07,0x10);//初始化1307的控制字,使其SOUT引脚输出1Hz的方波。
  102.         //初始化1307的时间
  103.         ds1307_write_date(0xd0,6,0x14);                 
  104.         ds1307_write_date(0xd0,5,0x06);   
  105.         ds1307_write_date(0xd0,4,0x09);
  106.         ds1307_write_date(0xd0,3,0x00);
  107.         ds1307_write_date(0xd0,2,0x23);
  108.         ds1307_write_date(0xd0,1,0x59);
  109.         ds1307_write_date(0xd0,0,0x55);

  110.         //初始化液晶显示器
  111.         lcd_write_com(0x38);//设置16*2行,5*7点阵,8位数据接口
  112.         lcd_write_com(0x06);//写字符指针和光标自动向右移动
  113.         lcd_write_com(0x0c);//开显示,不显示光标,光标不闪烁
  114.         lcd_write_com(0x01);//显示清屏
  115.         for(i=0;i<15;i++)
  116.         {
  117.                 lcd_write_date(table1[i]);
  118.         }
  119.         lcd_write_com(0x80+0x40);
  120.         for(i=0;i<10;i++)
  121.         {
  122.                 lcd_write_date(table2[i]);
  123.         }
  124.         
  125. //开启外部中断0
  126.         EA=1;
  127.         EX0=1;
  128.         IT0=1;
  129. }
  130. void IIC_start()
  131. {
  132.         //在时钟信号有效scl=1时,数据线负跳变
  133.         sda=1;
  134.         nop();
  135.         scl=1;
  136.         nop();
  137.         sda=0;
  138.         nop();
  139.         scl=0;//拉低为下个时钟数据作准备
  140.         nop();
  141. }
  142. void IIC_stop()
  143. {
  144.         //在时钟信号有效scl=1时,数据线正跳变,释放总线,使总线处于备用状态即非忙
  145.         sda=0;
  146.         nop();
  147.         scl=1;
  148.         nop();
  149.         sda=1;
  150.         nop();
  151.         nop();
  152.         nop();
  153. }
  154. void IIC_un_ack()
  155. {
  156.         //时钟信号有效时,sda给1,给出非应答
  157.         sda=1;
  158.         nop();
  159.         scl=1;
  160.         nop();
  161.         scl=0;//拉低为下个时钟数据作准备
  162.         nop();
  163. }
  164. /*
  165. void IIC_ack()
  166. {
  167.         //时钟信号有效时,sda给0,给出应答
  168.         sda=0;
  169.         nop();
  170.         scl=1;
  171.         nop();
  172.         scl=0;//拉低为下个时钟数据作准备
  173.         nop();
  174. }
  175. */
  176. void IIC_check_ack()
  177. {
  178.         //uchar i;
  179.         //时钟信号有效时,检测数据信号sda是否为0,给0说明有应答信号
  180.         scl=1;
  181.         //while((sda==1)&&(i<255)) i++;
  182.         nop();
  183.         scl=0;//拉低为下个时钟数据作准备
  184.         nop();
  185. }
  186. uchar IIC_read_byte( )
  187. {
  188.         uchar i,temp;//temp用于存放从数据线读到的数据

  189.         for(i=0;i<8;i++)//从数据线读取一个字节(8位)
  190.         {
  191.                 scl=1;
  192.                 nop();
  193.                 temp=(temp<<1)|sda;//temp左移,腾出第0位,然后将数据线上的一位数用或
  194.                                                                  //运算存放到temp的第0位
  195.                 scl=0;//拉低为下个时钟数据作准备        
  196.                 nop();
  197.         }
  198.         return temp;        
  199. }

  200. void IIC_write_byte(uchar byte)
  201. {
  202.         uchar i;
  203.         for(i=0;i<8;i++)//向数据线写一个字节(8位)
  204.         {
  205.                 byte=byte<<1;//左移位,将byte第7位移到PSW中的进位标志位CY中
  206.                 sda=CY;
  207.                 nop();
  208.                 scl=1;
  209.                 nop();
  210.                 scl=0;//拉低为下个时钟数据作准备
  211.                 nop();
  212.         }
  213.         sda=1;//释放总线,准备接收被控设备应答信号
  214.         nop();
  215. }

  216. void ds1307_write_date(uchar d_address,uchar r_address,uchar date)
  217. {

  218.         IIC_start();
  219.         IIC_write_byte(d_address & (~0x01));//写器件地址,方向是写,所以或上0x00
  220.         IIC_check_ack();//等待应答
  221.         IIC_write_byte(r_address);//写存储器数据存放的8位地址
  222.         IIC_check_ack();//等待应答
  223.         IIC_write_byte(date);//写一字节数据
  224.         IIC_check_ack();//等待应答
  225.         IIC_stop();
  226. }

  227. uchar ds1307_read_date(uchar d_address,uchar r_address)
  228. {
  229.         uchar r;
  230.         IIC_start();
  231.         IIC_write_byte(d_address & (~0x01));//写器件地址,方向是写
  232.         IIC_check_ack();//等待应答
  233.         IIC_write_byte(r_address);//写存储器数据存放的8位地址
  234.         IIC_check_ack();//等待应答

  235.         //换方向
  236.         IIC_start();
  237.         IIC_write_byte(d_address|0x01);//写器件地址,方向是读,所以或上1
  238.     IIC_check_ack();
  239.         r=IIC_read_byte();//读取一个字节数据
  240.         IIC_un_ack();
  241.         IIC_stop();
  242.         return r;//将读到的数据返回
  243. }
  244. void delay(uint z)//晶振频率12MHz时,z=1时延迟1ms
  245. {
  246.         uint a,b;
  247.         for(a=z;a>0;a--)
  248.                 for(b=110;b>0;b--);
  249. }



  250. void lcd_write_com(uchar com)//lcd写指令函数定义
  251. {
  252.         lcd_rs=0;
  253.         P0=com;
  254.         delay(1);
  255.         lcd_e=1;
  256.         lcd_e=0;
  257.         delay(2);
  258. }
  259. void lcd_write_date(uchar date)//lcd写数据函数定义
  260. {
  261.         lcd_rs=1;
  262.         P0=date;
  263.         delay(1);
  264.         lcd_e=1;
  265.         lcd_e=0;
  266.         delay(2);
  267. }


  268. void lcd_write_second(uchar sec)//向lcd写秒
  269. {
  270.         uchar h,l;
  271.         h=sec/10;
  272.         l=sec%10;
  273.         lcd_write_com(0x80+0x40+10);
  274.         lcd_write_date(0x30+h);
  275.         lcd_write_date(0x30+l);
  276. }
  277. void lcd_write_minute(uchar min)//向lcd写分
  278. {
  279.         uchar h,l;
  280.         h=min/10;
  281.         l=min%10;
  282.         lcd_write_com(0x80+0x40+7);
  283.         lcd_write_date(0x30+h);
  284.         lcd_write_date(0x30+l);
  285. }
  286. void lcd_write_hour(uchar hou)//向lcd写时
  287. {
  288.         uchar h,l;
  289.         h=hou/10;
  290.         l=hou%10;
  291.         lcd_write_com(0x80+0x40+4);
  292.         lcd_write_date(0x30+h);
  293.         lcd_write_date(0x30+l);
  294. }



  295. void inter0()interrupt 0
  296. {
  297.         run_time();
  298. }

  299. void run_time()//时钟走动函数定义
  300. {        
  301.         //从1307中读出时间
  302.         b_second=ds1307_read_date(0xd0,0);//返回函数r值秒        
  303.         b_minute=ds1307_read_date(0xd0,1);
  304.         b_hour=ds1307_read_date(0xd0,2);
  305.         //将读出的时间转换成十进值
  306.         second=bcdtodec(b_second);
  307.         minute=bcdtodec(b_minute);
  308.         hour=bcdtodec(b_hour);
  309.         //更新lcd显示时间
  310.         lcd_write_second(second);
  311.         lcd_write_minute(minute);
  312.         lcd_write_hour(hour);        
  313. }

  314. uchar dectobcd(uchar dec)//十进值到BCD码
  315. {
  316.         uchar x,y;
  317.         x=dec/10;//得到bcd的十位数
  318.         y=dec%10;//得到bcd的个位数
  319.         y=(x<<4)|y;
  320.         return y;
  321. }
  322. uchar bcdtodec(uchar bcd)//bcd码转十进值
  323. {
  324.         uchar x,y;
  325.         y=bcd/16;//得到十进制的十位数
  326.         x=bcd%16;//得到十进制的个位数
  327.         y=y*10+x;
  328.         return y;        
  329. }

  330. void keyscan()//菜单键按下扫描函数定义
  331. {
  332.         k0=1;
  333.         k1=1;
  334.         k2=1;
  335.         //判断菜单键k0是否按下
  336.         if(k0==0)
  337.         {
  338.                 delay(5);
  339.                 if(k0==0)
  340.                 {        
  341.                         while(!k0);//松手检测
  342.                         k0_num++;//记录菜单键k0是第几次按下,而判断是调节秒、分还是时。
  343.                         if(k0_num==1)//指示调节秒
  344.                         {
  345.                                 EX0=0;//关闭外部中断0,使时间走动停止,准备调时间
  346.                                 ds1307_write_date(0xd0,0,0x80|b_second);
  347.                                 lcd_write_com(0x80+0x40+11);//数据指针和光标移动秒出
  348.                                 lcd_write_com(0x0f);//使光标显示,并光标处字符格符闪烁,用来提示用户此时可以调节
  349.                                                                          //什么?是秒,是分还是时。        
  350.                         }
  351.                         if(k0_num==2)//指示调节分
  352.                         {
  353.                                 lcd_write_com(0x80+0x40+8);//数据指针和光标移动分出
  354.                         }
  355.                         if(k0_num==3)//指示调节时
  356.                         {
  357.                                 lcd_write_com(0x80+0x40+5);//数据指针和光标移动时出
  358.                         }
  359.                         if(k0_num==4)//退出时间调节菜单
  360.                         {
  361.                                 k0_num=0;//菜单键k0按下清零
  362.                                 lcd_write_com(0x0c);//恢复到时钟走动状态,即光标不显示,不闪烁
  363.                                 //将所调的时间转换成bcd码
  364.                                 b_second=dectobcd(second);
  365.                                 b_minute=dectobcd(minute);
  366.                                 b_hour=dectobcd(hour);
  367.                                 //将所调的时间向时钟写入
  368.                                 ds1307_write_date(0xd0,2,b_hour);
  369.                                 ds1307_write_date(0xd0,1,b_minute);        
  370.                                 ds1307_write_date(0xd0,0,b_second);

  371.                                 EX0=1;//开外部中断0,时间开始继续走动
  372.                         }
  373.                         
  374.                 }
  375.         }
  376.         //判断是否按下过时间调节菜单键k0,而处于需要调节时间状态
  377.         if(k0_num)
  378.         {
  379.                 //判断是否是上调键k1按下
  380.                 if(k1==0)
  381.                 {
  382.                         delay(5);
  383.                         if(k1==0)
  384.                         {
  385.                                 while(!k1);//松手检测
  386.                                 if(k0_num==1)//上调秒
  387.                                 {
  388.                                         second++;
  389.                                         if(second==60)
  390.                                                 second=0;
  391.                                         lcd_write_second(second);//向lcd写入被修改的时间
  392.                                         lcd_write_com(0x80+0x40+11);//光标位置重定位到所要调的时间处
  393.                                        
  394.                                 }
  395.                                 if(k0_num==2)//上调分
  396.                                 {
  397.                                         minute++;
  398. ……………………

  399. …………限于本文篇幅 余下代码请从51黑下载附件…………
复制代码

所有资料51hei提供下载:
DS1307实时时钟应用.rar (56.62 KB, 下载次数: 406)

评分

参与人数 1黑币 +50 收起 理由
admin + 50 共享资料的黑币奖励!

查看全部评分

回复

使用道具 举报

ID:210375 发表于 2018-3-18 14:34 | 显示全部楼层
看看看看,学习学习,dsn文件需要用 Proteus7.5版本来打开
回复

使用道具 举报

ID:150038 发表于 2018-4-14 22:54 | 显示全部楼层
太好了,学习学习
回复

使用道具 举报

ID:433509 发表于 2018-11-26 15:53 | 显示全部楼层
谢谢,希望东西是我想要的
回复

使用道具 举报

ID:433509 发表于 2018-11-26 16:12 | 显示全部楼层
谢谢,希望是我想要的资料
回复

使用道具 举报

ID:447180 发表于 2018-12-27 11:20 | 显示全部楼层
DS1307的手册时钟是100khZ,过高,过低是否可以,你用的晶振11.0592还是12M,有没有影响子
回复

使用道具 举报

ID:189330 发表于 2019-1-29 22:09 | 显示全部楼层

太好了,学习学习
回复

使用道具 举报

ID:478202 发表于 2019-2-19 17:14 | 显示全部楼层
写的太好了 学习一下
回复

使用道具 举报

ID:229821 发表于 2019-3-24 12:33 | 显示全部楼层
学习一下。谢谢啊!
回复

使用道具 举报

ID:497521 发表于 2019-3-24 21:03 | 显示全部楼层
学习一下,感谢分享!
回复

使用道具 举报

ID:73182 发表于 2019-3-25 09:45 | 显示全部楼层
感谢分享!
回复

使用道具 举报

ID:525478 发表于 2019-5-1 10:39 | 显示全部楼层
感谢分享  小白一个   分不够
回复

使用道具 举报

ID:156220 发表于 2019-6-5 17:46 | 显示全部楼层
谢谢,正在找DS1307资料
回复

使用道具 举报

ID:634897 发表于 2019-11-16 02:33 来自手机 | 显示全部楼层
1602无显示数据
回复

使用道具 举报

ID:648379 发表于 2019-11-24 22:14 | 显示全部楼层
今天正在学习电子钟,看到楼主的代码,收获颇多,谢谢楼主,学习了!
回复

使用道具 举报

ID:193022 发表于 2019-12-15 12:23 | 显示全部楼层
今天正在学习电子钟,看到楼主的代码,收获颇多,谢谢楼主,学习了!
回复

使用道具 举报

ID:439880 发表于 2019-12-22 13:45 | 显示全部楼层
支持一下啊
回复

使用道具 举报

ID:748788 发表于 2020-8-17 21:17 | 显示全部楼层
可以仿真,功能比较完善
回复

使用道具 举报

ID:841711 发表于 2020-11-20 16:12 | 显示全部楼层
时间可以调,日期调不了吗
回复

使用道具 举报

ID:991122 发表于 2021-12-12 09:33 | 显示全部楼层
时间可调,比ds1302更简洁
回复

使用道具 举报

ID:89537 发表于 2022-10-8 01:24 | 显示全部楼层
Proteus 8 打不开.dsn吗
回复

使用道具 举报

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

本版积分规则

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

Powered by 单片机教程网

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