tree844 发表于 2021-11-19 21:31

PIC16F877A定时器0和定时器1在重新赋初值时候的区别

本帖最后由 pzsh 于 2021-11-29 14:03 编辑

我根据手头上的两个例程,发现一个有趣的现象:TMR0在一开始初始化的时候是这样赋值的:
TMR0=58;
而在进入定时器中断函数之后,TMR0在重新赋初值的时候是这样写的:TMR0=TMR0+58;
如果不加上 TMR0 而是直接 TMR0=58 定时器中断发生的时间会变长,也就是说,在进入中断函数之后,TMR0仍在继续累加。



但是对于TMR1而言,赋初值和在中断函数中重新赋值的语句都是一样的:
TMR1L=(65536-12500)%256;
TMR1H=(65536-12500)/256;
经过我的测试,定时器中断的发生周期不会出现误差。

我的问题是:为什么两个定时器重新赋初值的方法不同,TMR0为什么不能直接赋成和初始化一样的值?
我查了书和datasheet,都没有看到有提到这一点的,希望各位大神多多指教!
(我判断定时器是否准确的方法 :用定时器中断的方式,结合数码管,做成一个秒表,看看时间走的快慢和手机上的秒表走的速度是否一致,没有用示波器等仪器,纯靠肉眼观察)

tree844 发表于 2021-11-20 19:17

本帖最后由 tree844 于 2021-11-20 21:10 编辑

#include <xc.h>
#define _XTAL_FREQ 4000000

const unsigned char TABLE[]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F};

unsigned int time;

void init(void);
void init_TIM0(void);
void disp(void);

void main(void)
{
    init();
    init_TIM0();
    while(1)
    {
      disp();
    }
}

void init(void)
{
    PORTD = 0x00;
    TRISD = 0x00;
    PORTA = 0x00;
    TRISA = 0x00;
    ADCON1 = 0x06;
}

void init_TIM0(void)
{
    TMR0 = 58;          //256-200=56;56+2=58
    OPTION_REG = 0x01;//0000 0001   4分频,定时周期200us*4=800us
    INTCON = 0xA0;      //1010 0000   
}

void __interrupt() isr_TMR0(void)
{
    static unsigned char i = 0;
    if(T0IE && T0IF)
    {
      TMR0 = TMR0 + 58;
      if(i < 124)
      {
            i++;
      }
      else    //0.8ms*125 = 100ms
      {
            i = 0;
            if(time < 999)
            {
                time++;
            }
            else
            {
                time = 0;
            }
      }
      T0IF = 0;
    }
}

void disp(void)
{
    PORTD = TABLE;
    PORTA = 0x01;
    __delay_ms(1);
    PORTA = 0x00;
   
    PORTD = TABLE | 0x80;
    PORTA = 0x02;
    __delay_ms(1);
    PORTA = 0x00;
   
    PORTD = TABLE;
    PORTA = 0x04;
    __delay_ms(1);
    PORTA = 0x00;
}

tree844 发表于 2021-11-21 21:38

这个问题没有人研究过吗?

麻花油条 发表于 2021-11-22 16:14

没遇到过

tree844 发表于 2021-11-23 17:56

麻花油条 发表于 2021-11-22 16:14
没遇到过

TMR0 和 TMR1 您都操作过吗?

ayb_ice 发表于 2021-11-24 08:35

可能测试不够准确,或者是内部有缓冲,在下个中断周期后才起作用,仔细看手册,应该有说明的

shizaigaole 发表于 2021-11-24 11:05

该换个芯片,并使用MCC代码配置器干事情了

lcczg 发表于 2021-11-26 12:04

有意思。这个例程是谁写的呢?从下面的 +2 能看出来已经考虑到这个延迟了。有可能是实测的。
TMR0 = 58;          //256-200=56;56+2=58

tree844 发表于 2021-11-27 21:50

本帖最后由 tree844 于 2021-11-27 21:52 编辑

lcczg 发表于 2021-11-26 12:04
有意思。这个例程是谁写的呢?从下面的 +2 能看出来已经考虑到这个延迟了。有可能是实测的。
TMR0 = 58;    ...
这个是另外一回事。写入TMR0 的时候,后续两个指令周期会暂停累加,所以需要加2。

wangchangwenqq 发表于 2021-11-28 08:01

个人猜测, 防止有高优先级中断,影响 TMR0 值,   假如 TMR0 溢出产生中断,如果有高优先级中断或者其它的,此时TMR 还在计数 溢出值不是0 ,直接附初值58 就 清掉了TMR0的计数值, 加上58 原先溢出之后还在计数的值在存在

pzsh 发表于 2021-11-29 14:03

这么老的芯片,不知道MCC是不是支持

粤原点科技 发表于 2021-12-1 18:15

Timer0和Timer1的中断机制是一样的:溢出中断。对于初值的赋值,赋值是一样的。并且这两个Timer无论触发了中断还是没有,他们都一直在累加(时钟源被设置为指令时钟)。因此TMR0+=58这种写**相对准一点,但写成TMR0=58也无伤大雅。

tree844 发表于 2021-12-2 20:54

粤原点科技 发表于 2021-12-1 18:15
Timer0和Timer1的中断机制是一样的:溢出中断。对于初值的赋值,赋值是一样的。并且这两个Timer无论触发了 ...
谢谢指教。我自己是用秒表测试的,现象是:直接用常用写法(TMR0=58),TMR0计时会变慢;而TMR1直接赋值,计时结果没有可见差异。但是我没有用示波器测量。
我在想,如果从进入中断开始到执行给定时器赋值语句为止,因为程序都差不多,所以操作两种定时器单片机所用的时间是差不多的,也就是累加器所累加的数字一样(都是x);而TMR0是8位的,误差位x/256;TMR1是16位的,误差是x/65536;导致TMR0例程的误差大到我容易观测,而TMR1的例程我光靠秒表无法观测到,如果有示波器或者其他精密仪器或者长时间观测也许就能发现问题。

粤原点科技 发表于 2021-12-3 10:39

tree844 发表于 2021-12-2 20:54
谢谢指教。我自己是用秒表测试的,现象是:直接用常用写法(TMR0=58),TMR0计时会变慢;而TMR1直接赋值, ...

是的,就是误差相对大小不一样。你可以把预分频和后分频开到最大,或许秒表可以测试出来。但还是非常建议搞个示波器,因为它太有用了。

andreilei 发表于 2021-12-4 22:25

《电子的奇妙世界》用定格动画的方式讲述发生在电子世界的故事,呈现元器件们的奇妙冒险!
整容二极管
晶振的噩梦
谁杀死了LED
保险丝的葬礼
妄自尊大的发光二极管
————
电子的奇妙世界,视频公开课
https://open.21ic.com/open/lesson/5766

wuhanrf 发表于 2021-12-17 11:00

你看李学海那本书,有叙述
页: [1]
查看完整版本: PIC16F877A定时器0和定时器1在重新赋初值时候的区别