独闷闷网

 找回密码
 立即注册
搜索
查看: 6083|回复: 1
收起左侧

[原创] 主函数与定时中断函数是如何交替运行的?已深入详细解答。

[复制链接]
发表于 2014-10-31 11:07:32 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
本帖最后由 jianhong_wu 于 2014-10-31 11:13 编辑

曹健-江苏:
昨天我把鸿哥的按键程序改动了一下,把原来按一次蜂鸣器响1声的程序改成了按一下响2声的程序。但是主函数与定时中断是如何工作的过程我还是有点模糊,请大家帮我讲解一下。
  1. void key_service()
  2. {
  3.     switch(ucKeySec)
  4.     {
  5.         case 1:
  6.             {
  7.         uiVoiceCnt=20;
  8.         ucKeySec=2;
  9.         break;
  10.             }
  11. //跟鸿哥的程序主要不同的在这里。当uiBeepTimeCnt加到6000
  12. //让蜂鸣器再响一次。这个程序能实现响两次
  13.         case 2:
  14.             {
  15.             if(0==uiVoiceCnt)
  16.                     {
  17.                 uiBeepTimeCnt++;
  18.                 if(6000<=uiBeepTimeCnt)
  19.                         {
  20.                     uiBeepTimeCnt=0;
  21.                     uiVoiceCnt=20;
  22.                         ucKeySec=0;
  23.                         }
  24.                 }        
  25.             break;
  26.             }
  27.     }
  28. }
复制代码
以上程序可以实现蜂鸣器响两声,程序先执行case 1中uiVoiceCnt=20; 然后再执行case 2:。那么case 2中if(0==uiVoiceCnt)  因为在case 1中,uiVoiceCnt=20所以case 2条件不成立,应该就不执行case 2中的程序了,为什么他还是执行呢?

fyt57889681-东莞:
case 1:成立的时候响了一声 。ucKeySec=2;这个条件让case 2:成立了。

曹健-江苏:
我知道会执行case 2,但是case 1中 uiVoiceCnt=20 ,case 2判断条件为if(0==uiVoiceCnt)。

fyt57889681-东莞:
case 2成立,则case 1就不成立。

曹健-江苏:
不懂。我先讲一下我的思路。你看错在哪里。程序运行,首先是执行case 1,此时 uiVoiceCnt= 20 ,然后ucKeySec=2,借着执行case 2,因为case 1中 uiVoiceCnt= 20 ,所以  case 2中if(0==uiVoiceCnt)不成立,然后跳出case2。

fyt57889681-东莞:
ucKeySec等于case后面的哪个值,就哪里成立。

曹健-江苏:
switch程序执行顺序,永远都是先case 1,后case 2?

fyt57889681-东莞:
if(0==uiVoiceCnt)不成立是对的,但是ucKeySec=2在case2 里面没人改变ucKeySec,就是说所以跳出了case2下个循环还是会回来。直到uiVoiceCnt被中断减到0了,就启动变量 uiBeepTimeCnt++这些。

曹健-江苏:
你的意思是当case 1执行好后执行case 2,因为case 1中uiVoiceCnt=20,所以case 2中if条件不执行?但是此时ucKeySec=2,  所以程序仍然会回来执行case 2?

fyt57889681-东莞:
是的。

曹健-江苏:
那if语句永远不成立,那不是死循环吗?

fyt57889681-东莞:
uiVoiceCnt不是会在中断uiVoiceCnt--吗?所以总有一个时刻uiVoiceCnt会到0。这个理解吗?case1和case2 是相互独立的。

东游取经-深圳:
首先判断ucKeySec等于几,然后进入对应的case 。

曹健-江苏:
我再讲一下我的理解。
是不是刚开始执行  case 1,此时  uiVoiceCnt=20,ucKeySec=2。接着执行case 2,此时uiVoiceCnt=20,所以if判断不成立,此时ucKeySec=2, 同时中断中uiVoiceCnt--,当uiVoiceCnt为0时,if判断成立, 执行if语句 uiVoiceCnt=20;ucKeySec=0;最后跳出循环.现在才算真正懂了.中断和主函数是分别在执行的.

fyt57889681-东莞:
是的,中断是优先执行的,是老大.主函数是小弟.

曹健-江苏:
那刚才这个程序,当起始运行到case 2  if语句不成立时,主函数是不是一直卡在这里?直到中断函数使uiVoiceCnt=0;主函数才执行case 2语句?

东游取经-深圳:
定时器是独立的,主函数不会卡在这里. 单独运行的满足条件才会溢出产生中断.

曹健-江苏:
那是不是这样的?起始主函数执行到case 2  if语句不成立,直接跳出case 2,继续从头开始. 定时中断函数一直在执行中断函数里的内容,当uiVoiceCnt=0发出中断请求,主函数直接跳转至case 2,执行case 2的内容.

fyt57889681-东莞:
不是从头再来,是执行break是结束当前switch.如果后面没有其他子函数就从头再来了.

曹健-江苏:
起始  case 1执行完成,因为case 2中条件不成立,跳出子函数,然后重新  进入while(1),同时  中断函数uiVoiceCnt--,当uiVoiceCnt = 0,是不是中断发出请求给主函数,此时不管主函数执行到哪里, 都会直接进入case 2中?
我这样理解,不知道对不对?

鸿哥--深圳:
不对,中断不会发出请求给主函数.主函数还是按部就班,中断函数也是按部就班.“此时不管主函数执行到哪里   都会直接进入case 2中”这句话是错的.应该是主函数继续循环运行,每个循环总会扫描判断一次case 2.

曹健-江苏:
那这样理解,当中断发出中断标志,此时主函数继续执行,当执行到case 2时,判断是否成立,成立  则执行case 2.

