51单片机学习笔记(中断系统)

本篇文章是本人对51单片机中断系统学习的整理与总结,较为详细地讲述了中断系统的内容,大部分内容来自《STC89Cxx中文参考手册》和《新概念51单片机C语言教程,入门、提高、开发》,并结合江科大自化协的51单片机教程添加了常见配置讲解与代码,侵删。
希望大家都能早日掌握单片机。

中断介绍

1、中断基本概念

(1)中断系统

中断系统:当中央处理器CPU正在处理某件事的时候外界发生了紧急事件请求,要求CPU暂停当前的工作,转而去处理这个紧急事件,处理完以后,再回到原来被中断的地方,继续原来的工作,这样的过程称为中断;实现这种功能的部件称为中断系统;请求CPU中断的请求源称为中断源

在这里插入图片描述

图1 单片机中断过程

(2)中断嵌套

中断嵌套:如果单片机正在处理一个中断程序,此时,又有另一个中断现象发生,单片机将会停止当前的中断程序,而转去执行新的中断程序;新中断程序处理完毕后再回到刚才停止的中断程序处继续执行,执行完这个中断后再返回主程序继续执行主程序。

在这里插入图片描述

图2 单片机中断嵌套

(3)中断优先级

中断优先级:微型机的中断系统一般允许多个中断源,当几个中断源同时向CPU请求中断,这就存在CPU优先响应哪一个中断源请求的问题。通常根据中断源的轻重缓急排队,有限处理最紧急事件的中断请求源,即规定每一个中断源都有一个优先级别

​ 中断优先级原则:

  • CPU同时接收到几个中断时,首先响应优先级别最高的中断请求
  • 正在进行的中断过程不能被新的同级或低优先级的中断请求所中断
  • 正在进行的低优先级中断服务,能被高优先级中断请求所中断

​ 为了实现上述后两条原则,中断系统内部设有两个用户不能寻址的优先级状态触发器。其中一个置1,表示正在响应高优先级的中断,它将阻断后来所有的中断请求;另一个置1,表示正在响应低优先级中断,它将阻断后来所有的低优先级中断请求。

(4)中断优点

中断优点:中断是为使单片机具有对外部或内部随机发生使劲按实时处理而设置的,中断功能的存在,很大程度上提高了单片机处理外部或内部事件的能力,不仅解决了快速主机与慢速I/O设备的数据传送问题,而且还具有以下优点:

  • 分时操作:CPU可以分时为多个I/O设备服务,提高了计算机的利用率;
  • 实时响应:CPU能够及时处理应用系统的随机事件,系统的实时性大大增强;
  • 可靠性高:CPU具有处理设备故障及掉电等突发性事件的能力,从而使系统可靠性提高。

2、中断结构及相关寄存器

(1)51单片机中断基本介绍

​ 51系列单片机一定具有基本的5个中断,分别为外部中断0/1(INT0/INT1)、定时器中断0/1(Timer0/TImer1)和串口中断(UART),详解如下:

  • INTO—外部中断0,由P3.2端口线引入,低电平下降沿引起;
  • INT1—外部中断1,由P3.3端口线引入,低电平或下降沿引起;
  • T0—定时器 / 计数器0中断,由T0计数器计满回零引起;
  • T1—定时器 / 计数器1中断,由T1计数器计满回零引起;
  • T1 / RI—串行口中断,串行端口完成一帧字符发送 / 接收后引起。

​ STC89C5X系列单片机提供了8个中断请求源,4个中断优先级,在此我们只讲以上5个基本的中断。

​ 所有中断源的默认中断级别如下图所示:
在这里插入图片描述

图3 STC89C5X系列单片机中断查询次数表

(2)中断结构

​ 51单片机中断的内部结构框图如下所示:

在这里插入图片描述

