当前位置:   article > 正文

基于51单片机的高精度时钟设计_1pps生成

1pps生成

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档

文章目录

  • 基本要求
  • 设计思路
  • 代码
  • 最终效果


基本要求

使用定时器/计数器实现电子钟,用LED数码管显示时、分、秒,24小时制,数码管上电初始显示为“12.00.00”,到24小时清零,然后反复,晶振11.0592MHz。理论误差小于0.1秒/天

扩展要求:简单的可调电子钟。增加“时增加”、“分增加”2个按键,按下“时增加”按键,时显示加1,加满24归零,按下“分增加”按键时,分显示加1,加满60归零。


设计思路

开启定时器中断,在定时器中断函数中设置时间变量,用于在main函数中计算小时, 分钟,秒。这里我采用的是定时器0的工作方式一,因为从定时,计数器产生中断请求到响应中断,需要3~8个机器周期。定时中断子程序中的数据人栈和重装定时,计数器的初值还需要占用数个机器周期。此外,从中断入口转到中断子程序也要占用一定的 机器周期。所以要在定时器中断中进行误差补偿,我开发板中用的是11.0592M的晶振, 那么一个机器周期为(1/11.0592M)*12,定时50ms为(50*10^-3)/机器周期=46080。可以 将TH0和TL0从产生溢出到被重新赋值的已有的计数值读出,并补偿到计数值初值中去,可以消除定时/计数器的定时误差。

先在定时器中断中禁止所有中断请求,关闭T0,即EA=0,TR0=0,将TL0中已计数 值写入修正变量fixtime,并加上修正操作所需的机器周期,经过仿真调试大概为10 个机器周期,即0x0A,所以fixtime=TL0+0x0A,再将fixtime赋给TL0,因为 (65536-46080)%256=0,所以新的TL0=0+fixtime,因为(65536-46080)/256=76=0x4C,且在 修正TL0时可能产生进位,要补偿到TH0,所以TH0=0x4C+(char)CY,CY为PSW寄存器中的进位标志位,之后再开启所有中断请求,开启T0,即EA=1,TR0=1。这样就完成了整个定时器误差补偿的过程。

利用数码管的动态扫描方式,将计算得出的时间分别给到给数码管显示数组中的常量表达式中,让数码管动态显示时间。

利用两个按键改变小时和分钟的数值,那么按键应进行消抖处理,且不能用while语句 进行按键释放处理,那样可能会导致数码管闪动。可以先定义一个有返回值的按键扫描 函数Key_Scan( ),让它返回按键值1或2,无按键按下则返回0。再定义一个按键处理 函数KEY_Handle( ),在函数中进行位运算,key_value用于记录按键 值,key_up用于记 录按键释放,key_down用于记录哪个按键按下,key_old用于记录上次的按键值,此函数可以实现“记忆”功能,即如果按键一直按着,也不会出现多次触发的现象,也解决了用while语句检测按键释放而导致数码管闪动的问题。再将此函数放入定时器1的中断处理函数中,进行每50ms一次的按键扫描,定时器1同样也进行误差补偿处理。

代码

