找回密碼
 立即注冊(cè)

QQ登錄

只需一步,快速開(kāi)始

搜索
查看: 6580|回復(fù): 16
打印 上一主題 下一主題
收起左側(cè)

51單片機(jī)做數(shù)字鐘 定時(shí)器中斷有誤差 如何提高精度

[復(fù)制鏈接]
跳轉(zhuǎn)到指定樓層
樓主
20黑幣
    使用51單片機(jī)做一個(gè)簡(jiǎn)單的數(shù)字鐘,但是用定時(shí)器中斷時(shí),進(jìn)入中斷服務(wù)函數(shù)時(shí)會(huì)有機(jī)器周期,會(huì)產(chǎn)生誤差。    怎么減少這種誤差?或者如果用補(bǔ)償?shù)姆绞皆黾佣〞r(shí)器的初值,應(yīng)該怎么計(jì)算需要補(bǔ)償?shù)臄?shù)值?
    以下部分代碼是我使用補(bǔ)償修正值的方式,但是修正值不正確。

u8 fixtime; //定義修正變量

void time0_init(void)
{
        TMOD |= 0X01;  //選擇為定時(shí)器0模式,工作方式1,僅用TR0打開(kāi)啟動(dòng)。

        TH0 = 0XD8;           //給定時(shí)器賦初值,定時(shí)10ms
        TL0 = 0XF0;       
        ET0 = 1;       //打開(kāi)定時(shí)器0中斷允許
        EA = 1;        //打開(kāi)總中斷
        TR0 = 1;       //打開(kāi)定時(shí)器                       
}

void Timer0() interrupt 1
{
        EA = 0;//禁止所有中斷請(qǐng)求
        TR0 = 0;//關(guān)閉T0
        fixtime = TL0 + 0X1B;//將TL0中已計(jì)數(shù)值寫(xiě)入fixtime,并加上修正操作占用的27個(gè)機(jī)器周期
        TL0 = 0XF0 + fixtime;//將修正值寫(xiě)入TL0
        TH0 = 0XD8 + (char)CY;//修正TL0時(shí)可能產(chǎn)生進(jìn)位,要補(bǔ)償?shù)絋H0
        EA = 1;//允許所有中斷請(qǐng)求
        TR0 = 1;//開(kāi)啟TR0
        msec++;
        if(msec == 100)          //1sec = 1000ms
        {
                msec = 0;
                sec++;
        }
        if(sec == 60)            //1min = 60sec
        {
                sec = 0;
                min++;
        }
        if(min == 60)            //1hour = 60min
        {
                min = 0;
                hour++;
        }
}


最佳答案

查看完整內(nèi)容

仿真受PC時(shí)鐘影響,不一定準(zhǔn),要用實(shí)物驗(yàn)證。仿真用不了STC89C52的EEPROM保存fixtime變量。給你基本補(bǔ)齊了。
分享到:  QQ好友和群QQ好友和群 QQ空間QQ空間 騰訊微博騰訊微博 騰訊朋友騰訊朋友
收藏收藏 分享淘帖 頂 踩
回復(fù)

使用道具 舉報(bào)

沙發(fā)
ID:213173 發(fā)表于 2020-5-18 18:59 | 只看該作者
LOVEqing 發(fā)表于 2020-5-20 18:47
#include
#include "lcd.h"
#define uint unsigned int

