[PIC®/AVR® MCU] PIC16F877A定时器0和定时器1在重新赋初值时候的区别

[复制链接]
10096|26
手机看帖
扫描二维码
随时随地手机跟帖
tree844|  楼主 | 2021-11-19 21:31 | 显示全部楼层 |阅读模式
本帖最后由 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-12-2 20:58 回复TA
@wangchangwenqq :我懂这一点。我的疑惑主要是TMR1没有加上这段累加的数值,而观测结果却没有偏差。不过我现在有点想明白了,我在最新的跟帖下面有说。谢谢您的讨论。 
wangchangwenqq 2021-11-28 12:13 回复TA
@tree844 : 因为是8位机 TMR0 ,TMR1 是16位定时器没有周期寄存器, 所以每次都要装载初值, 溢出0xFFFF ,此时有中断指令开销以及其它中断可能会影响, 但是定时器的计数在还在计数, 你直接附初值,不是把溢出之后计数的值清零,所以 加上计数的值可以消除产生的误差 
wangchangwenqq 2021-11-28 11:37 回复TA
@tree844 :TMR2, TMR4 都有周期寄存器, 每次都是0x00开始, 到周期匹配, 时序理论不会有误差, TMR1 ,TMR0,TMR3 是要装载初值的 一直到溢出0xFFFF, 这里就有延迟, 在TMR计数寄存器加上初值 可以将误差降低 
tree844 2021-11-28 11:24 回复TA
@wangchangwenqq :有一定道理。但是TM1和TM2为什么可以直接赋值而不用加上这段时间的累加值呢?我最在意的一点是,这个逻辑有没有相关文档有直接的说明? 
wangchangwenqq 2021-11-28 08:07 回复TA
16F877A 没有高优先级中断, 这就和你把中断有没有放最前面有关了,而且 就算你 进入中断 最先判断 TMR0的中断条件, 此时在之前产生了其它的中断 而且中断没有运行完成,中断触发都会默认的关闭总中断GIE,是不会立即运行TMR0的中断, 造成时序延迟 
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[time % 10];
    PORTA = 0x01;
    __delay_ms(1);
    PORTA = 0x00;
   
    PORTD = TABLE[time /10 % 10] | 0x80;
    PORTA = 0x02;
    __delay_ms(1);
    PORTA = 0x00;
   
    PORTD = TABLE[time/100];
    PORTA = 0x04;
    __delay_ms(1);
    PORTA = 0x00;
}


使用特权

评论回复

评论

tree844 2021-11-20 19:18 回复TA
这个是我写的用来测试的 TMR0 的例程源代码。 
tree844|  楼主 | 2021-11-21 21:38 | 显示全部楼层
这个问题没有人研究过吗?

使用特权

评论回复
麻花油条| | 2021-11-22 16:14 | 显示全部楼层
没遇到过

使用特权

评论回复
tree844|  楼主 | 2021-11-23 17:56 | 显示全部楼层

TMR0 和 TMR1 您都操作过吗?

使用特权

评论回复
ayb_ice| | 2021-11-24 08:35 | 显示全部楼层
可能测试不够准确,或者是内部有缓冲,在下个中断周期后才起作用,仔细看手册,应该有说明的

使用特权

评论回复

评论

tree844 2021-11-25 14:38 回复TA
中英文datasheet都看了,参考书也查了,暂时没有找到线索。 
shizaigaole| | 2021-11-24 11:05 | 显示全部楼层
该换个芯片,并使用MCC代码配置器干事情了

使用特权

评论回复

评论

tree844 2021-11-25 14:40 回复TA
这个MCU我只是学习用,它的资料比较多,实际我们公司里用的是别的型号。 我想弄明白这个区别是什么?例程这么写自然是有依据的,我想找到源头。 
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。

使用特权

评论回复

评论

tree844 2021-11-27 21:54 回复TA
添加不了图片,本来想附上datasheet里面的说明的。 
wangchangwenqq| | 2021-11-28 08:01 | 显示全部楼层
个人猜测, 防止有高优先级中断,影响 TMR0 值,   假如 TMR0 溢出产生中断,如果有高优先级中断或者其它的,  此时TMR 还在计数 溢出值不是0 ,  直接附初值58 就 清掉了TMR0的计数值, 加上58 原先溢出之后还在计数的值在存在

使用特权

评论回复

评论

tree844 2021-11-28 11:25 回复TA
关键在于为什么TM1和TM2不用?其他的单片机也没有这种操作。 
pzsh| | 2021-11-29 14:03 | 显示全部楼层
这么老的芯片,不知道MCC是不是支持

使用特权

评论回复

评论

tree844 2021-11-29 19:58 回复TA
不支持。 
粤原点科技| | 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

使用特权

评论回复

评论

tree844 2021-12-6 22:27 回复TA
? 
您需要登录后才可以回帖 登录 | 注册

本版积分规则