关于定时器中断MsTimer2

关于定时器中断MsTimer2

查看: 22301|回复: 7

关于定时器中断MsTimer2

[复制链接]

女神去哪了

女神去哪了

当前离线

积分152

电梯直达

1#

发表于 2015-3-18 09:23:37

|

只看该作者

|倒序浏览

|阅读模式

小弟刚接触arduino没多久,用定时器中断MsTimer2做了一个时钟实验。每1s调用一次定时器中断,中断里的内容就是second++,最后通过数码管显示。实验发现这个MsTimer2特别不准..每隔1小时就与正常时间差了将近20s!

是我程序的问题,还是定时器中断本身的缺陷?求大神解答{:soso_e118:}

#include 

int dataPin = 7;

int clockPin = 12;

int latchPin = 13;

unsigned char led_segbit[]={0x08,0x04,0x02,0x01};

unsigned char led_table[] = {0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,0x80,0x90,0x88,0x83,0xC6,0xA1,0x86,0x8E,0xFF,0xBF};

unsigned char led_disbuf[4]={0,0,0,0};

unsigned char led_date[4];

unsigned char second=00;

unsigned char minute=15;

unsigned char hour=16;

void change(){

   second++;

    if(second > 59)

    {

      second = 0;

      minute ++;

      if(minute > 59)

      {

        minute = 0;

        hour ++;

        if(hour > 23) hour = 0;

      }

    }

            

            

           

}

void setup()

{

    pinMode(dataPin,OUTPUT);

    pinMode(clockPin,OUTPUT);

    pinMode(latchPin,OUTPUT);

    MsTimer2::set(1000, change);

    MsTimer2::start();

    Serial.begin(9600);

}

void loop()

{

   

     

        LED4_Display ();

     

}    

    

void LED4_Display (void)

{

     led_date[0]=hour/10;

     led_date[1]=hour%10;

     led_date[2]=minute/10;

     led_date[3]=minute%10;

   

    unsigned char* led_address;

    for(int i=0;i<4;i++)

    {

       led_address=led_table+led_date;

       led_disbuf=*led_address;

digitalWrite(latchPin,LOW);

        shiftOut(dataPin,clockPin,MSBFIRST,led_disbuf);

        shiftOut(dataPin,clockPin,MSBFIRST,led_segbit);

        digitalWrite(latchPin,HIGH);

    }             

        

}

分享到:

QQ好友和群

收藏1

回复

使用道具

举报

林定祥

林定祥

当前离线

积分4152

2#

发表于 2015-3-18 10:59:22

|

只看该作者

时间定时通常使用内部计数器,也即是是一种机械式,如果工作时钟不怎么准确,计数后除出来的数可能产生误差,因此,如果是一个固定误差的话,可以在程序中进行修正。

回复

支持

反对

使用道具

举报

女神去哪了

女神去哪了

当前离线

积分152

3#

楼主|

发表于 2015-3-18 11:42:56

|

只看该作者

林定祥 发表于 2015-3-18 10:59

时间定时通常使用内部计数器,也即是是一种机械式,如果工作时钟不怎么准确,计数后除出来的数可能产生误差 ...

感觉像是一个固定误差,平均每小时就会慢20s左右。不过在程序中具体应该如何修正? 我在网上也看过其他人写的关于用数码管做时钟的程序,大部分都会有一个对时钟进行微调的常量,不过不太明白这个微调是如何对时间误差进行修正的

回复

支持

反对

使用道具

举报

林定祥

林定祥

当前离线

积分4152

4#

发表于 2015-3-18 20:31:49

|

只看该作者

中断程序中另加一个变量,没中断一次+1,满180,清零,同时时间计数器额外+1,这样每一小时加多了20妙秒,补偿那20秒。

回复

支持

反对

使用道具

举报

女神去哪了

女神去哪了

当前离线

积分152

5#

楼主|

发表于 2015-3-19 08:51:13

|

只看该作者

林定祥 发表于 2015-3-18 20:31

