单片机外部中断程序

2018-12-01 21:58:33 sinat_38816924 阅读数 6626

前言:单片机的中断系统(一)


        80C51单片机提供两个外部中断口:  INT0(P3.2)和INT1(P3.3)引脚输入。这两个引脚是功能复用引脚,既可以作为普通V0口,也可作为外部中断输入引脚。下面以部中断0来讲述。80C51单片机在每个机器周期的S5P2期间扫描外部中断输入引脚的电平状态。当外部中断设置为下降沿触发时,若处理器在连续两个机器周期扫描到INT0引脚的电平先后为高电平和低电平时,就会设置中断标志位IE0为1,表示外部有中断申请,该中断申请信号会一直保持,直到该中断被响应,该标志由内部硬件自动清除当外部中断设置为电平触发方式时,在外部中断引脚INTo变为低电平时,IE0变为1,并一直保持为1,直到引脚INTo的输入变为高电平时,IE0位才清0。因此,选择低电平触发方式时,对INT0的电平持续时间有严格要求,必须保持INTo引脚为低电平,直到中断被响应才 能变高,而且在中断返回前必须变成高电平,以撤销中断请求。若低电平时问太短,则可能导致中断不会被响应;若太长,在中断子程序执行完后仍为低电平,则IE0会一直保持为1,这时会导致一次中断请求,得到多次响应 ——————http://www.51dzw.com/embed/embed_110007.html

 

外部中断0实验 

按键作为外部中断的产生源,按下按键,led状态反转。

图一:单片机引脚图
图二:独立按键接线图
图三:LED引脚图

程序:

#include<reg52.h>

sbit key3=P3^2;//外部中断0的引脚接口
sbit led=P2^0;

void delay(int dat)
{
	while(dat--);
}

void Int0Init()
{
	IT0=1;//下降沿触发
	//IE0=0;请求标志位,无触发,或响应中断后,硬件自动置0
	EX0=1;//外部中断0允许标志
	EA=1;//打开总终端
}

void main(void)
{
	Int0Init();
	while(1);//如果不写while(1),单片机在主程序中会不断循环执行,导致不断初始化		
}

void LedRever() interrupt 0	//0是外部中断的中断号
{
	 delay(1000);
	 if(key3==0)
	 {
	 	led=~led;
	 }
}

 比较有意思的是,中断函数中增加了消抖部分。

如果不加消抖,可能想程序可能想多次执行这个中断。如果消抖在外面,可能已经进入中断了,还没进行消抖。

 

外部中断1实验:

接线引脚图如图一、二、三。

普中教程代码:

/**************************************************************************************
*		              外部中断1实验												  *
实现现象:下载程序后按下K4按键可以对D1小灯状态取反。
注意事项:无。																				  
***************************************************************************************/

#include "reg52.h"			 //此文件中定义了单片机的一些特殊功能寄存器

typedef unsigned int u16;	  //对数据类型进行声明定义
typedef unsigned char u8;

sbit k4=P3^3;  //定义按键K4
sbit led=P2^0;	 //定义P20口是led

/*******************************************************************************
* 函 数 名         : delay
* 函数功能		   : 延时函数,i=1时,大约延时10us
*******************************************************************************/
void delay(u16 i)
{
	while(i--);	
}

/*******************************************************************************
* 函 数 名         : Int1Init()
* 函数功能		   : 设置外部中断1
* 输    入         : 无
* 输    出         : 无
*******************************************************************************/
void Int1Init()
{
	//设置INT1
	IT1=1;//跳变沿出发方式(下降沿)
	EX1=1;//打开INT1的中断允许。	
	EA=1;//打开总中断	
}

/*******************************************************************************
* 函 数 名       : main
* 函数功能		 : 主函数
* 输    入       : 无
* 输    出    	 : 无
*******************************************************************************/
void main()
{	
	Int1Init();  //	设置外部中断1
	while(1);		
}

