硬件构成的定时/计数器在工作时不占用CPU 时间的优点,除非定时器/计数器溢出,才能中断 CPU 的当前操作,比使用循环程序产生延时要优越得多,可以提高 CPU 的效率
时钟系统
XTAL1 和 XTAL2 之间跨接晶体振荡器和微调电容,从而构成一个稳定的自激振荡器,MCS-51 振荡频率 6MHZ 或 12MHZ
机器周期:完成一个基本操作所需的时间,包含 12 个振荡周期 1 us 微秒
8051 定时器结构

- TH0 TL0 TH1 TL1
- TCON
- TMOD
T1 T0 定时器/计数器
十六位定时/计数器,由两个 8 位特殊功能寄存器构成
十六位计数器=高八位 (TH)+低八位 (TL) 计数器(Time High/Low TH/TL )
- 定时器 0
T0:TH0+TL0 - 定时器 1
T1:TH1+TL1
TCON 控制器寄存器
TCON 控制器寄存器 88H
除可字节寻址外,各位还可位寻址
低四位用于 外部中断
| 8FH | 8EH | 8DH | 8CH | 8BH | 8AH | 89H | 88H |
|---|---|---|---|---|---|---|---|
| TF1 | TR1 | TF0 | TR0 | IE1 | IT1 | TE0 | IT0 |
| T1 溢出标志 | T1 运行控制 | T0 溢出标志 | T0 运行控制 |
运行控制 TR:软件上的启动
置 1,来启动定时器
SETB TR1/TR0 启动定时器
置 0,来关闭定时器
溢出标志 TF:硬件上的标志位
定时器溢出时,硬件自动使得中断触发器置 1,并由 CPU 申请中断
CPU 响应中断进入中断服务程序后,会被硬件自动清 0, 也可软件清 0
如果进入到中断服务程序中,TF 会自动清零
但是如果只是查询方式溢出,未进入到中断服务程序中,要软件手动清零
TMOD 工作模式寄存器
TMOD 工作模式寄存器 89H
不可位寻址,只能用字节设置定时器的工作模式
- 低半字节设置T0
- 高半字节设置T1

| GATE | M1 | M0 | GATE | M1 | M0 | ||
|---|---|---|---|---|---|---|---|
| T1选通控制 | T1功能选择 | T1工作模式选择 | T1工作模式选择 | T0选通控制 | T0功能选择 | T0工作模式选择 | T0工作模式选择 |
GATE 选通控制
0:不受 控制
使计数器的 TR0 或 TR1 置 1就可启动对应的计数器 T0 或 T1
1:受 / 控制 先要硬件上的 / 的引脚为高电平 才能通过 TR0 或 TR1 置 1 启动对应的计数器
功能选择
0:定时方式 ,定时器计数 8051 片内脉冲,即对机器周期计数 定时器:数“内部时钟” → 计时。周期准,可做延时、波特率。
1:计数方式,计数器的输入来自T0(P3.4)或T1(P3.5)端的外部脉冲 计数器:数“外部脉冲” → 计数事件。测外部频率或事件个数。
M1 M0 工作模式选择
00:模式 0 13 位计数器 0 1:模式 1 16 位计数器 1 0:模式 2 自动再装入 8 位计数器,自动重装载 1 1:模式 3 T0 分成两个 8 位计数器,T1 停止计数
模式 1
16 位计数器 在这种模式下,16位寄存器(TH0和TL0)用于装载计数/定时的初值。启动定时器后, 当TL0的低8位溢出时,向TH0进位; TH0溢出时,向中断标志TF0进位(硬件置位TF0),并申请中断

