51单片机:中断

本文介绍了51单片机的中断原理,包括中断优先级、中断允许寄存器IE、中断请求标志TCON以及定时器工作方式寄存器TMOD的设置。通过实例详细讲解了如何初始化中断和定时器,实现秒表计时功能,包括数码管显示和中断处理函数的编写。
摘要由CSDN通过智能技术生成


前言

中断:CPU在处理事件A的过程中,中断源事件B产生中断请求,CPU暂停事件A的处理,CPU处理事件B,事件B处理完成后继续处理事件A。

51单片机仅包含:两个外部中断(INT0,INT1),两个定时器中断(T0 , T1),一个串口中断(UART)。

虽然STC89Cxx中文手册中说有8个中断,但在C51和C52芯片类型中只有5个中断,看CPU原理图可以找到。

大部分芯片都有四个中断优先级,且可自行定义每个中断的优先级(具体看芯片手册)C51类型只有两个中断优先级,在IP寄存器中可自行设置优先级

  1. 高优先级中断可以打断低优先级中断,低优先级中断不能打断高优先级中断
  2. 同优先级中断先到先处理

一、中断原理及初始化

CPU结构图
在这里插入图片描述

中断结构图
在这里插入图片描述

中断优先级

C51或C52的中断优先级只有两级,可由IP优先级寄存器对相应的中断设置优先级。同一优先级的中断请求,按时间先后顺序处理。

同一优先级,同一时刻中断请求,由硬件系统硬件确定的自然优先级形成,如下。
在这里插入图片描述

中断允许寄存器IE及优先级设置

在这里插入图片描述

要使用中断,首先要将相应中断允许寄存器置为1。由中断结构原理图可知,其中EA为总允许位,EX0到ES为相应中断的允许标志位
例如要启用定时器中断0(T0),并设置其优先级为高级:

EA=1;//总允许位
ET0=1;//定时计数器允许位
PT0=1;//设置为高优先级

中断请求标志TCON

76543210
字节地址:88HTF1TR1TF0TR0IE1IT1IE0IT0TCON
定时器1中断请求标志位定时器中断1运行控制位:同TR0定时器0中断请求标志位定时器中断0运行控制位:置1运行,置0停止外部中断1请求标志位外部中断1触发方式控制位:同IT0外部中断0请求标志位外部中断0触发方式控制位:置1下降沿触发;置0低电平触发

表格中请求标志位(黑色部分),当满足中断产生条件时,由硬件自动置1,处理完成后由硬件自动置0。亦可编程置位,一般编程中可不管

红色部分需要进行设置,以启用定时器中断0(T0),并设置其优先级为高级为例,除了要开启相关中断允许位,还要使定时器中断0开始工作。

EA=1;//总允许位
ET0=1;//定时计数器允许位
TR0=1;//定时器中断0开始运行
PT0=1;//设置为高优先级

定时器工作方式寄存器TMOD

76543210
字节地址:89HGATEC/ T ‾ \overline{\text{T}} TM1M0GATEC/ T ‾ \overline{\text{T}} TM1M0TMOD
GATE=0,定时器1溢出即可产生中断;GATE=1 , 定时器1溢出且P3^3引脚产生高电平才能产生中断C/ T ‾ \overline{\text{T}} T=0,定时模式;C/ T ‾ \overline{\text{T}} T=1,计数模式工作方式设置位工作方式设置位GATE=0,定时器0溢出即可产生中断;GATE=1 , 定时器0溢出且P3^2引脚产生高电平才能产生中断=0,定时模式;=1,计数模式工作方式设置位工作方式设置位

红色部分用于设置定时器0的工作方式,黑色部分用于设置定时器1工作方式。

M1M0工作方式说明计数方式
00方式013位定时/计数器,TH0八位及TL0低五位参与计数,TL0低五位溢出向TH0进位,TH0溢出产生中断X= 2 13 2^{13} 213-N,X为初值,N计数个数
01方式116位定时计数器,TH0和TL0参与计数X= 2 16 2^{16} 216-N
10方式28位自动重装定时计数器,TL0计数溢出产生中断后,TH0自动将其数值赋值给TL0, TL0从该值开始计数,TH0值不变X= 2 8 2^{8} 28-N
11方式3(仅对计数器T0有效)T0分为独立的8位计数器TL0和TH0,TL0由T0状态控制位控制,TL0可以为定时器或计数器。TH0由T1状态控制位控制,同时占用定时器T1的中断请求源TF1,并只能作为定时器使用。所以工作在方式3下时,T1无法产生中断,因为T1的中断请求源TF1被T0占用了。T0处于工作方式3时,T1可定为方式0、方式1和方式2,用来作为串行口的波特率发生器,或不需要中断的场合

定时计数器的初值计算

当外部晶振频率为 11.0592 M H Z 11.0592MHZ 11.0592MHZ,工作于方式1时,定时50ms, 需要设置的TH0,TL0初值计算如下:

  1. 51单片机内部时钟频率是外部时钟频率的12分频,即机器周期为: 12 11.0592 \frac{12}{11.0592} 11.059212=1.085069 , 即一个机器周期要1.085069us(微秒)
  2. 定时50ms(毫秒)需要多少个机器周期: 50000 1.085069 \frac{50000}{1.085069} 1.08506950000=46,080.01
  3. 工作于方式三,则初值为: 2 16 − 46080 = 19456 2^{16}-46080=19456 21646080=19456
  4. 19456 19456 19456转换为16进制为:4c00
  5. T H 0 = 0 x 4 c TH0=0x4c TH0=0x4c , T L 0 = 0 x 00 TL0=0x00 TL0=0x00

