当前位置:   article > 正文

51单片机——中断系统、定时器、计数器工作原理_51单片机中断源

51单片机中断源

目录

一、中断系统

1.中断源种类

2.中断地址入口

3.中断请求标志

(1)TCON寄存器

   (2)SCON寄存器

4.中断控制

二、中断案例实操

1.单一外部中断

2.两个外中断

 3.中断嵌套

三、定时器计数控制led灯周期性亮灭

1.定时器工作原理

(1)原理

(2)工作方式寄存器 TMOD

(3)控制寄存器 TCON

2.用定时器控制led灯亮灭

(1)设置TMOD寄存器    

(2)计算定时器T0的计数初值      

(3)设置IE寄存器      

(4)启动和停止定时器T0    

四、采用计数器中断,使led灯闪烁

1.原理

2.使用计数器中断实例

(1)设置TMOD寄存器

(2)计算定时器T0的计数初值  

(3)设置IE寄存器    

五、keil中采用逻辑分析仪观察波形

六、代码优化

总结


一、中断系统

1.中断源种类

51的中断系统共有5个中断源:

外部中断0(INT0):由P3.2引脚输入的中断请求信号。
外部中断1(INT1):由P3.3引脚输入的中断请求信号。
定时器T0中断(T0):由定时器/计数器T0的定时、计数溢出产生的中断请求。
定时器T1中断(T0):由定时器/计数器T1的定时、计数溢出产生的中断请求。
串行口中断(ES):由串行数据发生完成(TI)或串行数据接收完成(RI)产生的中断请求。

2.中断地址入口

中断源中断入口地址中断序号
外部中断00003H0
定时器T0000BH1
外部中断10013H2
定时器T1001BH3
串行口中断ES0023H

4

3.中断请求标志

(1)TCON寄存器

        TCON寄存器为定时器/计数器的控制寄存器,字节地址为88H,可位寻址。既包括定时器/计数器T0、T1溢出中断请求标志位TF0和TF1,也包括两个外部中断请求的标志位IE1与IE0,还包括两个外部中断请求源的中断触发方式选择位

TF0——定时器T0的溢出中断请求标志位。溢出时由硬件置1,即开始发送中断请求;单片机响应中断后,重新由硬件清0。
TR0——定时器/计数器0的启动控制。功能详见定时器知识。
IE0——外部中断0的中断请求标志位。触发中断时由硬件置1,即开始发送中断请求;单片机响应中断后,重新由硬件清0。
IT0——外部中断0的触发方式选择位。令它为1,则对应引脚为下降沿触发中断;令它为0,则对应引脚为低电平触发方式。
TF1、TR1,IE1、IT1则为定时器1、外部中断1的相关标志位,功能与上述相同。

   (2)SCON寄存器

        SCON寄存器 串行口控制寄存器,字节地址为98H,可位寻址。SCON的低二位锁存串口的发送中断和接收中断的中断请求标志TI和RI

TI——串行口发送完成中断请求标志位。串行口发送数据后,TI位被硬件置1;单片机响应串行口中断后,必须在服务程序中将TI手动清0。

RI——串行口接收完成中断请求标志位。串行口接收数据后,TI位被硬件置1;单片机响应串行口中断后,必须在服务程序中将TI手动清0

4.中断控制

EA——总中断允许控制位。用来开启或屏蔽所有的中断请求,令它为1,则开放中断请求,可以响应中断;令它为0,则屏蔽所有中断请求。
ES——串行口中断允许控制位。为1时开放串行口中断请求,为0时屏蔽。
ET1——定时器/计数器T1中断允许控制位。为1时开放TI的中断请求,为0时屏蔽。
EX1——外部中断1中断允许控制位。为1时开放外部中断1的中断请求,为0时屏蔽。
ET0、EX0则为T0、外部中断0的中断允许控制位。功能与上述相同。

二、中断案例实操

