51单片机(七)定时器

news2024/11/17 9:44:52

❤️ 专栏简介:本专栏记录了从零学习单片机的过程,其中包括51单片机和STM32单片机两部分;建议先学习51单片机,其是STM32等高级单片机的基础;这样再学习STM32时才能融会贯通。
☀️ 专栏适用人群 :适用于想要从零基础开始学习入门单片机,且有一定C语言基础的的童鞋。
🌙专栏目标:实现从零基础入门51单片机和STM32单片机,力求在玩好单片机的同时,能够了解一些计算机的基本概念,了解电路及其元器件的基本理论等。

⭐️ 专栏主要内容: 主要学习51单片机的功能、各个模块、单片机的外设、驱动等,最终玩好单片机和单片机的外设,全程手敲代码,实现我们所要实现的功能。
🌴 专栏说明 :如果文章知识点有错误的地方,欢迎大家随时在文章下面评论,我会第一时间改正。让我们一起学习,一起进步。
💑专栏主页:http://t.csdn.cn/HCD8v

本学习过程参考:https://space.bilibili.com/383400717

单片机安装软件、各种资料以及源码的路径:
https://pan.baidu.com/s/1vDTN2o8ffvczzNQGfyjHng
提取码:gdzf

本节主要介绍学习定时器的相关功能,包括定时器简介、定时器原理、计数器、时钟、中断系统等基础知识;并利用两个小实验来进行练习,分别是使用定时器实现按键控制流水灯模式以及使用定时器实现定时器时钟。

文章目录

  • 一、定时器介绍和本节目标
    • 1.1 定时器简介和定时器原理
      • 1.1.1 定时器简介
      • 1.1.2 定时器原理
        • 1.1.2.1 计数器
        • 1.1.2.2 时钟
        • 1.1.2.3 中断系统
        • 1.1.2.4 定时器和中断系统
        • 1.1.2.5 定时器相关寄存器
    • 1.2 本节目标
  • 二、按键控制LED流水灯模式
  • 三、定时器时钟

一、定时器介绍和本节目标

1.1 定时器简介和定时器原理

1.1.1 定时器简介

在这里插入图片描述
STC89C52的定时器资源,如下图所示,具体的可以 参考手册:\51单片机入门教程资料\课件及程序源码\相关资料\STC89C52.pdf 第七章 定时器/计数器

在这里插入图片描述

1.1.2 定时器原理

在这里插入图片描述
下面会学习什么是中断系统。

定时器的工作模式如下:
在这里插入图片描述

本文我们只学习模式1:16位定时器/计数器;其是最常用的;其他几个模式基本不怎么常用。

模式1的框图如下图所示:
在这里插入图片描述

可以将其分为三部分,时钟部分,计数器部分和中断部分,如下图所示:
在这里插入图片描述

1.1.2.1 计数器

计数器是如何进行计数的呢?上图中我们可以看到计数器部分有TL0和TH0,每个都存放8字节数据,总共可以存的数字为从0-65535;由左边的时钟给TL0和TL1提供脉冲,每提供一个脉冲,这16为计数器里面的值就会加1;当值加到最大值65535时,下一个脉冲再过来,就会造成计数器的溢出,溢出时计数器就会给到一个标志位给TF0,收到标志位,TF0就会给中断系统一个中断信号申请中断;

图中的TR0是控制定时器是否启动;

1.1.2.2 时钟

在这里插入图片描述
从图中可以看出,时钟的来源有两个,一个是SYSclk,即系统时钟;另一个是T0Pin,T0Pin是单片机外部的接口;如下图所示
在这里插入图片描述
在关键图中可以看出,14引脚的位置就是T0Pin;

所以时钟既可以由系统时钟(SYSclk)来提供,也可以通过外部引脚来提供;当由外部引脚来提供时钟的时候,我们的定时器就是一个计数器;因为外部来一个脉冲计数器就加一,所以就相当于一个脉冲计数器;计数器名字的来源也是来于此。

当然最常用的还是由系统时钟来提供脉冲。系统时钟也是晶振周期。晶振在开发部上的位置如下图所示:

