中断的流程分析及示例
一、用图文并茂的方式阐述中断的基本概念
对于单片机来讲,中断是指 CPU 在处理某一事件A时,发生了另一件事情B, 请求CPU迅速去处理(中断发生);CPU暂时停止当前的工作(中断响应),转去处理事件B(中断服务);待CPU将事件B处理完毕后,再回到原来事件 A 被中断的地方继续处理事件 A(中断返回),这一过程称为中断。中断是为使单片机具有对外部或内部随机发生的事件实时处理而设置的,中断功能的存在,很大程度上提高了单片机处理外部或内部事件的能力,它也是单片机最重要的功能之一。
1、中断的流程示意图
2、中断是如何执行的
中断是一种硬件或软件事件,它导致CPU停止正在执行的当前任务并转而执行另一个任务中断可以由多种原因引起,包括以下几种:
外部设备: 当外部设备(如键盘、鼠标、网络适配器等)需要CPU执行某些操作时,它们会向CPU发出中断请求。
内部事件: 当CPU执行某些操作时,它可能会发生内部故障(如除零错误、页故障等),这些故障会导致CPU停止当前任务并执行中断处理程序。
系统调用: 当进程需要访问系统资源(如文件、网络等)时,它必须通过系统调用请求操作系统执行某些操作。在这种情况下,操作系统会将进程的执行暂停,并执行系统调用处理程序。
3、中断的优势
可以提高CPU工作效率,CPU不必花费大量时间等待和查询外设工作。
具有实时处理功能,对实时控制系统中的各种参数和状态做出快速响应、及时处理。
具有故障处理功能,在掉电中断服务程序中将需要保存的数据和信息及时转移到具有备用电源的存储器中保护起来,待电源正常时再恢复。
实现分时操作,控制多个外设同时工作。
此外,中断系统还能用于程序调试、多机连接等方面。
4、中断函数与普通函数的异同
相同点:两者都需要保护断点(即下一条指令地址)、跳至子程序或中断服务程序、保护现场、子程序或中断处理、恢复现场、恢复断点(即返回主程序)。两者都可实现嵌套,即正在执行的子程序再调另一子程序或正在处理的中断程序又被另一新中断请求所中断,嵌套可为多级。
不同点:执行方式不同。中断函数是发生中断后自动执行的,不需要主函数调用,是否执行取决于相应的中断事件是否发生;普通子函数要主函数调用才能执行。使用情况不同。中断函数在中断发生时,先进入中断入口地址,再通过中断入口地址处放置的一条无条件转移指令,使程序执行转向中断服务程序入口;普通子函数调用时,直接进入函数入口地址。定义方式不同。中断服务程序用interrupt关键字来定义;普通子程序是一个大型程序中的某部分代码,由一个或多个语句块组成。
5、中断函数编码的注意事项
中断函数不能进行参数传递;中断函数没有返回值;在任何情况下都不能直接调用中断函数;中断函数使用浮点运算要保存浮点寄存器的状态;如果在中断函数中调用了其它函数,则被调用函数所使用的寄存器必须与中断函数相同,被调函数最好设置为可重入的;C51编译器对中断函数编译时会自动在程序开始和结束处加上相应的内容。
6、中断使用的注意事项
中断函数必须尽量短小:中断服务程序必须越短越好,不能包含复杂的算法和长时间的循环。这样可以保证在中断服务程序执行过程中,系统能够快速地响应其他事件。中断函数必须是可重入的:当一个中断处理正在进行时,另一个同类型的中断请求到来时,系统会立即触发新的中断响应。如果当前正在处理的中断还没有结束,就会出现重入问题。中断函数对全局变量、静态变量和动态内存分配等操作要小心:由于多个任务共享全局变量和静态变量等数据区域,因此在使用这些数据时要避免出现冲突或死锁。而动态内存分配则不适合用于实时系统或嵌入式系统,在使用前一定要慎重考虑。中断函数需要禁止其他同类型中断的触发:如果当前中断服务程序正在执行,而又有一个同类型的中断请求到来,则会出现重入问题。因此在编写中断服务程序时,应该在进入中断服务程序时屏蔽同类型的其他中断请求。
二、使用Keil建立完整的工程,并使用外部中断0触发数码管显示自己的学号后三位
此过程根据课本理论并使用ChatGPT辅助代码撰写
以下是修改GPT代码的过程截图
使用Keil建立完整的工程,并使用外部中断0触发数码管显示三位数字的代码如下
#include <reg52.h>
sbit LSA = P2^2;
sbit LSB = P2^3;
sbit LSC = P2^4;
unsigned char code Display_Table[] = { //共阴极数码管的显示表
0x3f,
0x06,
0x5b,
0x4f,
0x66,
0x6d,
0x7d,
0x07,
0x7f,
0x6f,
}
//选择数码管
void Select(unsigned char n)
{
switch(n)
{
case 0:
LSA = 0;
LSB = 0;
LSC = 0;
break;
case 1:
LSA = 1;
LSB = 0;
LSC = 0;
break;
case 2:
LSA = 0;
LSB = 1;
LSC = 0;
break;
case 3:
LSA = 1;
LSB = 1;
LSC = 0;
break;
case 4:
LSA = 0;
LSB = 0;
LSC = 1;
break;
case 5:
LSA = 1;
LSB = 0;
LSC = 1;
break;
case 6:
LSA = 0;
LSB = 1;
LSC = 1;
break;
case 7:
LSA = 1;
LSB = 1;
LSC = 1;
break;
default:
break;
}
}
//显示数字
void Display_Num(unsigned int num)
{
unsigned char i = 0;
unsigned char dis_buf[3] = {0};
if(num >= 1000)
{
num = 999;
}
dis_buf[0] = num / 100;
dis_buf[1] = (num / 10) % 10;
dis_buf[2] = num % 10;
for(i = 0; i < 3; i++)
{
Select(i);
P0 = Display_Table[dis_buf[i]];
delay_ms(1);
P0 = 0x00;
}
}
//延时函数
void delay_ms(unsigned int ms)
{
unsigned int i, j;
for(i = ms; i > 0; i--)
for(j = 110; j > 0; j--);
}
void main()
{
unsigned int count = 0;
while(1)
{
Display_Num(count);
delay_ms(1000);
count++;
if(count >= 1000)
{
count = 0;
}
}
}
在相关软件上烧录、运行代码,得到如下结果图