51单片机定时器/计数器中断
一、定时器/计数器
1-1 定时器
❤ CPU时序相关知识点
振荡周期:为单片机提供定时信号的振荡源的周期
状态周期:2个振荡周期为1个状态周期,其中振荡周期又称为时钟周期
机器周期:1个机器周期含6个状态周期,12个振荡周期(即12个时钟周期)
指令周期:完成1条指令所占用的全部时间,它以机器周期为单位。
例如:外接晶振为12MHZ时,51单片机相关周期的具体值为:
振荡周期=1/12MHZ=1/12 us
状态周期=2*振荡周期=1/6 us
机器周期=6状态周期=12振荡周期=1 us (定期/计算器的计数基本单位)
指令周期=1~4 us
❤ 定时器相关知识点
51单片机有两组定时/计数器;因为既可以定时,又可以计数,故称为定时/计数器
定时/计数器和单片机的CPU是相互独立的。定时/计数器工作过程是主动完成的,不需要CPU的参与
51单片机中的定时/计数器是根据机器内部的时钟或外部的脉冲信号对寄存器中的数据加1
STC89C5X 单片机内有两个可编程的定时/计数器T0、T1 和一个特殊功能定时器T2。
定时/计数器的实质是加1 计数器(16 位),由高8 位和低8 位两个寄存器THx 和TLx 组成。
它随着计数器的输入脉冲进行自加1,也就是每来一个脉冲,计数器就自动加1,当加到计数器为全1 时,再输入一个脉冲就使计数器回零,且计数器的溢出使相应的中断标志位置1,向CPU 发出中断请求(定时/计数器中断允许时)。如果定时/计数器工作于定时模式,则表示定时时间已到;如果工作于计数模式,则表示计数值已满。可见,由溢出时计数器的值减去计数初值才是加1 计数器的计数值
1-2 定时/计数器相关寄存器
定时/计数器0、1对应单片机的P3^4
、P3^5
引脚
51单片机定时/计数器的工作由两个特殊功能寄存器控制。其中TMOD寄存器
是控制工作方式和功能(即定时或计数),TCON寄存器
是控制启动和停止的溢出标志
❤ 工作方式寄存器TMOD(不可为寻址)
低四位用于T0,高四位用于T1
GATE是门控位,用于控制定时器的启动是否受外部中断源信号的影响
C/T表示定时/计数器模式选择位;C/T=0为定时模式,C/T=1为计数模式
M1、M0表示工作方式置位。有4种组合方式,构成4中工作方式(方式1是最常用的)
❤ 控制寄存器TCON(可为寻址)
TCON的低4位用于控制外部中断,高4位用于控制定时/计数器的开启和中断请求
TF1:表示T1溢出中断请求标志位,当T1计数溢出,由硬件自动将TF1置1(即TF1=1)。CPU响应中断后,TF1由硬件自动清0(即TF1=0)。当然TF1也可以用软件置1或清0,跟硬件置1或清0达到一样的效果。
TR1:表示T1的运行控制位,当TR1置1时,T1开始工作;TR1置0时,T1停止工作。TR1由软件置1或清0。所以用软件控制定时/计数器的启动与停止
TF0、TR0类比TF1、TR1
二、定时器/计数器T0中断实验
❤ 实验目的:每个1s点亮LED模块,每个1s熄灭LED模块
❤ 思路:使用定时/计数器T0算好定时1s时间,然后在中断函数中执行亮灭操作
计算定时/计数器T0的初值,选择方式1(16位寄存器 取值范围:0~63325),从初值0x00开始计数,定时中断时长:65536(晶振频率/12)= 65536(11.0592MHz/12) = 60,397.9776 us
通过调整初值,可以定义定时中断时长:定时时长 = (65536-初值)*[1000/(晶振频率/12]
很显然一次中断时长无法达到1s,可以选择多次中断积累;若选择定时时长为1000us,则需要中断积累1000次
1000us的定时触发的寄存器初始值:65536-[1000/(晶振频率/12)]
即 65536-[1000/(11.0592/12)] = 65536-1085 = 64451
转换成16进制 0xFBC3
❤ 实验代码
#include<REG52.h>
// 定时器0中断函数
void led_flash_t0() interrupt 1
{
static unsigned i; //静态局部变量累计中断次数(每次中断为1ms)
TH0 = 0xFB; //重新复位
TL0 = 0xC3;
i++;
if(i == 1000) //定时1s条件
{
i=0;
P2 = ~P2;
}
}
// 定时/计数器T0中断初始化
void time0_init(void)
{
TMOD=0x01; //选择定时/计数器T0模式,工作方式1(即16位寄存器计数)
TH0 = 0xFB; //给定时/计数器T0赋初值,定时1ms;可以通过51定时器计算工作得知
TL0 = 0xC3;
ET0=1; //开启定时/计数器T0中断允许
TR0=1; //打开定时/计数器T0
EA=1; //开启中断总允许
}
void main(void)
{
time0_init();
while(1)
{
}
}
❤ 实验结果
每个1s点亮LED模块,每个1s熄灭LED模块,熄灭状态就不放图了