找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 4354|回复: 16
收起左侧

51单片机做数字钟 定时器中断有误差 如何提高精度

[复制链接]
ID:516644 发表于 2020-5-18 18:59 | 显示全部楼层 |阅读模式
20黑币
    使用51单片机做一个简单的数字钟,但是用定时器中断时,进入中断服务函数时会有机器周期,会产生误差。    怎么减少这种误差?或者如果用补偿的方式增加定时器的初值,应该怎么计算需要补偿的数值?
    以下部分代码是我使用补偿修正值的方式,但是修正值不正确。

u8 fixtime; //定义修正变量

void time0_init(void)
{
        TMOD |= 0X01;  //选择为定时器0模式,工作方式1,仅用TR0打开启动。

        TH0 = 0XD8;           //给定时器赋初值,定时10ms
        TL0 = 0XF0;       
        ET0 = 1;       //打开定时器0中断允许
        EA = 1;        //打开总中断
        TR0 = 1;       //打开定时器                       
}

void Timer0() interrupt 1
{
        EA = 0;//禁止所有中断请求
        TR0 = 0;//关闭T0
        fixtime = TL0 + 0X1B;//将TL0中已计数值写入fixtime,并加上修正操作占用的27个机器周期
        TL0 = 0XF0 + fixtime;//将修正值写入TL0
        TH0 = 0XD8 + (char)CY;//修正TL0时可能产生进位,要补偿到TH0
        EA = 1;//允许所有中断请求
        TR0 = 1;//开启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++;
        }
}


最佳答案

查看完整内容

仿真受PC时钟影响,不一定准,要用实物验证。仿真用不了STC89C52的EEPROM保存fixtime变量。给你基本补齐了。
回复

使用道具 举报

ID:213173 发表于 2020-5-18 18:59 | 显示全部楼层
LOVEqing 发表于 2020-5-20 18:47
#include
#include "lcd.h"
#define uint unsigned int

仿真受PC时钟影响,不一定准,要用实物验证。仿真用不了STC89C52的EEPROM保存fixtime变量。给你基本补齐了。

无标题.jpg


