STC89C52单片机定时器及中断系统的介绍以及代码示例
目录
一,定时器介绍
定时器介绍:
51单片机的定时器属于单片机的内部资源,其电路的连接和运转均在单片机内部完成
定时器作用:
(1)用于计时系统,可实现软件计时,或者使程序每隔一固定时间完成一项操作
为什么有Delay函数了还要用什么定时器呢?
(2)Delay函数在使用时,CPU是被占用的,不能进行别的操作。而定时器是和主程序同时进行的,可以替代长时间的Delay,提高CPU的运行效率和处理速度
二,STC89C52定时器资源
定时器个数:
3个(T0、T1、T2),T0和T1与传统的51单片机兼容,T2是此型号单片机增加的资源
注意:定时器的资源和单片机的型号是关联在一起的,不同的型号可能会有不同的定时器个数和操作方式,但一般来说,T0和T1的操作方式是所有51单片机所共有的
三,定时器框图
看明白这个流程图哦
四,定时器工作模式
这里涉及到或门和与门的相关知识:
以与门为例介绍一下简单的逻辑电路:
2个引脚都置为高电平的时候:
二极管与电阻没有压降,所以输出是5V。为高电平
如果2个引脚一个为高电平,一个为低电平的时候:
这个电路里面有电流流过,二极管与电阻有压降,所以输出的电压为0.7V,为低电平。
定时器的工作模式:
这里注意SYSclk的分频我们选择的是12分频,然后6分频是要在烧写软件里面手动确认,这是因为51单片机没有AUXR(辅助寄存器),所以没法设置分频。,如下图所示:
还有关于定时器误差的计算:
这里的误差主要产生于系统频率与分频数的联系不大(倍数关系之类的),而且定时长度比较小,所以,这里计数1,相当于在12MHz计数:1x(12/fosc) ,fosc=11.0592MHz,所以得实际计时时间是:1.08506s,误差计算:(1.08506-1)/ 1=0.0851
五,中断系统及其流程
实际上单片机的优先级配置比较复杂这里我们只说两种优先级,方便理解(一般有四种优先级可以配置)
六,STC89C52中断资源
中断源个数:8个(外部中断0、定时器0中断、外部中断1、定时器1中断、串口中断、定时器2中断、外部中断2、外部中断3)
中断优先级个数:4个
中断号:
七,定时器与中断系统
定时器已经在之前的工作原理里面介绍了,下面主要是要介绍一下Interrupt是个什么东东?
传统的STC89C52的中断系统有4个优先级配置起来就比较复杂(主要是我们就配置了一个定时器中断,不是他优先还是谁优先,嘿嘿,所以我们不必搞得那么复杂)
这我们这我们之前在中断系统里面也聊过,但是还是给大家上图片看看:
这是传统的STC89C52的中断系统结构图
为了方便讲解,这里使用的中断系统图是传统51单片机的中断系统结构图,都是一样的哈,只不过说传统51单片机只有2个优先级,看着比较明白,方便理解:
在这里我们配置的是定时器1,看T0哪一行就好了
八,相关寄存器的认识与配置
配置一句两句说不清楚,而且不是很权威,所以我引用手册上面的介绍
首先是定时器模式的配置(TMOD)
这里对几种工作模式进行简单的介绍:
一,13位定时/计数器方式
计数值为N和初值X关系: X=8192-N /(12/fosc)
上次计数完,计数器值为0,要重复计数需重置初值。
(即在中断函数中将TH0,TL0,TH1,TL1置初值)
二,16位定时/计数器方式
计数值为N和初值X关系: X=65536-N/(12/fosc) { X=65536-N*(fosc/12) }
上次计数完,计数器值为0,要重复计数需重置初值。
如果上面的公式fosc与12不知道谁在分子谁在分母,那么其实可以假设fosc为11.0592Mhz,它比12Mhz计数慢(每个周期更大)可以以12Mhz为基准的话,在以11.0592Mhz为系统时钟的时候,相同的时间,11.0592Mhz计数少。所以就需要乘以一个小于1的数,即(fosc/12)
三,8位自动重置定时/计数器
四,8位定时/计数器(只有配置T0才能使用)
计数值为N和初值X关系: X=256-N /(12/fosc)
上次计数完,计数器自动重置初值。不需用户重置。
在一,二,三,四中fosc为晶振频率,51单片机一般为12MHz或者11.0592MHz
我们在使用定时器的时候一般使用的是模式二,16位定时/计数器方式
这里来详细讲讲12分频的过程,12MHz的系统时钟经过12分频以后,其频率变为1MHz,自然知道他的周期为1us,即在一个周期内计数为1。 所以自然:X=65536-N。而如果系统时钟是11.0592MHz那么,12分频后的的频率为(11.0592/12.0000)MHz,周期为(12.0000/11.0592)us,所以有等比式:(12.0000/11.0592)us /(xus)=(1)/(?),其中x为想要定时的时长(单位us),(?)则是需要计数的值。
其次是中断系统的配置:
这里的IT1与IT0的配置中,对于低电平触发与低电平触发可能会有些疑问:
低电平触发:
低电平触发中断顾名思义,就是检测到引脚为低电平就触发,从而进入中断函数中处理这个中断,并且在高或低电平保持的时间内持续触发,假设是低电平触发,只要引脚为低电平时间内中断一直有效,那么就会一直进入中断,直到电平变化为高电平
低电平触发:
数字电路中,数字电平从高电平(数字“1”)变为低电平(数字“0”)的那一瞬间叫作下降沿。 下降沿触发是当信号有下降沿时的开关动作,当电位由高变低而触发输出变化的就叫下降沿触发。也就是当测到的信号电位是从高到低也就是下降时就触发,叫做下降沿触发。
那么我们可以很好的理解两种触发:
上升沿触发 就是当电压从低变高时触发中断
下降沿触发 就是当电压从高变低时触发中断
当然,上升沿与下降沿检测的是电平变化的一瞬间,就会产生中断,这个时间是us级别的,但是如果中断引脚检测到一直保持低/高电平,则无法产生下次中断,也就是中断只会触发一次,只有在下次电平发生变化时才会重新触发中断
对照着中断图一起看思路会比较清晰
如果实在看不明白,全部置1也是没有问题的(下面的代码优先级PT0置的是0表示默认优先级,我们置1也是没有问题的)
九,定时器时钟代码演示
下面的是定时器的寄存器的相关配置:
系统时钟为12MHz的情况,即fosc=12.00MHz,计数值为N和初值X关系: X=65536-N/(12/fosc)公式就变成了X=65536-N
下面是中断函数的内容,包括:
1,重新设置定时器的TH0与TL0的初值,
2,一个计次计时的模块
3,最后是中断函数的主体部分也就是时,分,秒的进制关系(一般根据需求替换这一部分)
源代码如下:
#include <REGX52.H>
/**
* @brief 定时器0初始化,1毫秒@12.000MHz
* @param 无
* @retval 无
*/
void Timer0Init(void)
{
TMOD &= 0xF0; //设置定时器模式
TMOD |= 0x01; //设置定时器模式
TL0 = 0x18; //设置定时初值
TH0 = 0xFC; //设置定时初值
TF0 = 0; //清除TF0标志
TR0 = 1; //定时器0开始计时
ET0=1;
EA=1;
PT0=0;
}
/*定时器中断函数模板
void Timer0_Routine() interrupt 1
{
static unsigned int T0Count;
TL0 = 0x18; //设置定时初值
TH0 = 0xFC; //设置定时初值
T0Count++;
if(T0Count>=1000)//在中断函数中重新进行计次,这里是每1s进行一次相关操作,注意写中断函数时一定要和定时器配套写(即定时器的声明/初始化)
{
T0Count=0;
}
}
*/
void Timer0_Routine() interrupt 1
//中断函数中不可以加LCD这样的耗时过长的语句,显示的工作交由main(),否则会有L15报错
{
static unsigned int T0Count;
TL0 = 0x18; //设置定时初值
TH0 = 0xFC; //设置定时初值
T0Count++;
if(T0Count>=1000)//每1s进行一次相关操作
{
T0Count=0;
miao++;
if(miao>=60){
miao=0,fen++;
}
if(fen>=60){
shi++;fen=0;miao=0;
if(shi>=24)shi=0;
}
}
}
最后,小白一个,有什么不足的地方还请各位大佬指出,谢谢大家。