前言
在实时控制系统中,经常需要定时时钟以实现精准延时、定时,也经常需要计数功能以实现对外界脉冲进行计数, 本节,我们开始学习51单片机的定时器,然后开启一个定时器,实现1S翻转一次电平,控制LED灯亮灭。
一、基础知识
1.定时器简介
51单片机的定时器有两个,分别是T0和T1,它们可以用于定时或者对外部脉冲(事件)计数,还可以作为串行口的波特率发生器使用,定时器裸机结构图如下所示
定时器工作在定时方式时候,计数器对内部时钟机器周期数进行计数,每个机器周期等于12个晶体震荡周期,定时器工作在计数方式时候,计数脉冲来自外部输入引脚P3.4、P3.5,当外部输入信号从1到0跳变时,计数器的值加一。
2.定时器相关寄存器
(1) 控制寄存器TCON(88H)
TCON用于控制定时器的启动、停止、溢出标志和外部中断信号触发方式。
(2) 方式控制寄存器TMOD(89H)
从上图中可知,GATE为0时候,定时器由TR0或TR1控制启动,为1的时候,只有在外部中断引脚为高电平时候,TR0或者TR1才可以控制启动,对于T1,有3种工作方式,而T0有四种工作方式;
3.定时器工作方式
定时器工作方式如下
(1) 工作方式0
方式0为13位计数器,由TLi的低5位和THi的8位组成,当GATE为1的时候,取反为0,定时器启动需要外部中断i引脚为1,然后置位TRi启动定时器,当外部中断i引脚变为0时候,定时器停止计数,这种方式可用来测试外部中断引脚正脉冲的宽度,当处于计数模式时,计数脉冲是Ti引脚上的外部脉冲。
定时模式初值:
X = 2的13次方 - f/12 * T (其中X为计数器初值, f为时钟频率,T为定时时间)
计数模式初值:
X = 2的13次方 - 计数值
(2) 工作方式1
方式1和方式0结构几乎完全相同,唯一区别是计数器的长度不同,方式1定时器长度为16位
定时模式初值:
X = 2的16次方 - f/12 * T (其中X为计数器初值, f为时钟频率,T为定时时间)
计数模式初值:
X = 2的16次方 - 计数值
(3) 工作方式2
方式2是能自动重装载计数初值的8位计数器, TLi用作计数器,THi保存计数初值,当TLi计数溢出时,将TFi位置1,同时又将保存在高8位中的计数初值重新装入低8位计数器中。
定时模式初值:
X = 2的8次方 - f/12 * T (其中X为计数器初值, f为时钟频率,T为定时时间)
计数模式初值:
X = 2的8次方 - 计数值
(4) 工作方式3
方式3只有T0支持,T1不支持,若将T1设置为方式3,T1会立即停止计数,且方式3相比其他几种方式,方式3只用了TL0计数器,其他操作和方式0、方式1相同。
注意:通常定时器中定时使用方式1,串口通信使用方式2
二、实例
1.创建工程
将上一节工程复制出来,并修改名字为07-timer
2.程序
我们使用定时器T0的方式1实现一个20ms的中断,中断服务程序中软件计数,当达到50次,总计1S时候,翻转LED引脚电平
首先,计算初值X
X = 2的16次方 - f/12 * T (其中X为计数器初值, f为11.0592MHZ,T为0.02S)
X = 47104 = 0xB800
然后初始化定时器
void tiemr_init(void)
{
TMOD = 0x01; //使用模式1,16位定时器
TH0 = 0xB8;
TL0 = 0x00;
EA=1; //总中断打开
ET0=1; //定时器中断打开
TR0=1; //定时器开关打开
}
中断服务子程序
void timer0_func() interrupt 1
{
TH0 = 0xB8;
TL0 = 0x00;
if (count >50)
{
LED = ~LED;
count = 0;
}
count ++;
}
完整代码
/*------------------------------------------------------
*店铺网址:https://shop321633213.taobao.com/?spm=a1z10.3-c.0.0.33816af5iLgN2F
*适用于A08开发板
*实验现象:定时器中断实现LED 1S亮灭
*QQ群:906015840
-------------------------------------------------------*/
#include<reg51.h> //头文件
#include <intrins.h>
#define uchar unsigned char
#define uint unsigned int
sbit LED = P1^0;
int count = 0;
void tiemr_init(void)
{
TMOD = 0x01; //使用模式1,16位定时器
TH0 = 0xB8; // 20ms中断,初值0xB800
TL0 = 0x00;
EA=1; //总中断打开
ET0=1; //定时器中断打开
TR0=1; //定时器开关打开
}
void main(void) //主函数
{
tiemr_init();
while(1);
}
// 20ms进入一次中断,计数50次为一秒
void timer0_func() interrupt 1
{
TH0 = 0xB8;
TL0 = 0x00;
if (count >50)
{
LED = ~LED;
count = 0;
}
count ++;
}
注意:中断子程序中需要重新装载计数器初值
三、运行
将上述程序生成的hex文件烧录到板子中,可以看到P1^0对应LED灯每隔1秒亮灭一次,说明进入定时器中断程序执行成功。
四、结语
如您在使用过程中有任何问题,请加QQ群进一步交流。
QQ交流群:906015840 (备注:物联网项目交流)
源码获取:扫描下方二维码,关注公众号,回复"51单片机"即可
硬件获取:淘宝搜索店铺"小驿物联"。
一叶孤沙出品:一沙一世界,一叶一菩提