找回密码
 立即注册

QQ登录

只需一步,快速开始

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

单片机+1302数码管时钟程序调不了时间

[复制链接]
ID:725922 发表于 2021-9-26 00:07 | 显示全部楼层 |阅读模式
参考了几个程序的核心部分,自己修改组合了一下,就想实现一个基本的可调时钟。一共3个按键,设置,加,减。按设置可以在时,分钟之间切换,同时相应位会闪烁。秒是采用的led指示,通过定时器中断试验出的计数值来控制,不是特别准确,主要起装饰作用。。目前的现象是,能按照初始时间走时,按设置能切换闪烁,但无法加减小时或者分钟,应该是往1302写数据的程序有问题,但也没看出来有什么问题,没有解决的思路了,希望各位高手指点一下错误。

单片机源程序如下:
  1. #include<reg52.h>
  2. #include <intrins.h>
  3. #define uint unsigned int
  4. #define uchar unsigned char
  5. uint milsec;
  6. uchar i,t,a,d,sec,hour,hour1,min,min1,flag,temp,key=0,S_flag=0,k=0;

  7. unsigned char led[12]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0xbf,0xff};  //用一维数组定义0-9、横杠、全灭

  8. unsigned char b[4]={0x07,0x0b,0x0d,0x0e}; //扫描

  9. unsigned char c[4];

  10. sbit dula=P2^6;
  11. sbit wela=P2^7;

  12. sbit SCLK=P1^0;    //1302接口
  13. sbit IO=P1^1;
  14. sbit RST=P1^2;

  15. sbit ACC0=ACC^0;
  16. sbit ACC7=ACC^7;

  17. //sbit key=P3^7;                //按键接口
  18. sbit key1=P3^3;
  19. sbit key2=P3^1;
  20. sbit key3=P3^2;
  21. sbit S5=P1^3;                 //指示秒的led

  22. void delay(uint xms)//ms延时函数
  23. {
  24.         uint x,y;
  25.         for(x=xms;x>0;x--)
  26.          for(y=110;y>0;y--);
  27. }


  28. /*********************over***********************/
  29. /********************ds1302****************************/
  30. void write_byte(uchar dat)
  31. {
  32.         ACC=dat;
  33.         RST=1;
  34.         for(a=8;a>0;a--)
  35.         {
  36.                 IO=ACC0;
  37.                 SCLK=0;
  38.                 SCLK=1;
  39.                 ACC=ACC>>1;
  40.         }
  41. }
  42. uchar read_byte()
  43. {
  44.         RST=1;
  45.         for(a=8;a>0;a--)
  46.         {
  47.                 ACC7=IO;
  48.                 SCLK=1;
  49.                 SCLK=0;
  50.                 ACC=ACC>>1;

  51.         }
  52.         return (ACC);
  53. }
  54. void write_1302(uchar add,uchar dat)
  55. {

  56.         RST=0;
  57.         SCLK=0;
  58.         RST=1;
  59.         write_byte(add);
  60.         write_byte(dat);
  61.         SCLK=1;
  62.         RST=0;
  63. }
  64. uchar read_1302(uchar add)
  65. {
  66.         uchar temp;
  67.         RST=0;
  68.         SCLK=0;
  69.         RST=1;
  70.         write_byte(add);
  71.         temp=read_byte();
  72.         SCLK=1;
  73.         RST=0;
  74.         return(temp);
  75. }
  76. uchar BCD_Decimal(uchar bcd)
  77. {
  78. uchar Decimal;
  79. Decimal=bcd>>4;
  80. return(Decimal=Decimal*10+(bcd&=0x0F));
  81. }

  82. uchar Decimal_BCD(uchar dec)
  83. {
  84.   uchar bcd;
  85.   bcd=((dec%10)&0x0f)|(((dec/10)<<4)&0xf0);
  86.   return bcd;
  87. }



  88. void ds1302_init()
  89. {
  90. RST=0;
  91. SCLK=0;
  92. write_1302(0x8e,0x00);          //关写保护

  93. write_1302(0xc0,0xfe);         
  94. write_1302(0xc2,0xff);
  95.         
  96. write_1302(0x80,0x00);  //写初始sec
  97. write_1302(0x82,0x10);        //写初始min
  98. write_1302(0x84,0x18);         //写初始hour
  99.         
  100. write_1302(0x8e,0x80);        //开写保护

  101. }




  102. void display()
  103. {
  104.         
  105.     switch(key)
  106.         {
  107.         case 0: c[0]=led[hour/10];
  108.                         c[1]=led[hour%10];
  109.                         c[2]=led[min/10];
  110.                     c[3]=led[min%10];
  111.                         break;

  112.         case 1:        if(S_flag==0)   
  113.             {     
  114.                         c[0]=led[hour/10];
  115.                         c[1]=led[hour%10];
  116.             }   
  117.             else   
  118.             {
  119.                         c[0]=0xff;
  120.                         c[1]=0xff;
  121.             }   
  122.                         
  123.                         c[2]=led[min/10];
  124.                         c[3]=led[min%10];
  125.                         break;

  126.         case 2:        c[0]=led[hour/10];
  127.                         c[1]=led[hour%10];
  128.                
  129.                 if(S_flag==0)   
  130.             {     
  131.                         c[2]=led[min/10];
  132.                         c[3]=led[min%10];
  133.             }   
  134.             else   
  135.             {
  136.                         c[2]=0xff;
  137.                         c[3]=0xff;
  138.             }  
  139.                         break;         

  140.         }                                       
  141. }
  142.         

  143. void init()
  144. {
  145.         TMOD=0x01;
  146.         TH0=0xfc;     //定时1ms   
  147.     TL0=0x18;
  148.         EA=1;
  149.         ET0=1;
  150.         TR0=1;
  151.         S5=0;
  152. }


  153. void cmg(void)//数码管锁存函数
  154. {
  155.         dula=1;
  156.         P0=0x00;
  157.         dula=0;
  158.         wela=1;
  159.         P0=0x00;
  160.         wela=0;
  161. }



  162. void keyscan()
  163. {

  164.         if(key1==0)//key1为功能键
  165.         {
  166.         delay(2);
  167.         if(key1==0)
  168.         {
  169.         //while(!key1);
  170.         for(i=0;((i<10)&&(key1==0));i++)          //检测按键释放
  171.     {
  172.     delay(1);
  173.     }
  174.         key++;
  175.         
  176.         if(key>2)
  177.         key=0;
  178.         
  179.         if(key!=0)
  180.         {

  181.         switch(key)
  182.         {
  183.         
  184.         case 1:  
  185.                  if(key2==0)                         //调时
  186.                  delay(2);
  187.                          if(key2==0)
  188.                          {
  189.                            
  190.                                 for(i=0;((i<10)&&(key2==0));i++)           //检测按键释放
  191.                                 {
  192.                                 delay(1);
  193.                                 }
  194.                         
  195.                             hour1=hour;
  196.                                 hour1++;
  197.                                 if(hour1>23)
  198.                                 hour1=0;
  199.                                  
  200.                                 temp=Decimal_BCD(hour1);
  201.                                 //temp=(hour1)/10*16+(hour1)%10;
  202.                                write_1302(0x8e,0x00);
  203.                                write_1302(0x84,temp);
  204.                               write_1302(0x8e,0x80);                                 
  205.                          }
  206.         
  207.                          if(key3==0)                        
  208.                  delay(2);
  209.                          if(key3==0)
  210.                          {
  211.                            
  212.                                 for(i=0;((i<10)&&(key3==0));i++)                   //检测按键释放
  213.                                 {
  214.                                 delay(1);
  215.                                 }
  216.                 hour1=hour;
  217.                                 hour1--;
  218.                                 if(hour1<0)
  219.                                 hour1=23;
  220.                            
  221.                                  //temp=Decimal_BCD(hour1);
  222.                                 temp=(hour1)/10*16+(hour1)%10;
  223.                                write_1302(0x8e,0x00);
  224.                                write_1302(0x84,temp);
  225.                               write_1302(0x8e,0x80);
  226.                                                                  
  227.                          }
  228.                
  229.                          break;

  230.         case 2:  if(key2==0)                         //调分
  231.                  delay(2);
  232.                          if(key2==0)
  233.                          {
  234.                                    for(i=0;((i<10)&&(key2==0));i++)
  235.                {
  236.                 delay(1);
  237.                }
  238.                                 if(min<59)
  239.                                 min++;
  240.                                 else
  241.                                 min=0;
  242.                                 //temp=(min)/10*16+(min)%10;
  243.                                  temp=Decimal_BCD(min);
  244.                              write_1302(0x8e,0x00);
  245.                                write_1302(0x82,temp);
  246.                     write_1302(0x80,0x00);          //miao复位
  247.                                write_1302(0x8e,0x80);                                         
  248.                          }
  249.                

  250.                          if(key3==0)                        
  251.                  delay(2);
  252.                          if(key3==0)
  253.                          {
  254.                             for(i=0;((i<10)&&(key3==0));i++)
  255.                 {
  256.                 delay(1);
  257.                 }
  258.                                 if(min>0)
  259.                                 min--;
  260.                                 else
  261.                                 min=59;
  262.                                 temp=(min)/10*16+(min)%10;
  263.                                  //temp=Decimal_BCD(min);
  264.                              write_1302(0x8e,0x00);
  265.                                write_1302(0x82,temp);
  266.                                 write_1302(0x80,0x00);          //miao复位
  267.                                write_1302(0x8e,0x80);                                 
  268.                          }

  269.                         break;
  270.         }
  271.          
  272.    }
  273.    }
  274.    }
  275. }
  276.                
  277.            
  278.                   

  279. void main()
  280. {

  281.     cmg();//数码管锁存 (关闭开发板数码管)
  282.         ds1302_init();
  283.         init();
  284.         while(1)
  285.         {
  286.           keyscan();
  287.           display();
  288.     }
  289. }


  290. void timer0() interrupt 1
  291. {
  292.     TH0=0xfc;     //定时1ms   
  293.     TL0=0x18;
  294.     //TL0 = (65536-1932)/256;        //设置定时初值                10ms
  295.     //TH0 = (65536-1932)%256;
  296.         //TH0=0xfb;     //定时ms   
  297.      //TL0=0x74;
  298.         /*t++;
  299.         if(t==255)
  300.         {
  301.             t=0;
  302.                 S5=!S5;
  303.         }
  304.          */
  305.         
  306.         d++;
  307.         if(d==20)
  308.         {
  309.         d=0;
  310.     write_1302(0x8e,0x00);
  311.         //sec = BCD_Decimal(read_1302(0x81));
  312.         min = BCD_Decimal(read_1302(0x83));
  313.         hour = BCD_Decimal(read_1302(0x85));
  314.         write_1302(0x8e,0x80);
  315.         }
  316.         
  317.         milsec++;
  318.         if(milsec==440)
  319.         {
  320.                 milsec=0;
  321.                 S_flag=!S_flag;
  322.                 S5=!S5;
  323.         }
  324.         
  325.     if(k==4)  
  326.     k=0;   
  327.     P0=c[k];     
  328.     P2=b[k++];      
  329.     delay(1);     
  330.     P2=0xff;
  331. }
