单片机学习笔记(7)
定时器和中断概念的基本认识(上)
学习过程跟随up主@海创电子
经过一段时间的学习,终于走到了定时器中断的部分了!
接下来我们主要从两个实验入手:
实验一:LED小灯的闪烁
实验二:按键中断法点亮LED
在实验开始之前,我们先来了解一些概念。
时钟周期
时钟周期又叫做振荡周期(晶振周期)、节拍周期,定义为时钟晶振频率的倒数。时钟周期是计算机中最基本的、最小的时间单位。在一个时钟周期内,CPU仅完成一个最基本的动作。例如晶振为12M,则时钟周期为1/12us。又可以被定义为节拍。
机器周期
在计算机中,为了便于管理,常把一条指令的执行过程划分为若干个阶段,每一阶段完成一项工作。例如,取指令、存储器读、存储器写等,这每一项工作称为一个基本操作。完成一个基本操作所需要的时间称为机器周期。一般情况下,一个机器周期由若干个S周期(状态周期)组成。比如,取值周期,取数周期。在80C51内部,机器周期一般包括于6个状态周期,12个时钟周期。例如24M的晶振,机器周期为12/24M秒。
情景引入
例:利用定时器定时20ms
我们可以将定时器看作是一个容器,若定时的时间为20ms,则由公式计算可知:
次数X(12/12000000)=0.02s,得出次数需要20000次。
因为是从0开始计算,所以容器大小为65536,计算得出65536-20000=45536。因此我们需要在“容器”里头预先加载45536大小的“水”。
注意:这种计算方式需要单片机的晶振频率是12M。
一般我们常用的模式是“定时模式1”——确定“桶”的大小,接下来将45536如上图所示转化为十六进制进行“装载”。
注意:上图当中的45536%256结果应为224。
上图当中出现的两个寄存器——TH0和TL0含义如下:
T:time
H:high(高8位)
0:定时器0
L:low(低8位)
寄存器介绍
这里的TCON(定时器控制寄存器)是可位寻址的,我们既可以把值赋值给整个寄存器(TCON=0xAA),也可以针对该寄存器的单个位进行赋值(TF1=1)。
上图当中出现的两个寄存器——TF1和TR1含义如下:
T:time
F:flag(标志)——发生“溢出”时,标志位则置“1”
1:定时器1
R:run(运行)——开始往“桶”里“倒水”
采用查询法配置定时器的四个步骤
设置TMOD寄存器
视频里的教程在使用寄存器时,只使用了定时器0。因此在设置TMOD寄存器的时候设置的初始值是0x01。
在设置寄存器TMOD时,视频当中出现了一下代码:
TMOD=0x01; |
因为TMOD寄存器是不可位寻址的,因此第一句则直接将0x01赋值给TMOD。目的是为了设置TMOD寄存器当中的定时器0为“模式1”,一般情况下我们只需要编写第一句就能设置完了。
第二、三两句则是为了使代码更加严谨。事实上,我们在这里只使用定时器0。我们假设此时的定时器1也有被使用,且被设置为其他模式。而我们只需要设置定时器0,倘若直接使用第一句代码来设置TMOD,则会影响到当前定时器1的模式。因此我们需要进行“与或”运算来确保我们更改的只有定时器0的模式。(只使用定时器1的时候同理)
在这里就需要用到C语言当中的“与”、“或”这两种逻辑运算的知识了。
接下来咱们解释一下第二、三行代码的具体作用,两行代码对数据的处理一共分为两步:
第一步:
TMOD=TMOD&0xFC; |
对当前TMOD的值进行与运算,与上数值0xFC,目的是为了使定时器0的M1和M0这两个位的值为0,为第二步做准备。
第二步:
TMOD=TMOD|0x01; |
进行或运算,或上数值0x01,目的是为了使定时器0的M1和M0这两个位置的值分别为0和1,即“模式1”。而其他位则恢复为原来的数值。
接下来我们来解释一下这里的“严谨之处”
在这里我们假设定时器0和定时器1的模式均被设置为模式1,则:
0x10 —— 0001 0000 //一开始寄存器TMOD的状态,此时定时器1为模式1。 |
接下来我们需要执行一下与操作:
TMOD=TMOD&0xFC; |
注意,执行到这里的时候,定时器1的状态被保留了下来,而定时器0的状态则被重置了。
接下来我们执行第二步的操作:
TMOD=TMOD|0x01 |
执行到这里可以看出不仅定时器1的状态被保留了下来,定时器0也成功被设置位模式1,这就是只修改对应定时器状态的方法,虽然麻烦了点,但会更加的严谨。
查询法中断程序实现
以上程序当中的第15——17行:
TF0=0; //寄存器内数值“满”了之后标志位需要重新复位 |
中断法配置定时器
在使用中断的时候,中断遵循查询次序,优先级按照上图表格从上至下依次排列。表格当中用红色的框框选起来的几个定时器为常用的定时器,在使用时注意中断源所对应的中断号。
中断程序实现
上图的代码当中出现了这么一行:
static unsigned int cnt; |
这里的static目的是为了保留延时函数里的cnt变量的值,cnt作为延时函数当中的局部变量,在跳出延时函数时cnt的值会被清除,所以在定义时需要加上“static”这个关键字来保留它的值。
按键去抖操作的其他方法
下图代码属于对上图代码的补充。
if(cnt1!=0x00) //这条语句包括了弹起和抖动状态 |