C51单片机学习(二):定时器与中断系统详解
参考
51单片机入门教程
1. 定时器
1.1 定时器定义
1.2 定时器作用
1.3 STC89C52 定时器资源
注意:定时器的资源和单片机的型号是关联在一起的,不同的型号可能会有不同的定时器个数和操作方式,但一般来说,T0 和 T1 的操作方式是所有 51 单片机所共有的(T:Timer,计数器)
1.4 定时器框图

1.5 定时器工作模式

1.6 定时器时钟

2. 中断系统
2.1 概述
2.2 中断程序流程
2.3 STC89C52 中断资源

注意:中断的资源和单片机的型号是关联在一起的,不同的型号可能会有不同的中断资源,例如中断源个数不同、中断优先级个数不同等等
3. 定时器和中断系统
3.1 连接框图

3.2 相关寄存器
寄存器是连接软硬件的媒介,在单片机中寄存器就是一段特殊的 RAM 存储器

可位寻址/不可位寻址
3.3 寄存器配置
TMOD 配置
TCON 配置
3.4 中断配置
3.3 代码示例
1、按键控制 LED 流水灯模式
#ifndef __DELAY_H__
#define __DELAY_H__
void Delay(unsigned int xms);
#endif
void Delay(unsigned int xms) {
unsigned char i, j;
while (xms--) {
i = 2;
j = 239;
do {
while (--j);
} while (--i);
}
}
#ifndef __KEY_H__
#define __KEY_H__
unsigned char Key();
#endif
#include <REGX52.H>
#include "Delay.h"
/**
* @brief 获取独立按键键码
* @param 无
* @retval 按下按键的键码,范围:0~4,无按键按下时返回值为0
*/
unsigned char Key() {
unsigned char KeyNumber=0;
if (P3_1 == 0) {Delay(20); while (P3_1 == 0); Delay(20); KeyNumber = 1;}
if (P3_0 == 0) {Delay(20); while (P3_0 == 0); Delay(20); KeyNumber = 2;}
if (P3_2 == 0) {Delay(20); while (P3_2 == 0); Delay(20); KeyNumber = 3;}
if (P3_3 == 0) {Delay(20); while (P3_3 == 0); Delay(20); KeyNumber = 4;}
return KeyNumber;
}
#ifndef __TIMER0_H__
#define __TIMER0_H__
void Timer0Init(void);
#endif
#include <REGX52.H>
/**
* @brief 定时器 0 初始化,1 毫秒 @12.000MHz
* @param 无
* @retval 无
*/
void Timer0Init(void) {
TMOD &= 0xF0; // 把 TMOD 低 4 位清零,高四位保持不变
TMOD |= 0x01; // 把 TMOD 最低位置零,高四位保持不变
TL0 = 0x18; // 设置定时初值,低 8 位
TH0 = 0xFC; // 设置定时初值,高 8 位
TF0 = 0; // 清除 TF0 标志
TR0 = 1; // 定时器 0 开始计时
ET0 = 1;
EA = 1;
PT0 = 0;
}
/*定时器中断函数模板
void Timer0_Routine() interrupt 1 {
static unsigned int T0Count;
TL0 = 0x18; // 设置定时初值
TH0 = 0xFC; // 设置定时初值
T0Count++;
if (T0Count >= 1000) {
T0Count = 0;
}
}
*/
#include <REGX52.H>
#include "Timer0.h"
#include "Key.h"
#include <INTRINS.H>
unsigned char KeyNum, LEDMode;
void main() {
P2 = 0xFE;
Timer0Init();
while (1) {
KeyNum = Key(); // 获取独立按键键码
if (KeyNum) { // 如果按键按下
if (KeyNum == 1) { // 如果 K1 按键按下
LEDMode++; // 模式切换
if (LEDMode >= 2)
LEDMode = 0;
}
}
}
}
void Timer0_Routine() interrupt 1 {
static unsigned int T0Count;
TL0 = 0x18; // 设置定时初值
TH0 = 0xFC; // 设置定时初值
T0Count++; // T0Count 计次,对中断频率进行分频
if (T0Count >= 500) { // 分频 500 次,500ms
T0Count = 0;
if (LEDMode == 0) // 模式判断
P2 = _crol_(P2, 1); // LED 输出
if (LEDMode == 1)
P2 = _cror_(P2, 1);
}
}
2、 定时器时钟
#include <REGX52.H>
#include "Delay.h"
#include "LCD1602.h"
#include "Timer0.h"
unsigned char Sec=55,Min=59,Hour=23;
void main() {
LCD_Init();
Timer0Init();
LCD_ShowString(1, 1, "Clock:"); // 上电显示静态字符串
LCD_ShowString(2, 1, " : :");
while (1) {
LCD_ShowNum(2, 1, Hour, 2); //显示时分秒
LCD_ShowNum(2, 4, Min, 2);
LCD_ShowNum(2, 7, Sec, 2);
}
}
void Timer0_Routine() interrupt 1 {
static unsigned int T0Count;
TL0 = 0x18; // 设置定时初值
TH0 = 0xFC; // 设置定时初值
T0Count++;
if (T0Count >= 1000) { // 定时器分频,1s
T0Count = 0;
Sec++; // 1 秒到,Sec 自增
if (Sec >= 60) {
Sec = 0; // 60 秒到,Sec 清 0,Min 自增
Min++;
if (Min >= 60) {
Min = 0; // 60 分钟到,Min 清 0,Hour 自增
Hour++;
if (Hour >= 24) {
Hour = 0; // 24 小时到,Hour 清 0
}
}
}
}
}