51单片机定时器(控制流水灯和简易时钟案例)

发布时间:2024年01月23日


前言

了解定时器的原理以及使用


一、定时器

是单片机内部资源,其电路与运行皆在单片机内部
作用:

  • 用于计时系统,可实现软件计时,或使程序每一固定时间完成一个操作
  • 可以代替长时间的delay,提高cpu运行效率和处理速度等
stc89c52的定时器资源

在这里插入图片描述

定时器的框图

在这里插入图片描述

定时器的工作模式

定时器有四种模式,目前使用最多的模式是模式1,如下图:
在这里插入图片描述
计数当溢出后(大于65535)就会申请中断,开始处理事情
时钟(也可以由T0 Pin所外接的设备提供):
在这里插入图片描述

中断系统

优先级高的中断请求会抢占优先级低的中断请求,以下是主要概念
在这里插入图片描述
整体流程如下
在这里插入图片描述

stc89c52的中断资源

在这里插入图片描述
在这里插入图片描述
完整的流程图如下,通过TF0口去选择优先级
在这里插入图片描述

相关的寄存器

寄存器是连接软硬件的媒介,是一个特殊的存储器,既可以存取数据,还可以控制电路的连接,我们就需要通过寄存器去控制其内部的开关。
定时器/计数器 寄存器
在这里插入图片描述
定时器工作模式寄存器
不可位寻址只能整体赋值不能单个赋值
在这里插入图片描述
在这里插入图片描述

中断系统寄存器
在这里插入图片描述

二、使用定时器

1.配置定时器

按照原理图一一配置
放于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中复制初始化内容(第一句删掉)
在这里插入图片描述

2.使用中断函数

以流水灯为例,点击按键就改变其方向,中断函数一般放在主函数中,因为通常要使用在主函数定义的变量。
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;
}

3.使用LCD1602显示时钟效果

利用定时器每隔一秒在中断函数中进行进位,然后在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;
				}
			}
	   }
	}	
}

总结

定时器的相关知识很多,重点是寄存器管理的几个与中断相连接的开关,还有中断函数中不要放置太需要运算时间过长的程序,

文章来源:https://blog.csdn.net/qq_53922901/article/details/135730245
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。