找回密码
 立即注册

QQ登录

只需一步,快速开始

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

ds1302是如何实现按键改时间的,能麻烦大佬看一下吗?

[复制链接]
跳转到指定楼层
楼主
ID:1149524 发表于 2025-5-4 15:20 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
  1. #include<reg52.h>
  2. #include<intrins.h>
  3. #include<STDIO.H>
  4. #include<string.h>
  5. #define uchar unsigned  char
  6. #define uint  unsigned   int
  7. sbit k1=P1^0;
  8. /////////////////////////////////////////////////LCD12864串行显示相关驱动///////////////////////////
  9. uchar code num[]={"0123456789:.-"};//此数组用于显示数字转码
  10. uchar time_buf[8] = {0x20,0x23,0x05,0x04,0x09,0x09,0x55,0x04};//用于DS1302放置设置相关数据,此处初始时间2010年6月1号23点59分55秒 星期二
  11. uchar dis_time_buf[16]={0};//用于放置折分开的DS1302读回的数据,可用于LCD——12864显示
  12. //////////第一步,设置LCD12864串行显示所需的I/O口线,硬件接线图////////////////////////////////////
  13. sbit   CS    =  P3 ^5;        //片选 高电平有效 单片LCD使用时可固定高电平
  14. sbit   SID   =  P3 ^6;        //数据
  15. sbit   SCLK  =  P3 ^4;        //时钟
  16. sbit   PSB  =  P3 ^7;        //串并切换,0串,1并
  17. ////////////////DS1302引脚定义硬件接线图//////////////////////////////////////////////////////////
  18. sbit RST=P2^3;
  19. sbit IO=P2^2;
  20. sbit SCK=P2^1;
  21. //////////////////////////////////////////////////////////////////////////////////////////////////
  22. //LCD_12864专用延时函数
  23. void Delaynms(uint di) //延时
  24. {
  25.         uint da,db;
  26.          for(da=0;da<di;da++)
  27.                    for(db=0;db<10;db++);
  28. }
  29. //LCD_12864专用单字节必用函数
  30. void Send_byte(uchar bbyte) //发送一个字节
  31. {
  32.         uchar i;
  33.          for(i=0;i<8;i++)
  34.            {
  35.                    SID=bbyte&0x80; //取出最高位
  36.                  SCLK=1;
  37.                    SCLK=0;
  38.                    bbyte<<=1; //左移
  39.            }  
  40. }
  41. //LCD_12864写指令字节必用函数
  42. void Write_char(bit start, uchar ddata) //写指令或数据
  43. {
  44.         uchar start_data,Hdata,Ldata;
  45.           if(start==0)
  46.                 start_data=0xf8;         //写指令
  47.     else   
  48.             start_data=0xfa;  //写数据

  49.           Hdata=ddata&0xf0;                  //取高四位
  50.           Ldata=(ddata<<4)&0xf0;  //取低四位
  51.           Send_byte(start_data);          //发送起始信号
  52.           Delaynms(5); //延时是必须的
  53.           Send_byte(Hdata);              //发送高四位
  54.           Delaynms(1);  //延时是必须的
  55.           Send_byte(Ldata);                  //发送低四位
  56.           Delaynms(1);  //延时是必须的
  57. }
  58. //LCD_12864初始化函数,在显示之前必需先初始化
  59. void Lcd_init()        //初始化LCD
  60. {        
  61.           PSB=0;//串型模式
  62.           Delaynms(10); //启动等待,等LCM讲入工作状态
  63.           CS=1;
  64.           Write_char(0,0x30);  //8 位介面,基本指令集
  65.           Write_char(0,0x0c);  //显示打开,光标关,反白关
  66.           Write_char(0,0x01);  //清屏,将DDRAM的地址计数器归零  
  67. }
  68. //LCD_12864清屏函数,在需要清屏时调用
  69. void Clr_Scr()//清屏函数
  70. {
  71.         Write_char(0,0x01);
  72. }
  73. //LCD_12864设置显示行、列函数,X为行,Y为列
  74. void LCD_set_xy( uchar x, uchar y )
  75. {        //设置LCD显示的起始位置,X为行,Y为列
  76.     uchar address;
  77.         switch(x)
  78.         {  
  79.     case 1: address = 0x80 + y; break;
  80.                 case 2: address = 0x90 + y; break;
  81.            case 3: address = 0x88 + y; break;
  82.                 case 4: address = 0x98 + y; break;
  83.                 default:address = 0x80 + y; break;
  84.         }
  85.     Write_char(0, address);
  86. }
  87. //LCD_12864调用数组显示字串函数,包括汉字,X,Y为起始位置,S为数组名
  88. void LCD_Write_string(uchar X,uchar Y,uchar *s)
  89. {        //        中英文字符串显示函数
  90.         LCD_set_xy( X, Y );

  91.     while (*s)
  92.     {
  93.                         Write_char( 1, *s );
  94.                         s++;
  95.                         Delaynms(1);
  96.           }
  97. }
  98. //LCD_12864显示数字函数,
  99. void LCD_Write_number(uchar s)//数字显示函数
  100. {        
  101.         Write_char(1,num[s]);
  102.         Delaynms(1);
  103. }
  104. /////////////////////////////////////////////////LCD12864串行显示相关驱动///////////////////////////
  105. ////////////////////////////////////////////////DS1302驱动代码/////////////////////////////////////
  106. //DS1302地址定义,必需要有的程序
  107. #define ds1302_sec_add                          0x80                //秒数据地址
  108. #define ds1302_min_add                          0x82                //分数据地址
  109. #define ds1302_hr_add                            0x84                //时数据地址
  110. #define ds1302_date_add                          0x86                //日数据地址
  111. #define ds1302_month_add                  0x88                //月数据地址
  112. #define ds1302_day_add                          0x8a                //星期数据地址
  113. #define ds1302_year_add                          0x8c                //年数据地址
  114. #define ds1302_control_add                0x8e                //控制数据地址
  115. #define ds1302_charger_add                0x90                                          
  116. #define ds1302_clkburst_add                0xbe
  117. //DS1302初始化函数,使用时第一步用此函数初始化
  118. void ds1302_init()
  119. {
  120.         RST=0;                        //RST脚置低
  121.         SCK=0;                        //SCK脚置低
  122. }
  123. //向DS1302写入一字节数据,addr为地址,d为要写入的数据
  124. void ds1302_write_byte(uchar addr, uchar d)
  125. {
  126.         uchar i;
  127.         RST=1;                                        //启动DS1302总线        
  128.         //写入目标地址:addr
  129.         addr = addr & 0xFE;     //最低位 置零,寄存器 0位为0时写,为1时读
  130.         for (i = 0; i < 8; i ++)
  131.         {
  132.                 if (addr & 0x01)            //为0
  133.                 {
  134.                         IO=1;                        //输入
  135.                         }
  136.                 else
  137.                 {
  138.                         IO=0;
  139.                         }
  140.                 SCK=1;      //产生时钟
  141.                 SCK=0;
  142.                 addr = addr >> 1;  //右移1位
  143.                 }        
  144.         //写入数据:d
  145.         for (i = 0; i < 8; i ++) {
  146.                 if (d & 0x01)                  //为0
  147.                 {
  148.                         IO=1;                   //输入
  149.                         }
  150.                 else
  151.                 {
  152.                         IO=0;
  153.                         }
  154.                 SCK=1;    //产生时钟
  155.                 SCK=0;
  156.                 d = d >> 1;                   //右移1位
  157.                 }
  158.         RST=0;                //停止DS1302总线
  159. }
  160. //从DS1302读出一字节数据,addr为地址
  161. uchar ds1302_read_byte(uchar addr)
  162. {
  163.         uchar i,temp;        
  164.         RST=1;                                        //启动DS1302总线
  165.         //写入目标地址:addr
  166.         addr = addr | 0x01;    //最低位 置高,寄存器0位为0时写,为1时读
  167.         for (i = 0; i < 8; i ++) {
  168.                 if (addr & 0x01)
  169.                 {
  170.                         IO=1;
  171.                         }
  172.                 else
  173.                 {
  174.                         IO=0;
  175.                         }
  176.                 SCK=1;          //产生时钟
  177.                 SCK=0;
  178.                 addr = addr >> 1;        //右移1位
  179.                 }        
  180.         //输出数据:temp
  181.         for (i = 0; i < 8; i ++)
  182.         {
  183.                 temp = temp >> 1;        //右移1位
  184.                 if (IO)                 
  185.                 {
  186.                         temp |= 0x80;  //temp=temp|0x80         
  187.                         }
  188.                 else {
  189.                         temp &= 0x7F;         //temp=temp&0x80        
  190.                         }
  191.                 SCK=1;         //产生时钟
  192.                 SCK=0;
  193.                 }        
  194.         RST=0;                                        //停止DS1302总线
  195.         return temp;
  196. }
  197. //向DS1302写入时钟数据
  198. void ds1302_write_time()
  199. {
  200.         ds1302_write_byte(ds1302_control_add,0x00);                        //关闭写保护
  201.         ds1302_write_byte(ds1302_sec_add,0x80);                                //暂停时钟  
  202.         ds1302_write_byte(ds1302_year_add,time_buf[1]);                //年
  203.         ds1302_write_byte(ds1302_month_add,time_buf[2]);        //月
  204.         ds1302_write_byte(ds1302_date_add,time_buf[3]);                //日
  205.         ds1302_write_byte(ds1302_hr_add,time_buf[4]);     //时
  206.         ds1302_write_byte(ds1302_min_add,time_buf[5]);                //分
  207.         ds1302_write_byte(ds1302_sec_add,time_buf[6]);                //秒
  208.         ds1302_write_byte(ds1302_day_add,time_buf[7]);                //周
  209.         ds1302_write_byte(ds1302_control_add,0x80);                        //打开写保护     
  210. }
  211. //从DS1302读出时钟数据
  212. void ds1302_read_time()  
  213. {
  214.         time_buf[1]=ds1302_read_byte(ds1302_year_add);                //年
  215.         time_buf[2]=ds1302_read_byte(ds1302_month_add);                //月
  216.         time_buf[3]=ds1302_read_byte(ds1302_date_add);                //日
  217.         time_buf[4]=ds1302_read_byte(ds1302_hr_add);                //时
  218.         time_buf[5]=(ds1302_read_byte(ds1302_min_add))&0x7f;//分
  219.         time_buf[6]=(ds1302_read_byte(ds1302_sec_add))&0x7f;//秒,屏蔽秒的第7位,避免超出59
  220.         time_buf[7]=ds1302_read_byte(ds1302_day_add);                //周         
  221. }

  222. //////设置数据位置////////
  223. //用于将DS1302读回的数据,进行折分,折分后放入全局变量数组dis_time_buf[]中,以便显示调用
  224. void time_read_address (uchar *TUMP)
  225. {
  226.         uchar i,a;
  227.   ds1302_read_time();//读回的数据放在全局变量  dis_time_buf[]数组中
  228.         for(a=0,i=0;i<14;i=i+2,a++)/////做循环,让数据不断追加在数组里
  229.         {
  230.                 dis_time_buf[i]=(time_buf[a]>>4);     //取高四位
  231.                 dis_time_buf[i+1]=(time_buf[a]&0x0f);  //取低四位
  232.         }
  233.         if(i==14)
  234.         {
  235.      dis_time_buf[i]=(time_buf[7]&0x07);  ///星期单字节
  236.         }

  237. ////////显示位置////////////
  238.         LCD_set_xy(1,0);
  239.         LCD_Write_number(TUMP[0]);
  240.         LCD_Write_number(TUMP[1]);
  241.         LCD_set_xy(1,1);
  242.         LCD_Write_number(TUMP[2]);
  243.         LCD_Write_number(TUMP[3]);
  244.         LCD_set_xy(1,3);
  245.         LCD_Write_number(TUMP[4]);
  246.         LCD_Write_number(TUMP[5]);
  247.         LCD_set_xy(1,5);
  248.         LCD_Write_number(TUMP[6]);
  249.         LCD_Write_number(TUMP[7]);
  250.         LCD_set_xy(3,0);
  251.         LCD_Write_number(TUMP[8]);
  252.         LCD_Write_number(TUMP[9]);
  253.         LCD_set_xy(3,2);
  254.         LCD_Write_number(TUMP[10]);
  255.         LCD_Write_number(TUMP[11]);
  256.         LCD_set_xy(3,4);
  257.         LCD_Write_number(TUMP[12]);
  258.         LCD_Write_number(TUMP[13]);
  259.         LCD_set_xy(2,2);
  260.         LCD_Write_number(TUMP[14]);        
  261. }
  262. ////时间显示位置//////
  263. void  xianshi()
  264. {
  265.         LCD_Write_string(1,0,"    年  月  日");
  266.         LCD_Write_string(2,0,"星期");
  267.         LCD_Write_string(3,0,"  时  分  秒");
  268. }

  269. ////主程序///////
  270. void main()
  271. {
  272.         Lcd_init(); //第一步LCD12864初始化
  273.   Clr_Scr(); //清屏
  274.   Delaynms(200);//延时为了稳定
  275.         ds1302_init();     //DS1302初始化
  276.   Delaynms(1000);//为了稳定必需加延时///
  277.   ds1302_write_time();    //向DS1302写入初始年月时间值
  278.         xianshi();
  279.         while(1)
  280.         {
  281.                 time_read_address(dis_time_buf);
  282.                 if(k1==0)
  283.                 {time_read_address(dis_time_buf);}
  284.                 Delaynms(600);
  285.         }
  286. }
