搜索
bottom↓
回复: 180

关于定时器精确定时中断的讨论

[复制链接]

出0入0汤圆

发表于 2007-8-15 02:41:53 | 显示全部楼层 |阅读模式
转摘一些关于这方面的问题,以及我的回答,看看大家是否真的深入了解了定时器是如何工作的。



====================================================================================

在我新教材的第8章中,有个作业思考题如下:



5.当定时计数器工作在普通模式和CTC模式时,都可以产生一个固定的定时中断。如果要求精确的定时中断,采用那种模式比较好?为什么?



到现在没有一个学生给出完整、正确的回答。很多人连题目都看不懂。

====================================================================================



当你看完本贴后,能明白吗?

阿莫论坛20周年了!感谢大家的支持与爱护!!

月入3000的是反美的。收入3万是亲美的。收入30万是移民美国的。收入300万是取得绿卡后回国,教唆那些3000来反美的!

出0入0汤圆

 楼主| 发表于 2007-8-15 02:48:28 | 显示全部楼层
问题一:定时器0定时不准的问题



初学avr,碰到一问题困惑了好久,请大家指教。

用icc写的程序,使用atmega16的定时器0定时0.1ms,(7.7328M晶振,8分频,TCNT0 = 0xa4),用于产生频率5k的方波,用万用表测频率为4.9k(可能是万用表的测量精度问题),但在中断子程序中加了一段代码(这一段代码是个if语句,里面用到两个浮点数求和,但因为if条件不满足,这段代码根本就执行不到),再测频率就降到4.6k了,把if语句注释掉,频率恢复正常,真是奇怪。(没有开放其他中断)



中断子程序如下,其中变量error和ratio2均为float型,其他为整型。CHGBIT为改变某引脚值(用于产生方波)的宏定义。

#pragma interrupt_handler timer0_ovf_isr:10  //17 for atmega128

void timer0_ovf_isr(void)

{

   TCNT0 = 0xa4;//reload counter value   

  

   //7.3728M  (A4,0x02)for 10Khz   (D2,0x02)for 20Khz

   //8M       (9C,0x02)for 10Khz   (CE,0x02)for 20Khz

   if(lianji==1)

   {

      if(m1flag==0)

      {

         error+=ratio2;

         error_int=(int)error;

         error-=error_int;

      }  

      if(m1flag < (ratio1+ratio1+error_int+error_int))  

      {

         m1flag++;

         CHGBIT(PORTA,0);

         m1_total++;

      }

  }

  else

     CHGBIT(PORTA,0);

}



忘了说,变量liangji始终为0,所以满足if条件的语句根本就执行不到,这种情况下定时周期为什么会变长呢。即便是能执行到,if条件下也没几条语句啊,不应该影响定时啊 。



===============================================================================

我的回答情况:

使用atmega16的定时器0定时0.1ms,(7.7328M晶振,8分频,TCNT0 = 0xa4),用于产生频率5k的方波。



本身理论上就不是100us,而是99.826us。





你使用8M晶体、8分频、OCR0 = 0X63,采用CTC方式工作,比较中断,肯定可以得到精确的5K方波。



进了中断,马上将PA取反输出,然后再做你其它中断内的事情。只要你中断内的运行时间小于90us(大约700多条指令时间),保证你的5K方波非常精确。



而且使用AVR,只要初始化后,就可以得到5K方波,基本上属于硬件产生的,根本不用程序指令让输出反转。



《对方回复:用CTC方式中断定时很准确,谢谢马老师。不过还是想不明白前面提出的问题,那个奇怪的症状不知道怎么解释.......》



这不是奇怪的症状,是你还没有彻底和透彻的了解定时器到底是如何工作的。



所有的这些问题,在我的讲义中都讲到了,要求深入思考,而不是简单的表面的会“定时”中断。我的讨论组里也谈到这个问题的。你可以找一下。



回答你一个最基本的问题,其它你自己深入。



假定你算的很准(其实你第一次理论计算就不准),100us中断一次。它表示从TCNO的初值(0xa4)加到0XFF正好100us,申请中断。



OK!CPU响应中断需要时间的,这时TCNO又增加了计过好几个数了!!那么正确在中断中给TCNT0赋初值应该是“0xa4 + 中断响应时间 + 到设置TCNTO代码执行完的时间” ,你只是简单的再赋了0xa4,那么你实际的中断间隔就大于100us了,所以你的频率绝对是低于5K。



你说的第2种情况,如果你的中断代码如同LZ位贴上的,也就是进中断后,马上就设置TCNT0的初值,应该是不会产生的。如果你将IF语句什么的放在了设置TCNT0初值的语句前面了,那么语句的多少就会影响到输出频率的变化了。



使用溢出中断的话,中断中初值设置语句的位置如果不正确,也会影响定时中断的精度和准确性的。



上面忘记说明了,还有中断的现场保护时间。当你中断中有IF语句,尽管你说不用,但程序还是要把你可能要用的寄存器保护起来,时间长了,频率就低了。当你把IF等去掉,中断保护的内容就少了,频率就高一点了,中断现场保护部分,肯定在你给TCNT0重设初值前的。



不知道我是否解释清楚了。



LZ在5楼问到:“怎么没人理啊,是这个问题提得太没水准了吗?”



不是这个问题提得太没水准了,而是这个问题太有水准了,水平太高了,所以很少有人能正确、全面的回答,包括很多的现在在大学中“教”这门课的教师,也包括很多的“认为”自己有经验,能设计出产品的人。



