搜索
bottom↓
回复: 58

~~~ 延时不准,请大家来帮忙啊!!!~~~ 我头大了好久了,谢谢先!!

[复制链接]

出0入0汤圆

发表于 2011-10-25 08:53:33 | 显示全部楼层 |阅读模式
我用STC89C52RC做的一个测温湿度的节点,测试发现定时不准,我不知道为什么。我想问下面3个问题:
【1】我的程序和实现是否有问题?
【2】这个误差是否会与环境温度有关系? (节点测得的温度就是它的工作的环境温度,传感器和单片机、晶振都在一起。)
【3】除了上面2点,可能造成这个问题的原因还有什么?

我是这样实现的:
【1】用Timer0,计时50ms,晶振11.0592MHz


【2】在Timer0的中断程序里面,计数每20个50ms就是1秒,然后每到一定时间(比如5分钟)就将 sendDataFlag置1一次,


【3】main函数里面是while的死循环,如果sendDataFlag为1,就向上位机发送一次温湿度值,并把sendDataFlag置0。


下面上位机收到的结果,


我们可以看到有段时间7:29至8:19这段时间定时比较准,每5分钟一次
但是6:43至7点23这段时间定时就非常不准。

在我以往的试验中,也有这样不准的情况出现,每5分钟就会有1秒左右的误差。下面是昨晚试验的数据:



请大家指点一下,我迷惑了很久了。谢谢先!

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

一只鸟敢站在脆弱的枝条上歇脚,它依仗的不是枝条不会断,而是自己有翅膀,会飞。

出0入0汤圆

发表于 2011-10-25 10:07:15 | 显示全部楼层
可以闰秒,隔一段时间对计时修正,有条件用电网作时钟源,精度很高

出0入0汤圆

发表于 2011-10-25 10:43:09 | 显示全部楼层
中断判断==改成 》=     if(++t>=20)t1++;

出0入0汤圆

 楼主| 发表于 2011-10-25 10:44:50 | 显示全部楼层
回复【1楼】1ongquan  
可以闰秒,隔一段时间对计时修正,有条件用电网作时钟源,精度很高
-----------------------------------------------------------------------

感谢楼上的回复,不过我还是想找出问题的原因来。

我总感觉应该不是温度的引起的,因为同样在19度左右,有比较精确的情况出现,也有误差较大的情况出现。

请大家帮我看看我的定时器使用有没有问题?比如初始化定时器、中断程序等。
谢谢

出0入0汤圆

 楼主| 发表于 2011-10-25 10:48:42 | 显示全部楼层
回复【2楼】yao1  
中断判断==改成 》=     if(++t>=20)t1++;  
      
-----------------------------------------------------------------------

感谢2楼的回复。

好的,我试试。

不过我在写程序时,考虑到做">="要比"=="多化时间,所以我就用了"=="

能解释一下在什么样的情况下这个程序会跳过20吗?

出0入0汤圆

发表于 2011-10-25 11:29:38 | 显示全部楼层
我也是菜鸟, 我的理解(如果错误见谅):
   发送数据的函数如果时间大于50ms就会出现 如果程序在发送数据 此时恰好定时器进入中断并且T刚好也加到20 那么发送完数据再进入中断时就错过了这次的判断
     》= 已经包含了== 不会多花时间的 只要检测到==20就会进入中断 如果检测不到20 才会继续检测21.22.23 ....
你如果写==如果检测不到20, 就会隔20次才会再次检测 ;而》=是检测不到20,就隔1次再检测

出0入0汤圆

发表于 2011-10-25 11:31:02 | 显示全部楼层
中断判断==改成 》=     if(++t>=20)t1++;

出0入0汤圆

 楼主| 发表于 2011-10-25 12:08:39 | 显示全部楼层
回复【5楼】yao1  
    我也是菜鸟, 我的理解(如果错误见谅):
   发送数据的函数如果时间大于50ms就会出现 如果程序在发送数据 此时恰好定时器进入中断并且t刚好也加到20 那么发送完数据再进入中断时就错过了这次的判断
     》= 已经包含了== 不会多花时间的 只要检测到==20就会进入中断 如果检测不到20 才会继续检测21.22.23 ....