定时时间:
t=(2^{16}-t_{0})\times T\times 12 \end{align}$$ - $t$ 定时的时间 - $t_{0}$ 设置定时器的初值 - $T$ 振荡周期 $T=\dfrac{1}{f_{osc}}$ $f_{osc}$ 为晶振频率 - 12 表示一个基本操作占 12 个振荡周期 #### 实际的例子 设T0工作模式1,**定时时间为1ms**,fosc=12MH 编程实现其定时功能。定时时间到,P1.0取反 1. T0 工作模式 1 TMOD : 0000 0001 `MOV TMOD,#01H` 2. 定时时间为 1ms =1000×1us fosc=12MH --> 机器周期 1us 1ms =1000×1us 也即要计数 1000 次 设置 T0 计数器初值: $2^{16}-1000=64536$ 1111 1110 0001 1000 (二进制) FC 18(十六进制) 高八位 TH0:`MOV TH0,#0FCH` 低八位 TL0:`MOV TL0,#18H` 3. 启动 T0 定时器 TCON 可位寻址 `SETB TR0` #### 查询方式 ```C MOV TMOD,#01H ;定时器0 模式1 MOV TL0,#18H MOV TH0,#0FCH ;送初值 STEB TR0 ;启动定时器 LOOP:JBC TF0,NEXT SJMP LOOP NEXT:MOV TL0,#18H MOV TH0,#0FCH ;重新赋初值 CPL P1.0 SJMP LOOP ``` ```C #include<reg51.h> sbit P1_0=P1^0; void main(void) { TMOD=0x01; TH0=0xFC; TL0=0x18; TR0=1; while(1) { do{} while(!TF0); P1_0=!P1_0; TH0=0xFC; TL0=0x18; TF0=0; //溢出标志位清零 } } ``` [[C51\|C51]] #### 中断方式 [[8051中断系统\|8051中断系统]] 定时器中断标志位作为中断信号 标志位表征“重要的”事情发生了 CPU 来判断电信号的高低电平,作出响应 ```C ORG 000H RESET: AJMP MAIN ORG 000BH AJMP ISR0 ORG 0030H MAIN: MOV TMOD,#01H MOV TL0,#18H MOV TH0,#0FCH SETB EA SETB ET0 SETB TR0 HERE: SJMP HEAR ISR0: MOV TL0,#18H MOV TH0,#0FCH CPL P1.0 RETI ``` ```C #include<reg51.h> sbit P1_0=P1^0; void time0(void) interrput 1 { TH0=0xFC; //重新赋初值 TL0=0x18; P1_0=!P1_0; } void main(void) { TMOD=0x01; TH0=0xFC; TL0=0x18; EA=1; //中断总允许 ET0=1; //T0溢出允许 TR0=1; //启动定时器0 while(1) {} } ``` [[8051中断系统\|8051中断系统]] ### 模式二 该模式把TL0(TL1)配置成一个可以自动重装载的8位定时器/计数器 >定时器 1 模式二用于[[8051串口通信\|8051串口通信]]中的串行口波特率发生器 以 T0 定时器为例:  ==TL0== 用作 8 位计数器 0~255 ==TH0== 保存初值 **TL0计数溢出**时, - 不仅使溢出**中断标志位**TF0置1 - 而且还自动把TH0中的内容**重新装载**到TL0中 **计数次数:** $255+1-TH0$ **计数时间:** $$\begin{align} t=(2^{8}-TH_{0})\times \dfrac{1}{f_{osc}}\times_{1}2 \end{align}$$ TMOD 0110 0000 T1 计时器模式二 计数 100 次 256-100=156 -->1001 1100 --> 9CH ### 数码管 [[数码管\|数码管]] #### 静态显示 1.设计定时器,每隔1秒的时间,计时器自动加1,计时器个位满十向高位进位,累计计时99秒即清0重新计数。 2.计数过程中,能够分别实现计时器清零、暂停功能。(需增加开关电路) 3.清零或暂停功能选择其中一项功能通过中断方式设计实现。 ```C unsigned char table[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f} //声明table数组 ``` ```C #include<reg51.h> sbit P1_0 = P1^0; unsigned char counter=1000; unsigned char table[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f} unsigned char i= 0 ;unsigned char j=0; void main(void) { TMOD=0x01; P2=table[0]; P1=table[0]; TH0=0xFC; TL0=0x18; EA=1; ET0=1;EX0=1;EX1=1; TR=0; while(1) {} } void ISR0(void) interrupt 0 { TH0=0xFC; TL0=0x18; counter--; if(counter==0) { counter=1000; i++; if(i==10) { i=0; j++; if(j==10) { j=0; } } P1=table[i]; P2=table[j]; } } void ext_int0(void) interrupt 0 { P2=table[0]; P1=table[0]; i=0; j=0; //外部中断0,清零 } void ext_int1(void) interrupt 2 { TR0=!TR0; //外部中断1,暂停 } ``` #### 动态扫描 为了简化硬件电路,通常将所有位的段选线相应并联在一起,由一个8位I/O控制,形成段选线多路复用。而各位的共阳极或共阴极分别由相应的I/O线控制,实现各位的分时选通 在某一时刻,只让某一位位选线处于选通状态,而其他各位的位选线处于关闭状态,同时,段选线上输出相应位要显示的字符的字型码