找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 3350|回复: 20
打印 上一主题 下一主题
收起左侧

STC单片机定时器延时用官方程序快约5倍是什么原因?

  [复制链接]
跳转到指定楼层
楼主
ID:970121 发表于 2021-10-28 09:51 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
STC单片机定时器延时用官方程序快约5倍是什么原因?
运行是正常的,就是延时快约5倍,定时器是1ms,中断1000次就应该是1秒了,但LED灯闪烁很快,我将中断修改到5000次,闪烁才象是1秒闪1次的样子,是那里出错了?

  1. unsigned int t;

  2. sbit led=P2^0;


  3. void Timer0Init(void)                //1毫秒@18.432MHz
  4. {
  5.         AUXR |= 0x80;                //定时器时钟1T模式
  6.         TMOD &= 0xF0;                //设置定时器模式
  7.         TL0 = 0x00;                //设置定时初始值
  8.         TH0 = 0xB8;                //设置定时初始值
  9.         TF0 = 0;                //清除TF0标志
  10.         TR0 = 1;                //定时器0开始计时

  11.       
  12.   ET0=1;//打开定时器1中断允许
  13.   EA=1;//打开总中断
  14.                   
  15. }
  16. void main()
  17. {      
  18.         Timer0Init();//定时器0初始化
  19.         while(1)
  20.         {
  21.                 if(t == 1000)    //中断1000*1ms=1s
  22.                 {
  23.                         t=0;
  24.                         led=~led;
  25.                 }
  26.         }               
  27. }
  28. void Timer0() interrupt 1
  29. {
  30.         TL0 = 0x00;                //设置定时初始值
  31.         TH0 = 0xB8;                //设置定时初始值
  32.         t++;
  33. }
复制代码



分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏1 分享淘帖 顶 踩
回复

使用道具 举报

沙发
ID:624769 发表于 2021-10-28 13:27 | 只看该作者
你往机器里烧的时候,晶振选的是18.432么?
回复

使用道具 举报

板凳
ID:161164 发表于 2021-10-28 14:42 | 只看该作者
和我遇到的情況差不多STC 1T单片机的奇怪情况
中斷打斷了比較邏輯
提早進入了if( t == 0)
這樣改看看

  1. unsigned int t;

  2. sbit led=P2^0;
  3. bit t_DN;

  4. void Timer0Init(void)                //1毫秒@18.432MHz
  5. {
  6.         AUXR |= 0x80;                //定时器时钟1T模式
  7.         TMOD &= 0xF0;                //设置定时器模式
  8.         TL0 = 0x00;                //设置定时初始值
  9.         TH0 = 0xB8;                //设置定时初始值
  10.         TF0 = 0;                //清除TF0标志
  11.         TR0 = 1;                //定时器0开始计时

  12.       
  13.   ET0=1;//打开定时器1中断允许
  14.   EA=1;//打开总中断
  15.                   
  16. }
  17. void main()
  18. {      
  19.         Timer0Init();//定时器0初始化
  20.         while(1)
  21.         {
  22.                 if(t_DN)
  23.                 {
  24.                         t_DN=0;
  25.                         led=~led;
  26.                 }
  27.         }               
  28. }
  29. void Timer0() interrupt 1
  30. {
  31.         //TL0 = 0x00;                //设置定时初始值
  32.         //TH0 = 0xB8;                //设置定时初始值
  33.                 //TMOD &= 0xF0; 是自动重装
  34.         if(++t == 1000)    //中断1000*1ms=1s
  35.                 {
  36.                         t = 0;
  37.                         t_DN = 1;
  38.                 }
  39. }
复制代码



回复

使用道具 举报

地板
ID:970121 发表于 2021-10-28 14:45 | 只看该作者
188610329 发表于 2021-10-28 13:27
你往机器里烧的时候,晶振选的是18.432么?

板载晶振,没有用内置的,示波器测过,晶振频率很准,
回复

使用道具 举报

5#
ID:123289 发表于 2021-10-28 14:47 | 只看该作者
加一个标记:BJ。
在中断服务程序,判断:当t=1000时,置位BJ=1。并将t回0。
在主程序中:以BJ=1,决定LED灯的反转,并将BJ清0。
如果成功了,下次告诉你为什么。
回复