你如果写==如果检测不到20, 就会隔20次才会再次检测 ;而》=是检测不到20,就隔1次再检测
   
  还有就是c语言的这种计数本来就不是很准确 你要很准确要用汇编写
-----------------------------------------------------------------------

感谢你的回复。我更菜, 大家一起讨论下挺好的。

我引用你的话:“发送数据的函数如果时间大于50ms就会出现 如果程序在发送数据 此时恰好定时器进入中断并且t刚好也加到20 那么发送完数据再进入中断时就错过了这次的判断 ”

我觉得这个有问题。我认为判断不会错过,因为中断发生的时候,发送数据程序就暂停了,而是跳过去执行中断子程序,等中断完成后再跳回去继续执行发送数据的程序。 你觉得我说得对不对?

顺便说一下,在发送数据的过程中不会有其它的中断产生了。

不过我现在已经改了程序,用>=了,目前还是准的,有进一步结果我会来更贴的。

另外,我澄清一下,“考虑到做">="要比"=="多花时间” 我指的是执行判断指令==的时间比执行>=这个判断的时间长,而不是说延时的时间会更长。我看你好像误解我的意思了。

谢谢

出0入0汤圆

 楼主| 发表于 2011-10-25 12:14:20 | 显示全部楼层
回复一下2楼,改用 >= 后,还是不准。

这是最新的数据,每5分钟还是有1秒左右的误差。

出0入0汤圆

发表于 2011-10-25 12:14:42 | 显示全部楼层
难道是你的程序里面有其他的中断影响了?或者程序里有中断屏蔽?

出0入0汤圆

发表于 2011-10-25 12:37:07 | 显示全部楼层
试试看STC的办法,还能省电~~

(原文件名:QQ截图20111025122711.png)

出0入0汤圆

 楼主| 发表于 2011-10-25 12:37:18 | 显示全部楼层
回复【10楼】ruizhixing  睿
难道是你的程序里面有其他的中断影响了?或者程序里有中断屏蔽?
-----------------------------------------------------------------------

没有其它中断了。也没有屏蔽过中断。

出0入0汤圆

发表于 2011-10-25 12:39:47 | 显示全部楼层
还有就是C语言的这种计数本来就不是很准确1周期慢10几个微妙 时间长了就会有误差  C语言的计数没有计算机那么准确的,误差1秒 我认为正常 你要很准确得用汇编写

出0入0汤圆

 楼主| 发表于 2011-10-25 12:40:48 | 显示全部楼层
回复【11楼】renpeng009  大鹏集成
试试看stc的办法,还能省电~~

(原文件名:qq截图20111025122711.png)
-----------------------------------------------------------------------

呵呵 谢谢回复。

不过我主要是想搞清楚为什么会这样?

如果大家能确认我对定时器的用法没有问题,而且大家认为通过计数器只能实现这样的精度,那么我就再找其它解决方案。

出0入0汤圆

发表于 2011-10-25 12:44:55 | 显示全部楼层
咋不见读取温度的部分?

既然你自己都怀疑了,干脆去掉读取温湿度部分,发送假数据看看时间还准不准。

话说这么长的时间间隔,如果不采用RTC的话,还不如由上位机发送请求呢。。

出0入0汤圆

发表于 2011-10-25 13:00:02 | 显示全部楼层
看你程序中计数器判断的时候改为21和senddatainterval+1,结果可能会稍微好的……

出0入0汤圆

发表于 2011-10-25 13:12:22 | 显示全部楼层
你的T0中断里面重新送初值-------你想当然的认为TL0是0,其实是错误的.
如果要定时准确:
1. 把T0停下来
2. 给(TL0 TH0)这个 16-BIT 加上一个16-BIT常数(比你的那个0x4c00要稍大些-----要把暂停的时间考虑进去)
3. 重新启动T0

出0入0汤圆

发表于 2011-10-25 13:47:35 | 显示全部楼层
时间慢主要原因:

1、中断延迟
2、定时器用了软重赋值
头像被屏蔽

出0入0汤圆

发表于 2011-10-25 13:50:37 | 显示全部楼层
提示: 作者被禁止或删除 内容自动屏蔽

出0入0汤圆

发表于 2011-10-25 14:08:57 | 显示全部楼层
同意20楼 定时器初值改成:
TH0=(65536-45872)/256; //0X4C
TL0=(65536-45872)%256; //0XD0