仿真受PC時(shí)鐘影響,不一定準(zhǔn),要用實(shí)物驗(yàn)證。仿真用不了STC89C52的EEPROM保存fixtime變量。給你基本補(bǔ)齊了。






  1. //適用STC89C52RC單片機(jī)
  2. #include <reg52.h>
  3. #include <intrins.h>
  4. #define uint unsigned int
  5. #define uchar unsigned char

  6. //定義ISP的操作命令
  7. #define RdCommand 0x01                //讀命令
  8. #define PrgCommand 0x02                //寫(xiě)命令
  9. #define EraseCommand 0x03        //擦除命令
  10. #define Error 1
  11. #define Ok 0
  12. #define WaitTime 0x01                 //定義CPU的等待時(shí)間,寫(xiě)入硬件延時(shí)
  13. //STC89系列EEPROM寄存器聲明
  14. sfr ISP_DATA=0xe2;                //0000,0000 EEPROM數(shù)據(jù)寄存器
  15. sfr ISP_ADDRH=0xe3;                //0000,0000 EEPROM地址高字節(jié)
  16. sfr ISP_ADDRL=0xe4;                //0000,0000 EEPROM地址第字節(jié)
  17. sfr ISP_CMD=0xe5;                //xxxx,xx00 EEPROM命令寄存器
  18. sfr ISP_TRIG=0xe6;                //0000,0000 EEPRPM命令觸發(fā)寄存器
  19. sfr ISP_CONTR=0xe7;                //0000,x000 EEPROM控制寄存器

  20. sbit key0=P3^3;
  21. sbit key1=P3^4;
  22. sbit key2=P3^5;
  23. sbit rs=P2^6;         //寄存器選擇信號(hào) H:數(shù)據(jù)寄存器          L:指令寄存器
  24. sbit rw=P2^5;         //寄存器選擇信號(hào) H:數(shù)據(jù)寄存器          L:指令寄存器
  25. sbit e =P2^7;         //片選信號(hào)   下降沿觸發(fā)
  26. uchar sec=0,min=0,hour=12;
  27. uchar num=0;
  28. uint  usec=0;
  29. //uint  fixtime=10000; //定義修正變量
  30. uint  fixtime;        //定義修正變量
  31. bit   sec_flag=0;    //秒標(biāo)志

  32. // 打開(kāi) ISP,IAP 功能
  33. void ISP_IAP_enable(void)
  34. {
  35.         EA = 0;       /* 關(guān)中斷   */
  36.         ISP_CONTR = ISP_CONTR & 0x18;       /* 0001,1000 */
  37.         ISP_CONTR = ISP_CONTR | WaitTime; /* 寫(xiě)入硬件延時(shí) */
  38.         ISP_CONTR = ISP_CONTR | 0x80;       /* ISPEN=1  */
  39. }
  40. // 關(guān)閉 ISP,IAP 功能
  41. void ISP_IAP_disable(void)
  42. {
  43.         ISP_CONTR = ISP_CONTR & 0x7f; /* ISPEN = 0 */
  44.         ISP_TRIG = 0x00;
  45.         EA   =   1;   /* 開(kāi)中斷 */
  46. }
  47. // 公用的觸發(fā)代碼
  48. void ISPgoon(void)
  49. {
  50.         ISP_IAP_enable();   /* 打開(kāi) ISP,IAP 功能 */
  51.         ISP_TRIG = 0x46;  /* 觸發(fā)ISP_IAP命令字節(jié)1 */
  52.         ISP_TRIG = 0xb9;  /* 觸發(fā)ISP_IAP命令字節(jié)2 */
  53.         _nop_();
  54. }
  55. // 字節(jié)讀
  56. unsigned char byte_read(unsigned int byte_addr)
  57. {
  58.         ISP_ADDRH = (unsigned char)(byte_addr >> 8);/* 地址賦值 */
  59.         ISP_ADDRL = (unsigned char)(byte_addr & 0x00ff);
  60.         ISP_CMD   = ISP_CMD & 0xf8;   /* 清除低3位  */
  61.         ISP_CMD   = ISP_CMD | RdCommand; /* 寫(xiě)入讀命令 */
  62.         ISPgoon();       /* 觸發(fā)執(zhí)行  */
  63.         ISP_IAP_disable();    /* 關(guān)閉ISP,IAP功能 */
  64.         return (ISP_DATA);    /* 返回讀到的數(shù)據(jù) */
  65. }
  66. // 扇區(qū)擦除
  67. void SectorErase(unsigned int sector_addr)
  68. {
  69.         unsigned int iSectorAddr;
  70.         iSectorAddr = (sector_addr & 0xfe00); /* 取扇區(qū)地址 */
  71.         ISP_ADDRH = (unsigned char)(iSectorAddr >> 8);
  72.         ISP_ADDRL = 0x00;
  73.         ISP_CMD = ISP_CMD & 0xf8;   /* 清空低3位  */
  74.         ISP_CMD = ISP_CMD | EraseCommand; /* 擦除命令3  */
  75.         ISPgoon();       /* 觸發(fā)執(zhí)行  */
  76.         ISP_IAP_disable();    /* 關(guān)閉ISP,IAP功能 */
  77. }
  78. // 字節(jié)寫(xiě)
  79. void byte_write(unsigned int byte_addr, unsigned char original_data)
  80. {
  81.         ISP_ADDRH = (unsigned char)(byte_addr >> 8);  /* 取地址  */
  82.         ISP_ADDRL = (unsigned char)(byte_addr & 0x00ff);
  83.         ISP_CMD  = ISP_CMD & 0xf8;    /* 清低3位 */
  84.         ISP_CMD  = ISP_CMD | PrgCommand;  /* 寫(xiě)命令2 */
  85.         ISP_DATA = original_data;   /* 寫(xiě)入數(shù)據(jù)準(zhǔn)備 */
  86.         ISPgoon();       /* 觸發(fā)執(zhí)行  */
  87.         ISP_IAP_disable();     /* 關(guān)閉IAP功能 */
  88. }
  89. /********************************************************************
  90. * 名稱 : delay_uint()
  91. * 功能 : 小延時(shí)。
  92. * 輸入 : 無(wú)
  93. * 輸出 : 無(wú)
  94. ***********************************************************************/
  95. void delay_uint(uint i)
  96. {
  97.         while(--i);
  98. }

  99. /********************************************************************
  100. * 名稱 : write_com(uchar com)
  101. * 功能 : 1602命令函數(shù)
  102. * 輸入 : 輸入的命令值
  103. * 輸出 : 無(wú)
  104. ***********************************************************************/
  105. void write_com(uchar com)
  106. {
  107.         e=0;
  108.         rs=0;
  109.         rw=0;
  110.         P0=com;
  111.         delay_uint(25);
  112.         e=1;
  113.         delay_uint(25);
  114.         e=0;
  115. }

  116. /********************************************************************
  117. * 名稱 : write_data(uchar dat)
  118. * 功能 : 1602寫(xiě)數(shù)據(jù)函數(shù)
  119. * 輸入 : 需要寫(xiě)入1602的數(shù)據(jù)
  120. * 輸出 : 無(wú)
  121. ***********************************************************************/
  122. void write_data(uchar dat)
  123. {
  124.         e=0;
  125.         rs=1;
  126.         rw=0;
  127.         P0=dat;
  128.         delay_uint(25);
  129.         e=1;
  130.         delay_uint(25);
  131.         e=0;       
  132. }
  133. /***********************lcd1602初始化設(shè)置************************/
  134. void init_1602()
  135. {
  136.         write_com(0x38);       
  137.         write_com(0x0c);
  138.         write_com(0x06);
  139.         write_com(0x01);
  140. }
  141. void time0_init(void)
  142. {
  143.     TMOD = 0x02;//自動(dòng)重裝
  144.     TH0 = 0x9C; //100us
  145.     TL0 = 0x9C;
  146.     EA = 1;
  147.     ET0 = 1;
  148.     TR0 = 1;
  149. }

  150. void LCD1602_init(void)
  151. {
  152.         uchar i;
  153.         uchar a[]=" Digital Clock  ";
  154.         write_com(0x80);
  155.         for(i=0;i<16;i++)
  156.                 write_data(a[i]);
  157. }

  158. void display(void)
  159. {
  160.         write_com(0xc0+13);
  161.         if(num==0)
  162.                 write_data(' ');
  163.         else if(num==1)
  164.                 write_data('H');
  165.         else if(num==2)
  166.                 write_data('M');
  167.         else if(num==3)
  168.                 write_data('S');
  169.         write_com(0x80+0x44);
  170.         if(num==4)
  171.         {
  172.                 write_data('F');
  173.                 write_data('=');
  174.                 write_data('=');
  175.                 write_data(fixtime/10000%10+'0');
  176.                 write_data(fixtime/1000%10+'0');
  177.                 write_data(fixtime/100%10+'0');
  178.                 write_data(fixtime/10%10+'0');
  179.                 write_data(fixtime%10+'0');
  180.                 write_data(' ');
  181.                 write_data(' ');
  182.         }
  183.         else
  184.         {
  185.                 write_data(hour/10+'0');
  186.                 write_data(hour%10+'0');
  187.                 write_data(':');
  188.                 write_data(min/10+'0');
  189.                 write_data(min%10+'0');
  190.                 write_data(':');
  191.                 write_data(sec/10+'0');
  192.                 write_data(sec%10+'0');
  193.         }
  194. }

  195. void keyscan()
  196. {
  197.         static bit key_lock=0;        //按鍵自鎖標(biāo)志
  198.         static uchar count=0;        //消抖計(jì)數(shù)變量               
  199.         uchar i=0,a,b;
  200.         if(!key0||!key1||!key2)
  201.         {
  202.                 if(++count>=10 && key_lock==0)
  203.                 {
  204.                         key_lock=1;//自鎖
  205.                         if(!key0)
  206.                         {
  207.                                 num++;
  208.                                 num%=5;
  209.                         }
  210.                         if(!key1 && num>0)
  211.                         {
  212.                                 switch(num)
  213.                                 {
  214.                                         case 1: hour++;if(hour>=24)hour=0; break;
  215.                                         case 2: min++; if(min>=60) min=0;  break;
  216.                                         case 3: sec++; if(sec>=60) sec=0;  break;
  217.                                         case 4: fixtime++;
  218.                                                         a=fixtime>>8;
  219.                                                         b=fixtime;
  220.                                                         SectorErase(0x2000);//擦除扇區(qū)
  221.                                                         byte_write(0x2000,a);//重新寫(xiě)入數(shù)據(jù)高8位
  222.                                                         byte_write(0x2001,b);//重新寫(xiě)入數(shù)據(jù)低8位
  223.                                                         break;
  224.                                         default:  break;
  225.                                 }
  226.                         }
  227.                         if(!key2 && num>0)
  228.                         {
  229.                                 switch(num)
  230.                                 {
  231.                                         case 1: hour--;if(hour>=24)hour=23; break;
  232.                                         case 2: min--; if(min>=60) min=59;  break;
  233.                                         case 3: sec--; if(sec>=60) sec=59;  break;
  234.                                         case 4: fixtime--;
  235.                                                         a=fixtime>>8;
  236.                                                         b=fixtime;
  237.                                                         SectorErase(0x2000);//擦除扇區(qū)
  238.                                                         byte_write(0x2000,a);//重新寫(xiě)入數(shù)據(jù)高8位
  239.                                                         byte_write(0x2001,b);//重新寫(xiě)入數(shù)據(jù)低8位
  240.                                                         break;
  241.                                         default:  break;
  242.                                 }
  243.                         }
  244.                 }
  245.         }
  246.         else   //松手
  247.         {
  248.                 count=0;
  249.                 key_lock=0;
  250.         }
  251. }

  252. void Timing()//計(jì)時(shí)程序
  253. {
  254.         if(sec_flag)
  255.         {
  256.                 sec_flag=0;
  257.                 sec++;
  258.                 if(sec >= 60)
  259.                 {
  260.                         sec = 0;
  261.                         min++;
  262.                         if(min >= 60)
  263.                         {
  264.                                 min = 0;
  265.                                 hour++;
  266.                                 if(hour >= 24)
  267.                                         hour=0;
  268.                         }
  269.                 }
  270.         }
  271. }

  272. void main()
  273. {
  274.         init_1602();
  275.         LCD1602_init();
  276.         fixtime=byte_read(0x2000);//程序開(kāi)始時(shí)讀取EEPROM中數(shù)據(jù)
  277.         fixtime=fixtime<<8|byte_read(0x2001);//合并為整形數(shù)據(jù)
  278.         if(fixtime>15000||fixtime<5000) //防止首次上電時(shí)讀取出錯(cuò)
  279.                 fixtime=10000;
  280.         time0_init();
  281.         while(1)
  282.         {
  283.                 keyscan();
  284.                 Timing();
  285.                 display();
  286.         }
  287. }

  288. void Timer0() interrupt 1
  289. {
  290.         if(++usec>=fixtime)  //1sec
  291.         {
  292.                 usec = 0;
  293.                 sec_flag=1;
  294.         }
  295. }
