51单片机外部中断与计数器的实验

        在本文中,我介绍了51单片机中的中断和计数器操作,对其进行了简要描述,同时进行了实例展示加以说明。

一、外部中断

        中断技术主要用于实时监测与控制,要求单片机能及时地响应中断请求源提出的服务请求,并快速响应与及时处理。
        当中断请求源发出中断请求时,如中断请求被允许,单片机暂时中止当前正在执行的主程序,转到中断服务处理程序处理中断服务请求,处理完中断服务请求后,再回到原来被中止的程序之处(断点),继续执行被中断的主程序。中断系统结构如下图所示。

        中断系统共有5个中断请求源,它们是:
      (1)INT0—外部中断请求0,外部中断请求信号(低电平或负跳变有效)由INT0引脚输入,中断请求标志为IE0。
      (2)INT1—外部中断请求1,外部中断请求信号(低电平或负跳变有效)由INT1引脚输入,中断请求标志为IE1。
      (3)定时器/计数器T0计数溢出的中断请求,标志为TF0。
      (4)定时器/计数器T1计数溢出的中断请求,标志为TF1。
      (5)串行口中断请求,标志为发送中断TI或接收中断RI。

        5个中断请求源的中断请求标志分别由特殊功能寄存器“TCON”和“SCON”相应位锁存。
        TCON寄存器为定时器/计数器的控制寄存器,字节地址为88H,可位寻址。既包括定时器/计数器T0、T1溢出中断请求标志位TF0和TF1,也包括两个外部中断请求的标志位IE1与IE0,还包括两个外部中断请求源的中断触发方式选择位。
        SCON寄存器串行口控制寄存器,字节地址为98H,可位寻址。SCON的低二位锁存串口的发送中断和接收中断的中断请求标志TI和RI。

接下来我们来进行实例展示。

1.实例1-单一外中断的应用

        当程序启动时,P1口上的8只LED全亮。每按一次按钮开关K1,使引脚接地,产生一个低电平触发的外中断请求,在中断服务程序中,让低4位的LED与高4位的LED交替闪烁5次。然后从中断返回,控制8只LED再次全亮。

        首先利用“for循环”编写一个延时函数,以便实现LED灯闪烁操作;然后建立主函数,将EA置1,即允许总中断,将EX0置1,即允许外部中断0中断,将IT0置1,选择外部中断0为跳沿触发方式,进入编写的int0函数进行对应操作,同时让“P1=0”处于“”while“永真循环中;最后进行int0函数的编写,外部中断0被允许后。进入int0函数,将EX0置0,禁止中断,进入对应的操作,分别将P1置为”0x0f“和”0xf0“以便执行低4位的LED与高4位的LED交替闪烁的操作,最后再将EX0置1,允许中断,返回主程序。大致代码如下。

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

        将代码对应的hex文件录入Proteus中便能看到对应效果。

2.实例2-中断嵌套的应用

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

        大致操作与实例1相同,不同之处是这里使用了两个中断,分别用”EX0“和”EX1“表示中断0和中断1,同理置0时表允许中断,置1时表禁止中断,但这里引入了优先级的概念,将”PX0“置0表外部中断0为低优先级,将”PX1“置1表外部中断1为高优先级(当然也可以将”IP“置0表示两个中断都为低优先级,不分先后)。同样对应两个中断则需要编写两个函数进行对应操作,大致代码如下。

 #include <reg51.h>
 #define uchar unsigned char
 ​
 void Delay(unsigned int i)      //延时函数Delay( ),i为形式参                        //数,不能赋初值
 {
     uchar j;
     for(;i>0;i--)       
     for(j=0;j<125;j++)      
     {;}             //空函数
 }
 ​
 void  main( )                   //主函数
 {
     uchar display[9]={0xff,0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf, 0x7f}; 
                 //流水灯显示数据数组     
     unsigned int a;
     for(;;)
     {
         EA=1;               //总中断允许
         EX0=1;              //允许外部中断0中断
         EX1=1;                  //允许外部中断1中断
         IT0=1;              //选择外部中断0为跳沿触发方式
         IT1=1;  
         PX0=0;          //外部中断0为低优先级
         PX1=1;          //外部中断1为高优先级
 ​
         for(a=0;a<9;a++)
         {
             Delay(500);         //延时
             P1=display[a];  //将已经定义的流水灯显示数据送到P1口
         }
     }
 }
 ​
 void int0_isr(void)  interrupt 0  using 1//外中断0的中断服务函数
 {
     uchar  n;
     for(n=0;n<10;n++)       //高、低4位显示10次
     {
         P1=0x0f;        //低4位LED灭,高4位LED亮
         Delay(500);     //延时
         P1=0xf0;         //高4位LED灭,低4位LED亮
         Delay(500);     //延时
     } 
 }
 ​
 void int1_isr (void)  interrupt 2  using 2//外中断1中断服务函数
 {
     uchar  m;
     for(m=0;m<10;m++)               //闪烁显示10次
     {
         P1=0xff;                //全灭
         Delay(500);             //延时
         P1=0;                   //全亮
         Delay(500);                 //延时
     }
 }

        将代码对应的hex文件录入Proteus中便能看到对应效果。