TL0不赋值 每次多计数208 所以你的时间会变慢

出0入0汤圆

 楼主| 发表于 2011-10-25 14:46:16 | 显示全部楼层
首先感谢楼上各个楼层的回答。

回复17楼和20楼,

因为我计算出来的常数是0x4C00,TL0是从0开始的,所以就不用重装了。(不重装应该就是从0开始吧?)

我这样做的目的就是为了避免修正中断开始到定时器赋值这段时间。我的想法是:中断开始的时候,我只给TH0重装赋值,而TL0还是让它继续走,这样只要能保证在TH0的赋值过程能在TL0从0走到255之间完成,那么定时器就应该是准的。

我不知道这个想法正确否?

大家指正一下。


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

回复【20楼】bbs2009  
回lz:
   本人愚见:
    5 分钟就差1秒 绝对是程序有问题。 俺 n年前 c 做的 沙盘配解说的显示控制 15 分 也不会差 1秒。
   
    有二点供你参考:
    一:11.0592 m  是否可得到 精确 的 20ms  延时 值得 商榷,需要修正。
    二:c 可以写出精确的定时器程序, 但你要修正按公式计算的 tho tl0 数值,考虑进入中断到给
        定时器赋值的延时。
   
-----------------------------------------------------------------------

回复【17楼】gwdong  
你的t0中断里面重新送初值-------你想当然的认为tl0是0,其实是错误的.
如果要定时准确:
1. 把t0停下来
2. 给(tl0 th0)这个 16-bit 加上一个16-bit常数(比你的那个0x4c00要稍大些-----要把暂停的时间考虑进去)
3. 重新启动t0
-----------------------------------------------------------------------

出0入0汤圆

 楼主| 发表于 2011-10-25 14:56:01 | 显示全部楼层
回复【21楼】yao1  
同意20楼 定时器初值改成:
th0=(65536-45872)/256; //0x4c
tl0=(65536-45872)%256; //0xd0
tl0不赋值 每次多计数208 所以你的时间会变慢
-----------------------------------------------------------------------

难道是我的常数计算错了?!!

0x4C00就是19456,
而 (65536-19456)*12/11059200=0.05s=50ms 这个好像没问题吧
我当时特意找了一个低8为0的常数。我想这样就可以不用给TL0赋值了。

yao1能否说一下你这个0x4cd0是怎么算出来的?我没看明白。
谢谢

出0入0汤圆

发表于 2011-10-25 15:39:32 | 显示全部楼层
我是这么算定时器初值的:
   12个时钟周期=1个机器周期=12*(1/11059200)=1.09us (晶振11.0592)
  若t=50ms 那么N=50000/1.09=45872  要计数45872 TH0 TL0应该装入总数为65536-45872=19664
  把19664对256求模19664/256=76(十六进制4C) 装入TH0
  对256求余19664%256=208(十六进制D0) 装入TL0

出0入0汤圆

发表于 2011-10-25 15:55:26 | 显示全部楼层
定时器初值改成:
TH0=(65536-45872)/256; //0X4C
TL0=(65536-45872)%256; //0XD0

出0入0汤圆

发表于 2011-10-25 16:04:48 | 显示全部楼层
我四舍五入误差问题   
12个时钟周期=1个机器周期=12*(1/11059200)=1.085us (晶振11.0592)
若t=50ms 那么N=50000/1.085=45872  要计数46080 TH0 TL0应该装入总数为65536-45872=19456
  把19456对256求模19456/256=76(十六进制4C) 装入TH0  
  对256求余19456%256=0(十六进制0) 装入TL0
你的算法正确

出0入0汤圆

 楼主| 发表于 2011-10-25 16:06:41 | 显示全部楼层
回复【24楼】yao1  
   我是这么算定时器初值的:
   12个时钟周期=1个机器周期=12*(1/11059200)=1.09us (晶振11.0592)
  若t=50ms 那么n=50000/1.09=45872  要计数45872 th0 tl0应该装入总数为65536-45872=19664
  把19664对256求模19664/256=76(十六进制4c) 装入th0
  对256求余19664%256=208(十六进制d0) 装入tl0