图4 51单片机中断的内部结构框图
  • 与外部中断、定时器有关的寄存器有TCON、IE和IP。因为这三个寄存器中的8位符号均针对不同中断作用,所以一般不对寄存器整体赋值,而是对位符号单独置0/1(可进行位寻址)
  • 与串口有关的寄存器有SCON、IE和IP。因为SCON仅与串口中断有关,因此一般要对寄存器整体赋值
  • 对定时器进行设置时,还需要设置定时器工作方式寄存器TMOD;对串口进行设置时,还需要设置串口控制寄存器SCON;详细的调用方式会在后面讲到。

(3)通用寄存器(IE和IP)

Ⅰ、中断允许寄存器IE

在这里插入图片描述

图5 中断允许寄存器详解图
  • 在配置中断时,需要将EA与对应的中断允许位置1
Ⅱ、中断优先级寄存器IP

​ 中断优先级寄存器用来设定各个中断源属于两级中断中的哪一级,该寄存器可进行位寻址,详解如下图:

在这里插入图片描述

图6 中断优先级寄存器详解图
  • 只需开启一个中断时,一般将对应的优先级控制位置1

(2)特殊功能寄存器(TCON、TMOD、SCON和PCON)

​ 将在对应中断配置中讲到。

3、定时器/计数器中断

(1)基本介绍与原理

​ 51单片机内部共有两个16位可编程的定时器/计数器,即定时器T0和定时器T1,它们既有定时功能又有计数功能,通过设置于它们相关的特殊功能寄存器可以选择启用定时功能或计数功能(将在对应寄存器处讲解)。

​ 需要注意的是,这个定时器系统是单片机内部一个独立的硬件部分,它与CPU和晶振通过内部某些控制线连接并相互作用,CPU一旦设置开启定时功能后,定时器便在晶振的作用下自动开始计时。当定时器的计数器计满后,会产生中断,即通知CPU该如何处理。

​ 定时器/计数器的实质是加1计数器(16位),由高8位和低8位两个寄存器组成;每个定时器都有4种工作方式,通过TMOD寄存器设置。

TMOD是定时器/计数器的工作方式寄存器,确定工作方式和功能;TCON是控制寄存器,控制T0、T1的启动和停止及设置溢出标志,其结构框图如图所示:

在这里插入图片描述

图7 定时器结构框图

在这里插入图片描述

图8 定时器流程图

(2)特殊功能寄存器(TMOD和TCON)

Ⅰ、定时器/计数器工作方式寄存器TMOD

TMOD是定时器/计数器的工作方式寄存器,确定工作方式和功能,不能进行位寻址,讲解如下:

在这里插入图片描述
在这里插入图片描述

图9 定时器工作方式寄存器详解图
  • TMOD是不可位寻址的寄存器,因此我们使用与(&)或(|)式赋值法