复制代码


回复

使用道具 举报

ID:99987 发表于 2021-9-26 12:29 | 显示全部楼层
写入数据适当加延时或空操作,太快芯片反应不过来错误。
回复

使用道具 举报

ID:725922 发表于 2021-9-26 15:10 | 显示全部楼层
madell 发表于 2021-9-26 12:29
写入数据适当加延时或空操作,太快芯片反应不过来错误。

其实我也觉得可能是这个节奏上有问题,尤其是显示刷新的太快。
回复

使用道具 举报

ID:844772 发表于 2021-9-26 16:45 | 显示全部楼层
能否把写函数的这三句: IO=ACC0;  SCLK=0; SCLK=1;顺序改一下再加个延时,改为:  SCLK=0;  IO=ACC0;SCLK=1;_nop_(); 或者你再看看手册,按你写的时序,延时不够。
回复

使用道具 举报

ID:401564 发表于 2021-9-26 17:22 | 显示全部楼层
楼上已经有人说了,在读写时钟间增加延时
可以在调用函数时先让时钟线低电平SCLK=0;
这样的话,DS1302的SDA就会经历一个上升沿和一个下降沿,也就不用在乎它是上升沿写入还是下降沿写入了

IO=ACC0;
SCLK=1;
_nop_();
SCLK=0;
_nop_();
ACC=ACC>>1;
_nop_();
回复

