51单片机系列二:中断与延时

本篇通过闪烁led和数码管两个实验来分析延时与中断概念,以及实现软件仿真。

Chapter1.中断的概念

中断就是当CPU执行主程序时,突然被打断一下,去干别的事情,干完再回来执行主程序。这个过程类似于你在洗衣服时水开了,你停下洗衣服的动作去关掉火,再回来烧开水。

中断还可以进行嵌套,就是CPU在执行一个中断程序的时候又被打断,去执行另一个中断程序,执行完再回来执行第一个中断程序,执行完再回来执行主程序。类似于你在洗衣服的时候去关烧开水的火之后灌开水,正灌着呢发现电话响了去接电话,接完电话回来继续灌开水,灌完开水回来继续洗衣服。

“中断”这个概念来源于单片机本身是串行执行。也就是说,只有执行完一条语句才能执行下一条语句,在同一时间内只能干一件事情。FPGA等支持并行执行的硬件则可以同时干很多不同的事情。然而FPGA也有中断,这里不是特别了解不再阐述。

“中断”这一概念为实现某一信号的触发功能打下了基础。一般而言,52单片机有6个中断源,其中三个为信号中断源,分别是INT0,INT1(外部中断0/1号口)和TI/RI(串行口)中断,这里相当于执行主程序的时候等信号,等来了就执行相应的信号处理操作;三个为芯片内部定时器/计数器中断,分别为T0/T1/T2,它们记满回零后即可触发中断,这里也相当于在时钟电平变化时,就执行下一项操作。  

中断也不是随便进行的,状态比较多,设置很麻烦,每个程序执行中断前必须都不厌其烦地设定与检查中断状态。

1.中断的允许与使能

首先一个问题:到底要不要中断?

假如一个程序运行压根不需要用到中断,那么中断的存在可能会影响整个程序,因此默认状态下,中断一般是关着的。想要打开就必须对它进行操作。

允许中断了,但是有6个中断源,到底允许哪个中断呢?这就要再对分别控制6个中断源的寄存器口进行使能操作。

以上两个问题均由中断允许寄存器IE(interrupt enable)控制。它有八位,分别是:

位序号

D0

D1

D2

D3

D4

D5

D6

D7

说明

外部中断0

定时/计数0

外部中断1

定时/计数1

串行口中断

定时

2

溢出中断(

8052用)

无效位

全局中断位

位符号(写程序时直接引用)

EX0

ET0

EX1

ET1

ES

--

--

EA

以上所有位都是高电平有效。因此想要开中断,先让全局中断EA=1,再让中断源所对应的位等于1就可以了。

2.中断的优先级

假如洗衣服时水开了,同时电话铃声也响了,先干哪件呢?这就涉及到中断的优先级。

中断的优先级由寄存器IP(interrupt priority)控制。

以上的设定仅仅有0,1两个状态,只是“相对优先”,不能保证绝对状态。未设置时几个同级状态同时发生时,采用以下的默认优先级排序:注意:本条只针对同时到达的同级中断有效。

 假如外部中断1正在执行,然而外部中断0到了,在默认情况下并不会进行中断嵌套!要想实现中断嵌套,必须人为设置外部中断0的优先级高于外部中断1,也即前者优先级为1,后者优先级为0.假如同时设置两者优先级为1,则依然是按照中断到达的顺序执行。

3.定时器的设置

即便是设定好了中断的使能与优先级,定时器的四种工作方式和不同控制位的设定也需要操纵两个寄存器TMOD和TCON。

高四位控制寄存器T1,低四位控制寄存器T0。

  • GATE

0:仅由运行控制位TRx(x = 0,1)来控制定时器/计数器运行。
1:用外中断引脚( INT0或 INT1)上的电平与运行控制位TRx共同来控制定时器/计数器运行。

  • C/T’

0:为定时器工作模式,对单片机的晶体振荡器12分频后的脉冲进行计数。
1:为计数器工作模式,计数器对外部输入引脚T0(P3.4)或T1(P3.5)的外部脉冲(负跳变)计数。

M1/M2工作方式选择

M1M2工作方式
00方式0,是13位定时器/计数器
01方式1,是16位定时器/计数器
10方式2,8位常数自动装入定时器/计数器
11方式3,仅适用于T0,这时T0分为两个8位计数器,T1停止计数

 TCON:

TF为溢出标志,TR为相应的计数器使能控制位。

例如,计数器0在工作状态1(16位计数器) 下,先把低四位依次记满,然后向高四位进一位,这样往复直到所有16位都被记满,置TF0=1,此时向CPU请求中断。这样就实现了隔一定时间触发一次时钟沿。

Chapter2.延时的精确计算

在明白如何实现延时之前,应该先了解一些周期概念。

1.单片机的四种周期

<1>时钟周期

也叫振荡周期,就是单片机外接时钟晶振频率的倒数。这是CPU的最基本工作脉冲。

<2>状态周期

时钟周期的两倍。

<3>机器周期

在一个机器周期内,单片机完成一项基本操作(不一定是执行完一条指令)。机器周期相当于6个状态周期即12个时钟周期。

<4>指令周期

执行一条指令所需的时间,一般包含1~4个机器周期。

以下假设单片机采用的晶振为12Mhz(可以查阅单片机参数手册),即可算出几种延时分别需要的时间。

2.粗糙延时:不涉及芯片内部定时器

有一种方法是非常粗糙的延时:利用机器周期执行指令的时间实现延时。此种方法不能精确算出,只能用调试功能设断点测出,非常原始也非常不推荐。

void delayms(uint xms)//延时约xms毫秒

{

uint i,j;

for(i=xms;i>0;i--)

for(j=110;j>0;j--)

}

注意i不能超出255。调试前注意检查晶振频率是否正确,之后设断点计算sec的间隔即可得出函数执行一次延长的时间。与很多偶然因素有关,很不精确。

3.定时器延时

更精确的办法是使用中断和定时器。中断相关的设置开好之后,我们就面临一个给定时器寄存器赋初值的问题。

假设使用定时器0,将其作为16位定时器,其中TH0默认为高八位,TL0默认为低八位。先计算初值为0时装满一次要多长时间:

时钟周期=1/12M    机器周期=(1/12M)*12=1us

记满需要2^16-1个数,还要一条脉冲计数器溢出才能实现中断,也就是2^16=65536。按每个机器周期执行一条指令算,溢出一次一共需要65536us约等于65.5ms。假如需要延时为1s,可以让计数器记满50ms就溢出,之后重复20次中断再执行下一条指令。则可以每一轮都给定时器赋值,使其记到50ms就溢出,相当于每轮少记15536个数。使得T0总共的初值为15536就可以了。因为TL0有八位,则计算式为:

TH0=15536/256    TL0=15536%256  每轮溢出之后计数器会重置,因此要再给计数器赋一遍这样的初值。

完整的代码模板为:

主函数:设置定时器工作方式->装填初值->开总中断->开相应定时器中断->启动相应定时器->用while语句等待(很重要!必须有等待的环节)

中断函数:声明有特定格式,为void T0_time() interrupt 1//这里的1为序号,不能错

                 重装初值->溢出次数++->假如溢出次数到了xxx,溢出次数清零,执行到点后的操作

  • 4
    点赞
  • 34
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值