无标题1.jpg

  1. //适用STC89C52RC单片机
  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                //写命令
  9. #define EraseCommand 0x03        //擦除命令
  10. #define Error 1
  11. #define Ok 0
  12. #define WaitTime 0x01                 //定义CPU的等待时间,写入硬件延时
  13. //STC89系列EEPROM寄存器声明
  14. sfr ISP_DATA=0xe2;                //0000,0000 EEPROM数据寄存器
  15. sfr ISP_ADDRH=0xe3;                //0000,0000 EEPROM地址高字节
  16. sfr ISP_ADDRL=0xe4;                //0000,0000 EEPROM地址第字节
  17. sfr ISP_CMD=0xe5;                //xxxx,xx00 EEPROM命令寄存器
  18. sfr ISP_TRIG=0xe6;                //0000,0000 EEPRPM命令触发寄存器
  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:数据寄存器          L:指令寄存器
  24. sbit rw=P2^5;         //寄存器选择信号 H:数据寄存器          L:指令寄存器
  25. sbit e =P2^7;         //片选信号   下降沿触发
  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;    //秒标志

  32. // 打开 ISP,IAP 功能
  33. void ISP_IAP_enable(void)
  34. {
  35.         EA = 0;       /* 关中断   */
  36.         ISP_CONTR = ISP_CONTR & 0x18;       /* 0001,1000 */
  37.         ISP_CONTR = ISP_CONTR | WaitTime; /* 写入硬件延时 */
  38.         ISP_CONTR = ISP_CONTR | 0x80;       /* ISPEN=1  */
  39. }
  40. // 关闭 ISP,IAP 功能
  41. void ISP_IAP_disable(void)
  42. {
  43.         ISP_CONTR = ISP_CONTR & 0x7f; /* ISPEN = 0 */
  44.         ISP_TRIG = 0x00;
  45.         EA   =   1;   /* 开中断 */
  46. }
  47. // 公用的触发代码
  48. void ISPgoon(void)
  49. {
  50.         ISP_IAP_enable();   /* 打开 ISP,IAP 功能 */
  51.         ISP_TRIG = 0x46;  /* 触发ISP_IAP命令字节1 */
  52.         ISP_TRIG = 0xb9;  /* 触发ISP_IAP命令字节2 */
  53.         _nop_();
  54. }
  55. // 字节读
  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; /* 写入读命令 */
  62.         ISPgoon();       /* 触发执行  */
  63.         ISP_IAP_disable();    /* 关闭ISP,IAP功能 */
  64.         return (ISP_DATA);    /* 返回读到的数据 */
  65. }
  66. // 扇区擦除
  67. void SectorErase(unsigned int sector_addr)
  68. {
  69.         unsigned int iSectorAddr;
  70.         iSectorAddr = (sector_addr & 0xfe00); /* 取扇区地址 */
  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();       /* 触发执行  */
  76.         ISP_IAP_disable();    /* 关闭ISP,IAP功能 */
  77. }
  78. // 字节写
  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;  /* 写命令2 */
  85.         ISP_DATA = original_data;   /* 写入数据准备 */
  86.         ISPgoon();       /* 触发执行  */
  87.         ISP_IAP_disable();     /* 关闭IAP功能 */
  88. }
  89. /********************************************************************
  90. * 名称 : delay_uint()
  91. * 功能 : 小延时。
  92. * 输入 : 无
  93. * 输出 : 无
  94. ***********************************************************************/
  95. void delay_uint(uint i)
  96. {
  97.         while(--i);
  98. }

  99. /********************************************************************
  100. * 名称 : write_com(uchar com)
  101. * 功能 : 1602命令函数
  102. * 输入 : 输入的命令值
  103. * 输出 : 无
  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写数据函数
  119. * 输入 : 需要写入1602的数据
  120. * 输出 : 无
  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初始化设置************************/
  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;//自动重装
  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;        //按键自锁标志
  198.         static uchar count=0;        //消抖计数变量               
  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);//擦除扇区
  221.                                                         byte_write(0x2000,a);//重新写入数据高8位
  222.                                                         byte_write(0x2001,b);//重新写入数据低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);//擦除扇区
  238.                                                         byte_write(0x2000,a);//重新写入数据高8位
  239.                                                         byte_write(0x2001,b);//重新写入数据低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()//计时程序
  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);//程序开始时读取EEPROM中数据
  277.         fixtime=fixtime<<8|byte_read(0x2001);//合并为整形数据
  278.         if(fixtime>15000||fixtime<5000) //防止首次上电时读取出错
  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. }
复制代码



STC99封装.zip

26.37 KB, 下载次数: 7

回复

使用道具 举报

ID:584814 发表于 2020-5-19 11:08 | 显示全部楼层
如果仅用单片机内部时钟,除调整晶振频率等硬件外,软件通过调整定时器的初值,计算值加实验修正。
想获得精准时钟,直接外部时钟便宜且方便。
回复

使用道具 举报

ID:267719 发表于 2020-5-19 11:34 | 显示全部楼层
用方式2,自动重载模式。定时到比如100us。这样就只有相邻误差,没有累计误差。
晶振匹配不同的电容,实际的频率也是有误差的。这个补偿要累计去计算的,比如1个月后,误差多少个ms,平均每天或每小时差多少个ms(这个值小于1000),到整天或整小时的时候调整(根据实际情况去加或减。加好办,注意减的处理)。
仅提供一种思路做参考。。
回复

使用道具 举报

ID:213173 发表于 2020-5-19 16:35 | 显示全部楼层
给你一个程序框架,自己补充完整。可以做到日误差<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;                //秒标志

  10. void time0_init(void)
  11. {
  12.     TMOD = 0x02;//自动重装
  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;        //按键自锁标志
  22.         static uchar count=0;        //消抖计数变量               
  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.         //其它调时语句
  40. }

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

  45. void Timing()//计时程序
  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. }
复制代码
回复

使用道具 举报

ID:516644 发表于 2020-5-19 17:44 | 显示全部楼层
carpcarey 发表于 2020-5-19 11:34
用方式2,自动重载模式。定时到比如100us。这样就只有相邻误差,没有累计误差。
晶振匹配不同的电容,实际 ...

为什么我修改成方式2之后,1602显示的数值都不会变了。只修改了定时器的配置。定时时间是100us
回复

使用道具 举报