​ 与(&)或(|)式赋值法:

  • &为按位与,都为1才为1,其他为0,常用于对应位清0,其他位不变;

  • |为按位或,只要有一个为1就为1,其他为0,常用于对应位置1,其他位不变;

    以定时器0为例,配置TMOD寄存器:

  • 初始化:高四位不变,低四位清0;(TMOD &= 0xF0;)

  • 选择工作模式:门控制位置0即可(GATE = 0;),选用定时器模式(C/T = 0;),一般情况下我们多选用方式1(M1 = 0;M0 = 1;),当使用串行通信时才使用方式2(8位重装),综上所述,即将TMOD低四位置1(TMOD |= 0x01;

    若是定时器1,同理得:TMOD &= 0x0F;TMOD |= 0x10;

Ⅱ、定时器/计数器控制寄存器TCON

TCON是控制寄存器,控制T0、T1的启动和停止及设置溢出标志,可进行位寻址,详解如下:

在这里插入图片描述

图10 定时器控制寄存器详解图

​ 以定时器0为例,配置TCON寄存器:

  • 与定时器0有关的仅有TF0和TP0;
  • 为防止刚配置完成就开始中断,将TF0置0;(TF0 = 0;
  • 将TP0置1,是定时器开始工作;(TP0 = 1;

​ 若是定时器1,同理得:TF0 = 0;TP0 = 1;

(3)初值计算

在这里插入图片描述

Ⅰ、软件生成

​ 可以直接通过STC-ISP软件中的定时器计算器生成对应配置程序,注意系统频率定时器模式定时器时钟的选择,示例如下:

在这里插入图片描述

图11 软件生成定时器配置示例图
Ⅱ、计算验证

在这里插入图片描述
在这里插入图片描述

(4)配置方案

Ⅰ、定时器0/1配置(以11.0592KHz、1ms为例,包括中断函数)

在这里插入图片描述

​ 综上所述,定时器0配置代码如下:

#include <REGX52.H>

/**
  * @brief  定时器0初始化,1毫秒@11.0592MHz
  * @param  无
  * @retval 无
  */
void Timer0_Init()     //1毫秒@11.0592MHz
{
    
    
		TMOD &= 0xF0;		//设置定时器模式,低四位清0
		TMOD |= 0x01;		//设置定时器模式,低四位置1
		TH0 = 0xFC;		    //设置定时初值,TH0 = (65535-922)/256
		TL0 = 0x65;			//设置定时初值,TL0 = (65535-922)%256
		TF0 = 0;			//清除TF0标志
		TR0 = 1;			//定时器0开始计时
		ET0=1;
		EA=1;
		PT0=0;
}
//经计算,N约等于921.6,当取922时,TL0=0x65;当取921时,TL0=0x66

/*  定时器中断函数模板,共1s
void Timer0_Routine() interrupt 1
{
		static unsigned int T0Count;
		TH0 = 0xFC;		//设置定时初值	
		TL0 = 0x65;		//设置定时初值
		T0Count++;
		if(T0Count>=1000)
		{
				T0Count=0;
			
		}
}
*/

​ 定时器1配置代码如下:

#include <REGX52.H>

/**
  * @brief  定时器1初始化,[email protected]
  * @param  无
  * @retval 无
  */
void Timer1_Init(void)
{
    
    
	TMOD &= 0x0F;		//设置定时器模式
	TMOD |= 0x10;		//设置定时器模式
	TL1 = 0x9C;		//设置定时初值
	TH1 = 0xFF;		//设置定时初值
	TF1 = 0;		//清除TF1标志
	TR1 = 1;		//定时器1开始计时
	ET1=1;
	EA=1;
	PT1=0;
}

/*定时器中断函数模板
void Timer1_Routine() interrupt 3
{
	static unsigned int T1Count;
	TL1 = 0x9C;		//设置定时初值
	TH1 = 0xFF;		//设置定时初值
	T1Count++;
	if(T1Count>=1000)
	{
		T1Count=0;
		
	}
}
*/
Ⅱ、计时器0/1配置

​ 对原有的定时器中断初始化函数Timer0_Init() 进行修改:

  • 因为不需要进行中断,因此把中断允许位EA、ET0和优先级控制位PT0删除
  • 因为用于计时,则不需要对TH0和TL0赋初值,将TH0和TL0置0
  • 因为我们要控制计时的开始与结束,所以在初始化中将定时器运行控制位TR0先置0

​ 添加函数(计时器控制函数Timer0_Run()、计时器设置函数Timer0_SetCounter()和计时器取值函数Timer0_GetCounter()):

  • Timer0_Run():带参数,参数为标志位Flag,通过标志位控制计时器的启动与停止;
  • Timer0_SetCounter():带16位参数,参数为初值Value,高八位存于TH0,低八位存于TL0;此处可用于置0;
  • Timer0_GetCounter():有16位返回值,返回计时器的值。

先用Timer0_SetCounter()将初值置0,再通过Timer0_Run()启动定时器,中间放入程序,最后使用Timer0_GetCounter()取出计时器的值即可计算程序运行的时间。

#include <REGX52.H>

/**
  * @brief  定时器0初始化
  * @param  无
  * @retval 无
  */
void Timer0_Init(void)
{
    
    
	TMOD &= 0xF0;		//设置定时器模式
	TMOD |= 0x01;		//设置定时器模式
	TL0 = 0;		//设置定时初值
	TH0 = 0;		//设置定时初值
	TF0 = 0;		//清除TF0标志
	TR0 = 0;		//定时器0不计时
}

/**
  * @brief  定时器0设置计数器值
  * @param  Value,要设置的计数器值,范围:0~65535
  * @retval 无
  */
void Timer0_SetCounter(unsigned int Value)
{
    
    
	TH0=Value/256;
	TL0=Value%256;
}

/**
  * @brief  定时器0获取计数器值
  * @param  无
  * @retval 计数器值,范围:0~65535
  */
unsigned int Timer0_GetCounter(void)
{
    
    
	return (TH0<<8)|TL0;
}

/**
  * @brief  定时器0启动停止控制
  * @param  Flag 启动停止标志,1为启动,0为停止
  * @retval 无
  */
void Timer0_Run(unsigned char Flag)
{
    
    
	TR0=Flag;
}

4、外部中断

​ 外部中断比较简单。定时器为每隔一段设定的时间(初值设置)触发一次中断,而外部中断有两种触发方式:下降沿触发方式和低电平触发方式。

(1)相关寄存器

在这里插入图片描述
在这里插入图片描述

图12 外部中断相关寄存器图

(2)配置方案

​ 对与外部中断有关的寄存器进行配置:

  • 外部中断0请求标志IE0:置0
  • 外部中断0触发方式选择位IT0:置1,下降沿触发中断
  • 全局中断允许位EA:置1,允许;
  • 外部中断允许位EX0:置1,允许;
  • 外部中断0中断优先级控制位PX0:置1,高优先级。
#include <REGX52.H>

/**
  * @brief  外部中断0初始化
  * @param  无
  * @retval 无
  */
void Int0_Init(void)
{
    
    
	IT0=1;
	IE0=0;
	EX0=1;
	EA=1;
	PX0=1;
}

/*外部中断0中断函数模板
void Int0_Routine(void) interrupt 0
{
	
}
*/

​ 下降沿触发和计时器配合调用可以测出方波周期。

5、串行通信

(1)基本介绍与原理

​ STC89C51RC/RD+系列单片机内部集成有一个功能很强的全双工串行通信口,与传统8051单片机的串口完全兼容,串行中断是当串行发送数据第8位结束时,内部硬件自动向主机请求中断,需要软件复位(T1 = 1)。

​ STC89C51RC/RD+系列的单片机串行口对应的硬件部分对应的管脚是P3.0/RxDP3.1/TxD,其结构框图如图所示:

在这里插入图片描述

图13 串行结构图

(2)串行工作方式

​ 串行通信设有4种工作方式,其中两种方式的波特率是可变的,另外两种是固定的波特率由内部定时器/计数器产生,用软件设置不同的波特率和选择不同的工作方式,其中方式1、方式2和方式3为异步通信,每个发送和接收的字符都带有1个启动位和1个停止位。在模式0中,串行口被作为1个简单的移位寄存器使用。主机可通过查询或中断方式对接收/发送进行程序处理,使用十分灵活。

在这里插入图片描述

图14 串行工作方式图

​ 我们主要学习了解模式1:8位UARTA,波特率可变;因为该模式较为常用。

(3)串行相关寄存器

在这里插入图片描述

图15 串行相关寄存器图
  • 最下方的SADEN和SADDR寄存器,在51单片机中一般用不到,无需理会;
  • IE、IPH、IP都是与中断有关的寄存器,而串行中只需要用到T1溢出率(T1定时器溢出的频率)来计算波特率,不需要启动中断,因此IE、IPH、IP均为默认值即可,不需要配置;对于定时器T1,则需要启动定时器T1并设初值

在这里插入图片描述
在这里插入图片描述

图16 定时器工作方式图
  • 因为需要启动定时器T1,所以需要配置TMOD。先将定时器1的高八位清0,即TMOD &= 0x0F;因为工作方式1为8位,所以还需设置M1、MO分别为1、0,其他的为0,即TMOD |= 0x20

(16位时范围是:0到65535;8位时范围是0到255)

  • SBUF为串行口数据缓冲寄存器,分为读SBUF写SBUF不需要配置

    SCON和PCON均为串行口控制寄存器,详解如下:

Ⅰ、串行控制寄存器SCON

​ 串行控制寄存器SCON用于选择串行通信的工作方式和某些控制功能,可位寻址。详解如下:

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

图17 串行控制寄存器详解图
  • 我们用工作方式1,对SCON,SM0和SM1用于确认工作方式,由上图可知分别为0,1;其他的均为默认值即可,则SCON = 0100 0000 = 0x40
Ⅱ、电源控制寄存器PCON

​ 电源控制寄存器PCON中的SMOD用于设置方式1、方式2、方式3的波特率是否加倍,不可位寻址,详解如下:

在这里插入图片描述

图18 电源控制寄存器详解图
  • 我们用工作方式1,对PCON,SMOD为波特率选择位,为1则波特率加倍;为0则波特率不变。此处我们选择将波特率加倍,其他的均为默认值,则PCON = 1000 0000 = 0x80

(4)波特率计算

Ⅰ、波特率

​ 单片机或计算机在串口通信时的速率用波特率表示,它定义未每秒传输二进制代码的位数,即1波特=1位/秒,单位是bps(位/秒)

Ⅱ、波特率的计算

​ 在串行通信中,收、发双方对发送或接收数据的速率要有约定。通过编程可对单片机串行口设定位4种工作方式,其中方式0和方式2的波特率是固定的,而方式1和方式3的波特率是可变的,由定时器T1的溢出率来决定。

​ 串行口的4种工作方式对应三种波特率。由于输入的移位时钟的来源不同,所以各种方式的波特率计算公式也不相同,以下是4种波特率的计算公式:

在这里插入图片描述

​ 通常波特率都是固定的一些数据,如1200,2400,4800,9600等,所以都是根据所要使用的波特率来求定时器初值,详细求取初值的方法以下列例题为例:

在这里插入图片描述

(5)配置方案

Ⅰ、串行初始化

​ 设置SCON和PCON,配置定时器1但关闭定时器中断,由上总结可得串行初始化为:

void UART_Init()	//[email protected]
{
    
    
	SCON = 0x40;
	PCON|= 0x80;
	TMOD &= 0x0F;	//设置定时器模式
	TMOD |= 0x20;	//设置定时器模式
	TL1 = 0xF4;		//设定定时初值
	TH1 = 0xF4;		//设定定时器重装值
	ET1 = 0;		//禁止定时器1中断
	TR1 = 1;		//启动定时器1
}

/*串口中断函数模板
void UART_Routine() interrupt 4
{
	if(RI==1)
	{
		
		RI=0;
	}
}
*/

​ 也可通过软件直接生成:

image-20220813224645964

图19 软件生成波特率示意图
Ⅱ、发送数据
void UART_Init()	//[email protected]
{
    
    
	SCON = 0x40;
	PCON|= 0x80;
	TMOD &= 0x0F;	//设置定时器模式
	TMOD |= 0x20;	//设置定时器模式
	TL1 = 0xF4;		//设定定时初值
	TH1 = 0xF4;		//设定定时器重装值
	ET1 = 0;		//禁止定时器1中断
	TR1 = 1;		//启动定时器1
}

void UART_SendByte(unsigned char Byte)
{
    
    
	SBUF=Byte;
	while(TI==0);	//检测是否发送完成
	TI=0;			//软件控制将发送中断请求标志位清0
}

/*串口中断函数模板
void UART_Routine() interrupt 4
{
	if(RI==1)
	{
		
		RI=0;		//软件控制将接收中断请求标志位清0
	}
}
*/

猜你喜欢

转载自blog.csdn.net/lonelypasserby/article/details/128871627
今日推荐