LZ能问到和观察到这个现象还算脑筋认真学的,应该发扬。在我课堂教的学生中,决大部分的人根本连这个问题都提都提不出的。因为他们不会真正像LZ那样认真的动手实验,观察现象的,然后加深理解的。

在我新书中第8章中,有个作业思考题如下,是与你提出的问题相同的:



5.当定时计数器工作在普通模式和CTC模式时,都可以产生一个固定的定时中断。如果要求精确的定时中断,采用那种模式比较好?为什么?



到现在没有一个学生给出完整、正确的回答。很多人连题目都看不懂啦。



我现在回答了题目的一半了。

出0入0汤圆

 楼主| 发表于 2007-8-15 02:54:37 | 显示全部楼层
问题2:非常麻烦的问题:在定时器0的溢出中断程序中,进入第一行之前要51个时钟周期



在avrstudio4.09里面进行调试:



这个是溢出中断程序



void timer0_ovf_isr(void);//========》经仔细检查,进入此行时cycle=2089

{   

   TCNT0 = 236;          // =========》此时cycle=2140,化掉了51个clk??

   a++;                  //==========》此时cycle=2142

   if(a<4)

      PORTA=a;

   else

   {

      delay(2);

      PORTA=a;

      a=0;

   }

}



51个时钟周期啊,cpu干什么去了??这样搞得时间很不准啊!!如果用来编写显示时间的程序,要出大问题了!要不就把那段时间也算进去,那位高手能说一下吗??



=========================================================================

我的回复:



会汇编,光会用C,在单片机方面永远成不了真正的“高手”。



AVR的中断响应过程本身大约需要7个CLK左右,剩下的40几个CLK是中断现场保护,状态标志寄存器要保护吧?R0-R31共32个工作寄存器要保护吧?那就33个clk了。你不写,C帮你写了,否则你能说C好用吗。



但C写的中断保护是通用的,为了保证不出错,可能保护的最全了,有的时候可能会浪费(看你用的平台了)。因此要提高中断响应时间,自己写嵌入的汇编吧。

出0入0汤圆

 楼主| 发表于 2007-8-15 02:57:03 | 显示全部楼层
问题三:难道AVR的定时器真的这么不准吗?高手们进来帮帮忙啊



我用M32来做红外遥控解码,计划是用定时器0+外部中断0来做。



弄了很久都不行,后来才发现是定时器0的定时时间不准。



我用外部晶震8M,定时器0用普通模式8分频溢出中断。



为了求证时间准不准,我写了一个时钟程序来验证,结果发现定时时间比计算值长了,而且相差很大,大概60秒就差1秒,难道AVR定时器的精确度就只有这样?



望高手指教



===========================================================================

我的回答:



大家踏踏实实的看看我讲义的第8章吧。汗颜。



昨天已经回答了2个关于定时器定时时间不准的问题了。

出0入0汤圆

 楼主| 发表于 2007-8-15 03:15:03 | 显示全部楼层
总结:



1。他们能发现问题在一T/C0中断定时不正确,非常不容易。说明在动手中发现问题,并找到了原因,尽管不知道为什么。这比那些动手不动脑,发现不了问题要好多了。



2。有许多人认为自己知道,给了回复,但都是不正确的,或根本就没有说到点上,我没有转载这些人的回答。



3。AVR没问题,其它的单片机也没问题。问题我们的学习变成机械的照搬,不从根本上去理解了。



4。任何的单片机,使用溢出中断定时的话,肯定不准确,而且比你设计的中断时间间隔要长。问题很简单:就是CPU响应中断需要时间,进入中断后要做中断现场保护需要时间,然后是定时器设初值(如果定时器设初值放在中断最后,那更不准了)。“CPU响应的时间,进入中断后中断现场保护的时间”这两个时间没有扣除掉,所以中断间隔时间变长,表变慢的。



5。因此只有使用CTC方式,(51是自动重装方式)产生定时中断最准确了。各位知道为何吗?

出0入0汤圆

发表于 2007-8-16 09:30:27 | 显示全部楼层
看了这个帖子,发现自己的基础是实在是太差,迫切想看一下马老师讲讲义,请问马老师的讲义放在哪里?

出0入0汤圆

发表于 2007-8-17 16:10:25 | 显示全部楼层
硬件在计数值溢出时自动装载时间常数,不存在CPU响应中断时间,进入中断后中断现场保护时间造成的延时误差。

出0入0汤圆

发表于 2007-9-3 23:42:59 | 显示全部楼层
看了关于T0定时的问题,深有感触.

这是我在完成了用CTC模式精准定时之后,想到这儿找点什么问题时,看到的这些贴子.

马老师解释的很对,但那样理解起来很费劲.一种很简单明了的说明,我想应该是这样的:

1,要想得到精准的定时时间,请使用CTC模式,它跟51自动装填计数值一样;

2,定时时间不要超过中断程序运行指令的时间;

3,T0中断前面最好不要有其它中断源.因为T0中断级别很低,任何其它中断都有可能打断T0中断程序的运行,这样就有可能使T0中断运行时间超出定时间,造成定时不准.除非你定时时间很长.

出0入0汤圆

 楼主| 发表于 2007-9-4 07:30:32 | 显示全部楼层
7楼的理解还是有问题的。



1。正确



2。正确的理解应该是:中断程序运行指令的时间不要超过定时中断的间隔。其实,所有中断的服务程序的执行时间都应该尽量的短,这是中断服务编写的原则,我在讲义中明确说明过。



