请教由独立键盘程序联想到的中断概念

2019-03-24 19:15发布

郭天祥教程的练习题,三个独立键盘实现按下第一个时计时停止,按下第二个时计时开始,按下第三个是计数值清零从头开始。这是我自己编的程序,可以正常实现功能。但是我在自己调试程序排错的时候,想到了中断的概念。比如这里按key3键是计数值从0开始显示,我在想如果定时器中断时间到,刚好在bb=0;bai=bb/100;shi=bb%100/10;ge=bb%10;这几句话后面进入中断程序(程序中用红 {MOD}标出了),进入中断后,bb被加到1,中断程序执行完回到主程序,此时个,十,百位分别是1,0,0,这样不是和我们程序的要求不一致了么(程序要求复位从0开始计时)。但是我把程序下载到板子上面没有出现按key3是1的情况,都是符合题目要求的0。请前辈指点,我的概念哪里出错了? #include<reg52.h>
sbit dula=P2^6;
sbit wela=P2^7;
sbit key1=P3^4;
sbit key2=P3^5;
sbit key3=P3^6;
sbit key4=P3^7;
unsigned char aa,ge,shi,bai;
unsigned int bb;
void init();
void display(unsigned char,unsigned char,unsigned char);
void delay(unsigned int);
unsigned char code table[]={
0x3f,0x06,0x5b,0x4f,
0x66,0x6d,0x7d,0x07,
0x7f,0x6f,0x77,0x7c,
0x39,0x5e,0x79,0x71};
void main()
{
 init();
 while(1)
 {
 if(key1==0)
 {
  delay(5);
  if(key1==0)
  {
   TR0=0;
  }
 }
 if(key2==0)
 {
  if(key2==0)
  {
   TR0=1;
  }
 }  
 if(key3==0)      
 {
  bb=0;
  bai=bb/100;
  shi=bb%100/10;
  ge=bb%10;       //如果在这句话后,定时器中断定的时间到,进入定时器中断,那么bb被加1,个位被刷新为1,此时这个复位键复位到的是1??那么数码管也显示1?和要求不符,但实际下载程序到板子上的结果却是每次按这个键下去都是复位到0.
  if(key1==1){TR0=1;}
 }
 display(bai,shi,ge);
 }
}
void init()                         //初始化函数
{ wela=1;
 P0=0xff;
 wela=0;
 dula=1;
 P0=0x00;
 dula=0;
 aa=0;
 bb=0;
 P3=0xff;
 TMOD=0x01;
 TH0=(65536-10000)/256;
 TL0=(65536-10000)%256;
 EA=1;
 ET0=1;
 TR0=1;
}
void timer0() interrupt 1              //定时器0中断
{
 TH0=(65536-10000)/256;
 TL0=(65536-10000)%256;
 aa++;
 if(aa==1)
 {
  aa=0;
  bb++;
 }
 bai=bb/100;
 shi=bb%100/10;
 ge=bb%10;
 if(bb==999)
 {
  bb=0;
 }
}
void display(unsigned char one,unsigned char two,unsigned char three)       //显示函数
{
 dula=1;
 P0=table[one];
 dula=0;
 P0=0xff;
 wela=1;
 P0=0xfe;
 wela=0;
 delay(1);  dula=1;
 P0=table[two];
 dula=0;
 P0=0xff;
 wela=1;
 P0=0xfd;
 wela=0;
 delay(1);  dula=1;
 P0=table[three];
 dula=0;
 P0=0xff;
 wela=1;
 P0=0xfb;
 wela=0;
 delay(1);
}
void delay(unsigned int z)       //延时程序
{
 unsigned int x,y;
 for(x=z;x>0;x--)
  for(y=110;y>0;y--);
} 此帖出自小平头技术问答
友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。
该问题目前已经被作者或者管理员关闭, 无法添加新回复
19条回答
辛昕
1楼-- · 2019-03-25 20:39
让我们来简单理一下这个程序的执行路线,或者说流程也行
1 开机初始化一次。
2 循环检测3个按键,其检测顺序是 key1 key2 key3
   key1按下,则关闭定时器,即不再计数
   key2按下,反之
   key3按下,清零过后,还要保证key1没按下,才不会关闭定时器。
