51单片机学习记录08
中断系统
中断简介
当中央处理机CPU正在处理某件事的时候外界发生了紧急事件请求,要求CPU暂停当前的工作,转而去处理这个紧急事件,处理完后,再回到原来被中断的地方,继续原来的工作,这样的过程称为中断。
中断是为使单片机具有对外部或内部随机发生的事件实时处理而设置的,很大程度上提高了单片机处理外部或内部事件的能力,是单片机最重要的功能之一
- 中断执行顺序:根据中断优先级。优先级有默认值,也可以在寄存器中进行修改
- 中断嵌套:中断服务程序过程中有高优先级中断出现
- 单级中断:没有中断嵌套功能的中断系统
- 中断优点:分时操作、实时响应、可靠性高
中断结构
STC89C52系列单片机提供了8个中断请求源:外部中断0、定时器0中断、外部中断1、定时器1中断、串口中断、定时器2中断、外部中断2、外部中断3(前5个是基本,后三个根据芯片外设是否增加确定)
所有中断都具备4个中断优先级
用关总中断允许位(EA)或相应中断的允许位来屏蔽所有的中断请求
打开相应的中断允许位来使CPU响应相应的中断申请
每一个中断源可以由软件独立控制开中断或关中断的状态
- 中断结构
- 中断触发
- 中断优先级默认顺序 (中断序号)
INT0(0)——T0(1)——INT1(2)——T1(3)——串行口(4)
中断相关寄存器
寄存器是连接软、硬件的媒介
单片机通过配置寄存器来控制内部线路的连接
- 中断结构(基本结构)
两级控制: 各中断源首先受EA控制,其次还受各中断源自己的中断允许控制位控制
- 中断允许寄存器(IE)
位 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
---|---|---|---|---|---|---|---|---|
字节地址:A8H | EA | ES | ET1 | EX1 | ET0 | EX0 |
name | function |
---|---|
EA | CPU总中断允许控制位(EA=1,CPU开放中断 ; EA=0,CPU屏蔽所有的中断申请) |
ES | 串口中断允许位(ES=1,允许中断;ES=0,禁止中断) |
ET1、ET0 | 定时/计时器1、0的溢出中断允许位(ET=1,允许中断;ET=0,禁止中断) |
EX1、EX0 | 外部中断1、0中断允许位(EX=1,允许中断;EX=0,禁止中断) |
- 中断控制寄存器(TCON)中断触发方式、定时器设置
高四位控制定时/计数器;低四位控制外部中断
位 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
---|---|---|---|---|---|---|---|---|
字节地址:88H | TF1 | TR1 | TF0 | TR0 | IE1 | IT1 | IE0 | IT0 |
name | function |
---|---|
TF1、TF0 | T1、T0溢出中断标志(产生溢出时,由硬件置“1”,向CPU请求中断,CPU响应后,由硬件置“0”) |
TR1、TR0 | 定时器1、0运行控制位,软件控制 |
IE1、IE0 | 外部中断1、0请求源标志(IE=1,外部中断向CPU请求中断,当CPU响应该中断时,由硬件置“0”) |
EX1、EX0 | 外部中断1、0中断允许位(EX=1,允许中断;EX=0,禁止中断) |
IT1、IT0 | 外部中断1、0中断源触发方式控制位(IT=1,下降沿触发;IT=0,低电平触发) |
- 中断优先级控制寄存器(IP)
使用默认优先级
中断响应条件
- 中断源有中断请求
- 中断源的中断允许位为1
- CPU开中断(即EA=1)
以外部中断0为例,如下:
EA=1; //打开总中断开关
EX0=1; //允许外部中断0中断
IT0=0/1; //设置外部中断的触发方式,0低电平触发;1下降沿触发
void int() interrupt 0 //中断函数interrupt关键字+中断序号
{
//编写用户所需的功能代码
}
外部中断
外部中断简介
外部中断0(INT0)的优先级最高
外部中断0对应P3_2 外部中断1对应P3_3
连接引脚P3_2——IT0设置触发方式——标志判断(自动设置)——中断允许设置(总中断EA、外部中断)——使用默认优先级
连接——TCON——IE——IP(使用默认优先级)——CPU
外部中断配置
- 参考中断响应条件
外部中断实验
功能:使用独立按键K3控制LED亮灭
主函数、延时函数、中断函数
代码实现:
#include <REGX52.H>
#include "Delay.h" //添加延时函数.c.h文件到工程中
void exti0_init(void)//定义外部中断0
{
IT0=1; //下降沿触发
EX0=1; //允许外部中断0中断
EA=1; //开总中断
}
void main()
{
exti0_init();
while(1)
{
//按键没有按下时一直循环
}
}
void exti0() interrupt 0 //中断服务函数
{
Delay(10); //延时消抖
while(P3_2==0); //检测松手
Delay(10); //延时消抖
P2_0=~P2_0; //取反
}
定时器中断
定时器简介
基本51单片机都含有定时器0、1两个定时器且T0、T1都具有计数方式和定时方式两种工作方式
定时/计数器与CPU相互独立,工作时不需要CPU参与
定时/计数器时根据单片机内部时钟或外部脉冲信号来计数加一
CPU时序
1MHz=10^6Hz 1s=10^6μs
- 振荡周期:晶振提供的频率(12MHz)的倒数(1/12μs)
- 状态周期:两个振荡周期(1/6μs)
- 机器周期:六个状态周期;十二个振荡周期(1μs)
- 指令周期:完成1条指令所用的时间;1 ~ 4个机器周期(1 ~ 4μs)
定时器原理
定时器16位(TH高8位、TL低8位)
输入脉冲,进行加一
溢出后向CPU发出中断申请
定时器,定时时间到达;计数器,计数次数满了
计数次数/定时时间=溢出值-初值
定时/计数器结构
T1对应P3_5 T0对应P3_4
- 中断控制寄存器(TCON)
参考中断系统-中断控制寄存器 - 特殊功能寄存器(TMOD)
定时和计数功能的设置
高四位控制T1;低四位控制T0
位 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
---|---|---|---|---|---|---|---|---|
地址89H | GATE | C/T | M1 | M0 | GATE | C/T | M1 | M0 |
name | function |
---|---|
GATE | GATE=0时,直接用软件控制TR1、0; GATE=1时,只有在外部中断(INT1、0)为高且TR1、0控制位置1时才可以打开 |
C/T | 置“1”(Count)计数器;置“0”(Time)定时器 |
M1、M0 | 定时/计数器1、0的模式选择(4种) |
定时/计数器工作方式
模式 | M1 | M0 | 位 | function |
---|---|---|---|---|
0 | 0 | 0 | 13 | TL1低5位,TH1全8位 |
1 | 0 | 1 | 16 | TL1、TH1全用 |
2 | 1 | 0 | 8 | 自动重装 |
3 | 1 | 1 | 8 | T0分成两个独立的8位定时/计数器,T1停止计数 |
-
模式0
-
结构分析
GATE=0,非门为1,已满足或门,为了满足与门需要使TR0为1 (取决于TR)
GATE=1,非门为0,为了满足或门需要使INT0为1,为了满足与门需要使TR0为1 (取决于TR和INT)
C/T选择计数/定时模式
C(1)计数模式,计数源为对应引脚检测到的外部脉冲
T(0)定时模式,计数源为机器周期 -
模式1
-
模式2
-
模式3
定时器配置
- 对TMOD赋值,以确定T0和T1的工作方式。设置TCON
- 根据所需要定时的时间计算初值,并将其写入TH0、TL0或TH1、TL1
- 如果使用中断,则对EA赋值,开放定时器中断
- 使TR0、TR1置位,启动定时/计数器
-
51单片机的定时/计数器是以不断加1进行计数的,即属加1计数器(不断加1,不能停止),因此不能直接将实际的计数值作为计数初值送到计数寄存器TH、TL中去,而必须将实际计数值以2的8、13、16次方为模求补,以其补码作为计数初值设置TH、TL
-
实际计数值为x,计数长度为n(n=8、13、16),初始值=2^n-x
-
定时模式,是对机器周期计数,机器周期与选定的主频密切相关。
-
1个机器周期=12/主振频率=12个振荡周期
所需定时时间(已知)=所需计数次数*机器周期(已知)
次数补码=2^n-x (x为所需计数次数)
若选用工作模式1,2^16=65536,还需将得数分解为两个8位十六进制数,高8位(补码/256)装入TH中,低8位(补码%256)装入TL中 -
TMOD——初值——IE——TCON
void time0_init(void)
{
TMOD|=0x01;
//选择定时器0模式 0000 0001
//(GATE=0,T(0)选用定时器,M1=0;M0=1 “01即模式1,高(T1)低(T0),低上有值,使用T0”)
//用或运算,即TMOD=TMOD或0x01,为不干扰高四位(T1)
TH0=0xFC; //给定时器0赋初值,定时1ms
TL0=0x18;
ET0=1; //打开定时器0中断允许
EA=1; //打开总中断
TR0=1; //打开定时器0
}
定时器中断实现
一、通过定时器0中断控制LED1指示灯间隔1Ss闪烁
-
注意:定时器的工作不需要单片机的执行,是独立的一部分,依靠外部晶振产生的脉冲自动计数,单片机只是控制开始和初始值,定时器就可以自动累加,这过程中程序可以继续运行,当定时器自动累加到溢出时,就会产生中断信号,使程序跳转到interrupt 1中执行中断程序。
溢出后定时器从0开始累加,所以在中断后需要重新给计数器赋初值,定时器相当于在一直累加,和主程序同时运行。 -
因程序按照晶振频率为12MHz编写,所以闪烁时长与11.0592MHz存在一定误差
#include <REGX52.H>
void time0_init(void) //初始化设置为1ms
{
TMOD|=0x01; //模式1 16位
TH0=0xFC; //赋初始值转化为十六进制
TL0=0x18;
ET0=1; //定时器0溢出中断允许
EA=1; //总中断允许
TR0=1; //定时器0运行控制
}
void main()
{
time0_init();
while(1)
{
}
}
void time0work() interrupt 1 //中断服务函数
{
static unsigned int i; //静态变量
TH0=0xFC; //1ms溢出已满,模式1需要手动再次赋初值
TL0=0x18;
i++;
if(i==1000) //当i自增到1s时溢出
{
i=0;
P2_0=~P2_0;
}
}
二、LCD时钟
- 引用了一个LCD头文件,要注意添加到工程中。
创建了一个time0_init头文件,简化编程
#include <REGX52.H>
#include "LCD1602.h"
#include "TIME0_INIT.h"
unsigned int hour=23,min=59,sec=50; //测试例
void main()
{
LCD_Init(); //初始化
LCD_ShowString(1,1,"Clock:");
LCD_ShowString(2,1," : :");
time0_init();
while(1)
{
LCD_ShowNum(2,1,hour,2);
LCD_ShowNum(2,4,min,2);
LCD_ShowNum(2,7,sec,2);
}
}
void time0() interrupt 1 //中断服务函数
{
static unsigned int i;
TH0=0xFC; //赋初始值转化为十六进制
TL0=0x18;
i++;
if(i==1000) //1s
{
i=0;
sec++;
if(sec>=60)
{
sec=0;
min++;
if(min>=60)
{
min=0;
hour++;
if(hour>=24)
{
hour=0;
}
}
}
}
}