找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 2645|回复: 12
收起左侧

用ds1302,80c51做电子日历但时间总是比实际时间慢很多

[复制链接]
回帖奖励 5 黑币 回复本帖可获得 5 黑币奖励! 每人限 1 次
ID:657799 发表于 2019-12-12 18:45 | 显示全部楼层 |阅读模式
电子日历.png
这是电路仿真
下面程序实际运行中每分钟大概落后实际时间十几秒
不知道是哪里的问题。DS1302外接晶振是32768HZ
  1. #include<reg51.h>
  2. #include<DS18B20_3.H> //   程序中使用的头文件DS18B20_3.H
  3. //十进制温度最后返回到函数ReadTemperature()flag=ReadTemperature();
  4. //就可将18b2头文件运行返回的函数结果送到变量FLAG中,用于显示。
  5. #define uint unsigned int
  6. #define uchar unsigned char
  7. uchar a,miao,shi,fen,ri,yue,nian,week,flag,key1n,temp;
  8. //flag用于读取头文件中的温度值,和显示温度值
  9. #define yh 0x80 //LCD第一行的初始位置,因为LCD1602字符地址首位D7恒定为1(100000000=80)
  10. #define er 0x80+0x40 //LCD第二行初始位置(因为第二行第一个字符位置地址是0x40)
  11. //液晶屏的与C51之间的引脚连接定义(显示数据线接C51的P0口)
  12. sbit rs=P3^5;
  13. sbit en=P3^4;
  14. sbit rw=P3^6;
  15. //DS1302时钟芯片与C51之间的引脚连接定义
  16. sbit IO=P1^0;
  17. sbit SCLK=P1^1;
  18. sbit RST=P1^2;
  19. sbit ACC0=ACC^0;
  20. sbit ACC7=ACC^7;
  21. /*
  22. ACC累加器=A
  23. ACC.0=E0H
  24. ACC.0就是ACC的第0位。Acc可以位寻址。
  25. */
  26. //校时按键与C51的引脚连接定义
  27. sbit key1=P3^0;  //设置键
  28. sbit key2=P3^1;  //加键
  29. sbit key3=P3^2;  //减键
  30. sbit key4=P3^3;         //退出键
  31. uchar code tab1[]={"20  -  -   "}; //年显示的固定字符
  32. uchar code tab2[]={"  :  :    T=  "};//时间、温度显示的固定字符
  33. /*延时函数,后面经常调用*/
  34. void delay(uint xms)//延时函数,有参函数
  35. {
  36.         uint x,y;
  37.         for(x=xms;x>0;x--)
  38.          for(y=110;y>0;y--);
  39. }
  40. /*液晶写入指令函数与写入数据函数,以后可调用*/
  41. /*在这个程序中,液晶写入有关函数会在DS1302的函数中调用,所以液晶程序要放在前面*/
  42. write_1602com(uchar com)//****液晶写入指令函数****
  43. {
  44.         rs=0;//数据/指令选择,高电平选择数据寄存器,低电平选择指令寄存器
  45.         rw=0; //读写选择,高电平进行读操作,低电平进行写操作
  46.         P0=com;//送入数据
  47.         delay(1);
  48.         en=1;//拉高使能端,为制造有效的下降沿做准备
  49.         delay(1);
  50.         en=0;//en由高变低,产生下降沿,液晶执行命令
  51. }
  52. /*液晶写入数据函数*/
  53. write_1602dat(uchar dat)
  54. {
  55.         rs=1;//数据/指令选择为数据
  56.         rw=0; //读写选择为写
  57.         P0=dat;//送入数据
  58.         delay(1);
  59.         en=1; //en置高电平,为制造下降沿做准备
  60.         delay(1);
  61.         en=0; //en由高变低,产生下降沿,液晶执行命令
  62. }
  63. /*液晶初始化函数*/
  64. lcd_init()
  65. {
  66.         write_1602com(0x38);//设置液晶工作模式,意思:16*2行显示,5*7点阵,8位数据
  67.         write_1602com(0x0c);//开显示不显示光标
  68.         write_1602com(0x06);//整屏不移动,光标自动右移
  69.         write_1602com(0x01);//清显示
  70.         write_1602com(yh+0);//日历显示固定符号从第一行第0个位置之后开始显示
  71.         for(a=0;a<12;a++)
  72.         {
  73.         write_1602dat(tab1[a]);//向液晶屏写日历显示的固定符号部分,即{"20  -  -   "}
  74.         }
  75.         write_1602com(er+0);//时间显示固定符号写入位置,从第0个位置后开始显示
  76.         for(a=0;a<13;a++)
  77.         {
  78.         write_1602dat(tab2[a]);//写显示时间、温度固定符号,两个冒号,T=
  79.         }
  80. }
  81. /*DS1302有关子函数*/
  82. void write_byte(uchar dat)//写一个字节
  83. {
  84.         ACC=dat;
  85.         RST=1;
  86.         for(a=8;a>0;a--)
  87.         {
  88.                 IO=ACC0;
  89.                 SCLK=0;
  90.                 SCLK=1;
  91.                 ACC=ACC>>1;
  92.         }
  93. }
  94. uchar read_byte()//读一个字节
  95. {
  96.         RST=1;
  97.         for(a=8;a>0;a--)
  98.         {
  99.                 ACC7=IO;
  100.                 SCLK=1;
  101.                 SCLK=0;
  102.                 ACC=ACC>>1;
  103.         }
  104.         return (ACC);
  105. }
  106. void write_1302(uchar add,uchar dat)//向1302芯片写函数,指定写入地址,数据
  107. {
  108.         RST=0;
  109.         SCLK=0;
  110.         RST=1;
  111.         write_byte(add);
  112.         write_byte(dat);
  113.         SCLK=1;
  114.         RST=0;
  115. }
  116. uchar read_1302(uchar add)//从1302读数据函数,指定读取数据来源地址
  117. {
  118.         uchar temp;
  119.         RST=0;
  120.         SCLK=0;
  121.         RST=1;
  122.         write_byte(add);
  123.         temp=read_byte();
  124.         SCLK=1;
  125.         RST=0;
  126.         return(temp);
  127. }
  128. uchar BCD_Decimal(uchar bcd)//BCD码转十进制函数,输入BCD,返回十进制
  129. {
  130. uchar Decimal;
  131. Decimal=bcd>>4;
  132. return(Decimal=Decimal*10+(bcd&=0x0F));
  133. }
  134. //--------------------------------------
  135. void ds1302_init() //1302芯片初始化子函数(2019-12-12,13:00:00,Thu)
  136. {
  137. RST=0;
  138. SCLK=0;
  139. write_1302(0x8e,0x00); //允许写,禁止写保护
  140. //以下为初始值设置,不启用由DS1302芯片读取实时时钟
  141. //write_1302(0x80,0x00); //向DS1302内写秒寄存器80H写入初始秒数据00
  142. //write_1302(0x82,0x00);//向DS1302内写分寄存器82H写入初始分数据00
  143. //write_1302(0x84,0x13);//向DS1302内写小时寄存器84H写入初始小时数据13
  144. //write_1302(0x8a,0x04);//向DS1302内写周寄存器8aH写入初始周数据4
  145. //write_1302(0x86,0x12);//向DS1302内写日期寄存器86H写入初始日期数据12
  146. //write_1302(0x88,0x12);//向DS1302内写月份寄存器88H写入初始月份数据12
  147. //write_1302(0x8c,0x19);//向DS1302内写年份寄存器8cH写入初始年份数据19
  148. write_1302(0x8e,0x80); //打开写保护
  149. }
  150. /*温度显示子函数*/
  151. void write_temp(uchar add,uchar dat)//向LCD写温度数据,并指定显示位置
  152. {
  153.         uchar gw,sw;
  154.         gw=dat%10;//取得个位数字
  155.         sw=dat/10;//取得十位数字
  156.         write_1602com(er+add);//er是头文件规定的值0x80+0x40,显示为液晶屏第二行
  157.         write_1602dat(0x30+sw);//数字+30得到该数字的LCD1602显示码
  158.         write_1602dat(0x30+gw);//数字+30得到该数字的LCD1602显示码
  159.     write_1602dat(0xdf);//显示温度的小圆圈符号,0xdf是液晶屏字符库的该符号地址码
  160.           write_1602dat(0x43);        //显示"C"符号,0x43是液晶屏字符库里大写C的地址码               
  161. }
  162. /*时分秒显示子函数*/
  163. void write_sfm(uchar add,uchar dat)//向LCD写时分秒,有显示位置加数、显示数据,两个参数
  164. {
  165.         uchar gw,sw;
  166.         gw=dat%10;//取得个位数字
  167.         sw=dat/10;//取得十位数字
  168.         write_1602com(er+add);//er是头文件规定的值0x80+0x40
  169.         write_1602dat(0x30+sw);//数字+30得到该数字的LCD1602显示码
  170.         write_1602dat(0x30+gw);//数字+30得到该数字的LCD1602显示码                               
  171. }
  172. /*年月日显示子函数*/
  173. void write_nyr(uchar add,uchar dat)//向LCD写年月日,有显示位置加数、显示数据,两个参数
  174. {
  175.         uchar gw,sw;
  176.         gw=dat%10;//取得个位数字
  177.         sw=dat/10;//取得十位数字
  178.         write_1602com(yh+add);//设定显示位置为第一个位置+add
  179.         write_1602dat(0x30+sw);//数字+30得到该数字的LCD1602显示码
  180.         write_1602dat(0x30+gw);//数字+30得到该数字的LCD1602显示码       
  181. }
  182. /*星期显示子函数*/
  183. void write_week(uchar week)//写星期函数
  184. {
  185.         write_1602com(yh+0x0b);//星期字符的显示位置
  186.         switch(week)
  187.         {
  188.                    case 1:write_1602dat('S');//星期数据为1时显示
  189.                            write_1602dat('u');
  190.                            write_1602dat('n');
  191.                            break;
  192.                 case 2:write_1602dat('M');//星期数据为2时显示
  193.                            write_1602dat('o');
  194.                            write_1602dat('n');
  195.                            break;
  196.           
  197.                 case 3:write_1602dat('T');//星期数据为3时显示
  198.                            write_1602dat('u');
  199.                            write_1602dat('e');
  200.                            break;
  201.                
  202.                 case 4:write_1602dat('W');//星期数据为4时显示
  203.                            write_1602dat('e');
  204.                            write_1602dat('d');
  205.                            break;
  206.                
  207.                 case 5:write_1602dat('T');//星期数据为5是显示
  208.                            write_1602dat('h');
  209.                            write_1602dat('u');
  210.                            break;
  211.                
  212.                 case 6:write_1602dat('F');//星期数据为6时显示
  213.                            write_1602dat('r');
  214.                            write_1602dat('i');
  215.                            break;
  216.                
  217.                 case 7:write_1602dat('S');//星期数据为7时显示
  218.                            write_1602dat('a');
  219.                            write_1602dat('t');
  220.                            break;
  221. }
  222. }
  223. /*键盘扫描有关函数*/
  224. void keyscan()
  225. {
  226.         if(key1==0)//---------------key1为功能键(设置键)--------------------
  227.         {
  228.         delay(9);//延时,用于消抖动
  229.         if(key1==0)//延时后再次确认按键按下
  230.         {
  231.         while(!key1);
  232.                 key1n++;
  233.         if(key1n==9)
  234.                 key1n=1;//设置按键共有秒、分、时、星期、日、月、年、返回,8个功能循环
  235.         switch(key1n)
  236.         {       
  237.         case 1: TR0=0;//关闭定时器
  238.                         write_1602com(er+0x06);//设置按键按动一次,秒位置显示光标
  239.                            write_1602com(0x0f);//设置光标为闪烁
  240.                            temp=(miao)/10*16+(miao)%10;//秒数据写入DS1302
  241.                            write_1302(0x8e,0x00);
  242.                            write_1302(0x80,0x80|temp);//miao
  243.                       write_1302(0x8e,0x80);
  244.                            break;
  245.         case 2:  write_1602com(er+3);//按2次fen位置显示光标
  246.                         break;
  247.         case 3: write_1602com(er+0);//按动3次,shi
  248.                         break;
  249.         case 4: write_1602com(yh+0x0e);//按动4次,week                  
  250.                         break;
  251.         case 5: write_1602com(yh+0x08);//按动5次,ri                     
  252.                         break;
  253.         case 6: write_1602com(yh+0x05);//按动6次,yue                    
  254.                         break;
  255.         case 7: write_1602com(yh+0x02);//按动7次,nian                     
  256.                         break;
  257.         case 8: write_1602com(0x0c);//按动到第8次,设置光标不闪烁
  258.                    TR0=1;//打开定时器
  259.            temp=(miao)/10*16+(miao)%10;//十进制转换成DS1302要求的DCB码
  260.                    write_1302(0x8e,0x00);
  261.                    write_1302(0x80,0x00|temp);//miao数据写入DS1302
  262.                    write_1302(0x8e,0x80);
  263.             break;                                                                                                                                               
  264.         }                           
  265.         }          
  266.         }
  267. //key4直接 退出键,退出键按下,直接退出调整状态,进入走时。
  268. if(key1n!=0)
  269. {
  270.         if(key4==0)         //退出键按下,直接退出调整状态,进入走时。
  271.         {
  272.                 delay(10);
  273.                 if(key4==0)
  274.                 {
  275.                         key1n=0,
  276.                         write_1602com(0x0c);//设置光标不闪烁
  277.                         TR0=1;//打开定时器
  278.                         temp=(miao)/10*16+(miao)%10;//十进制转换成DS1302要求的DCB码
  279.                     write_1302(0x8e,0x00);
  280.                     write_1302(0x80,0x00|temp);//miao数据写入DS1302
  281.                     write_1302(0x8e,0x80);                  
  282.                 }
  283.         }
  284. }          
  285. //------------------------------加键key2----------------------------               
  286.         if(key1n!=0)//当key1按下以下。再按以下键才有效(按键次数不等于零)
  287.         {
  288.         if(key2==0)  //上调键
  289.         {
  290.         delay(10);
  291.         if(key2==0)
  292.         {                   
  293.                 while(!key2);
  294.         switch(key1n)
  295.         {
  296.         case 1:miao++;//设置键按动1次,调秒
  297.                         if(miao==60)
  298.                                 miao=0;//秒超过59,再加1,就归零
  299.                         write_sfm(0x06,miao);//令LCD在正确位置显示"加"设定好的秒数
  300.                         temp=(miao)/10*16+(miao)%10;//十进制转换成DS1302要求的DCB码
  301.                            write_1302(0x8e,0x00); //允许写,禁止写保护
  302.                            write_1302(0x80,temp); //向DS1302内写秒寄存器80H写入调整后的秒数据BCD码
  303.                            write_1302(0x8e,0x80); //打开写保护
  304.                         write_1602com(er+0x06);//因为设置液晶的模式是写入数据后,光标自动右移,所以要指定返回               
  305.                         break;
  306.         case 2:fen++;
  307.                         if(fen==60)
  308.                                 fen=0;
  309.                         write_sfm(0x03,fen);//令LCD在正确位置显示"加"设定好的分数据
  310.                         temp=(fen)/10*16+(fen)%10;//十进制转换成DS1302要求的DCB码
  311.                            write_1302(0x8e,0x00);//允许写,禁止写保护
  312.                            write_1302(0x82,temp);//向DS1302内写分寄存器82H写入调整后的分数据BCD码
  313.                            write_1302(0x8e,0x80);//打开写保护
  314.                         write_1602com(er+3);//因为设置液晶的模式是写入数据后,指针自动加一,在这里是写回原来的位置
  315.                         break;
  316.         case 3:shi++;
  317.                         if(shi==24)
  318.                                 shi=0;
  319.                         write_sfm(0,shi);//令LCD在正确的位置显示"加"设定好的小时数据
  320.                         temp=(shi)/10*16+(shi)%10;//十进制转换成DS1302要求的DCB码
  321.                            write_1302(0x8e,0x00);//允许写,禁止写保护
  322.                            write_1302(0x84,temp);//向DS1302内写小时寄存器84H写入调整后的小时数据BCD码
  323.                            write_1302(0x8e,0x80);//打开写保护
  324.                         write_1602com(er+0);//因为设置液晶的模式是写入数据后,指针自动加一,所以需要光标回位
  325.                         break;
  326.         case 4:week++;
  327.                         if(week==8)
  328.                                 week=1;
  329.             write_1602com(yh+0x0C);//指定'加'后的周数据显示位置
  330.                                 write_week(week);//指定周数据显示内容
  331.             temp=(week)/10*16+(week)%10;//十进制转换成DS1302要求的DCB码
  332.                            write_1302(0x8e,0x00);//允许写,禁止写保护
  333.                            write_1302(0x8a,temp);//向DS1302内写周寄存器8aH写入调整后的周数据BCD码
  334.                            write_1302(0x8e,0x80);//打开写保护
  335.                            write_1602com(yh+0x0e);//因为设置液晶的模式是写入数据后,指针自动加一,所以需要光标回位
  336.                         break;
  337.         case 5:ri++;
  338.                         if(ri==32)
  339.                                 ri=1;
  340.                         write_nyr(8,ri);//令LCD在正确的位置显示"加"设定好的日期数据
  341.                         temp=(ri)/10*16+(ri)%10;//十进制转换成DS1302要求的DCB码
  342.                            write_1302(0x8e,0x00);//允许写,禁止写保护
  343.                            write_1302(0x86,temp);//向DS1302内写日期寄存器86H写入调整后的日期数据BCD码
  344.                            write_1302(0x8e,0x80);//打开写保护
  345.                         write_1602com(yh+8);//因为设置液晶的模式是写入数据后,指针自动加一,所以需要光标回位
  346.                         break;
  347.         case 6:yue++;
  348.                         if(yue==13)
  349.                                 yue=1;
  350.                         write_nyr(5,yue);//令LCD在正确的位置显示"加"设定好的月份数据
  351.                         temp=(yue)/10*16+(yue)%10;//十进制转换成DS1302要求的DCB码
  352.                            write_1302(0x8e,0x00);//允许写,禁止写保护
  353.                            write_1302(0x88,temp);//向DS1302内写月份寄存器88H写入调整后的月份数据BCD码
  354.                            write_1302(0x8e,0x80);//打开写保护
  355.                         write_1602com(yh+5);//因为设置液晶的模式是写入数据后,指针自动加一,所以需要光标回位
  356.                         break;
  357.         case 7:nian++;
  358.                  if(nian==100)
  359.                         nian=0;
  360.                         write_nyr(2,nian);//令LCD在正确的位置显示"加"设定好的年份数据
  361.             temp=(nian)/10*16+(nian)%10;//十进制转换成DS1302要求的DCB码
  362.                            write_1302(0x8e,0x00);//允许写,禁止写保护
  363.                            write_1302(0x8c,temp);//向DS1302内写年份寄存器8cH写入调整后的年份数据BCD码
  364.                            write_1302(0x8e,0x80);//打开写保护
  365.                         write_1602com(yh+2);//因为设置液晶的模式是写入数据后,指针自动加一,所以需要光标回位
  366.                         break;                       
  367.         }
  368.         }
  369.         }
  370. //------------------减键key3,各句功能参照'加键'注释---------------
  371.         if(key3==0)
  372.         {
  373.         delay(10);//调延时,消抖动
  374.         if(key3==0)
  375.         {   
  376.         while(!key3);
  377.         switch(key1n)
  378.         {
  379.                 case 1:miao--;
  380.                                 if(miao==-1)
  381.                                         miao=59;//秒数据减到-1时自动变成59
  382.                         write_sfm(0x06,miao);//在LCD的正确位置显示改变后新的秒数
  383.             temp=(miao)/10*16+(miao)%10;//十进制转换成DS1302要求的DCB码
  384.                            write_1302(0x8e,0x00); //允许写,禁止写保护
  385.                            write_1302(0x80,temp); //向DS1302内写秒寄存器80H写入调整后的秒数据BCD码
  386.                            write_1302(0x8e,0x80); //打开写保护
  387.                         write_1602com(er+0x06);//因为设置液晶的模式是写入数据后,指针自动加一,在这里是写回原来的位置                       
  388.                         break;
  389.                 case 2:fen--;
  390.                                 if(fen==-1)
  391.                                         fen=59;
  392.                         write_sfm(3,fen);
  393.                         temp=(fen)/10*16+(fen)%10;//十进制转换成DS1302要求的DCB码
  394.                            write_1302(0x8e,0x00);//允许写,禁止写保护
  395.                            write_1302(0x82,temp);//向DS1302内写分寄存器82H写入调整后的分数据BCD码
  396.                            write_1302(0x8e,0x80);//打开写保护
  397.                         write_1602com(er+3);//因为设置液晶的模式是写入数据后,指针自动加一,在这里是写回原来的位置
  398.                         break;
  399.                 case 3:shi--;
  400.                            if(shi==-1)
  401.                                         shi=23;
  402.                         write_sfm(0,shi);
  403.                         temp=(shi)/10*16+(shi)%10;//十进制转换成DS1302要求的DCB码
  404.                            write_1302(0x8e,0x00);//允许写,禁止写保护
  405.                            write_1302(0x84,temp);//向DS1302内写小时寄存器84H写入调整后的小时数据BCD码
  406.                            write_1302(0x8e,0x80);//打开写保护
  407.                         write_1602com(er+0);//因为设置液晶的模式是写入数据后,指针自动加一,所以需要光标回位
  408.                         break;
  409.                 case 4:week--;
  410.                                 if(week==0)
  411.                                         week=7;                         
  412.             write_1602com(yh+0x0C);//指定'加'后的周数据显示位置
  413.                         write_week(week);//指定周数据显示内容
  414.                         temp=(week)/10*16+(week)%10;//十进制转换成DS1302要求的DCB码
  415.                            write_1302(0x8e,0x00);//允许写,禁止写保护
  416.                            write_1302(0x8a,temp);//向DS1302内写周寄存器8aH写入调整后的周数据BCD码
  417.                            write_1302(0x8e,0x80);//打开写保护
  418.                            write_1602com(yh+0x0e);//因为设置液晶的模式是写入数据后,指针自动加一,所以需要光标回位
  419.                         break;
  420.                 case 5:ri--;
  421.                                 if(ri==0)
  422.                                         ri=31;
  423.                         write_nyr(8,ri);
  424.                         temp=(ri)/10*16+(ri)%10;//十进制转换成DS1302要求的DCB码
  425.                            write_1302(0x8e,0x00);//允许写,禁止写保护
  426.                            write_1302(0x86,temp);//向DS1302内写日期寄存器86H写入调整后的日期数据BCD码
  427.                            write_1302(0x8e,0x80);//打开写保护
  428.                         write_1602com(yh+8);//因为设置液晶的模式是写入数据后,指针自动加一,所以需要光标回位
  429.                         break;
  430.                 case 6:yue--;
  431.                                 if(yue==0)
  432.                                         yue=12;
  433.                         write_nyr(5,yue);
  434.                         temp=(yue)/10*16+(yue)%10;//十进制转换成DS1302要求的DCB码
  435.                            write_1302(0x8e,0x00);//允许写,禁止写保护
  436.                            write_1302(0x88,temp);//向DS1302内写月份寄存器88H写入调整后的月份数据BCD码
  437.                            write_1302(0x8e,0x80);//打开写保护
  438.                         write_1602com(yh+5);//因为设置液晶的模式是写入数据后,指针自动加一,所以需要光标回位
  439.                         break;       
  440.                 case 7:nian--;
  441.                  if(nian==-1)
  442.                         nian=99;
  443.                         write_nyr(2,nian);
  444.          temp=(nian)/10*16+(nian)%10;//十进制转换成DS1302要求的DCB码
  445.                            write_1302(0x8e,0x00);//允许写,禁止写保护
  446.                            write_1302(0x8c,temp);//向DS1302内写年份寄存器8cH写入调整后的年份数据BCD码
  447.                            write_1302(0x8e,0x80);//打开写保护
  448.                         write_1602com(yh+2);//因为设置液晶的模式是写入数据后,指针自动加一,所以需要光标回位
  449.                         break;                                                       
  450.         }
  451.         }
  452.         }
  453.         }
  454. }
  455. //-------------------------------
  456. void init() //定时器、计数器设置函数
  457. {
  458.         TMOD=0x03; //指定定时/计数器的工作方式为3
  459.         TH0=0;  //定时器T0的高四位=0
  460.         TL0=0;  //定时器T0的低四位=0
  461.         EA=1;  //系统允许有开放的中断
  462.         ET0=1; //允许T0中断
  463.         TR0=1; //开启中断,启动定时器
  464. }
  465. /*主函数*/
  466. void main()
  467. {
  468.         lcd_init();      //调用液晶屏初始化子函数
  469.         ds1302_init();   //调用DS1302时钟的初始化子函数
  470.         init();          //调用定时计数器的设置子函数
  471.         while(1)  //无限循环下面的语句:
  472.         {       
  473.             keyscan();      //调用键盘扫描子函数       
  474.     }
  475. }
  476. void timer0() interrupt 1 //其后的1为定时器T0的中端编号
  477. {       
  478.    flag=ReadTemperature();//将18b2头文件运行返回的函数结果送到变量FLAG中,用于显示
  479.   //读取秒时分周日月年七个数据(DS1302的读寄存器与写寄存器不一样):
  480.                   //取得并显示日历和时间
  481.     miao = BCD_Decimal(read_1302(0x81));
  482.         fen = BCD_Decimal(read_1302(0x83));
  483.         shi  = BCD_Decimal(read_1302(0x85));
  484.         ri  = BCD_Decimal(read_1302(0x87));
  485.         yue = BCD_Decimal(read_1302(0x89));
  486.         nian=BCD_Decimal(read_1302(0x8d));
  487.         week=BCD_Decimal(read_1302(0x8b));
  488.         //显示温度、秒、时、分数据:  
  489.     write_temp(12,flag);//显示温度,从第二行第12个字符后开始显示
  490.     write_sfm(6,miao);//秒,从第二行第6个字后开始显示(调用时分秒显示子函数)
  491.         write_sfm(3,fen);//分,从第二行第3个字符后开始显示
  492.         write_sfm(0,shi);//小时,从第二行第0个字符后开始显示       
  493.         //显示日、月、年数据:
  494.         write_nyr(8,ri);//日期,从第一行第8个字符后开始显示
  495.     write_nyr(5,yue);//月份,从第一行第5个字符后开始显示
  496.         write_nyr(2,nian);//年,从第一行第2个字符后开始显示
  497.         write_week(week);
  498. }