复制代码

T0_arm.pdf

155.1 KB, 下载次数: 0

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

使用道具 举报

沙发
ID:1133081 发表于 2025-5-5 06:25 | 只看该作者
你这个程序不完整,K1形同虚设。给你一个示例参考。 4位数码管DS1302单键调时时钟 DS18B20程序 仿真.rar (153.84 KB, 下载次数: 0)

回复

使用道具 举报

板凳
ID:584814 发表于 2025-5-5 08:30 | 只看该作者
本坛找个ds1302时钟的工程文件,里面详细。
回复

使用道具 举报

地板
ID:469589 发表于 2025-5-5 09:34 | 只看该作者
你能启动ds1302,就能知道怎么停止,好像修改前需要停止,然后修改、再启动即可。
回复

使用道具 举报

5#
ID:1109793 发表于 2025-5-5 11:22 | 只看该作者
GlenXu 发表于 2025-5-5 09:34
你能启动ds1302,就能知道怎么停止,好像修改前需要停止,然后修改、再启动即可。

还需要停止?不是直接写入就行吗?
回复

使用道具 举报

6#
ID:69038 发表于 2025-5-5 11:49 | 只看该作者
GlenXu 发表于 2025-5-5 09:34
你能启动ds1302,就能知道怎么停止,好像修改前需要停止,然后修改、再启动即可。