在这里插入图片描述
本开发板上的晶振为12MHz,所以该开发板上的系统时钟也就是12MHz。

在这里插入图片描述

系统时钟输入的12MHz;12T模式会将输入的12MHz的系统时钟12分频,分频后输出的频率就是1MHz;所以定时器的周期就是1微秒(Hz代表每秒周期震动1次, 60Hz代表每秒周期震动60次 1MHZ=1000000HZ。所以1MHz为一秒震动一百万次)。即在图中画的红色线路(C/T=0)的情况下,定时器的计数单元每隔一微秒就计数一次。

我们本节定时器时钟的选择配置为:分频模式选择12分频,然后选择C/T=0,即定时器功能(当C/T=1时,是连接下面,即计数器功能); 所以整体流程为:系统时钟(SYSclk)->12分频(12T模式)->定时器模式(C/T=0),如下图所示:
在这里插入图片描述

1.1.2.3 中断系统

中断系统也是51单片机一个很重要的知识点,本节的定时器需要中断系统,后面要学习到的串口也需要中断系统;i/o口也需要中断系统,等等,许多设备都需要中断系统。所以中断系统会和许多外设打交道。

中断系统的介绍如下图所示(参考\51单片机入门教程资料\课件及程序源码\相关资料\STC89C52.pdf 第6章 中断系统
在这里插入图片描述
总结几个重点:
1、中断是可以使CPU拥有对外界紧急事件的实时处理能力
2、高优先级的中断可以打断中优先级的中断

中断的处理流程

中断的处理流程如下图所示:
在这里插入图片描述
当主程序正在运行时,如果突然来了一个中断请求,则CPU会响应中断请求,进而去处理中断处理程序,当中断处理程序执行完之后,再返回主程序执行主程序的任务。

中断资源

中断资源也是和单片机的型号关联在一起的,即不同种类的单片机可能拥有不同的中断资源,例如中断源个数不同,优先级个数不同等。

下图是STC89C5的中断资源:
在这里插入图片描述

1.1.2.4 定时器和中断系统

定时器和中断系统具体的关系图如下图所示(以传统51单片机为例):

在这里插入图片描述
整体的流程如下图红线部分所示:,由时钟到定时器再到中断系统;关于整个流程的具体代码实现下面会学习;
在这里插入图片描述

1.1.2.5 定时器相关寄存器

前面我们学过,单片机通过配置寄存器来控制内部线路的连接。通过内部线路的不同连接方式来实现不同的功能。

下图列出了和定时器有关的寄存器已经和中断有关的寄存器:
在这里插入图片描述
寄存器具体由什么作用呢?
在这里插入图片描述
前面我们讲到的具体模式的配置,也就是上图中的各个开关,具体拨到哪个位置上, 就是由寄存器来控制的。如下图所示:
具体的介绍请参考手册(\51单片机入门教程资料\课件及程序源码\相关资料\STC89C52.pdf 第7.1.1节
视频介绍请参考(https://www.bilibili.com/video/BV1Mb411e7re/?p=17&spm_id_from=pageDriver&vd_source=e2638d12685eef84cda913d9d67be0a9的第48分钟后)
在这里插入图片描述
总结如下:

1、寄存器是连接软硬件的媒介
2、在单片机中寄存器就是一段特殊的RAM存储器一方面,寄存器可以存储和读取数据,另一方面,每一个寄存器背后都连接了一根导线,控制着电路的连接方式
3、寄存器相当于一个复杂机器的“操作按钮

所以只要我们在程序中将相应的寄存器配置好,单片机的电路就会按照我们审定的模式去工作。

1.2 本节目标

目标1:按键控制LED流水灯模式
流水灯的效果在前面学习LED灯的时候已经演示过了,本节要做的就是通过定时器,将按键和流水灯结合在一起;效果还是流水灯的效果。

目标2:使用定时器实现时钟
在这里插入图片描述在这里插入图片描述

二、按键控制LED流水灯模式

代码路径:51单片机入门教程资料\课件及程序源码\程序源码\KeilProject\7-1 按键控制LED流水灯模式

代码的编写过程,请参考https://www.bilibili.com/video/BV1Mb411e7re/?p=18&spm_id_from=pageDriver&vd_source=e2638d12685eef84cda913d9d67be0a9

具体代码:

#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);
	}
}

其中,Timer0.c如下:

#include <REGX52.H>

/**
  * @brief  定时器0初始化,1毫秒@12.000MHz
  * @param  无
  * @retval 无
  */
void Timer0Init(void)
{
	TMOD &= 0xF0;		//设置定时器模式
	TMOD |= 0x01;		//设置定时器模式
	TL0 = 0x18;		//设置定时初值
	TH0 = 0xFC;		//设置定时初值
	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;
		
	}
}
*/