中断号

在这里插入图片描述

中断函数格式

void 自定义函数名(void) interrupt 中断号{
	中断处理代码;	
}

二、秒表计时代码

1.数码管显示工具代码Digit_utils.h

#include "reg52.h"
typedef unsigned int uint;
sbit P22=P2^2;
sbit P23=P2^3;
sbit P24=P2^4;

uint display[] = {0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,
				  0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71,0x00};

void Choose_Digit(int i){
	switch(i){
				case 1: P24=1;P23=1;P22=1;break;
				case 2: P24=1;P23=1;P22=0;break;
 				case 3: P24=1;P23=0;P22=1;break;
				case 4: P24=1;P23=0;P22=0;break;
				case 5: P24=0;P23=1;P22=1;break;
				case 6: P24=0;P23=1;P22=0;break;
				case 7: P24=0;P23=0;P22=1;break;
				case 8: P24=0;P23=0;P22=0;break;
			}
}
#endif

2.秒表处理代码StopWatch.h

#ifndef _STOPWATCH_H_
#define _STOPWATCH_H_
#include "Digit_utils.h"
/*缓存显示内容*/
int Second=0;
int Min=0;
int Hour=0;
int ShowBuffer[] = {0 , 0 , 0 , 0 ,0 , 0  };

void ClearBuffer(){
	int i;
	for(i=0 ; i<6;++i){
		ShowBuffer[i]=0;
	}
	Hour=0;
	Min=0;
	Second=0;
}

void Split_Time(){
	ShowBuffer[0] = Hour / 10;
	ShowBuffer[1] = Hour %10;
	ShowBuffer[2] = Min / 10;
	ShowBuffer[3] = Min % 10;
	ShowBuffer[4] = Second /10;
	ShowBuffer[5] = Second %10;
} 

void Show(){
	int i;
	Split_Time();
	for(i=0; i<6 ; i+=2){
		Choose_Digit(i+1);
		P0 = display[ShowBuffer[i]];		
		P0=0x00;

		Choose_Digit(i+2);
		P0= display[ShowBuffer[i+1]] | 0x80;//按位或是为了增加小数点
		P0=0x00;
	}	 
}
#endif

3.中断初始化代码Interrupt_utils.h

#ifndef _INTERRUPT_H_
#define _INTERRUPT_H_
#include "reg52.h"
/*中断初始化*/

/*外部中断0*/
void Int0_Init(const unsigned char *mode){//外部中断0的触发方式,0低电平触发,1下降沿触发
	EA=1;//总中断允许位
	EX0=1;//外部中断0允许位
	IT0=*mode;	
}
/*外部中断1*/
void Int1_Init(const unsigned char *mode){//外部中断1的触发方式,0低电平触发,1下降沿触发
	EA=1;//总中断允许位
	EX1=1;//外部中断0允许位
	IT1=*mode;	
}

void Timer0_Init(const unsigned char *mode ,const unsigned char *HighVal , const unsigned char *LowVal ){
	EA=1;//打开中断总允许位
	ET0=1;//打开T0中断允许位
	TR0=1;//定时/计数器中断0开始工作
	TMOD |= *mode;//设置T0工作模式
	TH0 = *HighVal; //高八位寄存器初值
	TL0 = *LowVal;  //第八位寄存器初值
} 

void Timer1_Init(const unsigned char *mode ,const unsigned char *HighVal , const unsigned char *LowVal ){
	EA=1;//打开中断总允许位
	ET1=1;//打开T0中断允许位
	TR1=1;//定时/计数器中断0开始工作
	TMOD |= *mode;//设置T0工作模式
	TH1 = *HighVal; //高八位寄存器初值
	TL1 = *LowVal;  //第八位寄存器初值
} 
#endif

4. 主函数 main.c

#include "interrupt_utils.h"
#include "StopWatch.h"
sbit k1=P3^1;
sbit k3=P3^2;
sbit BEEP = P2^5 ;
static int _50ms=0;
void main(){
	
	Int0_Init(1);//外部中断0初始化
	Timer0_Init(0x01 , 0x4c , 0x00);//定时器中断0初始化
	while(1){
		Show();
	}	
}

void Int0_Routine(void) interrupt 0{//K3外部中断,终止计数,显示数值
	while(1){
	  	Show();
	  	if(k1==0){//外部按键清0
			ClearBuffer();
			break;
		}	
	} 	
}
void Timer0_Routine(void) interrupt 1{ //定时器中断0,秒表定时
	++_50ms;
	if(_50ms==20){//中断一次50ms,中断20次1s
		BEEP = !BEEP;//中断同时蜂鸣器响应
		++Second;
		_50ms =0;
		if(Second==60){
			++Min;
			Second=0;
			if(Min==60){
				++Hour;
				Min=0;
			}
		}
	}		 
}

总结

关键在于看懂相关手册,结合原理图理解各个寄存器的含义,作用及工作方式。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值