中断程序中另加一个变量,没中断一次+1,满180,清零,同时时间计数器额外+1,这样每一小时加多了20妙秒,补 ...

谢谢大神

回复

支持

反对

使用道具

举报

tsaiwn

tsaiwn

当前离线

积分594

6#

发表于 2015-4-7 01:01:55

|

只看该作者

女神去哪了 发表于 2015-3-19 08:51

谢谢大神

这是因为 MsTimer2 使用 timer2 (废话 :-)

且 prescaler 用 64

timer2 是 8 bit counter

于是, 这使得它所谓的 1ms 其实是 1.024ms,

阿就是说其实其内部是每隔 1.024ms 产生一次中断, 不是每 1ms,

跟 timer0 帮忙 millis( ) 计算 millis 类似,

但是在 millis( ) 函数内有个调整机制,

里面偷用一个变数 unsigned char gg=0; 每次1.024中断做 gg+=3;

然后 if(gg >=125) { gg-=125; millis++; }

就是说大约 125/3 = 41.6 次中断会偷偷调整 1 millis;

但在 MsTimer2 库内没针对这做调整 !

所以, 如果你要用 MsTimer2 做出时钟, 那可以如下做法(仿照 millis( )):

(1)在 void setup( ) {

那句

MsTimer2::set(1000, change);

改为

MsTimer2::set(1, change); // 1.024 ms; 注意, 不是 1ms

(2)把你的 change 函数改如下

void change(){ // 每 1ms (1.024 ms) 来一次中断

static unsigned char gg = 0;

static int ms = 0;

++ms; gg += 3;

if(gg >= 125) { ++ms; gg -= 125; }

if(ms < 1000) return;

ms -= 1000;

//////

second++;

if(second > 59)

{

second = 0;

minute ++;

if(minute > 59)

{

minute = 0;

hour ++;

if(hour > 23) hour = 0;

}

}

这样就会很准 !

不信你测试看看 :-)

回复

支持

反对

使用道具

举报

女神去哪了

女神去哪了

当前离线

积分152

7#

楼主|

发表于 2015-4-8 15:08:16

|

只看该作者

tsaiwn 发表于 2015-4-7 01:01

这是因为 MsTimer2 使用 timer2 (废话 :-)

且 prescaler 用 64

timer2 是 8 bit counter

原来是这样. 解释的太详细了 谢谢

回复

支持

反对

使用道具

举报

tsaiwn

tsaiwn

当前离线

积分594

8#

发表于 2015-4-8 23:13:24

|

只看该作者

女神去哪了 发表于 2015-4-8 15:08

原来是这样. 解释的太详细了 谢谢

【补充】

这个调整 millis 的动作跟闰年(Leap year)原理类似,

因为地球绕太阳一圈的回归年其实是365.2421990741天,

不是 365天也不是 366天, 所以每四年要闰年一次多一天,

可是四年多一天等於算做一年是 365.25 天, 又不准了,

因此每一百年又把多算的一天取消(公元年/100整除不是闰年)做修正 !!

这里的算法是因每次误差 0.024 ms, 用 3 代表,

然后 125 就是代表 0.024ms * 125 = 1.000ms,

因此如果 (gg >= 125) 就要把 millis 加 1,

並且要做 gg -= 125;

注意不是设为 0 喔, 是减去 125,

因这时可能是125, 126, 127 这三个之一个,

多出来的误差要累计到下次的计算內。

回复

支持

反对

使用道具

举报

相关推荐

佰仟分期逾期费用怎么算?2024最新计算规则及避坑指南
摩洛哥VS伊朗(2018世界杯)
365bet提款要多久

摩洛哥VS伊朗(2018世界杯)

🪐 07-18 👁️ 7529
【心得】VR白金神作。失根 @PS4 / PlayStation4 哈啦板
365bet官网备用

【心得】VR白金神作。失根 @PS4 / PlayStation4 哈啦板

🪐 07-13 👁️ 4812