復(fù)制代碼



STC99封裝.zip

26.37 KB, 下載次數(shù): 7

回復(fù)

使用道具 舉報(bào)

板凳
ID:584814 發(fā)表于 2020-5-19 11:08 | 只看該作者
如果僅用單片機(jī)內(nèi)部時(shí)鐘,除調(diào)整晶振頻率等硬件外,軟件通過(guò)調(diào)整定時(shí)器的初值,計(jì)算值加實(shí)驗(yàn)修正。
想獲得精準(zhǔn)時(shí)鐘,直接外部時(shí)鐘便宜且方便。
回復(fù)

使用道具 舉報(bào)

地板
ID:267719 發(fā)表于 2020-5-19 11:34 | 只看該作者
用方式2,自動(dòng)重載模式。定時(shí)到比如100us。這樣就只有相鄰誤差,沒(méi)有累計(jì)誤差。
晶振匹配不同的電容,實(shí)際的頻率也是有誤差的。這個(gè)補(bǔ)償要累計(jì)去計(jì)算的,比如1個(gè)月后,誤差多少個(gè)ms,平均每天或每小時(shí)差多少個(gè)ms(這個(gè)值小于1000),到整天或整小時(shí)的時(shí)候調(diào)整(根據(jù)實(shí)際情況去加或減。加好辦,注意減的處理)。
僅提供一種思路做參考。。
回復(fù)