1.单一外部中断

 要求:在单片机P1口上接有8只LED。在外部中断0输入引脚(P3.2)接一只按钮开关K1。要求将外部中断0设置为电平触发。程序启动时,P1口上的8只LED全亮。每按一次按钮开关K1,使引脚接地,产生一个低电平触发的外中断请求,在中断服务程序中,让低4位的LED与高4位的LED交替闪烁5次。然后从中断返回,控制8只LED再次全亮。

代码如下:

  1. #include <reg51.h>
  2.   #define uchar unsigned char
  3.   void Delay(unsigned int i) //延时函数Delay( ),i形式参数,不能赋初值
  4.   {
  5.    unsigned int j;
  6.    for(;i > 0;i--)
  7.    for(j=0;j<333;j++) //晶振为12MHz,j选择与晶振频率有关
  8.    {;} //空函数
  9.   }
  10.  
  11. void main( ) //主函数
  12.   {
  13.    EA=1; //总中断允许
  14.    EX0=1; //允许外部中断0中断
  15.    IT0=1; //选择外部中断0为跳沿触发方式
  16.    while(1) //循环
  17. { P1=0;} // P1口的8只LED全亮
  18.   }
  19.  void int0( ) interrupt 0 using 0 //外中断0的中断服务函数
  20.   {
  21.    uchar m;
  22.    EX0=0; //禁止外部中断0中断
  23.    for(m=0;m<5;m++) //交替闪烁5
  24.    {
  25.    P1=0x0f; //4位LED灭,高4位LED亮
  26. Delay(400) ; //延时
  27.    P1=0xf0; //4位LED灭,低4位LED亮
  28.    Delay(400); //延时
  29.    EX0=1; //中断返回前,打开外部中断0中断
  30.   }

仿真效果图如下: 

一个中断

2.两个外中断

要求:在单片机P1口上接有8只LED。在外部中断0输入引脚(P3.2)接有一只按钮开关K1。在外部中断1输入引脚(P3.3)接有一只按钮开关K2。要求K1和K2都未按下时,P1口的8只LED呈流水灯显示,仅K1(P3.2)按下再松开时,上下各4只LED交替闪烁10次,然后再回到流水灯显示。如果按下再松开K2(P3.3)时,P1口的8只LED全部闪烁10次,然后再回到流水灯显示。设置两个外中断的优先级相同。

具体代码如下:

  1. #include <reg51.h>
  2.   #define uchar unsigned char
  3.   void Delay(unsigned int i) //延时函数Delay( ),i为形式参数,不能赋初值
  4.   {
  5.    uchar j;
  6.    for(;i>0;i--)
  7.    for(j=0;j<125;j++)
  8.    {;} //空函数
  9.   }
  10. void main( ) //主函数
  11. {
  12. uchar display[9]={0xff,0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf, 0x7f};
  13. //流水灯显示数据数组
  14. unsigned int a;
  15. for(;;)
  16. {
  17.   EA=1; //总中断允许
  18.   EX0=1; //允许外部中断0中断
  19.   EX1=1; //允许外部中断1中断
  20.   IT0=1; //选择外部中断0为跳沿触发方式
  21.   IT1=1; //选择外部中断1为跳沿触发方式
  22.       
  23. IP=0; //两个外部中断均为低优先级
  24. for(a=0;a<9;a++)
  25.    {
  26.    Delay(500); //延时
  27.    P1=display[a]; //将已经定义的流水灯显示数据送到P1
  28.    }
  29.    }
  30.   }
  31. void int0_isr(void) interrupt 0 using 1//外中断0的中断服务函数
  32.   {
  33.    uchar n;
  34.    for(n=0;n<10;n++) //高、低4位显示10
  35.    {
  36.    P1=0x0f; //4位LED灭,高4位LED亮
  37.    Delay(500); //延时
  38.    P1=0xf0; //4位LED灭,低4位LED亮
  39.    Delay(500); //延时
  40.    }
  41.   }
  42. void int1_isr (void) interrupt 2 using 2//外中断1中断服务函数
  43.   {
  44.    uchar m;
  45.    for(m=0;m<10;m++) //闪烁显示10
  46.    {
  47.    P1=0xff; //全灭
  48.    Delay(500); //延时
  49.    P1=0; //全亮
  50.    Delay(500); //延时
  51.    }
  52.   }

仿真效果图如下:  

两个中断

 3.中断嵌套

 要求:设计一中断嵌套程序:要求K1和K2都未按下时,P1口8只LED呈流水灯显示,当按一下K1时,产生一个低优先级外中断0请求(跳沿触发),进入外中断0中断服务程序,上下4只LED交替闪烁。此时按一下K2时,产生一个高优先级的外中断1请求(跳沿触发),进入外中断1中断服务程序,使8只LED全部闪烁。当显示5次后,再从外中断1返回继续执行外中断0中断服务程序,即P1口控制8只LED,上、下4只LED交替闪烁。设置外中断0为低优先级,外中断1为高优先级。

  1. #include <reg51.h>
  2. #define uchar unsigned char
  3. void Delay(unsigned int i) //延时函数Delay( )
  4. {
  5.   unsigned int j;
  6.   for(;i > 0;i--)
  7.   for(j=0;j<125;j++)
  8.   {;} //空函数
  9. }
  10. void main( ) //主函数
  11.  {
  12.    uchar display[9]={0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f};
  13. //流水灯显示数据组
  14. uchar a;
  15. for(;;)
  16. {
  17.    EA=1; //总中断允许
  18.    EX0=1; //允许外部中断0中断
  19.    EX1=1; //允许外部中断1中断
  20.    IT0=1; //选择外部中断0为跳沿触发方式
  21.    IT1=1; //选择外部中断1为跳沿触发方式
  22.    PX0=0; //外部中断0为低优先级
  23.    PX1=1; //外部中断1为高优先级
  24. for(a=0;a<9;a++)
  25. {
  26.   Delay(500); //延时
  27.    P1=display[a]; //流水灯显示数据送到P1口驱动LED显示
  28. }
  29.   
  30. }
  31. }
  32. void int0_isr(void) interrupt 0 using 0 //外中断0中断函数
  33. {
  34.   for(;;)
  35.   {
  36.    P1=0x0f; //4位LED灭,高4位LED亮
  37.    Delay(400); //延时
  38.    P1=0xf0; //4位LED灭,低4位LED亮
  39.   Delay(400); //延时
  40.   }
  41. }
  42. void int1_isr (void) interrupt 2 using 1 //外中断1中断函数
  43. {
  44.   uchar m;
  45.   for(m=0;m<5;m++) //8位LED全亮全灭5
  46.   {
  47.    P1=0; //8位LED全亮
  48.    Delay(500); //延时
  49.    P1=0xff; //8位LED全灭
  50.    Delay(500); //延时
  51.   }
  52. }

仿真效果图如下:  

嵌套中断

三、定时器计数控制led灯周期性亮灭

1.定时器工作原理

(1)原理

定时器实质上就是一个加1计数器。它随着计数器的输入脉冲进行自加1,也就是每来一个脉冲,计数器就自动加1,,当加到定数器满时,再输入一个脉冲就使定时器回零,且定时器的溢出使相应的中断标志位置1,向CPU发出中断请求。如果定时器工作于定时模式,则表示定时时间已到;如果工作于计数模式,则表示计数值已满。

定时器由高8位和低8位两个寄存器 TH0/TH1和TL0/TH1 组成。

51单片机定时/计数器的工作由两个特殊功能寄存器控制。TMOD 是定时器的工作方式寄存器,确定工作方式和功能;TCON 是控制寄存器,控制T0、T1的启动和停止及设置溢出标志。

(2)工作方式寄存器 TMOD

51单片机有两个定时器,所以 TMOD 里面有两组。

GATE:是门控位, 一般默认GATE=0

C/T :定时/计数模式选择位。低电平为定时模式;高电平为计数模式。

M1 M0:工作方式设置位。定时/计数器有四种工作方式。

(3)控制寄存器 TCON

TF1:T1溢出中断请求标志位。T1计数溢出时由硬件自动置TF1为1。CPU响应中断后TF1由硬件自动清0。T1工作时,CPU可随时查询TF1的状态。所以,TF1可用作查询测试的标志。TF1也可以用软件置1或清0,同硬件置1或清0的效果一样。

TR1:T1运行控制位。TR1置1时,T1开始工作;TR1置0时,T1停止工作。TR1由软件置1或清0。所以,用软件可控制定时/计数器的启动与停止。

TF0:T0溢出中断请求标志位,其功能与TF1类同。

TR0:T0运行控制位,其功能与TR1类同。

2.用定时器控制led灯亮灭

定时1s,即10000微秒,因此具体方法如下:

(1)设置TMOD寄存器    

 T0工作在方式1,应使TMOD寄存器的M1、M0=01;应设置C/T*=0,为定时器模式;对T0的运行控制仅由TR0来控制,应使相应的GATE位为0。定时器T1不使用,各相关位均设为0。所以,TMOD寄存器应初始化为0x01。

(2)计算定时器T0的计数初值      

设定时时间5ms(即5 000µs),设T0计数初值为X,假设晶振的频率为11.059 2MHz,则定时时间为:

 定时时间=(216−X)×12/晶振频率    

则  10 000=(216 −X) ×12/11.059 2

X=64614.4

 转换成十六进制:0xfc66,其中0xee装入TH0,0x00装入TL0。

(3)设置IE寄存器      

由于采用定时器T0中断,因此需将IE寄存器中的EA、ET0位置1。

(4)启动和停止定时器T0    

将定时器控制寄存器TCON中的TR0=1,则启动定时器T0;TR0=0,则停止定时器T0定时。

  1. #include<reg51.h>
  2. char i=100;
  3. void main ()
  4. {
  5. TMOD=0x01; //定时器T0为方式1
  6. TH0=0xfc; //设置定时器初值
  7. TL0=0x00;
  8. P1=0x00; //P18个LED点亮
  9. EA=1; //总中断开
  10. ET0=1; //开T0中断
  11. TR0=1; //启动T0
  12. while(1); //循环等待
  13. {
  14. ;
  15. }
  16. }
  17. void timer0() interrupt 1 //T0中断程序
  18. {
  19. TH0=0xfc; //重新赋初值
  20. TL0=0x00;
  21. i--; //循环次数减1
  22. if(i<=0)
  23. {
  24. P1=~P1; //P1口按位取反
  25. i=100; //重置循环次数
  26. }
  27. }

(5) keil中采用逻辑分析仪观察波形

由此可知完成一个周期的时间为1.0019秒,相比软件计时,用定时器更加的精确。 

四、采用计数器中断,使led灯闪烁

1.原理

 计数器模式时,计数脉冲来自外部输入引脚T0或T1。当输入信号产生负跳变时,计数值增1。每个机器周期S5P2期间,都对外部输入引脚T0或T1进行采样。如在第1个机器周期中采得值为1,而在下一个机器周期中采得的值为0,则在紧跟着的再下一个机器周期S3P1期间,计数器加1。由于确认一次负跳变要花2个机器周期,即24个振荡周期,因此外部输入的计数脉冲的最高频率为系统振荡器频率1/24。

2.使用计数器中断实例

(1)设置TMOD寄存器

T1工作在方式1,应使TMOD的M1、M0=01;设置C/T*=1,为计数器模式;对T0运行控制仅由TR0来控制,应使GATE0=0。定时器T0不使用,各相关位均设为0。所以,TMOD寄存器应初始化为0x50。

(2)计算定时器T0的计数初值  

计算定时器T1的计数初值 由于每按1次按钮开关,计数1次,按4次后,P1口的8只LED闪烁不停。因此计数器初值为65 536−4=65 532,将其转换成十六进制后为0xfffc,所以,TH0=0xff,TL0=0xfc。

(3)设置IE寄存器    

由于采用T1中断,因此需将IE寄存器的EA、ET1位置1。 (4)启动和停止定时器T1     将寄存器TCON中TR1=1,则启动T1计数;TR1=0,则停止T1计数。

  1. #include <reg51.h>
  2. void Delay(unsigned int i) //定义延时函数Delay( ),i是形 //式参数,不能赋初值
  3. {
  4. unsigned int j;
  5. for(;i>0;i--) //变量i由实际参数传入一个值 //因此i不能赋初值
  6. for(j=0;j<125;j++)
  7. {;} //空函数
  8. }
  9. void main( ) //主函数
  10. {
  11. TMOD=0x50; //设置定时器T1为方式1计数
  12. TH1=0xff; //向TH1写入初值的高8
  13. TL1=0xfc; //向TL1写入初值的低8
  14. EA=1; //总中断允许
  15. ET1=1; //定时器T1中断允许
  16. TR1=1; //启动定时器T1
  17. while(1) ; //无穷循环,等待计数中断
  18. }
  19. void T1_int(void) interrupt 3 //T1中断函数
  20. {
  21. for(;;) //无限循环
  22. {
  23. P1=0xff; //8位LED全灭
  24. Delay(500) ; //延时500ms
  25. P1=0; //8位LED全亮
  26. Delay(500); //延时500ms
  27. }
  28. }

五、代码优化

         一般来说,中断函数中要尽量避免使用执行时间较长(耗时)的代码,以避免中断服务影响到主程序代码的执行效率。但是在上面外部中断的实验中,中断函数采用了软件延时函数去控制LED亮灭的间隔周期。我们可以换一种方式,不在中断函数使用延时循环,实现同样的功能。可以在main函数中写好几种亮灯模式代码和对应的模式标志位,按键中断发生后,中断服务程序只改变模式标志位,不做其他处理;由主程序根据模式标志,选择不同的亮灯模式。

具体代码如下:

  1. #include <REGX52.H>
  2. void Delay(unsigned int xms) //延时函数
  3. {
  4. unsigned char i, j;
  5. while(xms--)
  6. {
  7. i = 2;
  8. j = 199;
  9. do
  10. {
  11. while (--j);
  12. } while (--i);
  13. }
  14. }
  15. void Init0()//外部中断0初始化
  16. {
  17. EA=1;
  18. EX0=1;
  19. IT0=1;//下降沿触发
  20. }
  21. unsigned char Key_Interrupt_Flag=0;//中断模式标志位
  22. void Init0_Routine() interrupt 0
  23. {
  24. Key_Interrupt_Flag=1;//模式标志位置1
  25. }
  26. void main()
  27. {
  28. unsigned char Mode=0;
  29. Init0();//外部中断初始化
  30. while(1)
  31. {
  32. if(Key_Interrupt_Flag)//如果中断标志位为1
  33. {
  34. Key_Interrupt_Flag=0;//标志位置0
  35. Mode++;//切换亮灯模式
  36. if(Mode>=3)
  37. {
  38. Mode=0;//循环切换
  39. }
  40. }
  41. switch (Mode)//亮灯模式选择
  42. {
  43. case 0:
  44. {P2=0xfe;}
  45. break;
  46. case 1:
  47. {P2=0xf0;Delay(300);P2=0X0F;Delay(300);}
  48. break;
  49. case 2:
  50. {P2=0XAA;Delay(300);P2=0x55;Delay(300);}
  51. break;
  52. default:
  53. break;
  54. }
  55. }
  56. }

参考链接:

https://blog.csdn.net/NPNtoPNP/article/details/109540098

https://blog.csdn.net/zhouhaoNB_/article/details/127287647

https://blog.csdn.net/Pijiojio/article/details/137385384


总结

        此次实验加深了对中断系统和定时器、计数器的了解,同时动手在开发板上运行代码更是增加了实践经验,为以后的学习打下基础。

文章多有不足,如有错漏请多指教。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/羊村懒王/article/detail/527052
推荐阅读
相关标签
  

闽ICP备14008679号