Key.c的内容如下:

#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;
}

代码解释,这里主要解释一下Timer0.c里的Timer0Init函数,

/**
  * @brief  定时器0初始化,1毫秒@12.000MHz
  * @param  无
  * @retval 无
  */
void Timer0Init(void)
{
	TMOD &= 0xF0;		//设置定时器模式
	TMOD |= 0x01;		//设置定时器模式
	TL0 = 0x18;		//设置定时初值
	TH0 = 0xFC;		//设置定时初值
	TF0 = 0;		//清除TF0标志
	TR0 = 1;		//定时器0开始计时
	ET0=1;
	EA=1;
	PT0=0;
}

在这里插入图片描述
首先是配置定时器模式TMOD:
TMOD &= 0xF0 表示将TMOD的低四位清零,高四位保持不变;
TMOD |= 0x01表示将TMOD的最低位置1,其他位不变;
这两步操作,其实跟TMOD=0x01;效果是一样的,好处是防止同时操作多个寄存器时串位的情况,能够在实现配置高四位的同时,不影响低四位。
TL0 = 0x18; TH0 = 0xFC; 表示设置定时初值,TL0为低位,TH0为高位。

TF0=0清除TF0标志;
TR0 = 1;如上图中,当TR0为1时,与门的输出结果就全取决于TR0下面那部分了。

ET0=1,打开ET0的开关;
EA=1,打开EA的开关;
PT0=0,设置为低优先级。

其实对定时器的设置不一定要我们手敲代码,简单方法是利用STC-ISP软件里的功能生成,步骤如下:
假设我们要设置一个1ms的定时器:
按照下图进行配置,点击生成C代码即可生成一个1ms的定时器代码,
在这里插入图片描述
但是AUXR是相对于最新版本的,我们的单片机并不需要,直接删掉就行。可以发现,跟我们自己上面写的代码是一致的。但是少了中断的配置,我们将中断的配置加上即可。

配置中断:
ET0=1,打开ET0的开关;
EA=1,打开EA的开关;
PT0=0,设置为低优先级。

所以后面我们在写定时器的代码时,直接用STC-ISP软件里生成代码,然后在后面加上以上配置中断的代码即可

前面讲了定时器的配置,那定时器达到定时时间后,需要触发中断,转而去执行中断处理程序,中断处理程序如下所示,其中在函数名定义后面加上 interrupt 1,就表示这是中断处理程序,当定时器达到时间后,就会自动触发中断去执行该中断处理程序。

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);
	}
}

每次执行中断处理程序,都要给TL0和TH0赋初值,具体设置为多少,参考上面STC-ISP生成的代码里的值即可。
T0Count用来控制时间,比如我们想要达到0.5秒间隔再去处理某件事,但是定时器每次触发的频率是1ms,所以就定义T0Count,每次触发中断处理函数,T0Count就加1,代表过了1ms了,当T0Count加到500时,就表示过了500ms,也就是0.5s了。

再后面的代码(中断控制函数里的代码)就是控制独立按键了。
_crol__cror_函数包含在INTRINS.H函数库中,含义分别是循环左移和循环右移

执行完中断处理函数后,继续执行主程序的代码。

最终的效果就是目标1了,即用按键控制流水灯模式。

三、定时器时钟

代码路径:51单片机入门教程资料\课件及程序源码\程序源码\KeilProject\7-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
				}
			}
		}
	}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/503466.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