复制代码


回复

使用道具 举报

ID:591385 发表于 2019-12-12 20:29 | 显示全部楼层
单片机的晶振频率是多少
回复

使用道具 举报

ID:278179 发表于 2019-12-12 21:03 | 显示全部楼层
一般我遇到这样的情况,直接换晶振,程序只要不是自动修改调整DS1302,在只读取的情况下,不会造成时间不准
回复

使用道具 举报

ID:657799 发表于 2019-12-12 22:16 | 显示全部楼层
dwhdeng 发表于 2019-12-12 20:29
单片机的晶振频率是多少

单片机12MHZ,DS1302外接32768HZ
回复

使用道具 举报

ID:657799 发表于 2019-12-12 22:44 来自手机 | 显示全部楼层
dwhdeng 发表于 2019-12-12 20:29
单片机的晶振频率是多少

单片机的晶振频率是12Mhz
回复

使用道具 举报

ID:662869 发表于 2019-12-12 23:01 | 显示全部楼层
晶振32768
回复

使用道具 举报

ID:662923 发表于 2019-12-13 01:02 | 显示全部楼层
DS1302的晶振有误差或者是晶振坏了,换一个试下。
回复

使用道具 举报

ID:235200 发表于 2019-12-13 02:04 | 显示全部楼层
这种情况是时钟芯片所接的32768Hz晶振误差太大,需要购买误差±5ppm的晶振,一天的误差不超过5秒,再经过测试误差,在每日的零点过后把误差用程序修正,时钟就很准了
回复

