![cover](https://img-blog.csdnimg.cn/direct/96ccb4cd0dd3468991ae29801ea82289.png)
【单片机】C51中的定时/计数器介绍
51单片机的定时器/计数器介绍
C51定时器和计数器
开发板:普中51-单核-A2;
仿真软件:proteus;
开发环境:Keil4;
参考资料:开发板所附视频;
如有错误,感谢指正。如有侵权请联系博主。
定时器原理
与CPU时序有关的知识
- 振荡周期:为单片机提供定时信号的振荡源的周期(晶振周期或外加振荡周期);
- 状态周期:2个振荡周期为1个状态周期,用S表示。振荡周期又称为S周期或时钟周期;
- 机器周期:1个机器周期含有6个状态周期等于12个震荡周期;
- 指令周期:完成1条指令所占用的全部时间,它以机器周期为单位;
T 机器周期 = 6 ∗ T 状态周期 = 12 ∗ T 振荡周期 T_{机器周期} = 6*T_{状态周期} = 12*T_{振荡周期} T机器周期=6∗T状态周期=12∗T振荡周期
若振荡周期为12MHz,那么 T 振荡周期 = 1 / 12 u s T_{振荡周期} = 1/12us T振荡周期=1/12us, T 机器周期 = 12 ∗ T 振荡周期 = 1 u s T_{机器周期} = 12*T_{振荡周期}=1us T机器周期=12∗T振荡周期=1us。指令周期通常是 1 4 u s 1~4us 1 4us.
- 51单片机有两组定时器/计数器。既可以定时,又可以计数。
- 定时器/计数器和单片机的CPU是相互独立的,定时器/计数器工作的过程是自动完成的,不需要CPU参与。
- 51单片机中的定时器/计数器是根据机器内部的始终或者外部的脉冲信号对寄存器中的数据加1.
- 有了定时器/计数器之后,可以增加单片机的效率,一些简单重复加1的工作可以交给定时器/计数器处理。CPU去处理一些复杂的事情,同时可以实现精确的定时作用。
定时器/计数器的工作原理
定时器/计数器实质是一个加1计数器。随着计数器的输入脉冲进行自加1,即每来一个脉冲,计数器就自动加1,当计数器全部为1时,再输入一个脉冲就是计数器回零。且计数器的溢出使响应的中断标志位置1,向CPU发出中断请求(定时器/计数器中断允许时)。
如果定时器/计数器工作于定时模式,则表示定时时间已到;如果工作于计数模式,则表示计数值已满。
由溢出时计数器的值减去计数初值是加1计数器的计数值。
51单片机定时器结构
定时器/计数器的实质是加1计数器(16位),由高8位和低8位两个寄存器THx和TLx组成。
TMOD
是定时器/计数器的工作方式寄存器,用以确定工作方式和功能;TCON
是控制寄存器,控制T0、T1的启动和停止及设置溢出标志。
TMOD
工作方式寄存器
TMOD低四位用于T0,高四位用于T1。
位 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | |
---|---|---|---|---|---|---|---|---|---|
字节地址: 89 H 89H 89H | G A T E GATE GATE | C / T ‾ C/\overline{T} C/T | M 1 M1 M1 | M 0 M0 M0 | G A T E GATE GATE | C / T ‾ C/\overline{T} C/T | M 1 M1 M1 | M 0 M0 M0 | T M O D TMOD TMOD |
-
G
A
T
E
GATE
GATE:门控位,用于控制定时器的启动是否受外部中断源信号的影响
- G A T E = 0 GATE=0 GATE=0时,只要软件使TCON种的TR0或TR1为1,就可以启动定时器/计数器;
- G A T E = 1 GATE=1 GATE=1时,要用软件TR0或TR1为1,同时外部中断引脚INT0/1也为高电平时,才能启动定时器/计数器工作,即此时定时器的启动工作加上了INT0/INT1引脚为高电平这一条件。
- C / T ‾ C/\overline{T} C/T:定时/计数器模式选择位
- C / T ‾ = 0 C/\overline{T}=0 C/T=0,为定时模式;
- C / T ‾ = 1 C/\overline{T}=1 C/T=1,为计数模式;
- M 1 M 0 M1M0 M1M0,工作方式设置位,有4种工作方式,经常使用方式1和方式2
M 1 M 0 M1M0 M1M0 | 工作方式 | 说明 |
---|---|---|
00 | 方式0 | 13位定时/计数器 |
01 | 方式1 | 16位定时/计数器 |
10 | 方式2 | 8位自动重装定时/计数器 |
11 | 方式3 | T0分成两个独立的8位定时/计数器,T1此方式停止计数 |
TCON
控制寄存器
TCON低四位控制外部中断,TCON高4位控制定时/计数器的启动和中断的申请。
位 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | |
---|---|---|---|---|---|---|---|---|---|
字节地址: 88 H 88H 88H | TF1 | TR1 | TF0 | TR0 | IE1 | IT1 | IE0 | IT0 | TCON |
- TF1(TCON.7):T1溢出中断请求标志位,T1计数溢出时由硬件自动置为1,CPU响应中断后TF1由硬件自动清0.T1工作时,CPU可随时查询TF1的状态,可以用TF1作为查询测试的标志。TF1也可以用软件置1或清0,同硬件置1或清0效果一样。
- TR1(TCON.6):T1运行控制位,软件置1或清0,软件可控制定时/计数器的启动于停止
- TR1=1,T1开始工作;
- TR1=0,T1停止工作;
- TF0:与TF1类似
- TR0:与TR1类似
定时/计数器的工作方式
方式0
方式0为13位计数,由TL的低5位和TH的8位组成。
定时器模式时: N = t / T c y N=t/T_{cy} N=t/Tcy;定时器的初值可以采用计数个数直接取补法获得;
计数初值计算公式: X = 2 13 − N X=2^{13}-N X=213−N,计数模式时,技术脉冲是T0引脚上的外部脉冲。
GATE决定是否由外部中断源信号触发。
方式1
方式1为16位计数,由TL的8位和TH的8位组成。
计数初值计算公式: X = 2 16 − N X=2^{16}-N X=216−N。
方式2
方式2为自动重装初值的8位计数方式。计数初值计算公式: X = 2 8 − N X=2^{8}-N X=28−N。
适合用于精确的脉冲信号发生器。
方式3
方式3只适用于定时/计数器T0,定时器T1处于方式3相当于TR=0,停止计数。
方式3将T0分为两个独立的8位计数器TL0和TH0。
使用定时器
初始化程序应该完成如下
- 对TMOD赋值,确定T0和T1的工作方式;
- 计算初值,并将其写入TH0、TL0或TH1、TL1。
- 中断方式时,需要对总中断EA置1,开放定时器中断;
- 使TR0或TR1置位,启动定时/计数器定时或计数。
计数器初值计算
定时1ms的初值计算: 1 m s / 1 u s = 1000 1ms/1us=1000 1ms/1us=1000,即累计1000个数,初值 = 65535-1000+1(实际上计数器计数到65536时才溢出,所以加1)。
1 u s 1us 1us是假设晶振频率是12MHz,那么机器周期就为 1 u s 1us 1us。
示例
/*
使用定时器0实现LED间隔一秒亮-灭 精确时间
*/
#include "reg52.h"
typedef unsigned char u8;
typedef unsigned int u16;
sbit LED=P2^0; // D1
// 定时器0初始化
void Timer0Init()
{
// 1. TMOD赋值,确定T0和T1的工作方式
// M1M0=01表示使用方式1,
// C/T=0表示使用定时模式,
// GATE=0表示仅使用TCON控制
TMOD |= 0x01; // 置M0=1
// 2. 计算初值,定时1ms, 65535-1000+1
TH0 = 0xFC;
TL0 = 0x18;
// 3. 开启中断
ET0=1; // 中断允许位置1
EA=1; // 打开总中断
//4. 打开定时功能
TR0=1;
}
void Timer1Init()
{
// 1. TMOD赋值,确定T0和T1的工作方式
// M1M0=01表示使用方式1,
// C/T=0表示使用定时模式,
// GATE=0表示仅使用TCON控制
TMOD |= 0x10; // 置M0=1
// 2. 计算初值,定时1ms, 65535-1000+1
TH1 = 0xFC;
TL1 = 0x18;
// 3. 开启中断
ET1=1; // 中断允许位置1
EA=1; // 打开总中断
//4. 打开定时功能
TR1=1;
}
void main()
{
Timer1Init();
while(1);
}
// 定时器0中断函数
void Timer0() interrupt 1
{
static u16 i=0;
// 重新装载初值TH0 TL0
TH0 = 0xFC;
TL0 = 0x18;
i++;
if(i==1000) // 表示1s了
{
i=0; // 清零i
LED = ~LED;
}
}
// 定时器1中断函数
void Timer1() interrupt 3
{
static u16 i=0;
// 重新装载初值TH1 TL1
TH1 = 0xFC;
TL1 = 0x18;
i++;
if(i==1000) // 表示已经1s
{
i=0; // 清零i
LED = ~LED;
}
}
结果显示:
![Logo](https://devpress.csdnimg.cn/79de2bf0b7994defa4242ef90d5513fa.jpg)
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)