代码如下:

  1. #include <reg52.h>
  2. #include <intrins.h>
  3. #define uchar unsigned char
  4. #define uint  unsigned int
  5.     
  6. sbit dula = P2^6;
  7. sbit wela = P2^7;
  8. sbit key1 = P3^4;
  9. sbit key2 = P3^5;
  10. uchar fixtime;    
  11. uint count_miao,count_fen0,count_fen1,count_shi,num_miao,num_fen,num_shi; 
  12. uint ge,shi,bai,qian,wan,shiwan;
  13. uchar key_value,key_up,key_down,key_old;
  14. float number,uwTick,uwTick_KEY;
  15. uchar table[] =
  16. {
  17.     0x3f,0x06,0x5b,0x4f,
  18.     0x66,0x6d,0x7d,0x07,
  19.     0x7f,0x6f,0x77,0x7c,
  20.     0x39,0x5e,0x79,0x71
  21. };
  22. uchar table_dot[]=
  23. {
  24.     0xbf,0x86,0xdb,0xcf,
  25.     0xe6,0xed,0xfd,0x87,
  26.     0xff,0xef,0xf7,0xfc,
  27.     0xb9,0xde,0xf9,0xf1
  28. };
  29. void delay(unsigned int x)
  30. {
  31.     unsigned int i,j;
  32.     for(i=1;i>0;i--)
  33.         for(j=x;j>0;j--);
  34. }
  35. void clean()
  36. {
  37.     wela = 1;
  38.     P0 = 0xff;
  39.     wela = 0;
  40.     
  41.     dula = 1;
  42.     P0 = 0x00;
  43.     dula = 0;
  44. }
  45. void dula_open()
  46. {
  47.     dula = 1;
  48.     dula = 0;
  49.     P0 = 0xff;
  50. }
  51. void wela_open()
  52. {
  53.     wela = 1;
  54.     wela = 0;
  55.     delay(1);
  56.     clean();
  57. }
  58. void display(uint shiwan,uint wan,uint qian,uint bai,uint shi,uint ge)
  59. {
  60.     P0 = table[shi];
  61.     dula_open();
  62.     
  63.     P0 = 0xef;
  64.     wela_open();
  65.     
  66.     P0 = table[ge];
  67.     dula_open();
  68.     
  69.     P0 = 0xdf;
  70.     wela_open();
  71.     
  72.     P0 = table[qian];
  73.     dula_open();
  74.     
  75.     P0 = 0xfb;
  76.     wela_open();
  77.     
  78.     P0 = table_dot[bai];
  79.     dula_open();
  80.     
  81.     P0 = 0xf7;
  82.     wela_open();
  83.     P0 = table[shiwan];
  84.     dula_open();
  85.     
  86.     P0 = 0xfe;
  87.     wela_open();
  88.     
  89.     
  90.     P0 = table_dot[wan];
  91.     dula_open();
  92.     
  93.     P0 = 0xfd;
  94.     wela_open();    
  95. }
  96. uchar key_scan()
  97. {
  98.     uchar key = 0;
  99.     if(key1 == 0)
  100.     {
  101.         return key = 1;
  102.     }
  103.     
  104.     if(key2 == 0)
  105.     {
  106.         return key = 2;
  107.     }
  108.     
  109.     return key;
  110. }
  111. void key_handle()
  112. {
  113.     key_value = key_scan();
  114.     key_down  = key_value & (key_value ^ key_old);
  115.     key_up    = ~key_value & (key_value ^ key_old);
  116.     key_old   = key_value;
  117.     if(key_down == 1)
  118.     {
  119.             num_shi++;
  120.             if(num_shi == 24)num_shi = 0;
  121.     }
  122.     
  123.     if(key_down == 2)
  124.     {
  125.         if(num_fen == 59)
  126.         {
  127.             num_fen = 0;
  128.             num_shi++;
  129.             if(num_shi == 24)num_shi=0;
  130.         }
  131.         else
  132.             num_fen++;
  133.     }
  134. }
  135. void T0_Handle_Program()
  136. {
  137.     if(count_miao == 20)
  138.     {
  139.         count_miao = 0;
  140.         num_miao++;
  141.         if(num_miao == 60)num_miao = 0;
  142.     }
  143.     
  144.     if(count_fen0 == 1200)
  145.     {
  146.         count_fen0 = 0;
  147.         num_fen++;
  148.         if(num_fen == 60)
  149.         {
  150.             num_fen=0;
  151.             num_shi++;
  152.             if(num_shi == 24)num_shi=0;
  153.         }
  154.         if(count_fen1 == 72000)
  155.         {
  156.             num_fen=0;
  157.         }
  158.     }
  159.     
  160.     if(count_shi == 72000)
  161.     {
  162.         count_shi = 0;
  163.         num_shi++;
  164.         if(num_shi == 24)num_shi = 0;        
  165.     }
  166. }
  167. void main()
  168. {
  169.     TMOD = 0x11;
  170.     TH0  = (65536-46080)/256;
  171.     TL0  = (65536-46080)%256;
  172.     TH1  = (65536-46080)/256;
  173.     TL1  = (65536-46080)%256;
  174.     EA   = 1;
  175.     ET0  = 1;
  176.     ET1  = 1;
  177.     TR0  = 1;
  178.     TR1  = 1;
  179.     
  180.     num_shi = 12;
  181.     while(1)
  182.     {        
  183.         
  184.         shiwan = num_shi/10;
  185.         wan        = num_shi%10;
  186.         qian = num_fen/10;
  187.         bai  = num_fen%10;
  188.         shi = num_miao/10;
  189.         ge  = num_miao%10;
  190.         display(shiwan,wan,qian,bai,shi,ge);
  191.     }
  192. }
  193. void T0_Handle() interrupt 1
  194. {
  195.     EA  = 0;
  196.     TR0 = 0;
  197.     fixtime = TL0+0x0A;
  198.     TL0 = fixtime;
  199.     TH0 = 0x4C+(char)CY;
  200.     EA = 1;
  201.     TR0 = 1;
  202.     count_fen0++;
  203.     count_fen1++;
  204.     count_shi++;
  205.     count_miao++;
  206.     
  207.     T0_Handle_Program();
  208. }
  209. void T1_Handle() interrupt 3
  210. {
  211.     EA  = 0;
  212.     TR1 = 0;
  213.     fixtime = TL1+0x0A;
  214.     TL1 = fixtime;
  215.     TH1 = 0x4C+(char)CY;
  216.     EA = 1;
  217.     TR1 = 1;
  218.     key_handle();
  219.     
  220. }


 

最终效果

误差:

可以看到在调试中,1分钟内的误差为0,理论误差满足设计要求。

效果:

 

 

 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/我家自动化/article/detail/562129?site
推荐阅读
相关标签
  

闽ICP备14008679号