写文章的软件-一款写作文章的软件

写文章的软件 写文章的软件是一种工具&#xff0c;可以帮助用户轻松快速地创作高质量的文章。该软件一般包括以下几个主要功能&#xff1a; 写作界面&#xff1a;提供简洁、美观的写作界面&#xff0c;让用户专注于文章创作&#xff0c;同时可以进行排版、字体、颜色等调整。 …

力扣707. 设计链表

707. 设计链表 - 力扣&#xff08;Leetcode&#xff09; class MyLinkedList { public:// 定义链表节点结构体struct LinkedNode {int val;LinkedNode* next;LinkedNode(int val):val(val), next(nullptr){}};// 初始化链表MyLinkedList() {_dummyHead new LinkedNode(0); // …

BasicVSR++代码解读(分模块介绍-前向传播函数)

一、前向传播函数def forward(self, lqs): 输入&#xff1a;低质量序列L,shape为**(n, t, c, h, w)。 输出&#xff1a;HR序列,shape为(n, t, c, 4h, 4w)**。 &#xff08;1&#xff09;读取输入数据的维度大小     这里的n,t,c,h,w分别表示&#xff1a;一个bitch的图片数…

数据结构之双向链表,实现双向链表的增删改查

目录 一、双向链表的定义 1.双向链表节点的定义 2.双向链表的初始化 二、双向链表的函数接口实现 1.双链表的尾插 2.双向链表的尾删 3.双向链表的头插 4.双向链表的头删 6.双向链表在pos前面插入 7.双向链表删除pos位置的节点 8.双向链表的销毁 总结 一、双向链表的定义 双向链…

PyQt5桌面应用开发(11):摸鱼也要讲基本法,两个字,16

本文目录 PyQt5桌面应用系列鼠标不要钱&#xff0c;手腕还不要钱吗&#xff1f;PyQt5源程序python文件资源定义界面定义文件 技术要素资源文件StyleSheetsQMainWindow设置窗体几何 结论 PyQt5桌面应用系列 PyQt5桌面应用开发&#xff08;1&#xff09;&#xff1a;需求分析 PyQ…

EC6110-Hi3798MV310-当贝纯净桌面-卡刷强刷固件包

EC6110-Hi3798MV310-当贝纯净桌面-卡刷强刷固件包-内有教程及短接点 特点&#xff1a; 1、适用于对应型号的电视盒子刷机&#xff1b; 2、开放原厂固件屏蔽的市场安装和u盘安装apk&#xff1b; 3、修改dns&#xff0c;三网通用&#xff1b; 4、大量精简内置的没用的软件&a…

【信息安全案例】——网络攻击分析(学习笔记)

&#x1f4d6; 前言&#xff1a;随着信息技术的发展&#xff0c;网络空间的斗争可谓是兵家必争之地&#xff0c;网络攻击的事件层出不穷。道高一尺魔高一丈&#xff0c;了解常见的网络攻击类型有利于我们日后工作生活的安全稳定。 目录 &#x1f552; 1. 网络攻击威胁&#x1f…

CM211-2-YS-Hi3798MV300/MV310-当贝纯净桌面线刷固件包(可救砖)

CM211-2-YS-Hi3798MV300&#xff0f;MV310-当贝纯净桌面线刷固件包&#xff08;可救砖&#xff09;-内有教程 特点&#xff1a; 1、适用于对应型号的电视盒子刷机&#xff1b; 2、开放原厂固件屏蔽的市场安装和u盘安装apk&#xff1b; 3、修改dns&#xff0c;三网通用&…

05- 算法解读 R-CNN (目标检测)

要点&#xff1a; R-CNN可以说是利用深度学习进行目标检测的开山之作。 一 R-CNN算法 R-CNN可以说是利用深度学习进行目标检测的开山之作。作者Ross Girshick多次 在PASCAL VOC的目标检测竞赛中折桂&#xff0c;曾在2010年带领团队获得终身成就奖。 RCNN算法流程可分为4个步…

ACM输入输出

