引言

其实人的一生和单片机的运行很类似。就拿人的一生来说:有些事只需要做一次,比如得了水痘以后,体内产生免疫,以后就不会再生这个病了。有些事需要反复做,比如反复读书,反复工作,反复与困苦打交道,反复地与人相处。而有其他一些事,只有当它突然发生时我们才会去处理的,比如中彩票,钱包丢了......

这个运行机制早被Arduino借鉴了。

/*******Arduino代码框架********/
void setup() { //只执行一次的代码 } void loop() { //反复执行的代码 } //------------经过Arduino编译器转译后的实质代码(有删改)-----------------------
#include <Arduino.h> int main(void)
{ init(); //最先调用init,初始化arduino 的硬件 setup(); //只执行一次的代码 for (;;) //反复执行的代码
{
loop(); } return ;
}

回想一下写C51代码的模式,其实也是一样的。不过上述代码中,还有一种机制没体现出来:突然发生的事情。这就是下面要剖析的中断机制。

关于中断

无论是Arduino 还是 C51,还有其他硬件平台,都有中断机制。

中断是单片机处理突发性事件的一种机制。只执行一次的代码可以放在大循环外,循环执行的放在大循环内,突发性事件的代码,则通过中断方式处理。我们的PC机,鼠标的点击,键盘的按下,都是以中断的方式处理的。

若程序正常运行的某一时刻,中断发生了,当前执行流程就会暂停,CPU会转去处理中断服务程序(执行中断函数),当中断服务程序执行完后,再返回来接着执行原来的指令。

这个过程就是中断响应和中断返回。

中断源

引起中断的根源,叫中断源。
当有中断发生时,会向单片机申请中断处理。标准C51中有5个中断源,也就是有5种情况会引发中断。
 
 
中断源 引发原因 默认优先级 中断序号(C语言)
入口地址(汇编用)
中断标号*8 +3得到
INT0 引脚输入低电平或者下降沿引发。此时标志位IE0=1 最高 0 0003
T0 T0对应的TF0溢出时发生。此时标志位TF0 = 1   1 000B
INT1 引脚输入低电平或者下降沿引发。此时标志位IE1=1   2 0013
T1 T1对应的TF1溢出时发生。此时标志位TF1 = 1   3 001B
串口中断 串口完成一帧字符的接受/发送引发。   4 0023
T2(如果有的话) T2对应的TF2溢出时发生。标志位TF2 = 1 最低 5 002B

若配置好了相应的中断,当中断发生时,单片机就会自动去调用中断函数,来处理中断。

在执行中断函数前,除了串行口中断的标志位需要用代码指令软件归零外,其他的中断标志位都是硬件自动归零。

中断函数

//无返回值,无参数,不用声明

//注意:不要让中断事件处理太复杂耗时的任务。中断函数应该速战速决。
//格式如下:
void functionName() interrupt 中断序号
{ //..... } //如下是计数器/定时器0中断函数
void interrupt_Timer0() interrupt 1
{
  
//这里写 计数器/定时器0发生中断时的处理代码
}

中断使能寄存器 IE(interrupt enable)

想要中断发生时,CPU能处理中断函数,就必须使能相应的中断,通过IE配置即可。

为1时使能,为0不使能
 
EA  (enable ALL ):中断使能总开关位。1开启,0关闭。若EA不开启,即便5个中断都开启,CPU也不会处理中断。
 
 
EX0:外部中断INT0使能
EX1:外部中断INT1使能
 
ET0:定时器0中断使能
ET1:定时器1中断使能
ET2:定时器2中断使能
 
ES   :  串口中断使能

中断优先级寄存器 IP (interrupt priority)

为1时表示为提升中断为高级中断,为0时表示为低级中断级别。
 
 
PX0  :外部中断0优先级提升 位
PX1  :外部中断1优先级提升 位
 
PT0 : 计时器0中断优先级提升 位
PT1:  计时器1中断优先级提升 位
pt2 : 计时器2中断优先级提升 位
 
PS:   串口中断优先级提升 位

被设置为1的中断,将提升位高级优先级,否则归纳为低级优先级。

      

同时发生的中断:

同优先级时,按照默认优先顺序执行

不同优先级时,高优先级 先 于 低优先级执行

验证:

#include<reg51.h>
typedef unsigned int uint;
typedef unsigned char uchar; /**************函数声明******************/
void delay(uint t);
void enableALL(void);
void init_interrupt(void);
bit isKeyPressed() ; /********************************/ /***********特殊功能位********************/
sbit redLED_TO = P0^;
sbit blueLED_T1 = P0^;
sbit key = P1^;
/*********************************/ void main()
{
init_interrupt();
key = ;
redLED_TO = ;
blueLED_T1 = ; //PT1 = 1;
//取消这里的注释,来验证:同时发生的中断,不同优先级时,高优先级 先 于 低优先级执行 while()
{
if(isKeyPressed())
{
enableALL();
TR0 = ;
TR1 = ;
} } } void init_interrupt(void)
{
EA = ; //关闭总中断使能,默认就是0
ET0 = ; //使能定时器0 中断
ET1 = ; //使能定时器1 中断 TMOD = ; //T0 T1 都是16位存储计数器模式 //T0
TH0 = ; //都设置为255,以便程序运行后马上就能引发中断
TL0 = ;
TR0 = ; //开启定时器,让定时器跑起来,引发中断 //T1
TH1 = ;
TL1 = ;
TR1 = ; } void enableALL(void)
{
//使能中断总开关
EA =;
} //定时器0 的中断函数
void interrupt_Timer0() interrupt
{
redLED_TO = ; //点亮红色LED
delay();
}
//定时器1 的中断函数
void interrupt_Timer1() interrupt
{
blueLED_T1 = ; //点亮蓝色色LED
delay();
} //按键检测函数,按下返回1,否则返回0
bit isKeyPressed()
{
bit pressed = ;
if(key==)
{
delay();
if(key == )
{
pressed = ;
while(key==);
}
} return pressed;
} void delay(uint t)
{
uchar j;
uint i;
for(i=t;i>;--i)
for(j=;j>;--j)
;
} /**************************************
实验效果:当程序跑起来后,2个LED都是熄灭的。
按下按键后,红色LED先亮,1s后蓝色LED亮。 取消 PT1 = 1; 这行注释。
按下按键后,蓝色LED先亮,1s后红色LED亮。
***************************************/

先后发生的中断:

高优先级中断打断正在执行的低优先级程序,执行高优先级中断函数,形成中断嵌套。

低优先级中断 不会打断 正在执行的高优先级程序。

同级优先级中断不会相互打断(书上如是说,但是我实验结果却不是这样,同级看默认优先级,高优先级的还是会打断低优先级的,求解释 --!)。

连线图同上。

/***高优先级中断打断正在执行的低优先级程序***/
#include<reg51.h>
typedef unsigned int uint;
typedef unsigned char uchar; /**************函数声明******************/
void delay(uint t);
void enableALL(void);
void init_interrupt(void);
bit isKeyPressed() ; /********************************/ /***********特殊功能位********************/
sbit redLED_TO = P0^;
sbit blueLED_T1 = P0^;
sbit key = P1^;
/*********************************/ void main()
{
init_interrupt();
key = ;
redLED_TO = ;
blueLED_T1 = ; PT0 = ; while()
{
if(isKeyPressed())
{
enableALL();
TR0 = ;
TR1 = ;
}
} } void init_interrupt(void)
{
EA = ; //关闭总中断使能,默认就是0
ET0 = ; //使能定时器0 中断
ET1 = ; //使能定时器1 中断 TMOD = ; //T0 T1 都是16位存储计数器模式 //T0
TH0 = ; //T0比T1慢溢出
TL0 = ;
TR0 = ; //开启定时器,让定时器跑起来,引发中断 //T1
TH1 = ; //T1先于T0溢出
TL1 = ;
TR1 = ; } void enableALL(void)
{
//使能中断总开关
EA =;
} //定时器0 的中断函数
void interrupt_Timer0() interrupt
{ redLED_TO = ; //点亮红色LED
delay();
}
//定时器1 的中断函数
void interrupt_Timer1() interrupt
{
delay();
blueLED_T1 = ; //点亮蓝色色LED } //按键检测函数,按下返回1,否则返回0
bit isKeyPressed()
{
bit pressed = ;
if(key==)
{
delay();
if(key == )
{
pressed = ;
while(key==);
}
} return pressed;
} void delay(uint t)
{
uchar j;
uint i;
for(i=t;i>;--i)
for(j=;j>;--j)
;
} /**************************************
实验效果:当程序跑起来后,2个LED都是熄灭的。
按下按键后,红色LED先亮, 后蓝色LED亮。 由于T1的初始值大,会先发生中断,进入中断处理函数后,延时10s,在延时期间,T1对应的蓝色LED
来不及点亮,后来的T0 发生中断,由于T0设置了高优先级,打断了T1的中断,进入T0的中断,红色LED点亮。
然后回到T1的中断,最终点亮蓝色LED。 ***************************************/

使用中断的一个例子:数码管显示跑秒

#include<reg51.h>
typedef unsigned int uint;
typedef unsigned char uchar; /**************函数声明******************/
void delay(uint t);
void showDigit(uint num);
void destroy_Timer0(void);
void init_Timer0(void);
/********************************/ uchar code TABLE[] = {0x3F, 0x06, 0x5B, 0x4F, 0x66, 0x6D, 0x7D, 0x07, 0x7F, 0x6F}; #define DUAN_XUAN P0
sbit Add0 = P2^;
sbit Add1 = P2^ ;
sbit Add2 = P2^ ; uchar T0_interruptCount = ;
uint times = ; void main()
{ init_Timer0();
while()
{
showDigit(times); } } void showDigit(uint num)
{
uchar c = ;
do{ switch(c)
{
case : Add2= ; Add1 = ; Add0= ; break;
case : Add2= ; Add1 = ; Add0= ; break;
case : Add2= ; Add1 = ; Add0= ; break;
case : Add2= ; Add1 = ; Add0= ; break;
case : Add2= ; Add1 = ; Add0= ; break;
case : Add2= ; Add1 = ; Add0= ; break;
case : Add2= ; Add1 = ; Add0= ; break;
case : Add2= ; Add1 = ; Add0= ; break;
default :break;
} DUAN_XUAN = TABLE[num%] ;
delay();
DUAN_XUAN = ;
++c; }while(num/=); } void init_Timer0(void)
{
TMOD = ;
TL0 = ;
TH0 = ;
EA = ;
ET0 =; TR0 =; } void interrupt_Timer0() interrupt
{
TL0 = ;
TH0 = ;
++T0_interruptCount ;
if(T0_interruptCount == )
{
++times;
T0_interruptCount = ;
}
} void delay(uint t)
{
uchar j;
uint i;
for(i=t;i>;--i)
for(j=;j>;--j)
;
}

计数器中断的运用

以后补。

INTx外部中断的运用

以后用到再补。

【C51】单片机中断的更多相关文章

  1. C51单片机中断实验

    实验要求: 要求通过中断方式检测有无按键 判断哪个按键(编号0-9),并且在数码管上显示对应的0-9 代码部分 #include<reg51.h> char led_mod[]={0x3f ...

  2. C51单片机_day_01(定时器和中断系统)

                c51单片机 51单片机是控制电路系统的开关,当然芯片就是51芯片,现在随着科技的发展,也是出了很多,功能更多,更全的芯片. 51是用c语言做为程序编程的语言 ——我对基本基础 ...

  3. 51单片机中断interrupt……using……

    51单片机中断细节的一些问题. interrupt0:外部中断0interrupt1:定时器中断0interrupt2:外部中断interrupt3:定时器中断1interrupt4:串口 using ...

  4. 关于C51的中断函数要注意的几个问题

    转载自:http://blog.21ic.com/user1/531/archives/2006/16909.html 最近在虾潭逛,发现一些小虾米对C51中断函数有些不了解,今天周末,抽空发个技术帖 ...

  5. ET 与RETI 基于51单片机中断跳出指令“RETI”浅议

    最近在基于51单片机编程的过程中出现了个很奇怪的问题“程序执行中在寄存器EA=1,ET0=1,TR0=1条件下,单TF0=1时并没有执行中断”.在有过单片机中断编程经历者都知道当EA=1,ET0=1的 ...

  6. C51单片机中data、idata、xdata、pdata的区别

    C51单片机中data.idata.xdata.pdata的区别 data: 固定指前面0x00-0x7f的128个RAM,可以用acc直接读写的,速度最快,生成的代码也最小. idata: 固定指前 ...

  7. c语言编写51单片机中断程序,执行过程是怎样的?

    Q:c语言编写51单片机中断程序,执行过程是怎样的? 例如程序:#include<reg52.h>  void main(void)  {   EA=1;      //开放总中断   E ...

  8. C51单片机头文件和启动文件

    STARTUP.A51//启动文件. 清理RAM.设置堆栈等.即执行完start.a51后跳转到.c文件的main函数 <reg51.h>  //特殊寄存器的字节地址和位地址,sfr定义字 ...

  9. C51 单片机的中断号以及中断向量

    1.外部中断0. 1:分别由引脚/INT0./INT1的电平信号引起. 2.定时/计数器0.1:分别由T0. T1的溢出引起. 3.串行口发送.接收:发送完一个字节或接收到一个字节引起. 上述共5个中 ...

随机推荐

  1. HTML-Geolocation API

    获取位置信息: 请求一个位置信息,如果用户同意,浏览器就会返回位置信息(由经纬度和其他元数据组成),该信息是通过支持html5地理定位功能的底层设备提供给浏览器的:该API不指定设备用哪种底层技术来定 ...

  2. Pebbles

    Pebbles Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Sub ...

  3. html5中manifest特性测试

    测试环境和工具   chromium  18.0.1025.151 (开发编译版 130497 Linux) Ubuntu 11.04 一.测试内容 1.A页面manifest缓存的js文件,B页面不 ...

  4. [Cocos2d-x For WP8]Progress 进度条

    Cocos2d-x可以有多种进度条的展示方式,进度条的种类是根据进度条运动的方向来区分,包括顺时针,逆时针,从左到右,从右到左,从下到上和从上到下6种方式,这和WP8的进度条是由很大的区别的.那么Co ...

  5. BZOJ4026: dC Loves Number Theory

    Description  dC 在秒了BZOJ 上所有的数论题后,感觉萌萌哒,想出了这么一道水题,来拯救日益枯 竭的水题资源.    给定一个长度为 n的正整数序列A,有q次询问,每次询问一段区间内所 ...

  6. 如何下载某些 flash 在线视频 并使用ffmpeg下载分段并加密的m3u8视频流

    有些网站使用 flash 在线播放视频,不方便进行下载. 可以使用 Chrome 的 Developer Tools 模拟成 iOS 设备(通过修改 User Agent),然后取得 h.264 视频 ...

  7. Spring_讲解

    http://s,i,s,h,u,o,k.com/forum/blogPost/list/6174.html

  8. .NET正则基础之——平衡组

    1        概述 平衡组是微软在.NET中提出的一个概念,主要是结合几种正则语法规则,提供对配对出现的嵌套结构的匹配..NET是目前对正则支持最完备.功能最强大的语言平台之一,而平衡组正是其强大 ...

  9. hdu Inverting Cups

    这题需要分类讨论: 第一种情况: n为奇数m为偶数的情况无解,因为m为偶数,每次翻转将把从正面翻到反面的个数x减去从反面翻到正面的个数y,得到的数必定为偶数.因为x+y为偶数,x-y也为偶数.而总个数 ...

  10. discuz全局数组变量 后台各项设置 完整版

    $_G 保存了 Discuz! 中所有的预处理数据 缓存能够很好的提高程序的性能,一些配置数据没必要每次都查询数据库,只要在修改了的时候更新下缓存即可. Discuz! 中所有的缓存保存在 $_G[c ...