使用道具 舉報(bào)

5#
ID:213173 發(fā)表于 2020-5-19 16:35 | 只看該作者
給你一個(gè)程序框架,自己補(bǔ)充完整?梢宰龅饺照`差<10秒
  1. #include <reg51.h>
  2. #define uint unsigned int
  3. #define uchar unsigned char

  4. sbit key1=P3^4;
  5. sbit key2=P3^5;

  6. uchar sec,min,hour;
  7. uint  usec=0;
  8. uint  fixtime=10000; //定義修正變量
  9. bit   sec_flag=0;                //秒標(biāo)志

  10. void time0_init(void)
  11. {
  12.     TMOD = 0x02;//自動(dòng)重裝
  13.     TH0 = 0x9C; //100us
  14.     TL0 = 0x9C;
  15.     EA = 1;
  16.     ET0 = 1;
  17.     TR0 = 1;
  18. }

  19. void keyscan()
  20. {
  21.         static bit key_lock=0;        //按鍵自鎖標(biāo)志
  22.         static uchar count=0;        //消抖計(jì)數(shù)變量               
  23.         if(!key1||!key2)
  24.         {
  25.                 if(++count>=100 && key_lock==0)
  26.                 {
  27.                         key_lock=1;//自鎖
  28.                         if(!key1)
  29.                                 fixtime++;
  30.                         if(!key2)
  31.                                 fixtime--;
  32.                 }
  33.         }
  34.         else   //松手
  35.         {
  36.                 count=0;
  37.                 key_lock=0;
  38.         }
  39.         //其它調(diào)時(shí)語(yǔ)句
  40. }

  41. void display()//顯示程序
  42. {
  43.         //顯示
  44. }

  45. void Timing()//計(jì)時(shí)程序
  46. {
  47.         if(sec_flag)
  48.         {
  49.                 sec_flag=0;
  50.                 sec++;
  51.                 if(sec >= 60)
  52.                 {
  53.                         sec = 0;
  54.                         min++;
  55.                         if(min >= 60)
  56.                         {
  57.                                 min = 0;
  58.                                 hour++;
  59.                                 if(hour >= 24)
  60.                                         hour=0;
  61.                         }
  62.                 }
  63.         }
  64. }

  65. void main()
  66. {
  67.         time0_init();
  68.         while(1)
  69.         {
  70.                 keyscan();
  71.                 Timing();
  72.                 display();
  73.         }
  74. }

  75. void Timer0() interrupt 1
  76. {
  77.         if(++usec>=fixtime)  //1sec
  78.         {
  79.                 usec = 0;
  80.                 sec_flag=1;
  81.         }
  82. }
復(fù)制代碼
回復(fù)

使用道具 舉報(bào)

6#
ID:516644 發(fā)表于 2020-5-19 17:44 | 只看該作者
carpcarey 發(fā)表于 2020-5-19 11:34
用方式2,自動(dòng)重載模式。定時(shí)到比如100us。這樣就只有相鄰誤差,沒(méi)有累計(jì)誤差。
晶振匹配不同的電容,實(shí)際 ...

為什么我修改成方式2之后,1602顯示的數(shù)值都不會(huì)變了。只修改了定時(shí)器的配置。定時(shí)時(shí)間是100us
回復(fù)

使用道具 舉報(bào)

7#
ID:732506 發(fā)表于 2020-5-19 20:42 | 只看該作者
讓鐘運(yùn)行較長(zhǎng)一段時(shí)間,比如10-20小時(shí),看誤差萬(wàn)分之多少,根據(jù)誤差調(diào)整fixtime的值。一次可能不行,多試幾次,應(yīng)該能不斷減小誤差。調(diào)整到每天誤差幾十秒應(yīng)該是可以的,要進(jìn)一步提高比較困難,因?yàn)槭褂冒存I時(shí)會(huì)對(duì)程序的執(zhí)行時(shí)間有影響。
回復(fù)

使用道具 舉報(bào)

8#
ID:267719 發(fā)表于 2020-5-20 09:09 | 只看該作者
LOVEqing 發(fā)表于 2020-5-19 17:44
為什么我修改成方式2之后,1602顯示的數(shù)值都不會(huì)變了。只修改了定時(shí)器的配置。定時(shí)時(shí)間是100us

看看代碼
回復(fù)

使用道具 舉報(bào)

9#
ID:516644 發(fā)表于 2020-5-20 16:51 | 只看該作者

#include "reg52.h"
#include "lcd.h"

#define u8 unsigned char
#define u16 unsigned int
       
u8 init[] = "0123456789";
u8 msec;       //毫秒
u8 sec;        //秒
u8 min;        //分
u8 hour;       //時(shí)

void LCD1602_init(void)
{
        LcdWriteCom(0x01);
        LcdWriteData(' ');
        LcdWriteData('D');
        LcdWriteData('i');
        LcdWriteData('g');
        LcdWriteData('i');
        LcdWriteData('t');
        LcdWriteData('a');
        LcdWriteData('l');
        LcdWriteData(' ');
        LcdWriteData(' ');
        LcdWriteData('C');
        LcdWriteData('l');
        LcdWriteData('o');
        LcdWriteData('c');
        LcdWriteData('k');
        LcdWriteData(' ');
}

void LCD1602_show(void)
{
        LcdWriteCom(0x80 + 0x40);
        LcdWriteData(init[hour / 10]);
        LcdWriteData(init[hour % 10]);
        LcdWriteData(':');
        LcdWriteData(init[min / 10]);
        LcdWriteData(init[min % 10]);
        LcdWriteData(':');
        LcdWriteData(init[sec / 10]);
        LcdWriteData(init[sec % 10]);
}
void time0_init(void)
{
        TMOD = 0X02;  //選擇為定時(shí)器0模式,工作方式2,僅用TR0打開(kāi)啟動(dòng)。

        TH0 = 0X9C;           //給定時(shí)器賦初值,定時(shí)0.1ms
        TL0 = 0X9C;       
        ET0 = 1;       //打開(kāi)定時(shí)器0中斷允許
        EA = 1;        //打開(kāi)總中斷
        TR0 = 1;       //打開(kāi)定時(shí)器
}

void main(void)
{
                LcdInit();
                time0_init();
                LCD1602_init();
                while(1)
                {
                                LCD1602_show();
                }
}

void Timer0(void) interrupt 1
{
        msec++;
        if(msec == 10000)          //1sec = 1000ms
        {
                msec = 0;
                sec++;
        }
        if(sec == 60)            //1min = 60sec
        {
                sec = 0;
                min++;
        }
        if(min == 60)            //1hour = 60min
        {
                min = 0;
                hour++;
        }
        if(hour == 24)
                        hour = 0;
}

大概是這樣
回復(fù)

使用道具 舉報(bào)

10#
ID:548551 發(fā)表于 2020-5-20 17:03 | 只看該作者
wulin 發(fā)表于 2020-5-19 16:35
給你一個(gè)程序框架,自己補(bǔ)充完整。可以做到日誤差

請(qǐng)問(wèn)老哥.51單片機(jī)都不初始化IO口嗎? 還有就是晶振頻率,以及上下拉打開(kāi)不打開(kāi). 還有看門(mén)狗也不初始化??
回復(fù)

使用道具 舉報(bào)

11#
ID:73435 發(fā)表于 2020-5-20 17:03 | 只看該作者
中斷里面處理盡可能快,所以你的很多代碼可以放到中斷外,中斷里面就是一個(gè)簡(jiǎn)單的累加就好了。
回復(fù)

使用道具 舉報(bào)

12#
ID:267719 發(fā)表于 2020-5-20 17:21 | 只看該作者
LOVEqing 發(fā)表于 2020-5-20 16:51
#include "reg52.h"
#include "lcd.h"

u8 msc  不對(duì) u16 msc因?yàn)楹竺?if (msec == 10000)          //1sec = 1000ms
如果u8 msc,始終不會(huì)等于10000的,最大只能255.
回復(fù)

使用道具 舉報(bào)

13#
ID:516644 發(fā)表于 2020-5-20 18:47 | 只看該作者
wulin 發(fā)表于 2020-5-19 16:35
給你一個(gè)程序框架,自己補(bǔ)充完整?梢宰龅饺照`差