3。有误。这个问题更加复杂,实际上,AVR的硬件缺省方式是不支持高优先级中断打断低优先级中断的。另外,在一个系统中不可能保证只使用T0一个中断。那么在这样的情况下,如何保证T0的定时呢?



    A)首先,确保T0中断服务的执行时间远小于T0中断间隔时间

    B)其他的中断服务程序必须采用中断嵌套的方式:进入中断后,禁止除T0外的其它中断,开放全局中断。这样保证了T0中断可以打断任何的中断服务,T0的中断时间是精确的,只是中断服务程序的执行稍微晚了一点。

出0入0汤圆

发表于 2007-9-5 22:45:03 | 显示全部楼层
听君一席言,胜读十年书!

出0入0汤圆

发表于 2007-9-19 17:38:17 | 显示全部楼层
老大你的第八章讲义在哪里,呵呵我想看看

出0入0汤圆

 楼主| 发表于 2007-9-22 10:17:53 | 显示全部楼层
10楼:饭已经在桌上了,还要喂吗?

出0入0汤圆

发表于 2007-11-2 08:54:54 | 显示全部楼层
8楼马老师的: B)其他的中断服务程序必须采用中断嵌套的方式:进入中断后,禁止除T0外的其它中断,开放全局中断。这样保证了T0中断可以打断任何的中断服务,T0的中断时间是精确的,只是中断服务程序的执行稍微晚了一点。

   这里是中断重入情况,也就是T0中断服务程序重入情况,注意堆栈的容量和全局变量的使用,

出0入0汤圆

发表于 2007-11-2 09:08:31 | 显示全部楼层
介绍的很详细啊,理解的更透彻了。

出10入0汤圆

发表于 2007-12-17 22:23:45 | 显示全部楼层
我的回答情况:
使用atmega16的定时器0定时0.1ms,(7.7328M晶振,8分频,TCNT0 = 0xa4),用于产生频率5k的方波。  

本身理论上就不是100us,而是99.826us。  


你使用8M晶体、8分频、OCR0 = 0X63,采用CTC方式工作,比较中断,肯定可以得到精确的5K方波。


马老师: 我是个初学者,上面的第一种这个周期是怎么算的? 你说的第二种是我能理解


第一种我计算出来怎么不是你说的 99.826us

我是这样算的:第一种是不是用TIMER0 的溢出中断来重设 TCNT0 的值来达到周期控制

   如果是这样:TCNT0=0xa4  TOP=0xFF;  TOP-TCNT0=FF-A4=0x5B=91    7.7328*1000000=7732800/8=966600
               t=(1000000/966600)*91=94.14us

怎么会相差那么多啊,还是我的方法完全错了?

出0入4汤圆

发表于 2007-12-17 23:32:09 | 显示全部楼层
应该是CTC比较的准确,在普通模式下,进入定时中断口,马上要给TCNTX付初值,但是,从中断促发到TCNTX付初值完成中间所需的时间我们没有考虑进去,所以实际的定时周期要长一些,二CTC模式,当比较两个寄存器相同后,TCNTX由硬件立刻付初始值,中间没有浪费的时间,所以比较的准确。


主要是51单片机缺乏CTC这样的功能,所以我们用51单片机只能使用普通模式。

出0入0汤圆

发表于 2007-12-18 14:04:31 | 显示全部楼层
汉一个先,这个问题问得确实没什么水平。

首先,在AVR中,无论用普通方式,还是CTC模式,都肯定会产生同样精确的定时中断。

至于中断后的程序是否能精确运行,是与产生的中断无关的。

再其次,就产生一个方波的问题,对AVR来说,是不需要中断的:在CTC模式下可以自动取反,即不需要溢出中断,也不需要比较匹配中断。

以上结论,俺地ATMEGA16上验证并一直在用,

出0入0汤圆

发表于 2007-12-18 15:42:42 | 显示全部楼层
我觉得这个问题的出现在于很多人在用到定时中断时都将:中断产生后到重新赋值这个时间内计数器仍在计数这一事实给忽略了引起的。

事实上严谨的定时程序是这样的:

一是如果该定时中断为最优先中断,则赋值时应减去:中断响应到重新辅值时计数器已计数值。

二是如果该定时中断不为最优先中断,则应在赋值前关闭中断,然后用理论的初值减去当前已计数值。


CTC方式仅在晶振频率合适的时候,可以用硬件产生一个精确的计时,但受限的情况太多了:

如遇到7.7328M晶振产生频率5k的方波问题时就无能为力的。

出0入0汤圆

 楼主| 发表于 2007-12-18 23:13:00 | 显示全部楼层
17楼说明不妥.

CTC方式就是自动重装方式,肯定比赋值溢出方式准确.一\二都不如CTC方式方便和准确.请再仔细想想.

>>如遇到7.7328M晶振产生频率5k的方波问题时就无能为力的
那你使用赋值溢出方式也做不到.这不是定时器的问题.定时器只是计脉冲数.如果7.7328M不能产生整数个脉冲为5K(即整数分频到5K),那什么方法也办不到.

出0入0汤圆

发表于 2007-12-21 09:34:41 | 显示全部楼层
真是越看越晕,大概懂了,但没完全懂。得好好把书再读几遍

出0入0汤圆

发表于 2007-12-21 10:44:50 | 显示全部楼层
问马老师:51的timer0是否CTC?

void timer0 () interrupt TF0_VECTOR      / */
{
clock=clock+1;
}

出0入0汤圆

 楼主| 发表于 2007-12-21 19:55:45 | 显示全部楼层
51定时器有一个自动重装模式,与CTC相类似.

它是加一到溢出,产生中断申请,然后硬件自动将初始值装入计数器.

