周期的概念
- 振荡周期:为单片机提供定时信号的振荡源的周期(晶振周期或外加振荡周期)。
- 状态周期:2个振荡周期为1个状态周期,用S表示。振荡周期又称S周期或者时钟周期。
- 机器周期:1个机器周期为6个状态周期,即12个振荡周期。
- 指令周期:完成1条指令所占用的全部时间,它以机器周期为单位。例如:外接晶振为12MHz时,51单片机相关周期的具体指为:
- 振荡周期 = 1/12 us;
- 状态周期 = 1/6 us;
- 机器周期 = 1 us;
- 指令周期 = 1~4 us;
PS:单位之间的换算
1s = 1000ms
1ms = 1000us
1us = 1000ns
1ns = 1000ps
定时器相关知识
- 51单片机有两组定时器/计时器;
- 定时器和CPU是相互独立的,定时器根据机器内部的时钟或者是外部的脉冲信号对寄存器中的数据加一;
- STC89C5X单片机内由两个可编程的定时器/计数器T0、T1和一个特殊功能定时器T2。定时器/计数器的实质是加一计数器(16位),由高八位和第八位两个寄存器THx和TLx组成。
计数值 = 溢出时计数器的值 - 计数初值 - 51单片机定时器/计数器的内部结构
T0和T1分别对应P3.4和P3.5管脚。
▶ 工作方式的选择:
通过工作方式寄存器TMOD可以设置定时/计数的工作方式,其中第四位用于T0,高四位用于T1。TCON为控制寄存器,用来控制定时器/计数器的启动和中断申请。
▶ 不同工作方式的结构图:
方式0:
方式1:
方式2:
方式3:
⚠ PS:逻辑运算符
定时器配置
- 对TMOD赋值,确定工作方式;
- 根据要定时的时间计算初值,并将其写入TH0,TL0,TH1,TL1;
- 如使用12MHz的晶振,则:
- 振荡周期:1/12 us;
- 状态周期:1/6 us;
- 机器周期:1 us;
如果想定时1ms,即1000us,则需要1000/1 = 1000个机器周期,即需要计数1000次,初值为
X = 65535 - 1000 + 1 = 64536
(因为实际上计数器计数到65536)。64536的十六进制为:0x1741
,即定时器/计数器的初值为THx = 0xFC
,TLx = 0x18
。(十六进制的一位是二进制的4位) - 如使用12MHz的晶振,则:
- 如果使用中断,需要对EA(总中断)赋值,开放定时器中断;
- 使TR0或者TR1置位,启动定时器/计数器。
PS:定时器/计数器的定时时间有限,上限是2^16 = 65536
。
定时器实例
使用定时器实现流水灯(灯全亮,不亮的灯每一秒移动一个)。
代码:
#include "REG52.H"
#include "INTRINS.H"
typedef unsigned int u16;
typedef unsigned char u8;
#define LED P2
// 定义定时器初始化函数
void Timer0Init() {
// 用|防止配置冲突
TMOD |= 0x01; // 设置定时器0的工作模式为定时器,工作方式为1,仅使用TR0启动
TH0 = 0xFC; // 给定时器赋初值,定时为1ms
TL0 = 0x18;
EA = 1; // 打开总中断
ET0 = 1; // 打开定时器0中断
TR0 = 1; // 打开定时器
}
void main() {
LED = 0x01;
Timer0Init();
while (1) {};
}
// 定时器0中断回调函数
void Timer0() interrupt 1 {
u16 flag;
TH0 = 0xFC;
TL0 = 0x18;
flag++;
if(flag == 1000){
flag = 0;
// _crol_函数是库函数"INTRINS.H"中的,按位左移
LED = _crol_(LED,1);
}
}