/*******************************************************************************
* 函 数 名         : Int1()	interrupt 2
* 函数功能		   : 外部中断0的中断函数
* 输    入         : 无
* 输    出         : 无
*******************************************************************************/

void Int1()	interrupt 2		//外部中断1的中断函数
{
	delay(1000);	 //延时消抖
	if(k4==0)
	{
		led=~led;
	}
}

 

参考文章:

外部中断0中断请求标志位。

 

 

 

 

 

 

 

 

2018-08-04 12:07:38 liming0931 阅读数 11162
;普中51开发板
;单片机的P3.2(INT0)引脚与按键K3脚连接
;用汇编语言实现:按一次K1外部中断INT0响应一次,LED显示值加1(十进制),
;前提是共阴数码LED第一位,需要设定,由P0口控制。
		ORG 0000H
		LJMP START
		ORG 0003H
		LJMP INTT0
		ORG 0600H
START: 	SETB EA
		SETB EX0 ; 打开外部中断0
		SETB IT0 ; 跳变沿出发方式(下降沿)	这个方法比较稳定
		;CLR IT0 ; 令中断0为电平触发,这个方式需要有延时程序,
		;否则,单片机处理速度快,按一下按键,
		;已经处理了很多个低电平中断了。
		CLR P2.2  ;段位选择第一位
		CLR P2.3
		CLR P2.4
CLR1:	MOV R0,#00H

DISPLAY: MOV DPTR,#TAB	;给字形表的初地址
		MOV A,R0	;将要显示的数给A
		;/////////////////////////
		MOV B, A   ;save a value
		CLR C
		SUBB A, #10H	;如果已计数到15,说明一次循环结束
		MOV A, B   ;load a value
		JNC CLR1   ;C=1,重新开始,R0=00H,若等于0,回display

		MOVC A,@A+DPTR ;在字形表中取数放到A
		MOV P0,A	;假设是P0口输出要显示的数据把A放到P0中

		
		SJMP DISPLAY ;循环显示等待中断

INTT0:	INC R0	;中断中有按键着加1
		RETI
TAB:	DB 3FH,06H,5BH,4FH,66H ;字形表0-15
		DB 6DH,7DH,07H,7FH,6FH
		DB 77H,7CH,39H,5EH,79H,71H
		END

 

2018-05-28 23:26:17 konglingshneg 阅读数 8584

新搭了一个系统,用线激光进行实时三维重建,不用每次都判断位置开始拍照,加了两个接近开关,当步进电机向某一方向运行时,利用两个传感器确定需要拍照的时刻,同时通过串行口向电脑发送一个字符,电脑收到这个字符开始拍照。今天先把keil端的程序弄上来,有时间再把串口通信的程序写一写。程序已经通过运行,如图所示:


利用串口调试工具试了一下完全可以,程序的思路大概就是设置了两个状态标志位flag0和flag1,当通过接近开关1时,p3.2出现下降沿,此时设置flag0=1,当通过接近开关2时,p3.3出现下降沿,此时进入外部中断1,如果满足flag0=1,就设置flag1=1,如果flag1=1,则向串口发送一串字符即可。当然这其中还需要相互制约,保证反方向进入时不会发送数据,具体一看程序就明白了。当然也可以使用外部中断计数器做。



#include <STC12C5A60S2.H>
bit Flag=0; 
bit flag0=0;    //0中断标志
bit flag1=0;    //1中断标志
void SendOneByte(unsigned char c)   
{
SBUF = c;           //把数据送往寄存器
while(!TI);         //等待发送完成TI=0时一直发送,直到TI=1,发送后硬件自动置1
TI = 0;             //发送完成标志
}
void SendString(unsigned char *p)
{
while(*p!='\0')
{SendOneByte(*p++);}
 flag1=0;
 flag0=0;
}