使用道具 举报

ID:10193 发表于 2019-12-13 07:57 | 显示全部楼层
DS1302方案精度不容易最好,试试DS3231内置晶振
回复

使用道具 举报

ID:655165 发表于 2019-12-13 08:23 来自手机 | 显示全部楼层
晶振误差调节
回复

使用道具 举报

ID:401564 发表于 2019-12-13 09:02 | 显示全部楼层
DS1302晶振的两个脚要接两个小电容的,大概每个是5-15pF左右,如果你有仪器就可以测试一下精度,如果没有就只能先给它走上十天半个月,然后再调节,这和单片机晶振是没有关系的
但你这个是一分钟慢十几秒,太离谱了,你看一下是不是其它的什么问题,正常来说一天误差一分钟还差不多,不会有你这个这么离谱的
回复

使用道具 举报

ID:663135 发表于 2019-12-13 14:12 | 显示全部楼层
应该是单片机与外接模块不同步,单片机调下等待时间
回复

使用道具 举报

ID:657799 发表于 2019-12-16 14:04 来自手机 | 显示全部楼层
已经解决了,我做了实物完全没有问题,误差很小。应该是Proteus仿真本来就和实际有所差距
回复

使用道具 举报

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

本版积分规则

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

Powered by 单片机教程网

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