-----------------------------------------------------------------------

“12个时钟周期=1个机器周期=12*(1/11059200)=1.09us ”  这个1.09是约数,要准确的话,下面这样算:

0.05/12*11059200=46080,初值为65536-46080=19456=0x4C00 跟我算的一样,对不对?

出0入0汤圆

 楼主| 发表于 2011-10-25 16:20:05 | 显示全部楼层
回复【15楼】huayuliang  花生
咋不见读取温度的部分?
既然你自己都怀疑了,干脆去掉读取温湿度部分,发送假数据看看时间还准不准。
话说这么长的时间间隔,如果不采用rtc的话,还不如由上位机发送请求呢。。
-----------------------------------------------------------------------

温度读取部分无关,我就没放上来干扰视线了。

我手头有块12c887的RTC,一个小时要慢几分钟,也不知道为何。

我认为5分钟间隔不算太长,应该可以做到精确的。

出0入0汤圆

发表于 2011-10-25 16:26:06 | 显示全部楼层
看看这篇文章 用c51语言实现单片机高精度定时的新算法ourdev_688564MYHN6Y.pdf(文件大小:715K) (原文件名:用C51语言实现单片机高精度定时的新算法.pdf)
头像被屏蔽

出0入0汤圆

发表于 2011-10-25 16:47:21 | 显示全部楼层
提示: 作者被禁止或删除 内容自动屏蔽

出0入0汤圆

 楼主| 发表于 2011-10-25 17:23:11 | 显示全部楼层
回复【16楼】Dalong357  
看你程序中计数器判断的时候改为21和senddatainterval+1,结果可能会稍微好的……
-----------------------------------------------------------------------

这样就在毫秒和秒级别都多了一次循环出来,不是吗?这样会更慢吧?

出0入0汤圆

 楼主| 发表于 2011-10-25 17:30:57 | 显示全部楼层
回复【31楼】bbs2009  
还是愚见:
1. 必须给tl0   赋值  。
2. 必须修正    0x4c00。不然一定慢 。

-----------------------------------------------------------------------
感谢您的回复。

能否解释一下第一点的原因?或者说如果不赋值给TL0会怎样? (千万别说定时会慢哦  呵呵)

我想当然的认为不重新赋值计数器还是从0开始计数的。


另外,怎么没有18楼和25楼? 奇怪  呵呵

出0入0汤圆

发表于 2011-10-25 17:37:38 | 显示全部楼层
回复【33楼】haozi007
-----------------------------------------------------------------------

18 25 是我发的贴 发现发出来有问题就删除了

出0入0汤圆

发表于 2011-10-25 17:38:44 | 显示全部楼层
看看30楼我发的那篇文章看来你只能修正TH0 TL0了

出0入0汤圆

 楼主| 发表于 2011-10-25 17:43:48 | 显示全部楼层
回复【34楼】yao1  

18 25 是我发的贴 发现发出来有问题就删除了
-----------------------------------------------------------------------

呵呵 谢谢   其实这个问题不用回答,我写出来供大家娱乐一下的 :)

出0入0汤圆

发表于 2011-10-25 18:31:38 | 显示全部楼层
看你的实验现象是大概5分钟慢1S 那50ms大概慢0.2ms 你让计数器计数到49.8ms进位看看
我大概算下修正:TH0=0X4C; TL0=0XB4;

出0入0汤圆

 楼主| 发表于 2011-10-25 20:29:11 | 显示全部楼层
回复【37楼】yao1  
看你的实验现象是大概5分钟慢1s 那50ms大概慢0.2ms 你让计数器计数到49.8ms进位看看
我大概算下修正:th0=0x4c; tl0=0xb4;
-----------------------------------------------------------------------

这样肯定不行,误差不到1秒,按0.2ms每50ms算误差肯定更大。

我读了你上面付的文章,我觉得应该是每次中断都延迟了中断转移指令周期的时间(T0),但是文章里面提到的T2和T3我就不是很理解了。有朋友出来指点一下吗?

另外,现在这个延时每次慢的时间是随机的,不是一直5分钟慢1秒。有时候有是准的,有时候又会慢。

所以我觉得还是要找出慢的原因来才能最终解决这个问题。