#include <reg52.h>
#include "lcd.h"
#define uint unsigned int
#define uchar unsigned char

uchar init[] = "0123456789";

sbit key1=P3^4;
sbit key2=P3^5;

uchar sec,min,hour;
uint  usec=0;
uint  fixtime=10000; //定義修正變量
bit   sec_flag=0;                //秒標(biāo)志

void time0_init(void)
{
    TMOD = 0x02;//自動(dòng)重裝
    TH0 = 0x9C; //100us
    TL0 = 0x9C;
    EA = 1;
    ET0 = 1;
    TR0 = 1;
}

void LCD1602_init(void)
{
        LcdWriteCom(0x01);
        LcdWriteData(' ');
        LcdWriteData('D');
        LcdWriteData('i');
        LcdWriteData('g');
        LcdWriteData('i');
        LcdWriteData('t');
        LcdWriteData('a');
        LcdWriteData('l');
        LcdWriteData(' ');
        LcdWriteData(' ');
        LcdWriteData('C');
        LcdWriteData('l');
        LcdWriteData('o');
        LcdWriteData('c');
        LcdWriteData('k');
        LcdWriteData(' ');
}

void LCD1602_show(void)
{
        LcdWriteCom(0x80 + 0x40);
        LcdWriteData(init[hour / 10]);
        LcdWriteData(init[hour % 10]);
        LcdWriteData(':');
        LcdWriteData(init[min / 10]);
        LcdWriteData(init[min % 10]);
        LcdWriteData(':');
        LcdWriteData(init[sec / 10]);
        LcdWriteData(init[sec % 10]);
}