不需要停止。
是你在修改之前,
要先取得RTC的时间做为基数,
然后对这个基数修改,
改完后把这个基数写入RTC中相应的地址就OK了。
回复

使用道具 举报

7#
ID:1149524 发表于 2025-5-5 13:35 | 只看该作者
WL0123 发表于 2025-5-5 06:25
你这个程序不完整,K1形同虚设。给你一个示例参考。

非常感谢。
回复

使用道具 举报

8#
ID:1149524 发表于 2025-5-5 13:35 | 只看该作者
man1234567 发表于 2025-5-5 08:30
本坛找个ds1302时钟的工程文件,里面详细。

非常感谢。
回复

使用道具 举报

9#
ID:1149524 发表于 2025-5-5 13:36 | 只看该作者
GlenXu 发表于 2025-5-5 09:34
你能启动ds1302,就能知道怎么停止,好像修改前需要停止,然后修改、再启动即可。

是的,我主要是想搞懂,就是如何通过按键来调它的时间。的确可以通过代码来改变初始的时间。。
回复

使用道具 举报

10#
ID:1109793 发表于 2025-5-5 14:09 | 只看该作者
单片机初学者336 发表于 2025-5-5 13:36
是的,我主要是想搞懂,就是如何通过按键来调它的时间。的确可以通过代码来改变初始的时间。。

把新数据放到对应变量,然后调用写入函数写入就OK了吧
至于新数据怎么来的,按键还是其他的渠道,都行
回复

使用道具 举报

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

本版积分规则

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

Powered by 单片机教程网

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