使用道具 举报

ID:624769 发表于 2021-9-26 20:48 | 显示全部楼层
那么多人给你分析了代码,我就不看你的代码了, 就提几个关键的时序,
RST = 0    =>  RST =1     手册上要求最少 4us 间隔,实际测试 2us 的间隔是有必要的。
CLK = 0   =>   RST =1     手册上要求最少2us 间隔  实际测试最少 0.3us 是有必要的。
在STC8系列单片机, 24MHz 下。
IO = 0  =>   IO = 1     如IO有上拉电阻, 可在 IO = 1 后 立刻 CLK = 1
如没有上拉电阻,  IO = 1 后  最少 3个 NOP 才可以 CLK = 1
IO = 1   =>   IO =0     无论有没有上拉电阻,  IO =0 后 都可以立刻  CLK = 1
回复

使用道具 举报

ID:725922 发表于 2021-9-26 23:17 | 显示全部楼层
感谢各位的指点,我再看下。单片机水平还很菜,不过也在努力吧。
回复

使用道具 举报

ID:725922 发表于 2021-10-5 12:18 | 显示全部楼层
找到问题了,不是1302写不进去时间,是按键扫描函数有问题。。按下设置后,再次扫描按键函数时,因为检测不到按键按下,所以进不去函数了,因此也无法扫描到加减语句,修改if嵌套就好了。但是现在加减还是有点卡顿,需要慢一点按,偶尔不太灵,不过还能接受吧
回复

使用道具 举报

ID:725922 发表于 2021-10-5 12:47 | 显示全部楼层
按键卡顿,把keyscan()函数放中断里面,设置一个合理的扫描时间,灵敏度提高,有改善。
回复

使用道具 举报