二、定时器/计数器

        定时器/计数器T0由特殊功能寄存器TH0、TL0构成,T1由特殊功能寄存器TH1、TL1构成。其结构框图如下图所示。

        T0、T1都有定时器和计数器两种工作模式,两种模式实质都是对脉冲信号进行计数,只不过计数信号来源不同。 计数器模式是对加在T0(P3.4)和T1(P3.5)两个引脚上的外部脉冲进行计数。 定时器模式是对系统时钟信号经12分频后的内部脉冲信号(机器周期)计数。由于系统时钟频率是定值,可根据计数值计算出定时时间。两个定时器/计数器属于增1计数器,即每计一个脉冲,计数器增1。

1.LED灯每隔1s周期性亮灭

        采用T0方式1的定时中断方式,使P1口外接的8只LED每1s闪亮一次。大致代码如下所示。

 #include<reg51.h>
 char  i=100;
 void main ()
 {
     TMOD=0x01;          //定时器T0为方式1
     TH0=0xee;           //设置定时器初值
     TL0=0x00;
     P1=0x00;                //P1口8个LED点亮
     EA=1;                   //总中断开
     ET0=1;                  //开T0中断
     TR0=1;                  //启动T0
     while(1);               //循环等待
     {
         ;
     }
 }
 void timer0() interrupt 1           //T0中断程序
 {
     TH0=0xee;               //重新赋初值
     TL0=0x00;
     i--;                    //循环次数减1
     if(i<=0)
     {
         P1=~P1;         //P1口按位取反
         i=100;              //重置循环次数
     }
 }

        将代码对应的hex文件录入Proteus中便能看到对应效果。

2.按4次按钮开关后P1口的8只LED闪烁不停

        T1采用计数模式,方式1中断,计数输入引脚T1(P3.5)上外接按钮开关,作为计数信号输入。按4次按钮开关后,P1口的8只LED闪烁不停。大致代码如下所示。

 #include <reg51.h>
 void Delay(unsigned int i)      //定义延时函数Delay( ),i是形式参数,不能赋初值
 {
     unsigned int j;     
     for(;i>0;i--)           //变量i由实际参数传入一个值
         for(j=0;j<125;j++)      
         {;}             //空函数
 }
 ​
 void  main( )               //主函数
 {
     TMOD=0x50;          //设置定时器T1为方式1计数
     TH1=0xff;           //向TH1写入初值的高8位
     TL1=0xfc;           //向TL1写入初值的低8位
     EA=1;                   //总中断允许
     ET1=1;              //定时器T1中断允许  
     TR1=1;              //启动定时器T1
     while(1) ;          //无穷循环,等待计数中断
 }
 ​
 void T1_int(void)  interrupt 3      //T1中断函数
 {
     for(;;)             //无限循环
     {
         P1=0xff;            //8位LED全灭
         Delay(500) ;        //延时500ms
         P1=0;           //8位LED全亮
         Delay(500);         //延时500ms 
     }               
 }

        将代码对应的hex文件录入Proteus中便能看到对应效果。

        在普中开发板上操作如下图所示。

三、总结

        在本文中,我介绍了我对于接触到的51单片机开发中的中断和计数器操作,学习了外部中断、定时器/计数器中断的编程方式;了解了中断响应、中断优先级、中断标志位复位等原理,学习了二级中断、中断嵌套的具体应用编程;了解了定时器/计数器的工作原理,学习了·计数器初值计算方法,定时/计数中断服务的编程开发。同时也在普中开发板上进行了相应的操作。但是对于中断和计数器操作仍有一定的不熟悉,日后仍需多多练习。
        对于文中出现的错误,希望各位大佬提出建议。

  • 31
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
51单片机可以通过外部中断来进行计数,具体步骤如下: 1. 配置中断引脚为外部中断模式,可以使用P3口的INT0和INT1引脚,或者P1口的T0和T1引脚。 2. 初始化中断相关的寄存器,包括IE(中断使能寄存器)、IP(中断优先级寄存器)和TCON(定时器/计数器控制寄存器)等。 3. 编写中断服务程序,当外部中断发生时,会自动跳转到中断服务程序中执行。 4. 在中断服务程序中对计数器进行操作,可以使用一个全局变量来保存计数值。 5. 在主程序中定时读取计数器的值,可以使用定时器或者延时函数来控制读取的时间间隔。 6. 在需要重置计数器时,可以在主程序中设置一个标志位,当标志位被置位时,将计数器清零。 示例代码如下: ```c #include <reg52.h> #include <intrins.h> sbit INT0 = P3^2; // 外部中断0引脚 unsigned int count = 0; // 计数器 void init_interrupt() { EA = 1; // 开启总中断 EX0 = 1; // 开启外部中断0 IT0 = 1; // 配置为下降沿触发 } void isr_int0() interrupt 0 { count++; // 计数器加1 } void main() { init_interrupt(); // 初始化中断 while(1) { // 定时读取计数器的值,可以使用定时器或者延时函数 _nop_(); // 空指令,延时一段时间 _nop_(); _nop_(); _nop_(); printf("count = %d\n", count); // 重置计数器 if(/*条件*/) { count = 0; } } } ``` 注意:在使用P3口的INT0和INT1引脚时,需要将P3口的其他引脚设置为输入模式,否则可能会影响中断的触发。同时,需要注意中断服务程序的执行时间,尽量保持短暂,不要阻塞主程序的执行。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值