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

[复制链接]
26900|28
 楼主| 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,都没有看到有提到这一点的,希望各位大神多多指教!
(我判断定时器是否准确的方法 :用定时器中断的方式,结合数码管,做成一个秒表,看看时间走的快慢和手机上的秒表走的速度是否一致,没有用示波器等仪器,纯靠肉眼观察)

评论

@wangchangwenqq :我懂这一点。我的疑惑主要是TMR1没有加上这段累加的数值,而观测结果却没有偏差。不过我现在有点想明白了,我在最新的跟帖下面有说。谢谢您的讨论。  发表于 2021-12-2 20:58
@tree844 : 因为是8位机 TMR0 ,TMR1 是16位定时器没有周期寄存器, 所以每次都要装载初值, 溢出0xFFFF ,此时有中断指令开销以及其它中断可能会影响, 但是定时器的计数在还在计数, 你直接附初值,不是把溢出之后计数的值清零,所以 加上计数的值可以消除产生的误差  发表于 2021-11-28 12:13
@tree844 :TMR2, TMR4 都有周期寄存器, 每次都是0x00开始, 到周期匹配, 时序理论不会有误差, TMR1 ,TMR0,TMR3 是要装载初值的 一直到溢出0xFFFF, 这里就有延迟, 在TMR计数寄存器加上初值 可以将误差降低  发表于 2021-11-28 11:37
@wangchangwenqq :有一定道理。但是TM1和TM2为什么可以直接赋值而不用加上这段时间的累加值呢?我最在意的一点是,这个逻辑有没有相关文档有直接的说明?  发表于 2021-11-28 11:24
16F877A 没有高优先级中断, 这就和你把中断有没有放最前面有关了,而且 就算你 进入中断 最先判断 TMR0的中断条件, 此时在之前产生了其它的中断 而且中断没有运行完成,中断触发都会默认的关闭总中断GIE,是不会立即运行TMR0的中断, 造成时序延迟  发表于 2021-11-28 08:07
 楼主| tree844 发表于 2021-11-20 19:17 | 显示全部楼层
本帖最后由 tree844 于 2021-11-20 21:10 编辑
  1. #include <xc.h>
  2. #define _XTAL_FREQ 4000000

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

  4. unsigned int time;

  5. void init(void);
  6. void init_TIM0(void);
  7. void disp(void);

  8. void main(void)
  9. {
  10.     init();
  11.     init_TIM0();
  12.     while(1)
  13.     {
  14.         disp();
  15.     }
  16. }

  17. void init(void)
  18. {
  19.     PORTD = 0x00;
  20.     TRISD = 0x00;
  21.     PORTA = 0x00;
  22.     TRISA = 0x00;
  23.     ADCON1 = 0x06;
  24. }

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

  31. void __interrupt() isr_TMR0(void)
  32. {
  33.     static unsigned char i = 0;
  34.     if(T0IE && T0IF)
  35.     {
  36.         TMR0 = TMR0 + 58;
  37.         if(i < 124)
  38.         {
  39.             i++;
  40.         }
  41.         else    //0.8ms*125 = 100ms
  42.         {
  43.             i = 0;
  44.             if(time < 999)
  45.             {
  46.                 time++;
  47.             }
  48.             else
  49.             {
  50.                 time = 0;
  51.             }
  52.         }
  53.         T0IF = 0;
  54.     }
  55. }

  56. void disp(void)
  57. {
  58.     PORTD = TABLE[time % 10];
  59.     PORTA = 0x01;
  60.     __delay_ms(1);
  61.     PORTA = 0x00;
  62.    
  63.     PORTD = TABLE[time /10 % 10] | 0x80;
  64.     PORTA = 0x02;
  65.     __delay_ms(1);
  66.     PORTA = 0x00;
  67.    
  68.     PORTD = TABLE[time/100];
  69.     PORTA = 0x04;
  70.     __delay_ms(1);
  71.     PORTA = 0x00;
  72. }


评论

这个是我写的用来测试的 TMR0 的例程源代码。  发表于 2021-11-20 19:18
 楼主| 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 | 显示全部楼层
可能测试不够准确,或者是内部有缓冲,在下个中断周期后才起作用,仔细看手册,应该有说明的

评论

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

评论

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

评论

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

评论

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

评论

不支持。  发表于 2021-11-29 19:58
粤原点科技 发表于 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

评论

?  发表于 2021-12-6 22:27
wuhanrf 发表于 2021-12-17 11:00 | 显示全部楼层
你看李学海那本书,有叙述

评论

他好像有不止一本书,具体是哪一本呢?  发表于 2021-12-21 11:22
您需要登录后才可以回帖 登录 | 注册

本版积分规则

个人签名:莫等闲、白了少年头,空悲切!

13

主题

243

帖子

3

粉丝
快速回复 在线客服 返回列表 返回顶部