当然,我也很感谢前面回帖的各位网友,给我指点了很多应该怎么做来解决的这个问题的办法和方向。但是到目前位置,还是没人能回答一下我这样做为什么会慢的问题。

谢谢

出0入0汤圆

 楼主| 发表于 2011-10-25 20:33:00 | 显示全部楼层
回复【30楼】yao1  
  看看这篇文章 用c51语言实现单片机高精度定时的新算法 (原文件名:用c51语言实现单片机高精度定时的新算法.pdf)

-----------------------------------------------------------------------

感谢您这么费心。我看了文章,有几个问题,大家指点一下:

【1】T0 中断转移指令周期,这个如何找到?技术手册吗? (我单片机才入门3个月不到,希望大家能用我可以懂的语言来回答)
【2】T2 中断返回指令的执行周期  (为什么这个指令会影响定时精度?)
【3】T3 中断返回断点后执行下一条指令的周期 (为什么这个指令会影响定时精度?)

出0入0汤圆

发表于 2011-10-25 21:02:03 | 显示全部楼层
若定时器工作在方式2,则可实现极短时间的精确延时;如使用其他定时方式,则要考虑重装定时初值的时间(重装定时器初值占用2个机器周期)。
  在实际应用中,定时常采用中断方式,如进行适当的循环可实现几秒甚至更长时间的延时。使用定时器/计数器延时从程序的执行效率和稳定性两方面考虑都是最佳的方案。但应该注意,C51编写的中断服务程序编译后会自动加上PUSH ACC、PUSH PSW、POP PSW和POP ACC语句,执行时占用了4个机器周期;如程序中还有计数值加1语句,则又会占用1个机器周期。这些语句所消耗的时间在计算定时初值时要考虑进去,从初值中减去以达到最小误差的目的。

出0入0汤圆

发表于 2011-10-25 21:07:05 | 显示全部楼层
汗! 我学了5个月了也是很多不明白 所以混论坛提高下自己
高手一般都懒的回答我们的问题的 一般都是水平差不多的回答

出0入0汤圆

发表于 2011-10-25 22:28:44 | 显示全部楼层
用C语言写的,定时器工作在手动重装初值模式下,定时时间是不能精确的预测的。
建议用自动重装初值的工作模式。

出0入0汤圆

 楼主| 发表于 2011-10-25 23:17:55 | 显示全部楼层
回复【42楼】jing43  
用c语言写的,定时器工作在手动重装初值模式下,定时时间是不能精确的预测的。
建议用自动重装初值的工作模式。
-----------------------------------------------------------------------

感谢您的回复,恕我太愚,我想追问一下:为什么“用c语言写的,定时器工作在手动重装初值模式下,定时时间是不能精确的预测的”?

特别是在我的这个特定例子,我觉得中断跳转、压栈和重装时间没有超过256个机器周期,应该是准确的呀?我这样想错在哪里呢?

不过顺便说明一下,从我观察到的现象来看,误差确实是随机的(至少我还没发现规律),这个比较复合您说的“不能精确的预测”。

出0入0汤圆

 楼主| 发表于 2011-10-25 23:21:51 | 显示全部楼层
回复【41楼】yao1  
   汗! 我学了5个月了也是很多不明白 所以混论坛提高下自己
高手一般都懒的回答我们的问题的 一般都是水平差不多的回答
-----------------------------------------------------------------------

不要汗 我学了3个月,但又没说是零基础开始学的 呵呵。和您交流非常愉快,感谢您花这么多时间在我这个问题上,希望您自己也有所收获。

高手们比较忙吧  呵呵  开个玩笑。 说实话,我觉得这个问题要说清楚还是要花点时间的,他们有更重要的事情要做,这个我可以理解的。

出0入0汤圆

 楼主| 发表于 2011-10-25 23:47:18 | 显示全部楼层
我看程序已经彻底凌乱了 呵呵,下面这个截图是最新的数据,居然还有4分钟的间隔。


在没人人回答我的问题之前,我打算先暂时放一放了, 今天耗了大家太多时间,我比较过意不去

出0入0汤圆

发表于 2011-10-25 23:58:56 | 显示全部楼层
你上位机不会有问题吧

出0入0汤圆

 楼主| 发表于 2011-10-26 00:13:21 | 显示全部楼层
