定时器介绍:
首先介绍简单解释一下两个与定时器时间有关的名词
时钟周期:时钟周期是指51单片机时序中最小的时间单位,与晶振的频率有关。我们所用的单片机中,晶振频率一般为11.0592M或12M,所对应的时钟周期为1/11.0592M或1/12M。
机器周期:机器周期即为,单片机最小的单位工作时间。对于目前我们所使用的Stc89c52的单片机来说,其机器周期为时钟周期的12倍,即单片机工作时间为:12/11.0592M或1M。
以上内容作为了解即可,接下来进入重头,定时器及其寄存器介绍及相关配置。
定时器,顾名思义,通过累加单位时间,来记录时间的东西,在日常生活中例如沙漏、钟表等。
拿沙漏来举例,假如一个沙漏完全流出的时间为30分钟,那么,从我们把沙漏倒置的那一刻开始,当我们看到最后一粒沙子流下去的时候,我们视觉上从沙漏这边接受到的信号便是,已经过去了30分钟。而在单片机中,这种计数模式是通过寄存器中的不断加一来体现的,假设我们的单片机中有一个16位的寄存器(寄存器这里可以当作一个存储数据的存储器),寄存器在这里是以二进制来进行计数的,16位为1的二进制,转换成十进制便是65535,在存储寄存器的最后一位计满之后,存储寄存器每一位便会变为0 从头开始(与钟表的满60变为0向上进1类似,在单片机中,我们把这种情况叫做溢出),其他相关寄存器就就会发生变化,这种变化作为一种信号告诉单片机,已经完成一次规定时间内的计时,这种工作方式就叫做定时。当脉冲信号来自内部时当作定时器使用,当脉冲信号来自外部银角时当作计数器使用。本节我们重点介绍定时器,对于计数器的部分只是简单带过。
单片机定时器的相关寄存器
51单片机中一般只有T0和T1两个定时器,此处的T对应的是timer也就是英文定时器的意思,部分增强型的会有增加的定时器。
在我们所用的Stc89c52单片机中,有定时器T0 和 T1 T2 三个定时器。
定时器存储寄存器,TH/TL
符号 | 描述 | 地址 | 复位值 |
TH0 | 定时器0的高位 | 8CH | 0X00 |
TH1 | 定时器1的高位 | 8DH | 0X00 |
TL0 | 定时器0的低位 | 8AH | 0X00 |
TL1 | 定时器1的低位 | 8BH | 0X00 |
在此节,我们配置寄存器时,一般是首先确定好我们所需要的定时器的值,可取值的范围大约是
0-71ms,通过改变TH/TL的值可以调节此值。
定时器控制寄存器TCON(地址88H 可位寻址)
位 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
符号 | TF1 | TR1 | TF0 | TR0 | IE1 | IT1 | IE0 | IT0 |
复位值 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
每一位的具体解释:
位 | 符号 | 描述 |
7 | TF1 | 定时器T1溢出的标志位,当定时器最高位产生溢出时,TF1被自动硬件置1,当进入定时器中断后,TF1被自动清零(也可以通过软件清零来实现)。 |
6 | TR1 | 当TR1被置为1时,定时器1开始工作。软件置位/清零来开始工作。 |
5 | TF0 | 定时器T0溢出的标志位,当定时器最高位产生溢出时,TF0被自动硬件置1,当进入定时器中断后,TF0被自动清零(也可以通过软件清零来实现)。 |
4 | TR0 | 当TR0被置为1时,定时器0开始工作。软件置位/清零来开始工作。 |
3 | IE1 | 外部中断的内容,此处暂时不讲。(在使用定时器时将其置为0即可) |
2 | IT1 | 外部中断的内容,此处暂时不讲。(在使用定时器时将其置为0即可) |
1 | IE0 | 外部中断的内容,此处暂时不讲。(在使用定时器时将其置为0即可) |
0 | IT0 | 外部中断的内容,此处暂时不讲。(在使用定时器时将其置为0即可) |
定时器模式寄存器TMOD(地址89H 不可位寻址)
位 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
符号 | GATE(T1) | C/T(T1) | M1(T1) | M0(T1) | GATE(T0) | C/T(T0) | M1(T0) | M0(T0) |
复位值 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
寄存器每位的详解
符号 | 描述 |
GATE | 在此节,使用定时器时,将GATE配置为0即可。 |
T1/T01 | T1/T0对应的就是定时器1和0; |
C/T | 计数器和定时器的选择。0时为定时器,1时为计数器。 |
M1 | M0 | 模式 | 描述 |
0 | 0 | 0 | 模式0,兼容 8048 单片机的13位定时器,THn 的8位和 TLn 的5位组成一个13位定时器。 |
0 | 1 | 1 | THn 和 TLn 组成一个16位的定时器。 |
1 | 0 | 2 | 8位自动重装模式,定时器溢出后 THn 重装到 TLn 中。 |
1 | 1 | 3 | 禁用定时器1,定时器0变成2个8位定时器。 |
模式0,是为了兼容老版本的8048的单片机,现在的51基本不会用到这种模式。
模式3,其功能用模式2也能完全取代。
所以我们重点学习下模式1和模式2。
模式1,TH和TL组成16位寄存器,从TL的初始值开始,每经过一个机器周期,TL值自增1,TL增加到255之后,再加1,TL变为0,TH加1,直至TL和TH都加到255时,即寄存器每位都被置为1以后,再加1,则寄存器溢出,寄存器溢出后只要不对 THn 和 TLn 重新赋值,则从0开始计数。其最大定时时间范围为0-71ms,可以通过改变TL与TH的值来选择我们所需要的定时时间。在定时器溢出的同时TF被置为1,通过此标志为作为一种信号,告诉单片机,其已经完成了一次定时。一边情况下都是定时器和定时器中断一块共同使用,通过此标志位进入定时器中断,完成相关功能。
模式2,每经过一个机器周期,TL的值加1,在TL的值达到255加1溢出后,TF的值就直接被置为1了,TH的值会自动赋值给TL,然后从此值继续进行定时。此模式多用来配置串口的波特率,在此节我们不做过多赘述。
Tips
可位寻址:可以直接改变寄存器中的某一位的值 拿TCON来举例子,要想改变寄存器中TR的值,可以直接令TR=1或TR=0,不需要对整个寄存器重新赋值。
不可位寻址:不可以直接改变寄存器中的某一位的值,如需改变某一位的值,需要直接对整个寄存器重新赋值。例如;想改变定时器的模式 就必须对TMOD重新赋值,而不能对单独某一位赋值。
模式1电路图讲解:
在解读电路图之前,我们先来学习一下一些简单的逻辑符号。
在高中的时候我们就已经学过 与或非的相关逻辑运算,在这了我们进行一个简单的复习。
与:二者与,同真为真,才为真,一方假,则为假3。
或:二者或,一方真,即为真,两方同假,才为假。
非:真非为假,假非为真。
在C语言和单片机中我们常用0表示假,1表示真。
上图为定时器0和1 模式1的电路图,二者逻辑电路方面完全一致。
从上半部分开始看,SYSclk为时钟频率,从前文中我们得知,我们所用此系列的单片机机器周期为时钟周期的12倍,(t=1/f)所以频率选择/12。当C/T开关(左边的开关)指向0时为定时器模式,指向1时为计数器模式。
下半部分,从GATE开始,经过一个非门后(这里可以理解成对GATE进行一个非运算),与INT进行一个或运算,之后与 TR进行一个与运算。由图易知,当TR与下边电路经过与运算后输出1,定时器才能进行正常的工作,所以TR必须置1,而当经过非运算的GATE与INT进行或运算时,只要有一方为1,定时器就能正常工作,当GATE为0时,不管INT0为什么电平,定时器都能正常进行工作。
定时器编写代码,配置寄存器部分小结:
1.选择定时器,在本节中选择 定时器0 1或者2 都可。2.配置特殊功能寄存器TMOD进而来配置相关工作模式,(在本节 配置为1模式即可 即TMOD=0X10(定时器1)或者TMOD=0X01(定时器0))。3.配置TCON 通过 TR=1 来让定时器正常工作。4. 根据所需要的时间来配置TL 和TH 的。
时间计算:假设我们现在需要定时0.02s,即20ms,我们所用的晶振为11.0592M。
0.02(12/11.0592M)=18432。则需要让定时器计数18432次。通过配置TH和TL的值,让定时器计数18432次。16位定时器的溢出值位65536(65535+1才溢出)
时间计算公式:65536-定时器累加的次数=定时的时间/(12/晶振频率(机器周期))
65536-18432=47103. 47104转为16进制为B800,则TH=0XB8 TL=0X00;
当我们将TH和TL都配置为0时,我们发现(65535*(12/11.0592M)~为71ms)最大定时时间也才为71ms。那么对于更大时间的定时,我们可以通过简单的逻辑逻辑运算来完成,在后文中断部分我们会详细讲到。
PWM(全称Pulse Width Modulation脉冲宽度调制)
PWM是利用微处理器的数字输出来对模拟电路进行控制的一种非常有效的技术,是一种数字信号。
-
脉冲周期(T),单位是时间,比如纳秒(ns)、微妙(μs)、毫秒(ms)等;
-
脉冲频率(f),单位是赫兹(Hz)、千赫兹(kHz)等,与脉冲周期成倒数关系,f=1/T;
-
脉冲宽度(W),简称“脉宽”,是脉冲高电平持续的时间。单位是时间,比如纳秒(ns)、微妙(μs)、毫秒(ms)等;
-
占空比(D),脉宽除以脉冲周期的值,百分数表示,比如50%。也常有小数或分数表示的,比如0.5或1/2。
如何理解PWM?
我们在给一个LED调节亮度时,在其所能承受的电压范围内,排除其他一切变量,当所给予的电压越大时,其亮度也就越亮。
如图,蓝色的代表的是直流电源输出的电压,而红色的则是输出的PWM波
经过前人的一些论证,以及具体的实验得知,图上的蓝色的直流电压与红色的PWM的作用效果是几乎一致的。
所以在没有多种电压输出的情况下,使用PWM也可以取得同等效果。
即 PWM可以理解为 通过改变脉冲的占空比 输出不同脉冲信号 来达到 与 输出不同电压相同效果 的 一种方式。
在单片机方面的应用例如驱动电机等等。
结合本节所学的定时器,那该如何用定时器产生PWM波呢?
我们通过编写代码以及定时器的计数,当计数值超过红色线的我们记为高电平,低于红色线的我们记为低电平。通过改变红色线的值(即比较值)便可得到不同占空比的PWM。
至于编写代码部分,待讲述完中断的内容后,我们再来叙述。
Tips
高电平和低电平是数字电路中经常会出现的专业名词,它们所表面的意思就是电路上有和无,两者之间没有中间值,在不同的电路上,电压的具体值也是各不相同的。如果用简单的语言表达它们的意思就是开和关,平时人们家中使用的照明灯泡都是220V电压,当人们按下开关让灯泡发光的时候,就是高电平,人们不需要用灯了,需要用开关把灯关闭,等关灯以后灯泡上的电压会随之消失,这时就是低电平。
在单片机的使用中 我们将高电平 用数字1来表示 低电平用数字0来表示。例:让P2_0口输出高电平,即配置P2_0=1。
中断
概念理解:什么是中断?试着想想一下这样一个场景,你正在厨房里面做饭,这时候一旁的手机响了,有人给你打来电话,你放下手中的厨具,去接电话,在接完电话之后再继续进行厨房中上次进行的事情。
在这个场景中,做饭可以理解成是主函数当中所需要执行的任务,而电话铃声的响起,相当于是一个中断信号,打电话这个过程相当于是中断函数所要执行的任务。
在听完例子之后我们再来看手册给出的具体概念:
具体概念:
主程序——接受中断信号——暂停主函数所进行的内容——进行中断函数中的内容——结束中断函数的内容——继续主函数中的内容
定时器中断
如何理解定时器中断?与上面的例子相类似,我们将接受到电话这个信号,改为定时烧水这个任务。假设你正在厨房里切菜,这时候需要一些热水,需要用热水器进行加热来获得,在预估烧水的大概时间后,在开始烧水的同时,定下一个闹钟,进行一段定时,然后继续进行厨房中的切菜任务,当闹钟响起的时候,你收到了水已经烧好了的信号,放下手中的任务去关掉烧水器,存储热水。结束后,再回到厨房进行你的切菜任务。
在这个过程中,厨房切菜相当于是主函数中的任务,定下闹钟相当于单片机定时器计时,闹钟响起相当于是TF被置1的中断信号,关掉烧水器相当于是中断函数中的任务。
相关寄存器的配置
在了解了相关概念后,我们来学习下相关寄存器的配置
IE,中断使能寄存器的位分配(地址0XA8 可位寻址):
位 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
符号 | EA | -- | ET2 | ES | ET1 | EX1 | ET0 | EX0 |
复位值 | 0 | -- | 0 | 0 | 0 | 0 | 0 | 0 |
IE,中断使能寄存器的位描述:
位 | 符号 | 描述 |
7 | EA | 总中断使能位,相当于总开关。 |
6 | -- | -- |
5 | ET2 | 定时器2中断使能 |
4 | ES | 串口中断使能 |
3 | ET1 | 定时器1中断使能 |
2 | EX1 | 外部中断1使能 |
1 | ET0 | 定时器0使能 |
0 | EX0 | 外部中断0使能 |
在使用中断时,首先需要将EA总中断寄存器置为1,将总中断打开,再根据所需要的其他中断分别置1对应的寄存器。例:需要使用定期器0中断 即配置 EA=1; ET0=1;
IP 中断优先级寄存器的位分配 (地址0XBB 可位寻址)
位 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
符号 | -- | -- | PT2 | PS | PT1 | PX1 | PT0 | PX0 |
复位值 | -- | -- | 0 | 0 | 0 | 0 | 0 | 0 |
位 | 符号 | 描述 |
7 | -- | |
6 | -- | |
5 | PT2 | 定时器2的中断优先级控制位 |
4 | PS | 串口中断优先级控制位 |
3 | PT1 | 定时器1中断优先级控制位 |
2 | PX1 | 外部中断1中断优先级控制位 |
1 | PT0 | 定时器0中断优先级控制位 |
0 | PX0 | 外部中断0中断优先级控制位 |
中断的优先级有两种:查询优先级和执行优先级。
在未配置IP寄存器时,遵循的是查询优先级,优先级顺序如下表所示:
即 在如下多个中断同时触发的情况下,单片机会从优先级最高到最低的顺序依次执行。在此优先级的条件下,并不会发生中断嵌套,即 在未配置IP寄存器中某位为1的情况下,不会发生中断嵌套。
而 在配置IP寄存器后,被配置为1的中断,其中断优先级便是高于配置为0的中断,即 当配置为0的中断执行时,配置为1的中断满足触发条件,这时候便会跳出配置为0 的中断,进而执行配置为1的中断,待配置为1的中断执行结束后,再去执行配置为0的中断。
在本节的代码书写中由于只有一个中断,所以不需要考虑中断优先级的东西。
中断函数的书写:
一个函数是由函数名和函数主题构成的。
中断函数和其他C语言函数的区别在于,在函数名之后需要加上相应的中断号,中断号是由interrupt+对应中断数字组成,不同中断的中断号如下图所示:
例:假如我们需要书写一个定时器0的中断函数 函数示例如下
则 void 函数名 interrupt 0
{
.................
}
定时器呼吸灯代码部分:
//因为定时器最大计数时间大约也只有71ms,我们可以通过设置变量,定时器每记完一次数,变量加1 ,通过观察变量的值 进行简单的逻辑运算来记录更大时间。
#include <REGX52.H>
void TIMER0()
{
TMOD=0X01;
TH=0XFF; //将定时时间配置为100us
TL=0X43;
TR=1;
TF=0;
EA=1;
ET0=1;
}
int main()
{
TIMER0();
}
void timer_interrupt() interrupt 1
{
int compare=0; change=0; count=0;
count++;
count%=100;
compare%=100;
if(compare>=99)
{
compare=0; // 改变占空比的方向
count=0;
change=!change;
}
if(change==0)
{
if(count>comare)
P2_0=1;
if(count<comare)
P2_0=0;
if(count>=99) //count每增加100 comare增加1
compare++; //相当于是以100us为一个周期 每个周期的占空比逐次增加1%
}
if(change==1)
{
if(count>comare)
P2_0=1;
if(count<comare)
P2_0=0;
if(count>=99)
compare++;
}
}
参考:江科大51单片机教学
6.6 单片机中断系统 - 单片机教程(一) - UDN开源文档