出0入0汤圆

发表于 2008-1-18 20:08:46 | 显示全部楼层
那AVR的T2要是自动溢出后,硬件自动赋值为0X00,我在中断里不赋初值,那定时会准确吗?

出0入0汤圆

 楼主| 发表于 2008-1-20 12:51:25 | 显示全部楼层
22楼:这样可以理解成自动重装的特例,定时中断准确的,但基本上没有实用价值,除非你的定时正好是从0x00-0xff.

因此,需要精确的定时中断,最好使用CTC模式(AVR),而且AVR的每个定时器都可以工作在CTC模式.

出0入0汤圆

发表于 2008-1-31 10:10:30 | 显示全部楼层
我就用到了这样的特例,特别是用手表晶振,而我用CTC模式反而误差更大

出0入0汤圆

 楼主| 发表于 2008-2-1 00:38:10 | 显示全部楼层
不会吧.CTC模式,将TOP值也设定为0xff不也一样么?

出0入0汤圆

发表于 2008-3-19 17:30:53 | 显示全部楼层
很好的问题。

出0入0汤圆

发表于 2008-3-20 17:03:30 | 显示全部楼层
如果定时初值在一直变化,采用CTC方式是否比普通模式准确?

出0入0汤圆

发表于 2008-4-16 22:23:45 | 显示全部楼层
这段时间一直都在看马老师的书,但我在学定时器时发现两个问题一直都搞不清楚,我还特意翻看了中文数据手册

(1)TOV0 的置位时刻到底是在何时
中文数据手册中有如下定义:
P69  Table 37. 定义
BOTTOM 计数器计到0x00 时即达到BOTTOM。
MAX    计数器计到0xFF ( 十进制的255) 时即达到MAX。
TOP    计数器计到计数序列的最大值时即达到TOP。TOP 值可以为固定值0xFF(MAX),或是存储于  
寄存器OCR0A 里的数值,具体由工作模式确定
P72
普通模式(WGM01:0 = 0) 为最简单的工作模式。在此模式下计数器不停地累加。计到8比特的最大值后(TOP = 0xFF),由于数值溢出计数器简单地返回到最小值0x00 重新开始。在TCNT0 为零的同一个定时器时钟里T/C 溢出标志TOV0 置位。
P78
Table 38. 波形产生模式的位定义
模式   WGM01 WGM00   T/C 的工作模式   TOP   OCR0的更新时间   TOV0 的置位时刻
0         0         0         普通         0xFF   立即更新           MAX

以上三段描述是从数据手册中择录的一部分,从上面第二段描述中,定时器T/C0在TCNT0 为零的同一个定时器时钟里T/C 溢出标志TOV0 置位;而在 波形产生模式的位定义中,TOV0 的置位时刻在TCNT0=MAX(MAX=0XFF);这似乎有些矛盾啊,如何理解这一点呢?TOV0 的置位时刻到底是在何时?
   (2)另外,我在用ICC+AVR来验证时,中断溢出标志是在0XFF加1为0时,从这里来看应该是计数256次,也就是说如果用1M的晶振,分频系数为1,TCNT0 = 0;那么定时时间应该是256US,可在ICC生成程序向导中,竟然算不出来TCNT0的初值,当定时时时间为255US时确可以算出,TCNT0=1!真是不解!
      
(原文件名:255.jpg)


(原文件名:256.jpg)

出0入0汤圆

 楼主| 发表于 2008-4-16 22:50:07 | 显示全部楼层
1.TOV0的置位时刻在到达MAX或TOP后,与下一个计数时钟的触发沿同步.具体参看T/C计数时序图.文字表述不严格.

2.楼上的计算是正确的.ICC的程序生成代码部分在这里的计算有点问题(可以算是ICC的BUG),例如配置成CTC模式时也会有偏差.要求精度高时,自己要具体算一算.

出0入0汤圆

发表于 2008-4-17 08:26:54 | 显示全部楼层
马潮老师讲解的很精辟。

出0入0汤圆

发表于 2008-4-17 08:49:41 | 显示全部楼层
对第一个问题还是搞不懂,看了T/C计数时序图,TOV0的置位时刻是在TCNT0 = MAX之后的下一计数时钟,也就在TCNT0 = BOTTOM 的同一个定时器时钟里T/C 溢出标志TOV0 置位,但书中表8.1及数据手册中波形产生模式的位定义都讲TOV0 的置位时刻在MAX,是不是该处有错误啊.

出0入0汤圆

 楼主| 发表于 2008-4-17 12:50:56 | 显示全部楼层
应该这样理解:置位在MAX结束时刻,不是开始时刻,相差1个计数时钟周期.说是错误有点过,只能算描述不严格吧.由于手册上是这样表述的,所以书中也按手册的表述,怕引起混乱.

要求精确的系统,应该按序图理解和处理,这应该是最正确的了.

出0入0汤圆

发表于 2008-4-17 13:10:57 | 显示全部楼层
谢谢马老师,我明白了

出0入0汤圆

发表于 2008-4-17 14:28:36 | 显示全部楼层
打处记号中…………………………………………………………

出0入0汤圆

发表于 2008-5-11 18:46:32 | 显示全部楼层
多谢马老师

出0入0汤圆

发表于 2008-5-11 20:00:29 | 显示全部楼层
学习一下!

出0入0汤圆

发表于 2008-5-17 10:48:38 | 显示全部楼层
复习了,谢谢!

出0入0汤圆

发表于 2008-5-22 17:00:56 | 显示全部楼层
请教马老师关于长时间延时的问题:
比如需要延时10个小时过着更长时间的延时,
在定时器中断中循环可以吗?