使用道具 举报

6#
ID:213173 发表于 2021-10-28 16:28 | 只看该作者
本帖最后由 wulin 于 2021-10-28 16:47 编辑
  1. #include <reg51.H>

  2. sfr AUXR = 0x8e;

  3. sbit led=P2^0;

  4. unsigned int t;

  5. void Timer0Init(void)    //1毫秒@18.432MHz
  6. {//下载用户程序时去掉选择内部时钟的勾
  7.         AUXR |= 0x80;         //定时器时钟1T模式
  8.         TMOD &= 0xF0;         //设置定时器自动重装模式!!!
  9.         TL0 = 0x00;           //设置定时初始值
  10.         TH0 = 0xB8;           //设置定时初始值
  11.         TF0 = 0;              //清除TF0标志
  12.         TR0 = 1;              //定时器0开始计时
  13. //        ET0=1;//打开定时器1中断允许
  14. //        EA=1;//打开总中断
  15. }
  16. void main()
  17. {      
  18.         Timer0Init();//定时器0初始化
  19.         while(1)
  20.         {
  21.                 if(TF0==1)
  22.                 {
  23.                         TF0=0;
  24.                         if(++t>=1000)    //中断1000*1ms=1s
  25.                         {
  26.                                 t=0;
  27.                                 led=~led;
  28.                         }
  29.                 }
  30.         }               
  31. }
  32. /*
  33. void Timer0() interrupt 1
  34. {
  35.         TL0 = 0x00;                //设置定时初始值
  36.         TH0 = 0xB8;                //设置定时初始值
  37.         t++;
  38. }
  39. */
复制代码
回复

使用道具 举报

7#
ID:970121 发表于 2021-10-28 17:08 | 只看该作者
lkc8210 发表于 2021-10-28 14:42
和我遇到的情況差不多STC 1T单片机的奇怪情况
中斷打斷了比較邏輯
提早進入了if( t == 0)

这样改真的可以了!有个小插曲,测下测下,可能有静电,下载板烧坏了,刚修好才验证,的确正常了。
回复

使用道具 举报

8#
ID:970121 发表于 2021-10-28 17:11 | 只看该作者
yzwzfyz 发表于 2021-10-28 14:47
加一个标记:BJ。
在中断服务程序,判断:当t=1000时,置位BJ=1。并将t回0。
在主程序中:以BJ=1,决定LE ...

你这个是对的,二楼也是这样做,经过验证,是能正确延时了!问题随然解决,但还不了解发生的原因,等大师科普知识!
回复

使用道具 举报

9#
ID:975745 发表于 2021-10-28 17:25 | 只看该作者
中断模式设置12T试试
回复

使用道具 举报

10#
ID:401564 发表于 2021-10-28 20:49 | 只看该作者
丝瓜侦探 发表于 2021-10-28 17:11
你这个是对的,二楼也是这样做,经过验证,是能正确延时了!问题随然解决,但还不了解发生的原因,等大师 ...

if(t == 1000)
这个逻辑本身就是错的
t是在中断中增加
如果程序还没有跑到if(t == 1000) 之前,t的值就已经大于1000了,那就错过了,t就会在1000的基础之上一直向上加,结果如何不知道,也不想知道,就知道是不对的
应该是比大小,不是求相等,if(t == 1000) 是查找,不是比较
回复

使用道具 举报

11#
ID:123289 发表于 2021-10-29 09:39 | 只看该作者
如果你了解汇编语句,会对你的理解有帮助。所以不懂汇编是不能称为精通单片机的。
C语言t=1000中的t,在CPU中必须用两个字节来表示,不妨起个名子叫NH和NL。t=NH,NL
你的主程序一直在等t=1000,也就等(NH,NL,16进制)=03E8H,但是CPU指令只能一个一个的判断,假设先判断NH=03,而后再判断NL=E8,逻辑上是没有毛病的。
你的中断是每1ms一次,中断发生时,你的程序运行到什么地方了呢?不太好确定吧,你的程序一直在等t=1000,估计多半会在此处中断。
注意,有个关键的特殊事件发生了,而且发生的概率还不了(程序不长)。
中断发生在CPU已判断了NH,还未判定NL。而中断服务程序会做t++,也即(NH,NL)+1,这就修改NL的值,问题来了。
例如:原先(NH,NL)=1000 = 03E8H,程序已确定NH=03,如果NL=E8,就反转LED灯。
但是中断发生在NH=03判断之后,而NL还未判定,中断时你将t++,也即(NH,NL)++,变成了 03E9H,中断返回后,再判断NL却不是E8,而是E9了。
如此,程序不会再做LED反转了。t将=1001,此后被加到65535,再回0,下次再加到1000。
也即,只要t=1000时发生中断,如果中断发生在主程序判断:NH=03与NL=E8之间。则本次LED的显示,就会超出你的预期!而且t会走向65535,再回0。

