4.1 中断程序设计
在Keil C51中编写中断服务程序
在Keil C51环境下,中断服务程序是处理中断事件的关键部分。下面以外部中断0为例进行说明:
#include <reg51.h>
// 外部中断0服务程序
void externalInterrupt0(void) interrupt 0 {
// 保护现场,保存可能会被修改的寄存器值
// 例如保存累加器A的值
push acc;
// 中断处理代码
// 这里以翻转P1.0引脚电平为例
P1 ^= 0x01;
// 恢复现场,将之前保存的寄存器值恢复
pop acc;
}
void main() {
// 设置外部中断0为下降沿触发
IT0 = 1;
// 使能外部中断0
EX0 = 1;
// 使能总中断
EA = 1;
while (1) {
// 主循环可以执行其他任务
}
}
在上述代码中:
void externalInterrupt0(void) interrupt 0
:定义了外部中断0的服务程序。void
表示函数没有返回值,externalInterrupt0
是函数名,(void)
表示函数没有参数,interrupt 0
表示该函数是外部中断0的中断服务程序,其中0
是外部中断0对应的中断号。push acc;
:将累加器A
的值压入堆栈,以保护现场,防止在中断处理过程中累加器A
的值被修改。P1 ^= 0x01;
:将P1
口的第0位电平翻转,作为中断处理的一个简单示例。pop acc;
:将之前压入堆栈的累加器A
的值弹出,恢复现场,使程序在中断返回后能继续正常执行。IT0 = 1;
:设置外部中断0为下降沿触发方式。当IT0
为1
时,外部中断0引脚上的下降沿信号会触发中断。EX0 = 1;
:使能外部中断0,允许外部中断0请求中断。EA = 1;
:使能总中断,只有当总中断使能且对应中断源的中断使能时,中断才能被响应。while (1)
:主循环,程序在此处不断循环,等待中断发生。
中断的嵌套与优先级管理
51单片机的中断系统支持中断嵌套,并且可以通过设置中断优先级来管理中断的响应顺序。下面以外部中断0和定时器0中断为例,展示中断嵌套和优先级管理的代码实现:
#include <reg51.h>
// 定时器0中断服务程序
void timer0Interrupt(void) interrupt 1 {
// 保护现场
push acc;
// 中断处理代码
// 这里以翻转P1.1引脚电平为例
P1 ^= 0x02;
// 恢复现场
pop acc;
}
// 外部中断0服务程序
void externalInterrupt0(void) interrupt 0 {
// 保护现场
push acc;
// 中断处理代码
// 这里以翻转P1.0引脚电平为例
P1 ^= 0x01;
// 进入中断嵌套,手动触发定时器0中断
TF0 = 1;
// 恢复现场
pop acc;
}
void main() {
// 设置定时器0为模式1
TMOD = 0x01;
// 装入定时器0初值
TH0 = (65536 - 50000) >> 8;
TL0 = (65536 - 50000) & 0xFF;
// 使能定时器0中断
ET0 = 1;
// 设置外部中断0为下降沿触发
IT0 = 1;
// 使能外部中断0
EX0 = 1;
// 设置定时器0中断为高优先级
PT0 = 1;
// 使能总中断
EA = 1;
// 启动定时器0
TR0 = 1;
while (1) {
// 主循环可以执行其他任务
}
}
在上述代码中:
void timer0Interrupt(void) interrupt 1
:定义定时器0的中断服务程序,interrupt 1
表示该函数是定时器0的中断服务程序,1
是定时器0对应的中断号。void externalInterrupt0(void) interrupt 0
:定义外部中断0的中断服务程序,interrupt 0
表示该函数是外部中断0的中断服务程序,0
是外部中断0对应的中断号。TF0 = 1;
:在外部中断0服务程序中手动触发定时器0中断,模拟中断嵌套。当TF0
置1
时,会产生定时器0中断请求。TMOD = 0x01;
:设置定时器0为模式1,即16位定时器/计数器模式。TH0 = (65536 - 50000) >> 8;
和TL0 = (65536 - 50000) & 0xFF;
:计算并装入定时器0的初值,定时50ms(假设晶振为12MHz)。ET0 = 1;
:使能定时器0中断。IT0 = 1;
:设置外部中断0为下降沿触发方式。EX0 = 1;
:使能外部中断0。PT0 = 1;
:设置定时器0中断为高优先级。当有多个中断请求同时发生时,高优先级中断会优先被响应。EA = 1;
:使能总中断。TR0 = 1;
:启动定时器0,开始计数。
4.2 定时器/计数器的应用
利用定时器实现定时功能
下面以定时器0为例,实现一个定时功能,每隔50ms翻转一次 P1.0
引脚电平:
#include <reg51.h>
// 定时器0中断服务程序
void timer0Interrupt(void) interrupt 1 {
// 重新装载定时器初值
TH0 = (65536 - 50000) >> 8;
TL0