ID:732506 发表于 2020-5-19 20:42 | 显示全部楼层
让钟运行较长一段时间,比如10-20小时,看误差万分之多少,根据误差调整fixtime的值。一次可能不行,多试几次,应该能不断减小误差。调整到每天误差几十秒应该是可以的,要进一步提高比较困难,因为使用按键时会对程序的执行时间有影响。
回复

使用道具 举报

ID:267719 发表于 2020-5-20 09:09 | 显示全部楼层
LOVEqing 发表于 2020-5-19 17:44
为什么我修改成方式2之后,1602显示的数值都不会变了。只修改了定时器的配置。定时时间是100us

看看代码
回复

使用道具 举报

ID:516644 发表于 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;       //时

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;  //选择为定时器0模式,工作方式2,仅用TR0打开启动。

        TH0 = 0X9C;           //给定时器赋初值,定时0.1ms
        TL0 = 0X9C;       
        ET0 = 1;       //打开定时器0中断允许
        EA = 1;        //打开总中断
        TR0 = 1;       //打开定时器
}

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;
}

大概是这样
回复

使用道具 举报

ID:548551 发表于 2020-5-20 17:03 | 显示全部楼层
wulin 发表于 2020-5-19 16:35
给你一个程序框架,自己补充完整。可以做到日误差

请问老哥.51单片机都不初始化IO口吗? 还有就是晶振频率,以及上下拉打开不打开. 还有看门狗也不初始化??
回复

使用道具 举报

ID:73435 发表于 2020-5-20 17:03 | 显示全部楼层
中断里面处理尽可能快,所以你的很多代码可以放到中断外,中断里面就是一个简单的累加就好了。
回复

使用道具 举报

ID:267719 发表于 2020-5-20 17:21 | 显示全部楼层
LOVEqing 发表于 2020-5-20 16:51
#include "reg52.h"
#include "lcd.h"

u8 msc  不对 u16 msc因为后面 if (msec == 10000)          //1sec = 1000ms
如果u8 msc,始终不会等于10000的,最大只能255.
回复

使用道具 举报

ID:516644 发表于 2020-5-20 18:47 | 显示全部楼层
wulin 发表于 2020-5-19 16:35
给你一个程序框架,自己补充完整。可以做到日误差

#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;                //秒标志

void time0_init(void)
{
    TMOD = 0x02;//自动重装
    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;        //按键自锁标志
        static uchar count=0;        //消抖计数变量               
        if(!key1||!key2)
        {
                if(++count>=100 && key_lock==0)
                {
                        key_lock=1;//自锁
                        if(!key1)
                                fixtime++;
                        if(!key2)
                                fixtime--;
                }
        }
        else   //松手
        {
                count=0;
                key_lock=0;
        }
        //其它调时语句
}

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

void Timing()//计时程序
{
        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的时候 手机秒表已经跑到28了
回复

使用道具 举报

ID:516644 发表于 2020-5-21 10:11 | 显示全部楼层
carpcarey 发表于 2020-5-20 17:21
u8 msc  不对 u16 msc因为后面 if (msec == 10000)          //1sec = 1000ms
如果u8 msc,始终不会等于 ...

哦哦哦 是的呢,忘记了
回复

使用道具 举报

ID:516644 发表于 2020-5-21 19:00 | 显示全部楼层
wulin 发表于 2020-5-21 12:09
仿真受PC时钟影响,不一定准,要用实物验证。仿真用不了STC89C52的EEPROM保存fixtime变量。给你基本补齐 ...

哈哈哈哈哈,有道理,主要是手头没有开发板,没法实物测试。你这都把钟基本做出来了
回复

使用道具 举报

ID:57657 发表于 2023-3-8 14:52 | 显示全部楼层
高精度必须自动重载初值,定时器0中断内不能向TH0和TL0寄存器赋值,有多个中断注意优先级问题。
回复

使用道具 举报

ID:1034262 发表于 2023-3-8 17:10 | 显示全部楼层
定时器工作于自动重装模式,本身不会造成误差。
我用一个有源恒温晶振,北斗模块校准过,作为单片机(STC8H4K64TL)的时钟,定时器工作于16位自动重装模式,1年的误差不超过0.3秒。
回复

使用道具 举报

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

本版积分规则

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

Powered by 单片机教程网

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