回复【46楼】packer  
你上位机不会有问题吧
-----------------------------------------------------------------------

在您的提示下,我检查了一番,没有看出明显问题。
我觉得我们可以暂时排除上位机有问题的可能性。

今天头已经彻底晕了,等明天我重新搭个电路,就只做定时和串口通信,试验过后再来跟大家汇报。

再次感谢楼上各位的帮忙,祝大家晚安!

出0入0汤圆

发表于 2011-10-26 01:41:17 | 显示全部楼层
LZ你把你T0中断服务程序中开始的“TH0 = 0x4C;”改成如下这样试试:
TR0 = 0;
TH0 = 0x4C-TH0;
TR0 = 1;


如果还不行,用方式2吧。

出0入0汤圆

发表于 2011-10-26 01:48:43 | 显示全部楼层
回复【15楼】huayuliang 花生
咋不见读取温度的部分?
既然你自己都怀疑了,干脆去掉读取温湿度部分,发送假数据看看时间还准不准。
话说这么长的时间间隔,如果不采用rtc的话,还不如由上位机发送请求呢。。
-----------------------------------------------------------------------

同意

出0入0汤圆

 楼主| 发表于 2011-10-26 11:34:48 | 显示全部楼层
回复【48楼】eduhf_123  经历
lz你把你t0中断服务程序中开始的“th0 = 0x4c;”改成如下这样试试:
tr0 = 0;
th0 = 0x4c-th0;
tr0 = 1;
如果还不行,用方式2吧。
-----------------------------------------------------------------------

感谢回复  不过我试了一下,误差比原来的还大。据我分析,应该是定时器被关闭后,没有补偿这3行代码执行时间所致。

不过我受你这个启发,把关闭、打开定时器代码去掉,只重装了th0,下面是执行的效果:(这是logger里面出来的数据,可以看到毫秒)

11:54:07.500 data received: ID 100 1 - 50 0 22 6, Length:5.
11:59:11.734 data received: ID 100 1 - 50 0 22 4, Length:5.
12:04:13.890 data received: ID 100 1 - 49 0 22 5, Length:5.
12:09:14.906 data received: ID 100 1 - 49 0 22 4, Length:5.
12:14:15.062 data received: ID 100 1 - 49 0 22 5, Length:5.
12:19:15.625 data received: ID 100 1 - 49 0 22 5, Length:5.
12:24:15.781 data received: ID 100 1 - 49 0 22 4, Length:5.
12:29:16.250 data received: ID 100 1 - 49 0 22 4, Length:5.


奇怪的是5分钟的定时飘忽不定,再次印证了42楼说的,但是为什么会这样呢?

出0入0汤圆

 楼主| 发表于 2011-10-26 20:10:25 | 显示全部楼层
来跟大家汇报一下今天晚上的测试结果,貌似准确了。

方法就是受48楼的朋友启发,重装TH0时考虑已有的计数进位,只是我没有关计数器。

我很惊讶,为什么中断跳转过程难道需要这么长时间?

下面是刚刚出炉的测试数据:

出0入0汤圆

发表于 2011-10-26 22:07:03 | 显示全部楼层
这是我很不喜欢用c的原因,尤其在对延时有较高要求的情况,我都要查看下汇编,是否有隐患

出0入0汤圆

发表于 2011-10-26 23:01:52 | 显示全部楼层
回复【51楼】haozi007  
来跟大家汇报一下今天晚上的测试结果,貌似准确了。
方法就是受48楼的朋友启发,重装th0时考虑已有的计数进位,只是我没有关计数器。
我很惊讶,为什么中断跳转过程难道需要这么长时间?
下面是刚刚出炉的测试数据:

-----------------------------------------------------------------------

这个数据现在只能说定时看起来准确了,其实问题很严重:看你在50楼发上来的数据就知道了,每两次收到数据的时间都比5分钟略长一点(头两行间隔的4秒多认为是上位机的问题,其他时间间隔最长的也有2.156秒,2156ms/300s≈72ms/s,快到1%了)。

不是说“中断跳转过程”有这么长,而在于在中断跳转之前还有“中断响应时间”存在(比如有很长一段关中断的时间、比如更高优先级或同级的中断服务程序在运行)。



如果一定要时间很准确,就一定要解决上面两个问题:

1、要减小关中断引起的中断响应延迟,就要尽量减少关中断、及时要关也尽量晚关并尽量早开(关中断过程中只处理临界区代码)。

2、要解决更高级中断服务程序或同优先级中断服务程序引起的中断响应延迟,就只能把T0的中断单独设为高优先级。这时候就只剩低优先级可以用了,如果其余中断服务程序还要区分优先级怎么办呢?
  这时候可以通过类似Linux中对中断服务程序的“上半段+下半段”处理方式给最低优先级的中断服务程序加个“壳”,让它们在主程序优先级上运行。
  具体的实现方式就是,把“中优先级”中断跟“低优先级”中断在IP中的对应位都设为0,但在“低优先级”中断服务程序中只把
实际的中断服务程序的入口地址给压入堆栈就返回,实际的中断服务程序写成一般子程序的形式(函数头部后面不带“interrupt N”),最后禁止这个子程序与其他子程序进行覆盖分析就好(或者把它的局部变量都定义成static的)。
  原理在于,“低优先级”中断服务程序中把实际入口压入堆栈后返回,编译器生成的是RETI指令,这时候就把51的“优先级锁”给复位了,CPU运行在主程序级别上,可以响应任何新的中断请求,但由于我们的压栈操作,这里的“返回”并没有回到主程序中的“断点”,而是“返回”到了实际的中断服务程序入口,在实际的中断服务程序返回的时候才真正返回到原来“断点”——这样就实现了在主程序级别上运行的“低优先级”中断服务程序,当然了,实际的中断服务程序中还是要保护“现场”。

出0入0汤圆

发表于 2011-10-26 23:19:43 | 显示全部楼层
回复【52楼】packer  
这是我很不喜欢用c的原因,尤其在对延时有较高要求的情况,我都要查看下汇编,是否有隐患
-----------------------------------------------------------------------

C与汇编混合编程就好。

出0入0汤圆

 楼主| 发表于 2011-10-27 12:06:51 | 显示全部楼层
感谢您的回复。

首先我强调一下,没有其它中断了,这个定时器是唯一的中断。

其次,我是没有关中断的,我就是想避免由此带来的延迟。

现在的问题在于每次定时的误差表现出来是随机的。同样的程序,有时候快,有时候慢,有时误差大,有时误差小,有时又准了(或没有可测量的误差)

不知道各位是否能解其详?


回复【53楼】eduhf_123  经历
回复【51楼】haozi007  
来跟大家汇报一下今天晚上的测试结果,貌似准确了。
方法就是受48楼的朋友启发,重装th0时考虑已有的计数进位,只是我没有关计数器。
我很惊讶,为什么中断跳转过程难道需要这么长时间?
下面是刚刚出炉的测试数据:
-----------------------------------------------------------------------
这个数据现在只能说定时看起来准确了,其实问题很严重:看你在50楼发上来的数据就知道了,每两次收到数据的时间都比5分钟略长一点(头两行间隔的4秒多认为是上位机的问题,其他时间间隔最长的也有2.156秒,2156ms/300s≈72ms/s,快到1%了)。
不是说“中断跳转过程”有这么长,而在于在中断跳转之前还有“中断响应时间”存在(比如有很长一段关中断的时间、比如更高优先级或同级的中断服务程序在运行)。

如......
-----------------------------------------------------------------------

出0入0汤圆

发表于 2011-10-27 22:57:45 | 显示全部楼层
回复【50楼】haozi007
-----------------------------------------------------------------------

用C写好程序后编译,再反汇编成汇编代码,就可以看到问题。

定时器中断响应后,最先执行的不是你装初值的代码!

而是先很多的PUSH ***,它叫保护现场,你来的地方(中断产生的时机)不同,会导致保护现场所执行的代码不同。

还有如果有其他的中断正被执行,那你的定时器的中断还可能挂起一阵子才能得到执行,这时你装初值的操作显然被延迟了。

出0入0汤圆

发表于 2011-11-10 16:46:43 | 显示全部楼层
mark

出0入0汤圆

发表于 2012-4-3 10:36:06 来自手机 | 显示全部楼层
学习气氛浓哇…路过!
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

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

GMT+8, 2024-5-20 02:33

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

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