void keyscan()
{
        static bit key_lock=0;        //按鍵自鎖標(biāo)志
        static uchar count=0;        //消抖計(jì)數(shù)變量               
        if(!key1||!key2)
        {
                if(++count>=100 && key_lock==0)
                {
                        key_lock=1;//自鎖
                        if(!key1)
                                fixtime++;
                        if(!key2)
                                fixtime--;
                }
        }
        else   //松手
        {
                count=0;
                key_lock=0;
        }
        //其它調(diào)時(shí)語(yǔ)句
}

void display()//顯示程序
{
      LCD1602_show();  //顯示
}

void Timing()//計(jì)時(shí)程序
{
        if(sec_flag)
        {
                sec_flag=0;
                sec++;
                if(sec >= 60)
                {
                        sec = 0;
                        min++;
                        if(min >= 60)
                        {
                                min = 0;
                                hour++;
                                if(hour >= 24)
                                        hour=0;
                        }
                }
        }
}

void main()
{
        time0_init();
        LcdInit();
        LCD1602_init();

        while(1)
        {
                keyscan();
                Timing();
                display();
        }
}

void Timer0() interrupt 1
{
        if(++usec>=fixtime)  //1sec
        {
                usec = 0;
                sec_flag=1;
        }
}

我就增加了1602顯示,用protues仿真,然后誤差還是蠻大的,大概1602顯示25s的時(shí)候 手機(jī)秒表已經(jīng)跑到28了
回復(fù)