出0入0汤圆

发表于 2008-5-22 18:24:23 | 显示全部楼层
楼上的10H,用定时器计数,然后主程序判断就行了。

出0入0汤圆

 楼主| 发表于 2008-5-23 15:41:16 | 显示全部楼层
用T/C做个比如1分钟的定时中断,中断服务中使用软件计数器,每次中断加1,到达600设定10小时到:

// 中断服务(1分一次)
{
   if (++time_10h >= 600)
   {
       time_10h = 0;
       time_10h_ok = true;
   }
}

出0入0汤圆

发表于 2008-5-23 18:23:22 | 显示全部楼层
谢谢马老师!做一下笔记。

出0入0汤圆

发表于 2008-5-23 19:40:38 | 显示全部楼层
收藏,谢谢

出0入0汤圆

发表于 2008-7-7 16:27:39 | 显示全部楼层
佩服,马老师的科研态度!

出0入0汤圆

发表于 2008-8-4 14:49:22 | 显示全部楼层
BIAOB标记一个。学习。。。。。

出0入0汤圆

发表于 2008-8-4 15:16:46 | 显示全部楼层
会用一颗单片机不难,要想用好一颗单片机要用心去学才行.对于这个问题如此深入的讲解.受教育了...学习...

出0入0汤圆

发表于 2008-8-4 17:52:07 | 显示全部楼层
有了马老师,是我们学习AVR人的福气。

另请教一个问题:


//----------------定时器0——5ms程序-----------------
//系统时钟:11059200Hz  分频:1024
//Timer0初始化
void Timer0_5ms_Init(void)
{
  TCCR0=0;
  TCCR0=0x0d;
  OCR0=26;
  TIMSK|=0x02;
}

//Timer0 CTC中断,此中断发生周期是:5毫秒
ISR(TIMER0_COMP_vect)
{
  if(autotimer)
  {
    if(sign_startioconter)
    {
      timer++;
          if(timer==2){counter_5ms++;timer=0;}
      if(counter_5ms==counter_1s)
      {
        second++;
        if(second==keytime)
        {
          sign_startioconter=0;
          second=0;
          counter_5ms=0;
        }
      }
    }
  }
}

5毫秒的CTC定时,怎么出来的结果是2.5ms?

不解。主程序里涉及到这个定时,外面的效果是0.5s就有变化了,我预期的效果是1s的。

出0入0汤圆

 楼主| 发表于 2008-8-4 20:36:45 | 显示全部楼层
楼上的,你自己计算过了吗?

出0入0汤圆

发表于 2008-8-11 14:04:59 | 显示全部楼层
mark

出0入0汤圆

发表于 2008-9-11 21:31:48 | 显示全部楼层
标记一个。学习。。。。。

出0入0汤圆

发表于 2008-9-11 22:14:22 | 显示全部楼层
马老师真是及时雨啊!
我的产品开发遇到了定时器中断计数值偏小的问题,居然晚上看的第一个帖子就解决了我的困惑!

谢谢!

出0入0汤圆

 楼主| 发表于 2008-11-15 18:59:51 | 显示全部楼层
楼上,如果使用CTC模式就不用那么麻烦了。



关键点在于:

1。不管什么状态,当T/C中断后,T/C并没有停止工作,仍旧还在继续计数!!

2。在CTC方式中,程序本身通常是不改动TCNT的值的,因此2次中断的产生的间隔是非常准确的。至于中断处理是否准确是另外的事情。

3。而普通的溢出中断,通常在中断服务中需要改动TCNT的初值,这样就把系统响应中断和现场保护的时间“抹”掉了,如果不补偿的话,2次中断产生的间隔肯定比你理论计算的长。如果向楼上那样采用补偿方式,实际是非常麻烦的,它与你使用的系统有关(C语言到底产生的中断现场保护是多少?),而且如果系统中有其它中断,比如T/C中断产生时,另外的中断还没退出,你的T/C中断就“挂”在那里了。等到前面的中断退出,在执行你的T/C中断,你需要如何补偿?

出0入0汤圆

发表于 2008-11-15 19:30:03 | 显示全部楼层
嗯,多谢马老师的关注。



的确,自从看了您定时器方面的帖子和讲义,我目前编写的都是CTC模式的。即简练又实用,何乐而不为呢。

出0入8汤圆

发表于 2008-12-18 17:05:33 | 显示全部楼层
//&nbsp;中断服务(1S一次)&nbsp;

{&nbsp;

&nbsp;&nbsp;&nbsp;if&nbsp;(++time_1min>=&nbsp;60)&nbsp;

&nbsp;&nbsp;&nbsp;{&nbsp;

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;time_1min&nbsp;=&nbsp;0;&nbsp;

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;time_1min_ok&nbsp;=&nbsp;true;&nbsp;&nbsp;

&nbsp;&nbsp;&nbsp;}&nbsp;

}&nbsp;

马老师,你好!请教一下,我用定时器的CTC方式产生比较准确的秒脉冲,在其中断程序内累加,加入软件累加器,其判断语句

会消耗一定的时间,那么产生的分钟的时间比实际长,不知如何解决这个问题??

出0入0汤圆

 楼主| 发表于 2008-12-18 22:31:20 | 显示全部楼层
还是有必要清楚最基本的概念:



使用CTC方式,中断的产生的间隔是非常准确的。

使用普通方式,中断的产生间隔不是非常准确的。



但是中断产生间隔准确并不说明你的程序能准确的执行定时的功能。



