中断系统
中断介绍
中断是为使单片机具有对外部或内部随机发生的事件实时处理而设置的,中断功能的存在,很大程度上提高了单片机处理外部或内部事件的能力。它也是单片机最重要的功能之一,是我们学习单片机必须要掌握的。很多初学者被困在中断中,学了很久仍然不知道中断究竟是如何运作的。千万不要认为它有多难,其实只要掌握正确的学习方法,没有哪个知识点是学不会的。
为了能让大家更容易理解中断概念, 我们先来举一个生活事例: 你打开火,烧上一壶水。然后去洗衣服,在洗衣服的过程中,突然听到水壶发出水开的报警声,这时,你停止洗衣服动作,立即去关掉火,然后将开水灌入暖水瓶中,灌完开水后,你又回去继续洗衣服。这个过程中实际上就发生了一次中断。对于单片机来讲,中断是指 CPU 在处理某一事件 A 时,发生了另一事件 B,请求 CPU 迅速去处理(中断发生);CPU 暂时停止当前的工作(中断响应), 转去处理事件 B(中断服务);待 CPU 将事件 B 处理完毕后,再回到原来事件 A 被中断的地方继续处理事件 A(中断返回),这一过程称为中断。
再回来看前面讲的生活事例,与单片机中断结合分析,你的主任务是洗衣服,水开报警这是一个中断请求,这一时刻相当于断点处,你响应中断去关火,然后将开水灌入暖水瓶中,这一动作实际上就是处理中断程序,灌完开水后再回去继续洗衣服,相当于处理完中断程序后再返回主程序继续执行主程序。这里需要注意的是,水开是随时都有可能的,但是无论什么时候开,只要一开你将立即去处理它,处理完后再回来继续接着洗刚才那件衣服。单片机在执行程序时,中断也随时有可能发生,但无论何时发生,只要一旦发生,单片机将立即暂停当前程序,赶去处理中断程序,处理完中断程序后再返回刚才暂停处接着执行原来的程序。
单片机在执行程序时其程序流程图如下:
引起 CPU 中断的根源称为中断源。中断源向 CPU 提出中断请求,CPU 暂时中断原来的事务 A,转去处理事件 B,对事件 B 处理完毕后,再回到原来被中断的地方(即断点),称为中断返回。实现上述中断功能的部件称为中断系统(中断机构)。
当中央处理机 CPU 正在处理某件事的时候外界发生了紧急事件请求,要求CPU 暂停当前的工作,转而去处理这个紧急事件,处理完以后,再回到原来被中断的地方,继续原来的工作,这样的过程称为中断。实现这种功能的部件称为中断系统,请示 CPU 中断的请求源称为中断源。微型机的中断系统一般允许多个中断源,当几个中断源同时向 CPU 请求中断,要求为它服务的时候,这就存在CPU 优先响应哪一个中断源请求的问题。通常根据中断源的轻重缓急排队,优先处理最紧急事件的中断请求源,即规定每一个中断源有一个优先级别。CPU 总是先响应优先级别最高的中断请求。
当 CPU 正在处理一个中断源请求的时候(执行相应的中断服务程序),发生了另外一个优先级比它还高的中断源请求。如果 CPU 能够暂停对原来中断源的服务程序,转而去处理优先级更高的中断请求源,处理完以后,再回到原低级中断服务程序,这样的过程称为中断嵌套。这样的中断系统称为多级中断系统,没有中断嵌套功能的中断系统称为单级中断系统。
中断的开启与关闭、设置启用哪一个中断等都是由单片机内部的一些特殊功能寄存器来决定的,在前面章节的学习中我们仅对单片机 IO 口操作过(实际上操作 IO 口即操作 IO 口寄存器,只不过编译器已经帮我们把 IO 口寄存器封装好直接操作 IO 即可,这些可在 51 单片机头文件内查看),从本章开始就会介绍单片机内部更多的特殊功能寄存器以及如何配置它实现相应的功能。
随着计算机技术的应用,人们发现中断技术不仅解决了快速主机与慢速 I/O设备的数据传送问题,而且还具有如下优点:
①分时操作。CPU 可以分时为多个 I/O 设备服务,提高了计算机的利用率;
②实时响应。CPU 能够及时处理应用系统的随机事件,系统的实时性大大增强;
③可靠性高。CPU 具有处理设备故障及掉电等突发性事件能力,从而使系统可靠性提高。
中断结构及相关寄存器
中断结构
STC89C5X 系列单片机提供了 8 个中断请求源,它们分别是:外部中断O(INTO)、外部中断 1(INT1)、外部中断 2(INT2)、外部中断 3(INT3)、定时器 0中断、定时器 1 中断、定时器 2 中断、串口(UART)中断。(注意:51 系列单片机一定有基本的 5 个中断,但不全有 8 个中断,需要查看芯片手册,通常我们使用的都是基本的 5 个中断:INT0、INT1、定时器 0/1,串口中断)。所有的中断都具有四个中断优先级(基本型只有两个)。用户可以用关总中断允许位(EA/IE.7)或相应中断的允许位来屏蔽所有的中断请求,也可以用打开相应的中断允许位来使 CPU 响应相应的中断申请。其中有些中断源可以用软件独立地控制为开中断或关中断状态。每一个中断的优先级别均可用软件设置。高优先级的中断请求可以打断低优先级的中断,反之,低优先级的中断请求不可以打断高优先级及同优先级的中断。当两个相同优先级的中断同时产生时,将由查询次序来决定系统先响应哪个中断。 STC89C5X 系列单片机的各个中断查询次序表如下图所示:
通过设置新增加的特殊功能寄存器 IPH 中的相应位,可将中断优先级设为四级,如果只设置 IP 或 XICON,那么中断优先级就只有两级,与传统 8051 单片机两级中断优先级完全兼容。上图中的中断查询次序即为中断号,这个中断号在编程时非常重要,当中断来临时,只有中断号正确才能进入中断。
下面我们以 51 单片机均有的 5 个中断来介绍,其内部结构框图如下所示:
①INT0 对应的是 P3.2 口的附加功能,可由 IT0(TCON.0)选择其为低电平有效还是下降沿有效。当 CPU 检测到 P3.2 引脚上出现有效的中断信号时,中断标志 IE0(TCON.1)置 1,向 CPU 申请中断。
②INT1 对应的是 P3.3 口的附加功能,可由 IT1(TCON.2)选择其为低电平有效还是下降沿有效。当 CPU 检测到 P3.3 引脚上出现有效的中断信号时,中断标志 IE1(TCON.3)置 1,向 CPU 申请中断。
③T0 对应的是 P3.4 口的附加功能,TF0(TCON.5),片内定时/计数器 T0 溢出中断请求标志。当定时/计数器 T0 发生溢出时,置位 TF0,并向 CPU 申请中断。
④T1 对应的是 P3.5 口的附加功能,TF1(TCON.7),片内定时/计数器 T1溢出中断请求标志。当定时/计数器 T1 发生溢出时,置位 TF1,并向 CPU 申请中断。
⑤RXD 和 TXD 对应的是 P3.0 和 P3.1 口的附加功能,RI(SCON.0)或 TI(SCON.1),串行口中断请求标志。当串行口接收完一帧串行数据时置位 RI 或当串行口发送完一帧串行数据时置位 TI,向 CPU 申请中断。
中断相关寄存器
(1)中断允许控制
CPU 对中断系统所有中断以及某个中断源的开放和屏蔽是由中断允许寄存器IE 控制的。
EX0(IE.0),外部中断 0 允许位;
ET0(IE.1),定时/计数器 T0 中断允许位;
EX1(IE.2),外部中断 0 允许位;
ET1(IE.3),定时/计数器 T1 中断允许位;
ES(IE.4),串行口中断允许位;
EA (IE.7), CPU 中断允许(总允许)位。
(2)中断请求标志 TCON
IT0(TCON.0),外部中断 0 触发方式控制位。
当 IT0=0 时,为电平触发方式。
当 IT0=1 时,为边沿触发方式(下降沿有效)。
IE0(TCON.1),外部中断 0 中断请求标志位。
IT1(TCON.2),外部中断 1 触发方式控制位。
IE1(TCON.3),外部中断 1 中断请求标志位。
TF0(TCON.5),定时/计数器 T0 溢出中断请求标志位。
TF1(TCON.7),定时/计数器 T1 溢出中断请求标志位。
(3)中断优先级
同一优先级中的中断申请不止一个时,则有中断优先权排队问题。同一优先级的中断优先权排队,由中断系统硬件确定的自然优先级形成,其排列如所示:
(4)中断号(单片机内部中断优先级由上到下,即由外部中断0到串行口中断,由高到低)
(5)中断响应条件
①中断源有中断请求;
②此中断源的中断允许位为 1;
③CPU 开中断(即 EA=1)。
以上三条同时满足时,CPU 才有可能响应中断。在使用中断时我们需要做什么呢?
①你想使用的中断是哪个?选择相应的中断号;
②你所希望的触发条件是什么?
③你希望在中断之后干什么?
我们以外部中断 0 为例,如下:
主程序中需要有以下代码:
EA=1;//打开总中断开关
EX0=1;//开外部中断 0
IT0=0/1;//设置外部中断的触发方式
中断服务函数
void int0() interrupt 0 using 1
{
//编写用户所需的功能代码
}
在中断函数中 int0 是函数名,可自定义,但必须符合 C 语言标识符定义规则,interrupt 是一个关键字,表示 51 单片机中断。后面的“0”是中断号,外部中断 0 中断号为 0,这个可参考前面的内容。后面的 using 1 可省略不写。
外部中断
外部中断介绍
先回顾一下 51 单片机的中断。当中央处理机 CPU 正在处理某件事的时候外界发生了紧急事件请求,要求CPU 暂停当前的工作,转而去处理这个紧急事件,处理完以后,再回到原来被中断的地方,继续原来的工作,这样的过程称为中断。实现这种功能的部件称为中断系统,请示 CPU 中断的请求源称为中断源。微型机的中断系统一般允许多个中断源,当几个中断源同时向 CPU 请求中断,要求为它服务的时候,这就存在CPU 优先响应哪一个中断源请求的问题。通常根据中断源的轻重缓急排队,优先处理最紧急事件的中断请求源,即规定每一个中断源有一个优先级别。CPU 总是先响应优先级别最高的中断请求。中断示意图如下所示:
STC89C5X 系列单片机提供了 4 个外部中断:外部中断 O(INTO)、外部中断1(INT1)、外部中断 2(INT2)、外部中断 3(INT3)。(注意:51 系列单片机一定有基本的 2 个外部中断,但不全有 4 个中断,需要查看芯片手册,通常我们都是使用基本的 2 个外部中断:INT0 和 INT1)。
下面我们来看下外部中断结构图,如下所示:
图中 INT0 和 INT1 即为外部中断 0 和外部中断 1 输入口。
①INT0 对应的是 P3.2 口的附加功能,可由 IT0(TCON.0)选择其为低电平有效还是下降沿有效。当 CPU 检测到 P3.2 引脚上出现有效的中断信号时,中断标志 IE0(TCON.1)置 1,向 CPU 申请中断。
②INT1 对应的是 P3.3 口的附加功能,可由 IT1(TCON.2)选择其为低电平有效还是下降沿有效。当 CPU 检测到 P3.3 引脚上出现有效的中断信号时,中断标志 IE1(TCON.3)置 1,向 CPU 申请中断。
(1)中断允许控制
CPU 对中断系统所有中断以及某个中断源的开放和屏蔽是由中断允许寄存器IE 控制的。
EX0(IE.0),外部中断 0 允许位;
ET0(IE.1),定时/计数器 T0 中断允许位;
EX1(IE.2),外部中断 1 允许位;
ET1(IE.3),定时/计数器 T1 中断允许位;
ES(IE.4),串行口中断允许位;
EA (IE.7), CPU 中断允许(总允许)位。
(2)中断请求标志 TCON
IT0(TCON.0),外部中断 0 触发方式控制位。
当 IT0=0 时,为电平触发方式。
当 IT0=1 时,为边沿触发方式(下降沿有效)。
IE0(TCON.1),外部中断 0 中断请求标志位。
IT1(TCON.2),外部中断 1 触发方式控制位。
IE1(TCON.3),外部中断 1 中断请求标志位。
TF0(TCON.5),定时/计数器 T0 溢出中断请求标志位。
TF1(TCON.7),定时/计数器 T1 溢出中断请求标志位。
外部中断配置
我们知道要让 51 单片机发生中断必须要满足以下 3 个条件,这 3 个条件的顺序可以任意:
①中断源有中断请求;
②此中断源的中断允许位为 1;
③CPU 开中断(即 EA=1)。
比如我们配置外部中断 0,对应的配置程序如下:
EA=1;//打开总中断开关
EX0=1;//开外部中断 0
IT0=0/1;//设置外部中断的触发方式
如果要配置的是外部中断 1,只需将 EX0 改为 EX1,IT0 改为 IT1。
因为独立按键一端是共地的,当按下后对应单片机 IO 口被拉低,而默认单片机 IO 口是高电平,这样就有一个下降沿过程,所以通常使用外部中断都是配置为下降沿触发,即 IT0=1;
在编写程序时通常我们会将外部中断的配置放到一个自定义函数内便于管理维护。如下所示:
void exti0_init(void)
{
IT0=1;//跳变沿触发方式(下降沿)
EX0=1;//打开 INT0 的中断允许
EA=1;//打开总中断
}
当触发中断后即会进入中断服务函数,外部中断 0 中断服务函数如下:
void exti0() interrupt 0 //外部中断 0 中断函数
{
//执行所需的功能
}
在中断函数中 exti0 是函数名,可自定义,但必须符合 C 语言标识符定义规则,interrupt 是一个关键字,表示 51 单片机中断。后面的“0”是中断号,外部中断 0 中断号为 0,如果是外部中断 1,则中断号为 2,这个可参考中断章节的内容。
硬件设计
本实验使用到硬件资源如下:
(1)独立按键模块(K3)
(2)LED 模块(D1)
A5-A7可按照A2-A4开发板的电路将 K3键连接在单片机 P3.2 口(外部中断 0),K4 按键连接在 P3.3 口(外部中断 1)。D1 指示灯连接在单片机 P2.0 口。D2 指示灯连接在单片机 P2.1口。通过按键按下,LED灯的点亮来实现外部中断。
软件编程
以外部中断0和1为例介绍外部中断的使用。使用独立按键 K3 控制 LED 1亮灭;使用独立按键K4控制LED2亮灭。
#include"reg52.h"
typedef unsigned char u8;
typedef unsigned int u16;
sbit KEY3=P3^2;
sbit KEY4=P3^3;
sbit LED1=P2^0;
sbit LED2=P2^1;
void delay_1ms(u16 ms)
{
u16 i,j;
for(i=ms;i>0;i--)
for(j=110;j>0;j--);//注意分号
}
void delay_10us(u16 ten_us)
{
while(ten_us--);
}
void exti0_init(void)
{
IT0=1;//跳变沿触发方式(下降沿)
EX0=1;//打开 INT0 的中断允许
EA=1;//打开总中断
}
void exti2_init(void)
{
IT1=1;
EX1=1;
EA=1;
}
void main()
{
exti0_init();//外部中断 0 配置
exti2_init();//外部中断 1 配置
while(1)
{
}
}
void exti0() interrupt 0 //外部中断 0 中断函数
{
delay_10us(1000);//消抖
if(KEY3==0)//再次判断 K3 键是否按下
LED1=!LED1;//LED1 状态翻转
}
void exti2() interrupt 2 //外部中断 1 中断函数
{
delay_1ms(10);//消抖
if(KEY4==0)//再次判断 K4 键是否按下
LED2=!LED2;//LED2 状态翻转
}
首先定义 K3 键与 LED1 的控制管脚,然后定义了外部中断 0 配置函数 exti0_init,该函数内容是按照前面介绍的配置方法实现,即开启总中断、外部中断 0 功能,设置外部中断 0 为下降沿触发。然后进入 while循环,在循环体内没有执行任何功能程序。
而为什么在主函数中怎么没有看到按键对 LED 的控制呢?因为我们在exti0_init()函数内就已经把按键管脚配置为外部中断 0 下降沿触发,当有按键按下(因为管脚默认为高电平,而按键按下为低电平 GND),即会进入对应中断服务函数执行相应的功能程序,LED 的控制就在中断函数内完成的。外部中断 1 的使用与外部中断 0 是一样的。
实验现象
定时器中断
定时器介绍
-
CPU 时序的有关知识
①振荡周期:为单片机提供定时信号的振荡源的周期(晶振周期或外加振荡
周期)。
②状态周期:2 个振荡周期为 1 个状态周期,用 S 表示。振荡周期又称 S 周
期或时钟周期。
③机器周期:1 个机器周期含 6 个状态周期,12 个振荡周期。
④指令周期:完成 1 条指令所占用的全部时间,它以机器周期为单位。
例如:外接晶振为 12MHz 时,51 单片机相关周期的具体值为:
振荡周期=1/12us;
状态周期=1/6us;
机器周期=1us;
指令周期=1~4us; -
学习定时器前需要明白的几点
①51 单片机有两组定时器/计数器,因为既可以定时,又可以计数,故称之为定时器/计数器。
②定时器/计数器和单片机的 CPU 是相互独立的。定时器/计数器工作的过程是自动完成的,不需要 CPU 的参与。
③51 单片机中的定时器/计数器是根据机器内部的时钟或者是外部的脉冲信号对寄存器中的数据加 1。
有了定时器/计数器之后,可以增加单片机的效率,一些简单的重复加 1 的工作可以交给定时器/计数器处理。CPU 转而处理一些复杂的事情。同时可以实现精确定时作用。
51 单片机定时器原理
STC89C5X 单片机内有两个可编程的定时/计数器 T0、T1 和一个特殊功能定时器 T2。定时/计数器的实质是加 1 计数器(16 位),由高 8 位和低 8 位两个寄存器 THx 和 TLx 组成。它随着计数器的输入脉冲进行自加 1,也就是每来一个脉冲,计数器就自动加 1,当加到计数器为全 1 时,再输入一个脉冲就使计数器回零,且计数器的溢出使相应的中断标志位置 1,向 CPU 发出中断请求(定时/计数器中断允许时)。如果定时/计数器工作于定时模式,则表示定时时间已到;如果工作于计数模式,则表示计数值已满。可见,由溢出时计数器的值减去计数初值才是加 1 计数器的计数值。
51 单片机定时/计数器结构
51 单片机定时器/计数器内部结构如下所示:
上图中的 T0 和 T1 引脚对应的是单片机 P3.4 和 P3.5 管脚。51 单片机定时/计数器的工作由两个特殊功能寄存器控制。TMOD 是定时/计数器的工作方式寄存器,确定工作方式和功能;TCON 是控制寄存器,控制 T0、T1 的启动和停止及设置溢出标志。
- 工作方式寄存器 TMOD
工作方式寄存器 TMOD 用于设置定时/计数器的工作方式,低四位用于 T0,高四位用于 T1。其格式如下:
GATE 是门控位, GATE=0 时,用于控制定时器的启动是否受外部中断源信号的影响。只要用软件使 TCON 中的 TR0 或 TR1 为 1,就可以启动定时/计数器工作;GATA=1 时,要用软件使 TR0 或 TR1 为 1,同时外部中断引脚 INT0/1 也为高电平时,才能启动定时/计数器工作。即此时定时器的启动条件,加上了 INT0/1 引脚为高电平这一条件。
C/T :定时/计数模式选择位。C/T =0 为定时模式;C/T =1 为计数模式。
M1M0:工作方式设置位。定时/计数器有四种工作方式。
- 控制寄存器 TCON
TCON 的低 4 位用于控制外部中断,已在前面介绍。TCON 的高 4 位用于控制定时/计数器的启动和中断申请。其格式如下:
TF1(TCON.7):T1 溢出中断请求标志位。T1 计数溢出时由硬件自动置 TF1为 1。CPU 响应中断后 TF1 由硬件自动清 0。T1 工作时,CPU 可随时查询 TF1 的状态。所以,TF1 可用作查询测试的标志。TF1 也可以用软件置 1 或清 0,同硬件置 1 或清 0 的效果一样。
TR1(TCON.6):T1 运行控制位。TR1 置 1 时,T1 开始工作;TR1 置 0 时,T1 停止工作。TR1 由软件置 1 或清 0。所以,用软件可控制定时/计数器的启动与停止。
TF0(TCON.5):T0 溢出中断请求标志位,其功能与 TF1 类同。
TR0(TCON.4):T0 运行控制位,其功能与 TR1 类同。
51 单片机定时/计数器的工作方式
- 方式 0
方式 0 为 13 位计数,由 TL0 的低 5 位(高 3 位未用)和 TH0 的 8 位组成。TL0 的低 5 位溢出时向 TH0 进位,TH0 溢出时,置位 TCON 中的 TF0 标志,向 CPU发出中断请求。其结构图如下所示:
门控位 GATE 具有特殊的作用。当 GATE=0 时,经反相后使或门输出为 1,此时仅由 TR0 控制与门的开启,与门输出 1 时,控制开关接通,计数开始;当 GATE=1时,由外中断引脚信号控制或门的输出,此时控制与门的开启由外中断引脚信号和 TR0 共同控制。当 TR0=1 时,外中断引脚信号引脚的高电平启动计数,外中断引脚信号引脚的低电平停止计数。这种方式常用来测量外中断引脚上正脉冲的宽度。计数模式时,计数脉冲是 T0 引脚上的外部脉冲。计数初值与计数个数的关系为:X=2^
13-N。
- 方式 1
方式 1 的计数位数是 16 位,由 TL0 作为低 8 位,TH0 作为高 8 位,组成了16 位加 1 计数器。其结构图如下所示:
计数初值与计数个数的关系为:X=2^ 16-N
3.方式 2
方式 2 为自动重装初值的 8 位计数方式。工作方式 2 特别适合于用作较精确的脉冲信号发生器。其结构图如下所示:
计数初值与计数个数的关系为:X=2^ 8-N
- 方式 3
方式 3 只适用于定时/计数器 T0,定时器 T1 处于方式 3 时相当于 TR1=0,停止计数。工作方式 3 将 T0 分成为两个独立的 8 位计数器 TL0 和 TH0。其结构如下所示:
这几种工作方式中应用较多的是方式 1 和方式 2。定时器中通常使用定时器方式 1,串口通信中通常使用方式 2。
定时器配置
在使用定时器时,应该如何配置使其工作?其步骤如下(各步骤顺序可任意):
①对 TMOD 赋值,以确定 T0 和 T1 的工作方式,如果使用定时器 0 即对 T0 配置,如果使用定时器 1 即对 T1 配置。
②根据所要定时的时间计算初值,并将其写入 TH0、TL0 或 TH1、TL1。
③如果使用中断,则对 EA 赋值,开放定时器中断。
④使 TR0 或 TR1 置位,启动定时/计数器定时或计数。
上述中有一个定时/计数器初值的计算,下面我们来看下如何计算定时/计数器初值。
前面我们介绍过机器周期的概念,它是 CPU 完成一个基本操作所需要的时间。其计算公式是:机器周期=1/单片机的时钟频率。51 单片机内部时钟频率是外部时钟的 12 分频,也就是说当外部晶振的频率输入到单片机里面的时候要进行 12分频。比如说你用的是 12MHZ 晶振,那么单片机内部的时钟频率就是 12/12MHZ,当你使用 12MHZ 的外部晶振的时候,机器周期=1/1M=1us。如果我们想定时 1ms的初值是多少呢?
1ms/1us=1000。也就是要计数 1000 个,初值=65535-1000+1(因为实际上计数器计数到 65536(2 的 16 次方)才溢出,所以后面要加 1)=64536=FC18H,所以初值即为 THx=0XFC,TLx=0X18。
也可以使用计时小程序算时间。
知道了如何计算定时/计数器初值,那么想定时多长时间都可以计算出,当然由于定时计数器位数有限,我们不可能直接通过初值定时很长时间,如果要实现很长时间的定时,比如定时 1 秒钟。可以通过初值设置定时 1ms,每当定时 1ms结束后又重新赋初值,并且设定一个全局变量累计定时 1ms 的次数,当累计到1000 次,表示已经定时 1 秒了。需要其他定时时间类似操作,这样我们就可以使用定时器来实现精确延时来替代之前的 delay 函数。
这里以定时器 0 为例介绍配置定时器工作方式 1、设定 1ms 初值,开启定时器计数功能以及总中断,如下:
void time0_init(void)
{
TMOD=0X01;//选择为定时器 0 模式,工作方式 1
TH0=0XFC;(65536-1000)/256 //给定时器赋初值,定时 1ms
TL0=0X18;(65536-1000)%256
ET0=1;//打开定时器 0 中断允许
EA=1;//打开总中断
TR0=1;//打开定时器
}
对于定时器 1 的使用方法是一样的,只是将上述的 0 变为 1 即可,具体可参考我们定时器 1 实验例程。
硬件设计
本实验使用到硬件资源如下:
(1)LED 模块(D1)
(2)定时器 0
本章硬件电路非常简单,只使用到开发板上 LED 模块的 D1,至于定时器 0它属于 51 单片机内部资源,只需通过软件配置即可使用。
软件设计
程序附加定时器0的使用
#include"reg52.h"
typedef unsigned char u8;
typedef unsigned int u16;
sbit LED1=P2^0;
sbit LED2=P2^1;
void delay_1ms(u16 ms)
{
u16 i,j;
for(i=ms;i>0;i--)
for(j=110;j>0;j--);//注意分号
}
void delay_10us(u16 ten_us)
{
while(ten_us--);
}
void time0_init(void)
{
TMOD|=0X01;//选择为定时器 0 模式,工作方式 1
TH0=0XFC; //给定时器赋初值,定时 1ms,12HZ晶振
TL0=0X18;
ET0=1;//打开定时器 0 中断允许
EA=1;//打开总中断
TR0=1;//打开定时器
}
void time1_init(void)
{
TMOD|=0X10;//选择为定时器 1 模式,工作方式 1
TH0=0XFC; //给定时器赋初值,定时 1ms,12HZ晶振
TL1=0X18;
ET1=1;//打开定时器 1 中断允许
EA=1;//打开总中断
TR1=1;//打开定时器
}
void main()
{
time1_init();
time0_init();//定时器 0 中断配置
while(1)
{
}
}
void time1()interrupt 1 //定时器 1 中断函数
{
static u16 i;//定义静态变量 i
TH0=0XFC; //给定时器重新赋初值,定时 1ms
TL0=0X18;
i++;
if(i==1000)//1s
{
i=0;
LED1=!LED1;
}
}
void time0()interrupt 3 //定时器 1 中断函数
{
static u16 i;//定义静态变量 i
TH1=0XFC; //给定时器重新赋初值,定时 1ms
TL1=0X18;
i++;
if(i==1000)//1s
{
i=0;
LED2=!LED2;
}
}