记录学习中断的使用。
1. 使用工具
使用开发板:
普中科技开发板
编译软件:
keil
2. 复习中断及相关概念
CPU在处理 事件A 时,中断源 发出中断请求,请求cpu处理事件B ,cpu 中断 当前工作,转去处理事件B(中断响应和中断服务),待cpu将 事件B 处理完成后,再回到原来被中断的地方,继续处理事件A。
作用:分时操作,提高计算机的利用率。实时响应,及时处理应用系统的随机事件。可靠性高,具有处理设备故障及掉电等突发性事件。
89C51的中断系统有5个中断源 (INT0, T0, INT1, T1, RI/TI)
中断允许控制
CPU 对 中断系统所有中断是否打开及相应控制 由 中断允许寄存器IE 控制的。
- EX0:外部中断 0 允许位。IE0
- ET0:定时/计数器T0 中断允许位。IE1
- EX1:外部中断 1 允许位。IE2
- ET1:定时/计数器 T1 中断允许位。IE3
- ES:串行口 中断 允许位。
- EA: CPU中断允许位(总允许,)。所有中断都需要打开。
中断请求标志
中断标志
- IT0:外部中断0 触发方式控制位。TI0=0时,为电平触发方式,IT0=1, 为 边沿触发方式(下降沿有效)。
- IE0: 外部中断0 中断请求标志位。
- IT1:外部中断1 触发方式控制位。IT1=0时,为电平触发方式,IT1=1时,为边沿触发方式(下降沿有效)。
- IE1:外部中断1 中断请求标志位。
- TF0:定时 /计数器T0 溢出中断请求标志位。
- TFI:定时/计数器T1 溢出中断请求标志位。
各个中断源响应优先级及中断服务。当同一等级优先级的有多个时,存在排队问题。
各个中断源:
51单片机的中断优先级三条原则:
- CPU 同时接收多个中断请求时,优先响应优先级级别最高的。
- 正在进行的中断 不能被新的 同级别或更低优先级的中断请求中断 。
- 正在进行的低等级中断服务, 能被更高优先级 的中断请求中断。
中断响应条件
- 中断源发出中断请求。
- 此中断源的中断允许位打开(置1)。
- CPU总中断打开(EA=1)。
#include "reg52.h"
typedef unsigned int u16;
typedef unsigned char u8;
sbit k3=P3^2;
sbit k4=P3^3;
sbit led=P2^0;
/*******************************************************************************
* 函 数 名 : delay
* 函数功能 : 延时函数,i=1时,大约延时10us
*******************************************************************************/
void delay(u16 i)
{
while(i--);
}
/*******************************************************************************
* 函 数 名 : Interrupt0Init
* 函数功能 : 设置外部中断0
* 输 入 : 无
* 输 出 : 无
*******************************************************************************/
void Interrupt0Init()
{
//设置中断0 INT0
IT0 = 1;//跳变沿出发方式(1:下降沿,0:低电平触发)
EX0 = 1;//打开INT0 的中断允许
EA= 1 ;//打开总中断
}
/*******************************************************************************
* 函 数 名 : Interrupt1Init
* 函数功能 : 设置外部中断1
* 输 入 : 无
* 输 出 : 无
*******************************************************************************/
void Interrupt1Init()
{
//设置中断1 INT1
IT1 = 1;//跳变沿出发方式(下降沿)
EX1 = 1;//打开INT1 的中断允许
EA= 1 ;//打开总中断
}
/*******************************************************************************
* 函 数 名 : main
* 函数功能 : 主函数
* 输 入 : 无
* 输 出 : 无
*******************************************************************************/
void main()
{
Interrupt0Init();// 设置外部中断0
while(1);
}
/**************************************************************************************
* 外部中断0实验 *
实现现象:下载程序后按下K3按键可以对D1小灯状态取反。
注意事项:无。
***************************************************************************************/
void InterruptTest0() interrupt 0 //外部中断0 的 中断函数
{
delay(1000); //延时消抖
if(k3 == 0)
{
led=~led;
}
}
/**************************************************************************************
* 外部中断0实验 *
实现现象:下载程序后按下K3按键可以对D1小灯状态取反。
注意事项:无。
***************************************************************************************/
void InterruptTest2() interrupt 2 //外部中断1 的 中断函数
{
delay(1000); //延时消抖
if(k4 == 0)
{
led=~led;
}
}
3. 定时器和计数器概念复习
振荡周期:为单片机提供定时信号的振荡源的周期(晶振周期或外加振荡周期)
状态周期:2个振荡周期为1个状态周期。
机器周期:1个机器周期含6个状态周期, 12 个振荡周期。
指令周期:完成1条指令所占用的全部时间。它心机器周期为单位。
例如:常用外接晶振为12MHz, 振荡周期为 1/12us, 状态周期:1/6us, 机器周期:1us,指令周期:1~4us。
定时器/计数器需要注意以下几点:
第一点:定时器/计数器和单片机的CUP是相互独立的。定时器/计数器工作过程是自动完成的, 不需要CPU的参与。
第二点:51单片机中的定时器/计数器量根据机器内部的时钟或者是的脉冲信号对寄存器中的数据加1。
定时/计数器的工作原理:
定时/计数器实质上是一个加1计数器。它随着计数器的输入脉冲进行自加1。也就是每来一个脉冲计数器就自动加1,池加到计数器为全1时,再输入一个脉冲就使计数器回零,且计数器的溢出使相应的中断标志位置 1, 向CPU发出中断请求(定时/计数器中断允许时)。
由溢出时计数器的值 减 去计数初值才是加1 计数器的计数值。
定时器的结构
定时/计数器的实质量加1 计数器(16位),由高8位和低8位两个寄存器THx和TLx组成。TMOD是定时/计数器的工作方式寄存器,确定工作方式和功能: TCOM 是控制寄存器T0,T1的启动和停止胡设置溢出标志。
定时/计数器的控制
工作方式寄存器TMOD
低四位用于T0,高四位用于T1。
GATE是门控位,GATE=0时,用于控制定时器 的 启动是否受外部中断 中断源信号 的影响。只要用软件TCON中TR0或TR1为1,就可以启动定时/计数器工作:GATE=1时,要用软件TR0或TR1为1,同时外部中断引脚INT0/1也为高电平时,才能启动定时/计数器工作。
C/T::定时、计数模式选择位。C/T=0 为定时模式;C/T=1时,为计数模式。
M1M0:工作方式设置位。定时/计数器有四种工作方式。
控制寄存器TCON
TCON的低4位用于控制外部中断,高4位用于控制定时/计数器的启动和中断申请。
- TF1:T1溢出中断请求标志位。T1计数溢出时由硬件自动置TF1为1.CPU响应中断后TF1由硬件自动清零。T1计数器工作时,CPU可随时查询TF1的状态。TF1可用作查询测试的标志。TF1也可以用软件置1或清零,同硬件置1或清0的效果一样。
- TR1:T1运行 控制位。TR1置1时,T1开始工作;TR1置0时,T1停止工作。TR1由软件置1或清0。用软件可控制定时/计数器的启动与停止。
- TF0:T0溢出中断请求标志位。T0计数溢出时由硬件自动置 TF0为1。CPU响应中断后TF0由硬件自动清零。功能与TF1类似。
- TR0:T0运行控制位。TR0置1时,T0开始工作;TR0置0时,T0停止工作。TR0由软件置1或清0。用软件可控制定时/计数器T0的启动与停止。功能与TR1类似。
定时/计数器的工作方式
定时器模式时 N=t/Tcy
计数初值的公式为:X= 2^n-N;n为计数位数(方式0为13位,方式1为16位)。定时器的初值还可以采用计数个数直接取补法获得。
计数模式时,计数脉冲是T0引脚上的外部脉冲。
门控位GATE具有特殊的作用。当GATE=0时,经反相后使或门输出为1 ,此时仅由TR0控制与门的开启。当GATE=1时,由外中断引脚信号控制或门输出,此时控制与门的开启由外中断引脚信号和TR0共同控制。当TR0=1时,外中断引脚信号引脚的高电平启动计数,外中断引脚信号引脚的低电平停止计数。常用来测量外中断引脚上正脉冲的宽度。
方式0:
方式0为13位计数。由TL0的低5位和TH0的8位组成。TL0的低5位溢出时向TH0进位,TH0溢出时,置位TCON中的TF0标志,向CPU发出中断请求。
方式1:
方式1的计数位数是16位,由TL0作为低8位,TH0作为高8位,组成了16位加1计数器。
计数个数与计数初值的关系为:X=2^16-N
方式2:
方式2为看上去重装初值的8拉计数方式。
计数个数与计数初值的关系为:X=2^8-N
工作方式2特别适合用于作较精确的脉冲信号发生器。
方式3:
方式3只适用于定时/计数器T0,定时器T1处于方式3时相当于TR1-0,停止计数。
使用定时器步骤:
- 对TMOD赋值,即确定T0和T1的工作方式。
- 计算初值,并将其写入TH0、TL0(或TH1,TL1)。
- 选择中断方式,对EA赋值,打开定时器中断。
- 使TR0或TR1置位,启动定时/计数器定时或计数。
计数器初值的计算
时钟周期与时钟频率互为倒数。例如:频率为20赫兹(Hz),周期为1/20=0.05秒(s)。
- 机器周期=1/单片机的时钟频率(时钟频率通常指同步电路中时钟的基础频率,它以“若干周期每秒来度量”,频率为周期的倒数)。
- 51单片机内部时钟频率是外部时钟的12分频。当外部晶振的频率输入单片机里面的时候要进行12分分频。例如:单片机选择12MHZ的晶振,它的时钟周期是1/12us,机器周期为12*(1/12)us 。如果一个单片机选择了12兆赫兹晶振,它的时钟周期是1/12us,它的一个机器周期是12×(1/12)us,也就是1us。
例如:要求1s的初值,1s/1us=1000000 ,需要计数1000000,初值=0XFFFF-1000000+1(65535=0xFFFF 即 16位计数),注意:此时计数已经超过 65535 所以 不能直接 定时1 s.
示例代码:
#include "reg52.h"
typedef unsigned int u16;
typedef unsigned char u8;
sbit k3=P3^2;
sbit k4=P3^3;
sbit led=P2^0;
u16 m = 0;
/*******************************************************************************
* 函 数 名 : delay
* 函数功能 : 延时函数,i=1时,大约延时1s
*******************************************************************************/
void delay(u16 i)
{
while(1)
{
if(m == i*20)
{
m = 0;
led=~led;
}
}
}
/*******************************************************************************
* 函 数 名 : Timer0Init
* 函数功能 : 定时器0初始化
* 输 入 : 无
* 输 出 : 无
*******************************************************************************/
void Timer0Init()
{
TMOD |= 0X01;//启用定时模式
TH0= 0Xfc; //给定时器赋初值,定时1ms
TL0 = 0X18;
ET0=1;//打开定时器0中断允许
EA = 1;//打开总中断
TR0 =1; //打开定时器
}
/*******************************************************************************
* 函 数 名 : Timer1Init
* 函数功能 : 定时器1初始化
* 输 入 : 无
* 输 出 : 无
*******************************************************************************/
void Timer1Init()
{
TMOD |= 0X10;//启用定时模式 ,使用或(|),防止0位对TMOD寄存器产生干扰
TH1= 0X3c; //给定时器赋初值,定时50ms
TL1 = 0Xb0;
ET1=1;//打开定时器1中断允许
EA = 1;//打开总中断
TR1 =1; //打开定时器
}
/*******************************************************************************
* 函 数 名 : main
* 函数功能 : 主函数
* 输 入 : 无
* 输 出 : 无
*******************************************************************************/
void main()
{
//Interrupt0Init();// 设置外部中断0
Timer1Init();
delay(5);
}
/**************************************************************************************
* 外部中断0实验 *
实现现象:下载程序后按下K3按键可以对D1小灯状态取反。
注意事项:无。
***************************************************************************************/
void InterruptTest0() interrupt 0 //外部中断0 的 中断函数
{
delay(1000); //延时消抖
if(k3 == 0)
{
led=~led;
}
}
/**************************************************************************************
* 外部中断0实验 *
实现现象:下载程序后按下K3按键可以对D1小灯状态取反。
注意事项:无。
***************************************************************************************/
void InterruptTest2() interrupt 2 //外部中断1 的 中断函数
{
delay(1000); //延时消抖
if(k4 == 0)
{
led=~led;
}
}
/*******************************************************************************
* 函 数 名 : void Timer0InterruptTest() interrupt 1
* 函数功能 : 定时器0中断函数
* 输 入 : 无
* 输 出 : 无
* 注意事项 :如果执行程序过长,则不能放在中断中
*******************************************************************************/
void Timer0InterruptTest() interrupt 1
{
static u16 i;
TH0= 0Xfc;
TL0 = 0X18;
i++;
if(i == 1000)
{
i=0;
led=~led;
}
}
/*******************************************************************************
* 函 数 名 : void Timer1InterruptTest() interrupt 3
* 函数功能 : 定时器1中断函数
* 输 入 : 无
* 输 出 : 无
* 注意事项 :如果执行程序过长,则不能放在中断中,否则将会影响产生中断时间,将执行程序放入延时delay函数中
*******************************************************************************/
void Timer1InterruptTest() interrupt 3
{
TH1= 0X3c;
TL1 = 0Xb0;
m++;
}