void main(void)
{
//单片机初始化


//通信设置,串行口中断
TMOD = 0x20;
SCON = 0x50;
TH1 = 0xFD;
TL1 = TH1;
PCON = 0x00;
EA = 1;
ES = 1;
TR1 = 1;
//外部中断0
IT0=1;      //外部中断0下降沿触发方式
EX0=1;      //开外部中断0


//开外部中断1
IT1=1;      //外部中断1下降沿触发方式
EX1=1;      //开外部中断1
while(1)
{
while(flag1)
{
SendString("konglingsheng");
while(!Flag); //flag=0一直循环,循环结束flag=1;
Flag=0;
}
}
}
void int0(void) interrupt 0   //外部0中断服务
{
        EX0=0;
        flag1=0;
        flag0 = 1;
        EX0=1;
}
void int1(void) interrupt 2 //外部1中断服务
{    EX1=0;
    if(flag0) //如果0已中断
    {
       flag0=0;
flag1=1;
    }
    else
{
flag1 = 0;
  flag0= 0;
}
EX1=1;
}
void UARTInterrupt(void) interrupt 4  //4号串行中断
{
  RI = 0;                                    //停止接受
  Flag=1;                                     //标志位使循环 

作者:kls 2018.5.28  23:26

2016-08-27 18:09:32 xiaocheng_sky 阅读数 34877

寄存器是干什么的?怎么配置它?配置完寄存器后,有什么作用呢?
寄存器是中央处理器内的组成部分。它是有限存贮容量的高速存贮部件,它们可用来暂存指令、数据和地址。寄存器可以用来暂存指令、暂存数据、暂存地址。换而言之,我们配置寄存器,便是给寄存器中赋予一定的值,而这些值又要与我们的目的想对应,这样它便会有相应的作用。
例如,芯片的资料规定,当给芯片的 A 寄存器赋“0x11”时,它会出现 B 现象;赋“0x77”时,它会出现 C 现象。那么当我们目的是完成 B 现象时,我们就只需要配置 A 寄存器为“0x11”即可。
虽说看起来很简单,并且去完成目的时的流程并非这么容易。但是,实实在在而言,这些就是控制寄存器的根本!
这里以外部中断0(INT0)为例,使得外部中断0每发生一次,最后一位数码管的数值加1。
前一篇博文已经提到,要实现外部中断0,就必须要配置好两个寄存器IP、IE。而对于中断优先级寄存器IP,当我们使用默认优先级时(上篇博文的优先级表格所述),就不必要去配置IP。
接下来附上IE寄存器的每一位的作用:
这里写图片描述
首先,中断允许位寄存器 IE 是可位寻址的,意思是说,我们可以单独的对D0~D7每一位进行操作,而不需要对 IE 整个赋值(为什么可以这样,因为keil的头文件“reg52.h”已经对 IE 的地址进行了定义)。
在这里说明一点,对于51单片机的 I/O 口而言,上电时,默认输出为高电平。对于其寄存器而言,上电是,默认为0。可见,当要完成外部中断0的配置时,我们只需要配置中的EX0、EA,当然还有外部中断0的触发方式(产生方式),这里就要看到中断及控制寄存器TCON,其成员及意义如下:
这里写图片描述
这里写图片描述
可见外部中断0和外部中断1的设置方式雷同,跟据上表所述,我们通过设置IT0来设置外部中断0的触发方式(分别为:低电平触发、下降沿触发),其中 IE 位由硬件自身控制,不需要软件操作。

实例的核心代码如下:

/*数码管配置完成*/
void main()
{
    IT0 = 1//设置为下降沿触发
    EX0 = 1//外部中断0中断允许位                    
    EA = 1while(1);                           //等待外部中断0发生 
    {
        display();
    }                           
}

void INT0() interrupt 0                //中断服务函数的书写格式
{
    if( IE == 1//产生了外部中断,IE 自动置为1
    {
        dspbuf[0]++;    
    }
}

在上面可以看到配置外部中断0相关的寄存器时,我们先打开EX0=1,允许外部中断产生,再EA = 1,打开总中断,这样就配置好了能产生外部中断0的先决条件,通过IT0 来配置中断的触发方式。在中断服务函数中,函数名“INT0”可自由编写,并且中单服务函数不需要声明,后面所加的“interrupt X”X为该中断对应的C语言序号。
值得注意的是,对于51单片机而言,上电之后,所有寄存器的值默认为“0”,所有 I/O 口的值默认为“1”。
通过外部中断的理解,很方便的能引出下一节的定时器/计数器中断。

未完待续……

2016-07-11 18:12:15 opshres169 阅读数 3439

/*以下是能在keilC 中变异的源码,直接粘贴过去就行,外部中断0(INT0)和外部中断1都有(INT1)*/

/*程序很简单,但是对新手来说还是很实用的*/

/*******************************************************************/
/*                                                                 */
/* 单片机开发系统演示程序 - INT0 INT1 中断计数                     */
/*                                                                 */
/* 6位数码管显示                                                   */
/*                                                                 */
/* 作者:曾露337  店铺:http://shop58430712.taobao.com             */
/*                                                                 */
/*【声明】此程序仅用于学习与参考,引用请注明版权和作者信息!       */
/*                                                                 */
/*******************************************************************/
 
#include < reg51.h >
#include <intrins.h>

#define uchar unsigned char
#define uint  unsigned int

unsigned char code  LEDData[ ] = {0xC0,0xF9,0xA4,0xB0,0x99,0x92,
                                  0x82,0xF8,0x80,0x90,0xff};
                                    
unsigned char data  display[8] = {0x00,0x00,0x00,0xff,0xff,0x00,0x00,0x00};

unsigned char code  scan_bit[8] = {0x7f,0xbf,0xdf,0xef,0xf7,0xfb,0xfd,0xfe};

unsigned char count0,count1,temp=0 ;

/********************************************************
*                                                       *
* 延时函数                                              *
*                                                       *
********************************************************/
void delay(uint ms) 
// 延时子程序
{
 uchar k;
 while(ms--)
 {
  for(k = 0; k < 100; k++);
 }
}

/********************************************************
*                                                       *
*  数据处理与显示函数                                   *
*                                                       *
********************************************************/
void  disp_count()
{
    char n; 

    temp=count0;

    display[2]=temp/100;    //数据处理
    temp=temp%100;
    display[1]=temp/10;
    display[0]=temp%10;

 if(display[2]==0)        //高位为0,不显示 
 { 
   display[2]=0x0a;
   if(display[1]==0)
   display[1]=0x0a;  
    }

    temp=count1;

    display[7]=temp/100;    //数据处理
    temp=temp%100;
    display[6]=temp/10;
    display[5]=temp%10;

 if(display[7]==0)        //高位为0,不显示 
 { 
   display[7]=0x0a;
   if(display[6]==0)
   display[6]=0x0a;  
    } 
     
    for(n=0;n<8;n++)
    {  
      P0 =LEDData[display[n]] ;  //显示段码
      P2 =scan_bit[n];           //输出位码
      delay(1);
   P2 = 0xff;                 //关闭显示
    } 
}

/********************************************************
*                                                       *
* 主程序                                               *
*                                                       *
********************************************************/
void main(void)
{  
   P0=0xff;
   P1=0xff;
   P2=0xff;   
   
   IT0=0;          //低电平触发
//   IT0=1;        //下降沿触发
   IT1=0;          //低电平触发
//   IT1=1;        //下降沿触发
   PX0=1;
   EA=1;
   EX1=1;
   EX0=1;

   while(1)
   {
      disp_count();
   }
}

/********************************************************
*                                                       *
* INT0中断函数                                          *
*                                                       *
********************************************************/
void  counter0(void) interrupt 0
{
   uchar  x;
   EX0=0;
   count0++;
    
   for(x=0;x<10;x++)
   {
     disp_count();
   }
   EX0=1;
}

/********************************************************
*                                                       *
* INT1中断函数                                          *
*                                                       *
********************************************************/
void  counter1(void) interrupt 2 
{
   uchar  x;
   EX1=0;
   count1++;
    
   for(x=0;x<10;x++)
   {
     disp_count();
   }
   EX1=1;
}

/********************************************************/