就拿楼上的代码举例:采用了CTC方式,肯定能保证1秒产生1次中断。如果你的程序中没有其它的中断,那么执行到time_1min_ok&nbsp;=&nbsp;true;的时间基本上是固定的一个延时(中断响应时间+现场保护+判断与清另),其误差在1个CLK。(中断产生时当前指令正好执行完,与中断产生时当前指令还没执行完)。



因此尽管每次1分钟到比60次中断要拖后一点时间(假定20个CLK),但两次1分钟到的时间间隔还是60秒(最多差1CLK)。如果系统里面还有其它的中断的话,就可能会使两次1分钟到的时间间隔变化大一点(原因是尽管CTC中断产生了,但CPU可能正在执行另一个中断,不能马上响应CTC中断),但就是在这种情况下,这个误差是不会积累的。



而使用普通模式的话,就是没有其它中断,产生的误差也会积累的。



估计这样解释你也不一定搞的清楚和明白。



那么我简单回答你的问题:“产生的分钟的时间比实际长”的说法是没有意义的。应该是“2次产生分钟到之间的间隔,即2次执行time_1min_ok&nbsp;=&nbsp;true;的间隔就是60秒。就是有其它中断的影响,使得这次的间隔长了一点(60.0001秒),那么下次的间隔就会短于60秒(59.9999秒)

出0入8汤圆

发表于 2008-12-18 23:28:50 | 显示全部楼层
谢谢,马老师!!明白了!

出0入0汤圆

发表于 2008-12-19 10:31:36 | 显示全部楼层
mark

出0入0汤圆

发表于 2008-12-19 10:46:58 | 显示全部楼层
学习了

出0入0汤圆

发表于 2008-12-19 14:31:38 | 显示全部楼层
不错,不知道Atemel8L做时钟一天能误差多少mS??



我觉得除了马老师的计算方法之外,还要用32.768K的晶振做为外部振源;否则用高振荡的晶振受干扰大,用来做时钟根本不精确.

出0入8汤圆

发表于 2008-12-20 21:31:33 | 显示全部楼层
org&nbsp;0000h

ajmp&nbsp;main

org&nbsp;000bh

ajmp&nbsp;timer0

org&nbsp;30h

main:

&nbsp;&nbsp;&nbsp;&nbsp;mov&nbsp;tmod,#02h

&nbsp;&nbsp;&nbsp;&nbsp;mov&nbsp;tl0,#(256-200)&nbsp;;时钟频率为12MHZ,200us中断

&nbsp;&nbsp;&nbsp;&nbsp;mov&nbsp;th0,#(256-200)

&nbsp;&nbsp;&nbsp;&nbsp;setb&nbsp;tr0&nbsp;

&nbsp;&nbsp;&nbsp;&nbsp;setb&nbsp;et0

&nbsp;&nbsp;&nbsp;&nbsp;setb&nbsp;ea

&nbsp;&nbsp;&nbsp;&nbsp;mov&nbsp;r0,#0

&nbsp;&nbsp;&nbsp;&nbsp;mov&nbsp;r1,#0

&nbsp;m:ajmp&nbsp;m



timer0:

&nbsp;&nbsp;&nbsp;&nbsp;cpl&nbsp;p1.7&nbsp;&nbsp;;计时器在低电平计时,高电平不计时

&nbsp;&nbsp;&nbsp;&nbsp;inc&nbsp;r0

&nbsp;&nbsp;&nbsp;&nbsp;cjne&nbsp;r0,#2,t_ret

&nbsp;&nbsp;&nbsp;&nbsp;clr&nbsp;tr0&nbsp;&nbsp;&nbsp;;第二次入中断时关定时器便于观察计时

&nbsp;&nbsp;&nbsp;&nbsp;mov&nbsp;r0,#0

&nbsp;&nbsp;&nbsp;&nbsp;inc&nbsp;r1

&nbsp;&nbsp;&nbsp;&nbsp;cjne&nbsp;r1,#50,t_ret

&nbsp;&nbsp;&nbsp;&nbsp;mov&nbsp;r1,#0

t_ret:&nbsp;reti&nbsp;&nbsp;

end

马老师,再次请教你,我现在用51单片测试,T0工作于模式2方式(自动重载),用proteus仿真,

我主要想理解定时的定时精度问题。就用proteus仿真,用COUNTER&nbsp;TIMER计时,P1.7低电平计时

高电平不计时。发现其间隔很准,但是我不明白每次为是只199us而不是我想设定的200us。如果

中断产生时,指令没有执行完,时间变长,而不是变短。真的不明白,学生不明白,请马老师指

教指教!!

出0入8汤圆

发表于 2009-1-1 19:52:46 | 显示全部楼层
马老师,烦有时间指导一下!谢谢!!

出0入0汤圆

发表于 2009-2-23 08:31:29 | 显示全部楼层
学习

出0入0汤圆

发表于 2009-3-7 09:12:58 | 显示全部楼层
好帖子,学习了,记住了.
精确定时,必须CTC(自动重装).

出0入0汤圆

发表于 2009-3-7 10:14:16 | 显示全部楼层
是的,最好采用这种方式,反正硬件有这功能。另外对于硬件没有这种功能的,我以前所用的方法与此类似,但(以51为例)如果硬件我能自动加载的话,那么定时器有个特点就是溢出后是从0开始计数的,所以可以我按照教材的方法来初始化,而是在进入了中断后,向上叠加初始值。(程序中的运行指令时间是固定的,只要查出来在初始值上面修正一下就可以了)这也就相当于是自动加载了。