鸿哥--深圳:
不是中断发出中断标志,注意不要用“发出”这个词。是中断改变了某个标志变量,而主循环扫描到这个变量的时候再做出相应的处理.主函数和定时中断是交叉运行的。你运行一会停下来歇歇,我运行一会停下来歇歇,它们是交叉运行的。

曹健-江苏:
中断和主函数的关系是什么?我这样理解,不知道对不对.主函数做自己的事情,中断也做自己的事情,但是  中断函数执行时,会改变主函数内的部分变量的数值,原先主函数做事时,可能因为变量数值与条件不符合,就直接跳过,但是因为中断会改变变量数值 , 当某个变量数值改变导致主函数某个条件符合,主函数就会执行这个程序.


鸿哥--深圳:
差不多接近,但是还有一个地方是错的.“主函数做自己的事情   中断也做自己的事情 ”这句话是错的.“主函数做自己的事情 中断也做自己的事情 ”你这句话的理解相当于有2个人,每个人都可以独立同时做事。-----这个是错的。应该是主函数是一件事情,中断是另外一件事情,但是只有一个人在做这两件事情,这个人不能同时做这两件事情,要么放下中断去做主函数的事情,要么放下主函数去做中断的事情,其实这个人在整个生命周期里,在反复往返跑来跑去,做一会主函数的事情,又做一会中断的事情,当他切换得很快的时候,就会给我们外边的人一个错觉,以为这两件事情是同时并发进行的,其实某一个时刻只能做一件。


胖纸—沈阳:
嗯只有一个内核,一个时间就只能做一个事情,木有分身术.

曹健-江苏:
这个人首先执行主函数,当主函数执行到开启中断时,这个人就去做中断里的事情,此时主函数是不执行的 , 中断函数执行一次 .然后关闭中断函数,接着去做主函数里的事情,这样循环.

鸿哥--深圳 :
对了。我再帮你改一下,这个人首先执行主函数,当定时时间到时这个人就去做中断里的事情,此时主函数是不执行的。中断函数执行一次,定时时间清零重新开始定时,接着去做主函数里的事情,这样循环。

曹健-江苏:
就以你的程序为例:
在void T0_time() interrupt 1中  首先是关闭中断  TF0 = 0;
        TR0 = 0;  我就没有方向了

鸿哥--深圳:
但是我在退出那个中断函数的时候又打开了.

曹健-江苏:
是的,
    TH0=0XF8;
    TL0=0X2F;
        TR0 = 1;  那这个人此时  是继续执行中断  还是去执行主函数
因为你最后又打开中断,我认为他应该继续执行中断.

鸿哥--深圳:
这句话的含义是让定时器重新清零,重新开始计时,然后他就跑去执行主函数了.
它会等下一次定时时间到来的时候才会去执行定时中断.

小侠--广州:
中断和定时不能弄混了,定时独立于主函数,中断本质和主函数是一样的,是程序的一部分.
TH0=0XF8;
    TL0=0X2F;
        TR0 = 1;这段是给定时器重新赋值,让定时器重新开始计时,


土豆づMr.--浙江:
2014-10-31 10:16:28
时间到了,中断标志位置位就置位了,进入对应的中断入口,鸿哥进入中断就把中断标志清零了,定时器也暂停了,
在void T0_time() interrupt 1中  首先是关闭中断  TF0 = 0;
        TR0 = 0;  ,执行完中断函数里面的所有程序,鸿哥最后赋值,重新打开定时器,TH0=0XF8;
    TL0=0X2F;
        TR0 = 1;又开始新的一轮计数,就这样一直循环。这样说应该很好理解了吧

just-珠海:
时间刚好到,那程序怎么停止现在的主函数任务呢?

土豆づMr.--浙江:
将正在执行的程序地址存入堆栈.响应ISR。执行完ISR里面的函数后,继续从刚刚堆栈地址的内容开始往后执行啊 .

行者--赣州:
中断是靠堆栈来实现的,定时中断到的时候把主函数正在做的事情压栈,保护现场,等中断结束后再从出栈,恢复现场,继续执行.

鸿哥--深圳:
这个是芯片厂家做好的设备,这个设备就是有这样的规律的,你也可以当做游戏规则来遵守就好了。再深入一步理解。其实是主函数每运行一两条指令的时候都会判断一次某个中断标志位,如果这个标志位置1了,它就自动跳去执行相对应的中断函数。只不过这些细节不用我们来实现,是芯片厂家做好给我们用的。

土豆づMr.--浙江:
学C不用深入研究堆栈,这起编译的时候,汇编会帮你处理好的.

just-珠海:
鸿哥,经过这样讨论理解很多.

曹健-江苏:
根据群友的指点,我对主函数和中断函数执行的步骤理解如下:
进入主函数的while(1)死循环,当中断标志位没有到来时,这个人会一直在while(1)中埋头猛干。当计时器溢出,发出中断标志位时,这个人才不情愿的进入中断函数,此时,TF0 = 0;//清除中断标志,TR0 = 0;//停止定时器T0 (定时器被关闭),这个人又会做中断中的事情一次。在出中断前,会将定时器重装初始值,并打开定时器。接着去做主函数的事情,因为在进入中断前,他记录了主函数中的事情做到哪里了(俗称堆栈),重新执行主函数时又会接着做刚才没有做完的事情,循环往复。

鸿哥--深圳:
对了。
乐于分享,勇于质疑!
发表于 2015-2-5 11:26:46 | 显示全部楼层
{:soso__3409329614010722382_4:}
乐于分享,勇于质疑!
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|Archiver|手机版|独闷闷网 ( 粤ICP备12007667号-2 )

GMT+8, 2021-9-20 01:21 , Processed in 0.166948 second(s), 17 queries .

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