评分

参与人数 1黑币 +15 收起 理由
dalaoshi + 15 很给力!

查看全部评分

回复

使用道具 举报

12#
ID:964308 发表于 2021-10-29 11:00 来自手机 | 只看该作者
晶振选对了吗
回复

使用道具 举报

13#
ID:970121 发表于 2021-10-29 14:07 | 只看该作者
哈尼小可爱 发表于 2021-10-28 17:25
中断模式设置12T试试

一样的
回复

使用道具 举报

14#
ID:970121 发表于 2021-10-29 14:09 | 只看该作者
Y_G_G 发表于 2021-10-28 20:49
if(t == 1000)
这个逻辑本身就是错的
t是在中断中增加

有道理!在程序大时的确可能会产生问题,但现在就这一个1ms中断测试,不会影响它判断,是别的问题
回复

使用道具 举报

15#
ID:970121 发表于 2021-10-29 14:13 | 只看该作者
yzwzfyz 发表于 2021-10-29 09:39
如果你了解汇编语句,会对你的理解有帮助。所以不懂汇编是不能称为精通单片机的。
C语言t=1000中的t,在CP ...

理是这个理,但那应该是慢一倍以上,而不是快呀,搞得我现在还弄不明白那里的问题。
回复

使用道具 举报

16#
ID:970121 发表于 2021-10-29 14:13 | 只看该作者

对的,外部晶振,用示波器测过,正确!
回复

使用道具 举报

17#
ID:959346 发表于 2021-10-29 14:51 | 只看该作者
丝瓜侦探 发表于 2021-10-29 14:13
理是这个理,但那应该是慢一倍以上,而不是快呀,搞得我现在还弄不明白那里的问题。

一个可能是在判断到一半时中断了,另一个可能是在清零到一半时中断了,具体看一下编译后的汇编代码,再分析一下就知道了。
回复

使用道具 举报

18#
ID:401564 发表于 2021-10-29 15:25 | 只看该作者
丝瓜侦探 发表于 2021-10-29 14:09
有道理!在程序大时的确可能会产生问题,但现在就这一个1ms中断测试,不会影响它判断,是别的问题

逻辑是跟定时器时间长短没有关系的
我把你的代码完全复制到STC8A4K上运行,并没有你说的快5倍
实际闪灯的频率是大概1秒左右,因为没有仪器,只能是个大概
那么,我有理由认为,你代码的其它地方有问题,把完整的上传看一下
单片机是很少有问题的,绝大多数的问题是代码的问题
回复

使用道具 举报

19#
ID:123289 发表于 2021-10-30 11:17 | 只看该作者
只是举了一个特例是这样,CPU判定t=1000的方式也可能是采用的是其它方案。
这里强调的是:会在t=1000的判定上,因中断的介入而出现非常的情况。
如果你要穷尽原因,就去分析编译后的汇编语句!
这一点也不难办到,好在程序也不长,就看你愿不愿意去分析了。
回复

使用道具 举报

20#
ID:160500 发表于 2021-10-30 11:35 | 只看该作者
同一个全局变量在中断和主程序里都要改变它的值,如果考虑不全面非常容易出现数据错误。一般不建议这样使用。
回复

使用道具 举报

21#
ID:881715 发表于 2021-10-30 11:51 来自手机 | 只看该作者
yzwzfyz 发表于 2021-10-29 09:39
如果你了解汇编语句,会对你的理解有帮助。所以不懂汇编是不能称为精通单片机的。
C语言t=1000中的t,在CP ...

大神,您能提供点与单片机编程相关的汇编基础的书或资料吗?
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

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