出0入0汤圆

 楼主| 发表于 2009-3-7 17:11:45 | 显示全部楼层
定时器溢出后从0开始计数,所以可以按照教材的方法来初始化,在进入了中断后,向上叠加初始值。(程序中的运行指令时间是固定的,只要查出来在初始值上面修正一下就可以了)这也就相当于是自动加载了。

严格讲与自动加载还是不同。如果系统中有多个中断,当定时器中断时,MCU不能及时响应,那么就会又要等待,这个修正是很难估计出的。

因此在任何时候,CTC方式都能产生最准确的定时中断申请,至于中断程序的执行也会产生稍微不同的延时。

出0入0汤圆

发表于 2009-3-10 15:53:25 | 显示全部楼层
学习

出0入0汤圆

发表于 2009-3-30 10:02:34 | 显示全部楼层
mark下 学习

出0入0汤圆

发表于 2009-4-1 11:00:45 | 显示全部楼层
上个星期买了马老师的书
相当受教,很感谢马老师,要是我上大学时能遇上像马老师的一样的导师就好了,哪怕是1/10好也行呀

出0入0汤圆

发表于 2009-4-4 23:50:04 | 显示全部楼层
很好,记下

出0入0汤圆

发表于 2009-4-14 09:30:01 | 显示全部楼层
了解好多好多东西。

出0入0汤圆

发表于 2009-4-15 15:04:49 | 显示全部楼层
AVR单片机的系统内部时钟源可不可以用外部晶振作为时钟源

出0入0汤圆

发表于 2009-4-15 15:12:52 | 显示全部楼层
当然可以~配置下熔丝

出0入0汤圆

发表于 2009-4-21 21:21:36 | 显示全部楼层
马老师你好!我想问一下你有没有这个版本的编辑器:code vision AVR 1.25.7a .

出0入0汤圆

发表于 2009-4-21 21:47:21 | 显示全部楼层
先做个记号。

出0入0汤圆

发表于 2009-4-21 22:05:16 | 显示全部楼层
先踩一步,明天再来看!

出0入0汤圆

发表于 2009-4-22 08:48:25 | 显示全部楼层
天天向上

出0入0汤圆

发表于 2009-4-22 19:28:34 | 显示全部楼层
记号

出0入0汤圆

发表于 2009-4-25 01:02:37 | 显示全部楼层
学习了,很受教啊!

出0入4汤圆

发表于 2009-6-13 21:24:58 | 显示全部楼层
受教受教

出0入0汤圆

发表于 2009-7-3 12:28:38 | 显示全部楼层
说的好,  学习咯!

出0入0汤圆

发表于 2009-7-3 13:28:05 | 显示全部楼层
回【60楼】 fangmcu 方谭

我想这是个问题
T0计数是准确的,只不过中断有一个响应时间后才执行cpl p1.7,但这个响应时间不固定。

用52单片机的T2直接从引脚输出看一下应该比较准。

出0入0汤圆

发表于 2009-7-3 13:49:12 | 显示全部楼层
mark

出0入0汤圆

发表于 2009-7-8 21:14:26 | 显示全部楼层
刚入门,研究过一段时间汇编!看是看明白了就是没实践啊!

出0入0汤圆

发表于 2009-7-10 17:03:04 | 显示全部楼层
mark

出0入0汤圆

发表于 2009-7-28 13:32:19 | 显示全部楼层
mark!

出0入0汤圆

发表于 2009-8-5 17:23:51 | 显示全部楼层
有所学习,哈哈!

出0入0汤圆

发表于 2009-8-8 14:56:55 | 显示全部楼层
mark下了

出0入0汤圆

发表于 2009-8-10 16:39:02 | 显示全部楼层
定时器可真有用,而也真麻烦
还得继续思考

出0入0汤圆

发表于 2009-9-28 11:22:54 | 显示全部楼层
认识上有进步,感谢!

出0入0汤圆

发表于 2009-10-14 16:52:22 | 显示全部楼层
mark 大师

出0入0汤圆

发表于 2009-10-15 16:52:30 | 显示全部楼层
我想他们在AVR编程的时候还是使用的51单片机中的思想。因为在51单片机中我见不少同学使用定时器0或者1来定时的时候,都是在进入中断后给定时器赋值,如果没有计算好时间关系,误差大是必然的——所以我讨厌使用51单片机的定时器来精确定时,宁愿使用外部时钟电路。

在52单片机中定时器2,支持16位重载方式,这就和AVR的CTC方式一样,但我注意到很多人都没用这个……可能与使用的教材有关,因为很多51单片机教材中都没有提到T/C2。

当然,使用7.3728MHz的晶振来产生5KHz的方波能行吗?7.3728M÷5K=1474.46,得到的商不是个整数,所以得不到准确的5KHz方波。

一家之言,呵呵!

出0入0汤圆

 楼主| 发表于 2009-10-15 17:16:42 | 显示全部楼层
标准51有8位自动重载功能,同AVR的CTC模式。

出0入0汤圆

发表于 2009-10-15 18:13:30 | 显示全部楼层
mark

出0入0汤圆

发表于 2009-10-17 13:58:39 | 显示全部楼层
"===============================================================================
我的回答情况:
使用atmega16的定时器0定时0.1ms,(7.7328M晶振,8分频,TCNT0 = 0xa4),用于产生频率5k的方波。  

本身理论上就不是100us,而是99.826us。  


你使用8M晶体、8分频、OCR0 = 0X63,采用CTC方式工作,比较中断,肯定可以得到精确的5K方波。  

