09-定时器的进阶综合案例
定时器的进阶综合案例
由上可知,这边使用的是定时器1的模式,所以这边需要先了解下定时器:
1. 定时器/计数器0/1控制寄存器TCON
TCON为定时器/计数器T0、T1的控制寄存器,同时也锁存T0、T1溢出中断源和外部请求
中断源等,TCON格式如下:
TCON : 定时器/计数器中断控制寄存器 (可位寻址)
SFR name | Address | bit | B7 | B6 | B5 | B4 | B3 | B2 | B1 | B0 |
---|---|---|---|---|---|---|---|---|---|---|
TCON | 88H | name | TF1 | TR1 | TF0 | TR0 | IE1 | IT1 | IE0 | IT0 |
TF1:T1溢出中断标志位。产生溢出时,硬件置1,请求中断。进入中断后硬件清0;
TR1:0—关闭T1,1—打开T1;
TF0:T0溢出中断标志位。产生溢出时,硬件置1,请求中断。进入中断后硬件清0;
TR0:0—关闭T0,1—打开T0;
IE1:外部中断1请求源(INT1/P3.3)标志。IE1=1,外部中断向CPU请求中断,当CPU响应该
中断时由硬件清“0”IE1。
IT1:外部中断源1触发控制位。IT1=0,上升沿或下降沿均可触发外部中断1。IT1=1,外部中
断1程控为下降沿触发方式。
IE0:外部中断0请求源(INT0/P3.2)标志。IE0=1外部中断0向CPU请求中断,当CPU响应外
部中断时,由硬件清“0”IE0(边沿触发方式)。
IT0:外部中断源0触发控制位。IT0=0,上升沿或下降沿均可触发外部中断0。IT0=1,外部中
断0程控为下降沿触发方式
2.TMOD定时器/计数器0/1工作模式寄存器
SFR name | Address | bit | B7 | B6 | B5 | B4 | B3 | B2 | B1 | B0 |
---|---|---|---|---|---|---|---|---|---|---|
TMOD | 89H | name | GATE | C/ \(\overline{T}\) | M1 | M0 | GATE | C/ \(\overline{T}\) | M1 | M0 |
定时器1 | 定时器0 |
高四位控制定时器1:
GATE :置1时只有在INT1脚为高及TR1控制位置1时才可打开定时器/计数器1;
C / \(\overline{T}\):0—T1为定时器模式,对内部系统时钟计数,1—T1为计数器模式,对引脚T1/P3.5的外部脉冲计数;
M1 | M0 | 定时器/计数器1模式选择 |
---|---|---|
0 | 0 | 16位自动重装载模式,溢出时将RL_TH1和RL_TL1存放的值自动装入TH1和TL1 |
0 | 1 | 16位不可重装载模式 |
1 | 0 | 8位自动重装载,溢出时将TH1存放的值自动装入TL1 |
1 | 1 | 定时器/计数器1无效(停止计数) |
低4位控制定时器0:
GATE ::置1时只有在INT0脚为高及TR0控制位置1时才可打开定时器/计数器0;
C / \(\overline{T}\):0—T0为定时器模式,对内部系统时钟计数,1—T0为计数器模式,对引脚T0/P3.4的外部脉冲计数;
M1 | M0 | 定时器/计数器1模式选择 |
---|---|---|
0 | 0 | 16位自动重装载模式,溢出时将RL_TH0和RL_TL0存放的值自动装入TH0和TL0 |
0 | 1 | 16位不可重装载模式 |
1 | 0 | 8位自动重装载,溢出时将TH0存放的值自动装入TL0 |
1 | 1 | 不可屏蔽中断的16位自动重装载定时器,即中断不受EA控制,只由ET0控制(此处与T1不同) |
3.AUXR辅助寄存器(不可位寻址)
STC15系列单片机是 1T 的8051单片机,为兼容传统8051,定时器0 、定时器1,和定时器2复位后是传统8051的速度,即12分频,这是为了兼容传统8051。但也可不进行12分频,通过设置新增加的特殊功能寄存器AUXR,将T0,T1,T2设置位1T,
AUXR:辅助寄存器(不可位寻址)
SFR name | Address | bit | B7 | B6 | B5 | B4 | B3 | B2 | B1 | B0 |
---|---|---|---|---|---|---|---|---|---|---|
AUXR | 8EH | name | T0x12 | T1x12 | UART_M0x6 | T2R | T2_C / \(\overline{T}\) | T2x12 | EXTRAM | S1ST2 |
T0x12: 定时器0速度控制位
0, 定时器0是传统8051速度,12分频;
1, 定时器0的速度是传统8051的12倍,不分频
T1x12: 定时器1速度控制位
0, 定时器1是传统8051速度,12分频;
1, 定时器1的速度是传统8051的12倍,不分频
如果UART1/串口1用T1作为波特率发生器,则由T1x12决定UART1/串口1是12T还是1T
UART_M0x6: 串口1模式0的通信速度设置位。
0, 串口1模式0的速度是传统8051单片机串口的速度,12分频;
1, 串口1模式0的速度是传统8051单片机串口速度的6倍,2分频
T2R: 定时器2允许控制位
0, 不允许定时器2运行;
1, 允许定时器2运行
T2_C / \(\overline{T}\): 控制定时器2用作定时器或计数器。
0, 用作定时器(对内部系统时钟进行计数);
1, 用作计数器(对引脚T2/P3.1的外部脉冲进行计数)
T2x12: 定时器2速度控制位
0, 定时器2是传统8051速度,12分频;
1, 定时器2的速度是传统8051的12倍,不分频
如果串口1或串口2用T2作为波特率发生器,则由T2x12决定串口1或串口2是12T还是1T.
EXTRAM: 内部/外部RAM存取控制位
0, 允许使用逻辑上在片外、物理上在片内的扩展RAM;
1, 禁止使用逻辑上在片外、物理上在片内的扩展RAM
S1ST2: 串口1(UART1)选择定时器2作波特率发生器的控制位
0, 选择定时器1作为串口1(UART1)的波特率发生器;
1, 选择定时器2作为串口1(UART1)的波特率发生器,此时定时器1得到释放,可以作为
独立定时器使用
5.定时器T0和T1的中断控制寄存器:IE和IP
IE:中断允许寄存器(可位寻址)
SFR name | Address | bit | B7 | B6 | B5 | B4 | B3 | B2 | B1 | B0 |
---|---|---|---|---|---|---|---|---|---|---|
IE | A8H | name | EA | ET1 | ET0 |
EA: CPU的总中断允许控制位,EA=1,CPU开放中断,EA=0,CPU屏蔽所有的中断申请。
EA的作用是使中断允许形成多级控制。即各中断源首先受EA控制;其次还受各中断源自己的中断允许控制位控制。
ET1 : 定时/计数器T1的溢出中断允许位,ET1=1,允许T1中断,ET1=0,禁止T1中断。
ET0 : T0的溢出中断允许位,ET0=1允许T0中断,ET0=0禁止T0中断。
IP:中断优先级控制寄存器(可位寻址)
SFR name | Address | bit | B7 | B6 | B5 | B4 | B3 | B2 | B1 | B0 |
---|---|---|---|---|---|---|---|---|---|---|
IP | B8H | name | PT1 | PT0 |
PT1:
定时器1中断优先级控制位。
当PT1=0时,定时器1中断为最低优先级中断(优先级0)
当PT1=1时,定时器1中断为最高优先级中断(优先级1)
PT0:
定时器0中断优先级控制位。
当PT0=0时,定时器0中断为最低优先级中断(优先级0)
当PT0=1时,定时器0中断为最高优先级中断(优先级1)
注意:当定时器/计数器0工作在模式3(不可屏蔽中断的16位自动重装载模式)时,不需要允许EA/IE.7(总中断使能位)只需允许ET0/IE.1(定时器/计数器0中断允许位)就能打开定时器/计数器0的中断,此模式下的定时器/计数器0中断与总中断使能位EA无关。一旦此模式下的定时器/计数器0中断被打开后,该定时器/计数器0中断优先级就是最高的,它不能被其它任何中断所打断(不管是比定时器/计数器0中断优先级低的中断还是比其优先级高的中断,都不能打断此时的定时器/计数器0中断),而且该中断打开后既不受EA/IE.7控制也不再受ET0控制了,清零EA或ET0都不能关闭此中断
7. 定时器T2、T3和T4的中断控制寄存器:IE2
IE2 : 中断允许寄存器 (不可位寻址)
SFR name | Address | bit | B7 | B6 | B5 | B4 | B3 | B2 | B1 | B0 |
---|---|---|---|---|---|---|---|---|---|---|
IE2 | AFH | name | ET4 | ET3 | ES4 | ES3 | ET2 | ESPI | ES2 |
ET4:定时器4的中断允许位。
1,允许定时器4产生中断;
0,禁止定时器4产生中断。
ET3:定时器3的中断允许位。
1,允许定时器3产生中断;
0,禁止定时器3产生中断。
ES4: 串行口4中断允许位。
1,允许串行口4中断;
0,禁止串行口4中断
ES3:串行口3中断允许位。
1,允许串行口3中断;
0,禁止串行口3中断。
ET2:定时器2的中断允许位。
1,允许定时器2产生中断;
0,禁止定时器2产生中断。
ESPI:SPI中断允许位。
1,允许SPI中断;
0,禁止SPI中断。
ES2: 串行口2中断允许位。
1,允许串行口2中断;
0,禁止串行口2中断。
以上案例代码如下:
#include <REGX52.H>
sbit S4 = P3^3;
sbit S5 = P3^2;
unsigned char minute,second,ms=0;
void _74HC138(unsigned char n) {
switch(n) {
case 4: P2 = (P2 & 0x1f) | 0x80;
break;
case 5: P2 = (P2 & 0x1f) | 0xa0;
break;
case 6: P2 = (P2 & 0x1f) | 0xc0;
break;
case 7: P2 = (P2 & 0x1f) | 0xe0;
break;
}
}
void SystemInit(void) {
_74HC138(5);
P0 = 0x00;
_74HC138(4);
P0 = 0xff;
}
void Display_Key(unsigned int t) {
while(t--);
}
void Nixie(unsigned char Location,Number)
{
unsigned char code Num[11] = {
0xc0, // 0 1100 0000
0xf9, // 1 1111 1001
0xa4, // 2 1010 0100
0xb0, // 3 1011 0000
0x99, // 4 1001 1001
0x92, // 5 1001 0010
0x82, //6 1000 0010
0xf8, // 7 1111 1000
0x80, // 8 1000 0000
0x90, // 9 // 1001 0000
0xbf // - 1011 1111
};
switch(Location) {
case 1: _74HC138(6);P0 = 0x01;break;
case 2: _74HC138(6);P0 = 0x02;break;
case 3: _74HC138(6);P0 = 0x04;break;
case 4: _74HC138(6);P0 = 0x08;break;
case 5: _74HC138(6);P0 = 0x10;break;
case 6: _74HC138(6);P0 = 0x20;break;
case 7: _74HC138(6);P0 = 0x40;break;
case 8: _74HC138(6);P0 = 0x80;break;
}
_74HC138(7);
P0 = Num[Number];
// 动态数码扫描
Display_Key(600);
P0 =0xFF;
}
void Display_Nixie(void) {
Nixie(1,minute/10);
Nixie(2,minute%10);
Nixie(3,10);
Nixie(4,second/10);
Nixie(5,second%10);
Nixie(6,10);
Nixie(7,ms/10);
Nixie(8,ms%10);
}
void ScanKey(void) {
if(S4 == 0) { // 启动与暂停
Display_Key(200);
if(S4 == 0) {
// 第一次按下S4时,关闭定时器,第二次按下定时器开启
TR1 = ~TR1;
while(S4 == 0) {
Display_Nixie();
}
}
}
if(S5 == 0) {
Display_Key(200);
if(S5 == 0) {
minute = 0;
second = 0;
ms = 0;
// 当S5按下的时候实时进行数码管的更新
while(S5 == 0) {
Display_Nixie();
}
}
}
}
void Timer1Init(void) {
TMOD = 0x10;
// 50000 us == 50ms 50*20 = 1000ms = 1s
TH1 = (65535 - 50000) /256;
TL1 = (65535 - 50000) %256;
ET1 = 1;
EA = 1; // 打开总中断
TR1 = 1; // 打开定时器
}
void main(void) {
SystemInit();
Timer1Init();
while(1) {
Display_Nixie();
ScanKey();
}
}
void Timer1_Rountine(void) interrupt 3 {
TH1 = (65535 - 50000) /256;
TL1 = (65535 - 50000) %256;
ms++;
if(ms > 20) {
second++;
ms= 0;
if(second > 59) {
minute++;
second=0;
if(minute > 59) {
minute = 0;
}
}
}
}