使用道具 舉報(bào)

14#
ID:516644 發(fā)表于 2020-5-21 10:11 | 只看該作者
carpcarey 發(fā)表于 2020-5-20 17:21
u8 msc  不對(duì) u16 msc因?yàn)楹竺?if (msec == 10000)          //1sec = 1000ms
如果u8 msc,始終不會(huì)等于 ...

哦哦哦 是的呢,忘記了
回復(fù)

使用道具 舉報(bào)

15#
ID:516644 發(fā)表于 2020-5-21 19:00 | 只看該作者
wulin 發(fā)表于 2020-5-21 12:09
仿真受PC時(shí)鐘影響,不一定準(zhǔn),要用實(shí)物驗(yàn)證。仿真用不了STC89C52的EEPROM保存fixtime變量。給你基本補(bǔ)齊 ...

哈哈哈哈哈,有道理,主要是手頭沒(méi)有開(kāi)發(fā)板,沒(méi)法實(shí)物測(cè)試。你這都把鐘基本做出來(lái)了
回復(fù)

使用道具 舉報(bào)

16#
ID:57657 發(fā)表于 2023-3-8 14:52 | 只看該作者
高精度必須自動(dòng)重載初值,定時(shí)器0中斷內(nèi)不能向TH0和TL0寄存器賦值,有多個(gè)中斷注意優(yōu)先級(jí)問(wèn)題。
回復(fù)

使用道具 舉報(bào)

17#
ID:1034262 發(fā)表于 2023-3-8 17:10 | 只看該作者
定時(shí)器工作于自動(dòng)重裝模式,本身不會(huì)造成誤差。
我用一個(gè)有源恒溫晶振,北斗模塊校準(zhǔn)過(guò),作為單片機(jī)(STC8H4K64TL)的時(shí)鐘,定時(shí)器工作于16位自動(dòng)重裝模式,1年的誤差不超過(guò)0.3秒。
回復(fù)

使用道具 舉報(bào)

本版積分規(guī)則

手機(jī)版|小黑屋|51黑電子論壇 |51黑電子論壇6群 QQ 管理員QQ:125739409;技術(shù)交流QQ群281945664

Powered by 單片機(jī)教程網(wǎng)

快速回復(fù) 返回頂部 返回列表