了解定时器的原理以及使用
是单片机内部资源,其电路与运行皆在单片机内部
作用:
定时器有四种模式,目前使用最多的模式是模式1,如下图:
计数当溢出后(大于65535)就会申请中断,开始处理事情
时钟(也可以由T0 Pin所外接的设备提供):
优先级高的中断请求会抢占优先级低的中断请求,以下是主要概念
整体流程如下
完整的流程图如下,通过TF0口去选择优先级
寄存器是连接软硬件的媒介,是一个特殊的存储器,既可以存取数据,还可以控制电路的连接,我们就需要通过寄存器去控制其内部的开关。
定时器/计数器 寄存器:
定时器工作模式寄存器
不可位寻址只能整体赋值不能单个赋值
中断系统寄存器:
按照原理图一一配置
放于Time0Init.c中
// 配置定时器
void Time0_Init(){
// TMOD = 0x01; // 0000 0001 ,会改变另一个定时器的配置
TMOD &= 0XF0; // 把TMOD低四位清零,高四位不变
TMOD |= 0X01; // 设为0001
TF0 = 0; // 定时器溢出后中断清0
TR0 = 1; // 允许开始计数
// 每个盒子8位即最大1111 1111,就是256
// 将64535的高八位低八位分别装入TH0、TL0中
// 这样每溢出一次就是1ms
TH0 = 64535/256; // 65535-64535=1000us
TL0 = 64535%256;
ET0 = 1; // 允许TF0的中断请求
EA = 1; // 总开关打开
PT0 = 0; // 选择优先级(低)
}
也可以直接在stc中复制初始化内容(第一句删掉)
以流水灯为例,点击按键就改变其方向,中断函数一般放在主函数中,因为通常要使用在主函数定义的变量。
main.c
#include <REGX52.H>
#include "Time0Init.h"
#include "Key.h"
#include <intrins.h> // 可以使用移位函数(循环移位)
unsigned char KeyNum; // 接收按键值
unsigned char LEDMode;
void main(){
P2 = 0xfe;
// 初始化定时器
Time0_Init();
while(1){
KeyNum = Key();
if(KeyNum == 1){
LEDMode++;
if(LEDMode>=2) LEDMode = 0;
}
}
}
// 中断函数
void Timer0_Routine() interrupt 1
{
static unsigned int count;
count++;
// 中断后会归零,需重新赋值
TL0 = 0x18; //设置定时初始值
TH0 = 0xFC; //设置定时初始值
if(count>=500){
count = 0;
if(LEDMode == 0){
P2 = _crol_(P2,1); // 循环左移
}
if(LEDMode == 1){
P2 = _cror_(P2,1); // 循环右移
}
}
}
Key.c
#include <REGX52.H>
#include "Delay.h"
unsigned char Key(){
unsigned char KeyNum = 0;
if(P3_1==0){
Delayms(20);
while(P3_1==0);
Delayms(20);
KeyNum = 1;
}
if(P3_0==0){
Delayms(20);
while(P3_0==0);
Delayms(20);
KeyNum = 2;
}
if(P3_2==0){
Delayms(20);
while(P3_2==0);
Delayms(20);
KeyNum = 3;
}
if(P3_3==0){
Delayms(20);
while(P3_3==0);
Delayms(20);
KeyNum = 4;
}
return KeyNum;
}
利用定时器每隔一秒在中断函数中进行进位,然后在LCD1602上显示,代码实现如下
main.c
#include <REGX52.H>
#include "Delay.h"
#include "LCD1602.h"
#include "Time0Init.h"
// 定义秒、分、时
unsigned char Sec = 0,Min = 0,Hour = 0;
void main(){
// 初始化定时器与LCD1602
Time0_Init();
LCD_Init();
LCD_ShowString(1,1,"clock");
while(1){
LCD_ShowNum(2,1,Hour,2);
LCD_ShowString(2,3,":");
LCD_ShowNum(2,4,Min,2);
LCD_ShowString(2,6,":");
LCD_ShowNum(2,7,Sec,2);
}
}
// 中断函数
void Timer0_Routine() interrupt 1
{
static unsigned int count;
count++;
// 中断后会归零,需重新赋值
TL0 = 0x18; //设置定时初始值
TH0 = 0xFC; //设置定时初始值
// 进位逻辑
if(count>=1000){
count = 0;
Sec++;
if(Sec>=60){
Sec = 0;
Min++;
if(Min>=60){
Min = 0;
Hour++;
if(Hour>=24){
Hour = 0;
}
}
}
}
}
定时器的相关知识很多,重点是寄存器管理的几个与中断相连接的开关,还有中断函数中不要放置太需要运算时间过长的程序,