3 同时循环扫描数码管。

对你的第三个问题,我们只考虑key1 key3的情况,key2跟它们没关系,如果key2按下了,给关了,那啥事都没了。
如果你一直按着key3不松手。并且保证key1是松开的。
这个时候将不断计数。
同时,数码管也不断扫描最新的时间值。

你所担心的问题是,如果bb已经被清零,偏偏在它到执行数码管显示那一刻中间,偏偏被中断打断了,刚好加了1,那就会很惨的出现从1开始。
这的确是有可能的,然而也如同你所说的,如果你一直按着key3——其实从程序执行的速度来说,就算你只不过是按了一下key3,相对于这个没经过消抖处理的key3来说,那也等于说,一直按着key3,我的意思是,反复进入key3清零。

我当时说如果定时长度和这段代码执行的时间相差太远,则这种担心是不必要的,意思正是
不管你的定时中断是否有那么巧刚好在中间打断了。
如你所说,定时中断执行完加1马上就会回来,然后经由数码管显示(这里面,数码管显示程序的刷新频率到底有多快,对你这个问题就很有意义。)
如果数码管的刷新频率快的人眼无法察觉,那么,这个加1是没机会让人看到的,理由正如你所说的,加完1,主循环又马上检测到key3按着,再次清零。
这回,可就没那么容易被定时器打断了,试想,定时器的周期有10个毫秒,而你这段代码(当然我没考虑你那几个delay到底有多长——这种延迟方法本身是有问题的,以后再谈)
假设说,这几个delay没多长,至少不要在毫秒级的级别,也就是说,整个主循环执行一次估计才几个毫秒,那么,就意味着,这个key3清零,频率在几个毫秒,这种水平,人眼是很难看到的,至多看到出现有时冒出个不清晰的1.

请注意,这一切分析,都以主流程和定时器长度的相对比例而言,一般的程序,像这种主流程,本该是很短的,别说10个毫秒,就是1个毫秒相比,也显得很长,故而,你的担心是没必要的。

但是,这个程序写的很是粗糙,首先它在主循环里用循环等待这种方法延时,你那几个delay都是消抖,既然是消抖,时间肯定少不过几个到10个毫秒,而数码管的刷新水平,其中的延迟还是这种办法,这就导致了这个主流程实际跑起来的时间较长,和定时器相比,反而要长好多,那么,你说的这种情况,也许就会出现,偶尔能看到一个1闪过。
辛昕
2楼-- · 2019-03-25 21:55
说到了这个delay。
建议楼主学习一下其他方式的延时方法,这种纯粹靠循环递减方式的延时方法,只有在这种学习的代码中才能见到,真正实用的程序中这样写,再高的CPU也会让你弄得非常迟钝。
qrswll
3楼-- · 2019-03-26 02:12
原帖由 辛昕 于 2012-4-15 01:46 发表 说到了这个delay。建议楼主学习一下其他方式的延时方法,这种纯粹靠循环递减方式的延时方法,只有在这种学习的代码中才能见到,真正实用的程序中这样写,再高的CPU也会让你弄得非常迟钝。
:carnation: 前辈回答得好耐心=。=不对...以后就叫前辈学长了~~ 仔细研读了学长的回答,觉得如果偶尔复位出现了1,想下次刚好还在那个位置出现1的话...说不定可以去买彩票了.......我看的是郭天祥的视频,暂时学到的只是delay().......看来在实际应用中,应该少用delay()......其他的延时方法,是指定时器么?还是有一些更好的方法呢?
辛昕
4楼-- · 2019-03-26 05:38
郭老师的视频对入门很有帮助,但入门以后还要学习更多更规范,看看其他人不同的思路。
辛昕
5楼-- · 2019-03-26 06:08
 精彩回答 2  元偷偷看……
qrswll
6楼-- · 2019-03-26 11:52
原帖由 辛昕 于 2012-4-17 15:41 发表 不要乱叫前辈,我很年轻。要是找不到媳妇,你给我找啊?
学长=。=

一周热门 更多>