定时/计数器
定时/计数器概述
概述
- T0 and T1 编程选用作为定时器或计数器。
- 不占用CPU时间(delay)
引脚
- TCON定时器控制寄存器&TMOD定时器方式寄存器。
原理
-
加一计数器
-
通过软件设置为4种工作方式,每种方式都可以 用作定时或计数
-
当设置了工作方式,并启动定时器/计数器工作 后,对内部时钟或对外部事件计数,均按照设定的工作方式独立工作,不再占用CPU的时间, 只有在计数器溢出时,才会中断CPU当前的操作
-
CPU可以随时重新设置定时器的工作方式,改变定时器的操作
-
作为定时器
-
每一个机器周期加1,即对片内振荡器的12分频信号计数,直至计数器溢出为止;
计数周期 T = 1 f osc × 1 12 计数周期\\ T=\frac{1}{f_{\text {osc }} \times \frac{1}{12}} 计数周期T=fosc ×1211
osc:晶振oscillator
-
作为计数器
-
对来自引脚T0(P3.4)和T1(P3.5)的外部信号进行计数;
-
外部脉冲的下降沿触发计数;
-
在每个机器周期的S5P2期间采样引脚的电平,若前一个机器周 期采样值为1,后一个机器周期采样值为0,则计数器加1。在下 一个机器周期的S3P1期间,计数器值更新
-
因此,检测一个从1到0的跳变需要2个机器周期,所以,对外部 事件的最高计数频率为振荡器频率的1/24
控制方法
- TMOD
- 设置工作方式以及控制模式
-
TCON
-
控制定时器启停
MOV TMOD #53H SETB TR1;启动定时器1 CLR TR0;关闭定时器0 //初始化
手册
使定时器1为计数工作方式,软件启动,按方式1工 作;定时器0为定时方式,软件启动,按方式3工作
定时器/计数器初值的设定方法
-
M: 定时器的最大计数值;
-
X: 初值
-
X = M − 计数值 X=M-计数值 X=M−计数值
example:
时钟频率6MHz,16位模式,要求产生1ms定时:
计数周期 = 1 f osc × 1 12 = 2 μ s 计数值 = 1 m s 2 μ s = 500 初值 = M − 计数值 = 65536 − 500 = 65036 计数周期=\frac{1}{f_{\text {osc }} \times \frac{1}{12}}=2\mu s\\计数值=\frac{1ms}{2\mu s}=500\\初值 = M -计数值 = 65536 - 500 = 65036 计数周期=fosc ×1211=2μs计数值=2μs1ms=500初值=M−计数值=65536−500=65036
工作方式
定时/计数器T0/T1的工作方式
-
方式0 13位定时/计数方式,由THx提供高8 位、TLx提供低5位的计数初值,最大计数值为
M = 2 13 = 8192 M=2^{13}=8192 M=213=8192
,每次启动计数前均需预置计数初值。 -
方式1 16位定时/计数方式
-
最大计数值为
M = 2 16 = 65536 M=2^{16}=65536 M=216=65536 -
由THx和TLx寄存器各提供8位计数初值,每次 启动计数前均需预置计数初值
-
-
方式2
-
方式3
看门狗定时器(重要)
- WDT: watchdog timer
- 功能——微控制器不正常工作时,产生一个复位信号
- 系统软件工作不正常时,产生复位信号,防止程序进 入不可预料操作
定时/计数器的主要功能
- 定时
- 计数
- 输入捕捉
- 输出比较
应用举例
基本信息
初始化——将控制字写入定时器/计数器的过程
确定工作方式——工作方式控制字写入方式寄存器 TMOD;
预置定时或计数的初值——直接将初值写入TH0,TL0 或TH1,TL1;
中断控制: 根据需要开放定时/计数器的中断——直接对IE寄存器的定时器 中断位赋值;
启动定时/计数器,启动方式由TMOD寄存器的GATE 位确定;
若软件启动,置位TR0或TR1;
若由外中断引脚电平启动,则给相应引脚加启动电平
TIMER
-
用定时器T1定时,完成日历时钟秒、 分、时的定时,晶振为12MHz
定时器的计时周期为一个机器周期,即:
T 计时周期 = 1 f osc × 1 12 = 1 μ s T_{计时周期}=\frac{1}{f_{\text {osc }} \times \frac{1}{12}}=1\mu s T计时周期=fosc ×1211=1μs
最大计数值=65536 选择50ms作为定时周期,则: 50000= 65536−M 即定时器初值:M=15536
ORG 0000H
LJMP MAIN
ORG 0100H
MAIN: MOV 50H,#20
MOV R1,#0
MOV R2,#0
MOV R3,#0
MOV TMOD,#10H
MOV TH1,#3CH
MOV TL1,#0B0H
SETB TR1
L1: JNB TF1,L1 ;jump to L1 if TF1=0(TF=1 when overflow)
CLR TF1 ;clear by software in query mode
MOV TH1,#3CH
MOV TL1,#0B0H
DJNZ 50H,L1 ;(50H)-=1,jump to L1 if (50H) <> 0
MOV 50H,#20
INC R1
CJNE R1,#60,L1 ;jump to L1 if (R1)<>60
MOV R1,#0
INC R2
CJNE R2,#60,L1
MOV R2,#0
INC R3
CJNE R3,#24,L1
MOV R3,#0
SJMP L1
END
这段代码使用了8051微控制器的指令集来实现一个定时器循环计数器。在程序执行过程中,定时器1被设置为10H模式,初始计数值为3CH和0B0H,当定时器1溢出时(TF1标志位为1),程序会执行特定操作,并继续循环,直到R1、R2和R3寄存器的值分别达到60、60和24为止。from chatGPT
ORG 0000H ; 设置程序起始地址为0000H
LJMP MAIN ; 无条件跳转至MAIN标签
ORG 0100H ; 设置程序的内存地址为0100H
MAIN: ; 主程序入口标签
MOV 50H, #20 ; 将数据20H加载到寄存器50H中
MOV R1, #0 ; 将0加载到寄存器R1中
MOV R2, #0 ; 将0加载到寄存器R2中
MOV R3, #0 ; 将0加载到寄存器R3中
MOV TMOD, #10H ; 初始化定时器模式为10H
MOV TH1, #3CH ; 初始化定时器1的高位计数器为3CH
MOV TL1, #0B0H ; 初始化定时器1的低位计数器为0B0H
SETB TR1 ; 启动定时器1
L1:
JNB TF1, L1 ; 如果TF1标志位为0,则跳转到L1标签(TF1在定时器溢出时为1)
CLR TF1 ; 通过软件清除TF1标志位(在查询模式下)
MOV TH1, #3CH ; 重新加载定时器1的高位计数器为3CH
MOV TL1, #0B0H ; 重新加载定时器1的低位计数器为0B0H
DJNZ 50H, L1 ; (50H)-=1,如果(50H)不等于0,则跳转到L1标签
MOV 50H, #20 ; 重新将数据20H加载到寄存器50H中
INC R1 ; R1寄存器加1
CJNE R1, #60, L1 ; 如果R1不等于60,则跳转到L1标签
MOV R1, #0 ; 将0加载到寄存器R1中
INC R2 ; R2寄存器加1
CJNE R2, #60, L1 ; 如果R2不等于60,则跳转到L1标签
MOV R2, #0 ; 将0加载到寄存器R2中
INC R3 ; R3寄存器加1
CJNE R3, #24, L1 ; 如果R3不等于24,则跳转到L1标签
MOV R3, #0 ; 将0加载到寄存器R3中
SJMP L1 ; 无条件跳转到L1标签
END ; 程序结束标签
##code from chatGPT
#include "main.h"
UINT8 u8_s,u8_m,u8_h,u8_TNcnt; //秒、分、时、定时器计数值
//UINT8 TH1_Val,TL1_Val; //计算需要时间较长,可提前计算
void main(void)
{
//变量初始化
u8_s=0;
u8_m=u8_h=0;
u8_TNcnt=T_NUM;
//定时器初始化
TMOD=0x10; //00010000定时器1:模式1,16位定时器
TH1=TH_N; //定时器赋初值
TL1=TL_N;
TR1=1; //启动定时器
while (1)
{
if(TF1==1)
{
TF1=0; //查询方式下需要软件清0
TH1=TH_N;
TL1=TL_N;
u8_TNcnt--;
if(u8_TNcnt==0) //=0后就是溢出
{
u8_TNcnt=T_NUM;
u8_s++;
if(u8_s>=60)
{
u8_s=0;
u8_m++;
if(u8_m>=60)
{
u8_m=0;
u8_h++;
if(u8_h>=24)
{
u8_h=0;
}
}
}
}
}
}
}
//main.h
#ifndef __MAIN_H__
#define __MAIN_H__
#ifdef __cplusplus
extern "C" {
#endif
//头文件
#include <reg51.h>
//变量类型
typedef unsigned char UINT8;
typedef unsigned int UINT16;
//宏定义
#define F_CLK 12000000
#define T_PERD 1000000
#define TIMER_PERD 50000
#define TH_N (65536-(TIMER_PERD/(1000000/(F_CLK/12)))) / 256
#define TL_N (65536-(TIMER_PERD/(1000000/(F_CLK/12)))) % 256
#define T_NUM (T_PERD/TIMER_PERD)
#if ((1000000/(F_CLK/12))==0)
#error "parameters error"
#endif
#ifdef __cplusplus
}
#endif
#endif