ID:161164 发表于 2021-10-5 15:51 | 显示全部楼层
wdmcp 发表于 2021-10-5 12:47
按键卡顿,把keyscan()函数放中断里面,设置一个合理的扫描时间,灵敏度提高,有改善。

中断里不要放太多东西
不要用太长(>1ms)的delay
贴段代码让你参考一下
  1. void keyscan()
  2. {static u8 Delay_XD;//静态局部变数,离开函数后保持数值
  3. bit Key_Add, Key_Dec;//局部变数,离开函数后清零
  4.         if(!key1 || !key2 || !key3)//有键按下
  5.         {
  6.                 if(Delay_XD<0xFF)Delay_XD++;//消抖延时并限制溢出
  7.                 if(Delay_XD == 250)//延时250个周期
  8.                 {
  9.                         if(!key1)//功能键按下
  10.                         {
  11.                                 key++;
  12.                                 if(key>2)key=0;
  13.                         }
  14.                         if(!key2)//加键按下
  15.                         {
  16.                                 Key_Add = 1;//加标志位置1
  17.                         }
  18.                         if(!key3)//减键按下
  19.                         {
  20.                                 Key_Dec = 1;//减标志位置1
  21.                         }                       
  22.                 }
  23.         }else{
  24.                 Delay_XD = 0;//没有键按下清零
  25.         }
  26.         switch(key)
  27.         {
  28.                 case 1:
  29.                         if(Key_Add)
  30.                         {
  31.                                 hour1=hour;
  32.                                 hour1++;
  33.                                 if(hour1>23)
  34.                                         hour1=0;

  35.                                 temp=Decimal_BCD(hour1);
  36.                                 //temp=(hour1)/10*16+(hour1)%10;
  37.                                 write_1302(0x8e,0x00);
  38.                                 write_1302(0x84,temp);
  39.                                 write_1302(0x8e,0x80);
  40.                         }

  41.                         if(Key_Dec)
  42.                         {
  43.                                 hour1=hour;
  44.                                 hour1--;
  45.                                 if(hour1<0)
  46.                                         hour1=23;

  47.                                 //temp=Decimal_BCD(hour1);
  48.                                 temp=(hour1)/10*16+(hour1)%10;
  49.                                 write_1302(0x8e,0x00);
  50.                                 write_1302(0x84,temp);
  51.                                 write_1302(0x8e,0x80);
  52.                         }
  53.                         break;

  54.                 case 2:
  55.                         if(Key_Add)
  56.                         {
  57.                                 if(min<59)
  58.                                         min++;
  59.                                 else
  60.                                         min=0;
  61.                                 //temp=(min)/10*16+(min)%10;
  62.                                 temp=Decimal_BCD(min);
  63.                                 write_1302(0x8e,0x00);
  64.                                 write_1302(0x82,temp);
  65.                                 write_1302(0x80,0x00);          //miao复位
  66.                                 write_1302(0x8e,0x80);
  67.                         }

  68.                         if(Key_Dec)
  69.                         {
  70.                                 if(min>0)
  71.                                         min--;
  72.                                 else
  73.                                         min=59;
  74.                                 temp=(min)/10*16+(min)%10;
  75.                                 //temp=Decimal_BCD(min);
  76.                                 write_1302(0x8e,0x00);
  77.                                 write_1302(0x82,temp);
  78.                                 write_1302(0x80,0x00);          //miao复位
  79.                                 write_1302(0x8e,0x80);
  80.                         }
  81.                         break;
  82.                
  83.                 default:
  84.                         break;
  85.         }
  86. }
复制代码
回复

使用道具 举报

ID:725922 发表于 2021-10-5 20:10 | 显示全部楼层
lkc8210 发表于 2021-10-5 15:51
中断里不要放太多东西
不要用太长(>1ms)的delay
贴段代码让你参考一下

谢谢热心的回复。
回复

使用道具 举报

ID:824490 发表于 2021-10-7 11:57 | 显示全部楼层
判断问题要精准!
1302能走时,说明初始化正常,说明写入时间正常,说明写入代码没问题。不能设置时间,就去查按键代码了。

什么延时啊、节奏啊、中断啊、、、都是空的!除非你初始化用的不是与设置时间是2套写入代码。。
回复

使用道具 举报

ID:725922 发表于 2021-10-8 18:06 | 显示全部楼层
名字不是重点 发表于 2021-10-7 11:57
判断问题要精准!
1302能走时,说明初始化正常,说明写入时间正常,说明写入代码没问题。不能设置时间,就 ...

对,排查问题思路要清晰,我就有点糊涂了。开始以为是定时器读取频率太快,可能导致写入时间出问题,直到增加延时还不行,我才看出按键函数有大漏洞。。
回复

使用道具 举报

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

本版积分规则

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

Powered by 单片机教程网

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