写在前面 主要记录一下ACM输入输出的写法&#xff1b; 一、输入数值 1. 给定N的定长多行输入 题目&#xff1a;https://ac.nowcoder.com/acm/contest/5657/B&#xff1b; 代码&#xff1a; #include <iostream> #include <stdio.h> using namespace std;int m…

JavaWeb《后端内容:1. Tomcat - Servlet - Thymeleaf》

目录 1. 基础概念 1.1 BS架构和CS架构 1.2 Tomcat图解 2.TomCat 2.1 IDEA配置web项目和tomcat 2.2 idea启动TomCat因为端口号失败的问题 3.Servlet使用流程 3.1 Servlet简单图解 3.2 Servlet导入依赖 3.3 编写Servlet和add.html 3.4 试着使用Jdbc和Dao层连接水果库存…

如何是Jetpack Compose构建漂亮的应用程序

如何是Jetpack Compose构建漂亮的应用程序 Jetpack compose 是在 Android 上构建 UI 的未来。 如果您完全不熟悉 android 并且不知道 Jetpack Compose 是什么——它基本上是一种构建本机用户界面的新方法。 Jetpack compose官方站点 https://developer.android.com/jetpack/co…

MySQL执行顺序

MySQL执行顺序 MySQL语句的执行顺序也是在面试过程中经常问到的问题&#xff0c;并且熟悉执行顺序也有助于SQL语句的编写。 SELECT FROM JOIN ON WHERE GROUP BY HAVING ORDER BY LIMIT执行顺序如下&#xff1a; FROM ON JOIN WHERE GROUP BY # (开始使用别名) SUM # SUM等…

4.4——多重继承

在前面学习了一个派生类只有一个基类&#xff0c;这种派生方法称为单继承或单基派生。当一个派生类具有两个或多个基类时&#xff0c;这种派生方法称为多重继承或多基派生。 多重继承派生类的声明 在C中&#xff0c;声明具有两个以上基类的派生类与声明单基派生类的形式相似&a…

K8S:二进制安装K8S(单台master)

目录 一、安装K8S 1、拓扑图​编辑 2、系统初始化配置 3、部署docker引擎 4、部署etcd集群 ①etcd简介 ②准备签发证书环境 ③etcd部署 5、master部署组件 6、 部署 Worker Node 组件 7、 node节点部署flannel网络插件 一、安装K8S 1、拓扑图​​​​​​​ 2、系…

C++好难(4):类和对象(下)

okk我们终于来到了C类和对象的最后一节&#xff0c;大多都是对之前学习的内容做的补充 所以加油继续冲啦&#xff01; ∧_∧::   (&#xff65;ω&#xff65;):: /⌒  ⌒):: /へ_&#xff3f; / /:: (&#xff3f;&#xff3c;&#xff3c; &#xff90;)/::   &am…

一种轻松且客观介绍大模型方式,避免过度解读:一

这是我关于《一种轻松且客观介绍大模型方式&#xff0c;避免过度解读》第一篇 一、前言 这篇文章旨在为没有计算机科学背景的读者提供一些关于ChatGPT及其类似的人工智能系统&#xff08;如GPT-3、GPT-4、Bing Chat、Bard等&#xff09;如何工作的原理。ChatGPT是一种聊天机器…

【网络安全】mysql数据库提权

数据库提权 数据库提权适用场景前提条件提权步骤如何探查数据库服务是否启动 mysql提权mysql 获取数据库最高权限账号密码方法1.读取网站配置文件2. 读取数据库存储或备份文件3. 脚本暴力破解 利用udf提权udf定义udf提权原理udf常用函数1. 获取mysql版本号2.udf.dll放置到被攻击…

华为P60 Pro灵犀双Wi-Fi流畅通信,让你体验超凡网速

家里装有宽带的朋友&#xff0c;用手机进行无线网络连接时&#xff0c;经常会发现有2.4G和5G两个Wi-Fi信号网络。Wi-Fi信号是通过无线电波传输的&#xff0c;2.4G和5G是两个不同的频段&#xff0c;Wi-Fi信号就在这样的频段内进行传输。 2.4G信号频率低&#xff0c;在空气或障碍…