进了中断,马上将PA取反输出,然后再做你其它中断内的事情。只要你中断内的运行时间小于90us(大约700多条指令时间),保证你的5K方波非常精确。"
*******************************
马老师:
1.我怎么算的也不等于99.825us,8*(0xff-0xa4+1)/7.7328=95.1789...。8*x/7.7328=99.825,x=0x60,0x100-0x60=0xa0。老师是不是看成了0xa0了,呵呵~。
2.下一句话我有个理解:工作在CTC模式,上升沿触发,计数时间是100us,如果波形由OC0输出的话电平跳变位置应该是正好在TOP的下个时钟的上升沿,这种是我们想像的那种情况。但是把波形由PA0输出,在比较匹配时进入中断时像您说的需要中断响应时间、赋值时间,然后才触发了电平。就和第一种不一样了,但波形应该还是精确的。因为在赋值前这段时间,等于定时器走的时间,在下一次触发的时候。两次触发的时间间隔等于((TOP+1)*时钟周期-中断赋值前定时器走的时间)+中断赋值前定时器走的时间,时间还是相等的。这种情况是叫相位变化了吧。不知道说的清不清楚、对不对?[看马老师的电子书(不舍得花钱买,老师请不要怪罪,:) ,目前看到PWM波,不知道怎么没有11章以后的章节]
3.再下一行,您说“只要你中断内的运行时间小于90us”,意思就是中断不要太长以影响下次中断的意思吧,否则影响PA0,有误差。100-90=10us
10us是留给保护和恢复现场用的?10/(1/8)=80条指令,保护和恢复大约各占40?

出0入0汤圆

发表于 2009-10-17 14:27:05 | 显示全部楼层
我是LS,还想问下马老师定时器的模式选择,WGM1:0,00时是普通模式,01时电子书(是电子书)上书上写的是“PWM,相位可调”,10时是CTC,11时快速PWM。可你所有涉及的程序中CTC写的确是01,仿真了下是正确的,改成10有错误。我看了datasheet英文、中文都是10。所以我想马老师写教材的时候是不是直接把那张表复制过来,没有细看,而这张表存在错误。

出0入0汤圆

 楼主| 发表于 2009-10-17 15:55:38 | 显示全部楼层
没有错,注意WGM0[1:0]两个控制位在TCCR0寄存器中的位置是反的,WGM00在前面,WGM01在后面。

资料上描述为WGM0[1:0] = 10,写TCCR0时则为01,因为WGM00在前面。

出0入0汤圆

发表于 2009-10-17 16:44:04 | 显示全部楼层
偶,真是那样,马虎了。谢谢老师。
还是不要怀疑datasheet了。

出0入0汤圆

发表于 2009-10-17 16:49:31 | 显示全部楼层
mark

出0入0汤圆

 楼主| 发表于 2009-10-17 17:23:32 | 显示全部楼层
回94楼:

1。产生脉冲序列,实际使用CTC模式比较匹配触发输出,根本可以不需要中断的。我不知道原来在中断中还要做什么,才保留了中断。

2。在中断中将一个I/O取反输出,实际是51的概念,因为标准51的T/C没有什么较匹配触发的输出。新的控制器中的T/C都会有这样功能,这也是我推荐应该从AVR,而不是51入手学习的原因。要尽量掌握新的东西,新的功能。有许多人认为会51,使用AVR也没有困难,这是错误的观点。在AVR上用51的方法当然可以,但你没有发挥AVR的特点,做不出更好的东西。就如同这个简单的5K发生,用AVR根本不需要中断,而51就必须使用中断。很多人停止不前,被51固化和害了。

3。在中断中将I/O取反,也能精确,但时间晚点(相位拖后),这是对的。但如果系统中还有其它的中断,这个就说不清楚了。不管你是中断嵌套,还是等待,产生脉冲精度就不准了。

4。中断应该尽量的短,这是我的书中已经给出的原则。我留10us只是估计,当然是越短越好。它的中断中还要做什么我不知道,所以中断现场的保护也不知道需要多少时间。另外,你的系统不能光中断吧,主程序不处理其它事情了?

5。这个只是讲一个如何精确产生5K的例子。实际从代码结构看,好多地方都不合适,思路和处理方法也不对。一看就知道是受了51的毒。

出0入0汤圆

发表于 2009-10-26 21:57:10 | 显示全部楼层
看了马老师的帖子,十分感谢马老师的无私教诲。
最近也在使用精确定时,但我遇到了和46楼一样的问题,自己设定的是5s的定时,示波器显示2.5s。
频率就是根据公式计算所得,为什么会是这样呢?还有就是在中断中没有设置TIMSK_OCIE1A = 0和TIMSK_OCIE1A = 1时,定时时间是随机值,这个中断允许标志位需要这样设置吗?请教马老师,谢谢。
代码如下:
void DELAYX1S(Byte SECOND)
{
  DelayTime = 10*SECOND;
  Timer1_Init();
  while(DelayTime > 0);
}

void Timer1_Init(void)
{
  TCCR1A = 0x00;     
  TCCR1B = 0x0C;     // CLK/256
  TCNT1  = 0x0000;
  OCR1A  = 6249;
  TIMSK_OCIE1A = 1;  // T/C1匹配中断允许
}

#pragma vector = TIMER1_COMPA_vect
__interrupt  void timer1_compa(void)
{  
  TIMSK_OCIE1A = 0;
  DelayTime--;
  TIMSK_OCIE1A = 1;
  if(DelayTime < 1)
  {
    DelayTime = 0;
    TIMSK_OCIE1A = 0;
  }
}
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-4-26 14:27

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

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