51之定时器与中断系统

news2024/12/24 21:06:15

目录

1.定时器与中断系统简介

1.1中断系统

1.2定时器

1.2.1定时器简介

1.2.2定时器大致原理及其配置

1.2.3定时器所需的所有配置总介

2.定时器0实现LED闪烁

3.使用软件生成定时器初始化程序


1.定时器与中断系统简介

1.1中断系统

        首先,我们需要来了解一下什么是中断系统:首先,中断系统指的是我们程序运行过程中由于中断指令而需要停下当前的动作去做中断所要求的事情,完成中断要求的事情之后才可以回来继续完成之前事情的一个规则。

        就好比我们正在吃饭,但是突然厨房的水烧开了,我们就不得不去先去处理烧开的水,处理完之后再回来继续吃饭。我们去处理厨房烧开的水这个动作就叫做我们的”中断“。

        中断分为三大类:外部中断,定时器中断和串口中断

        我们使用的STC89C5X系列单片机提供了 8个中断请求源,其中,外部中断有四个,分别是外部中断0(INT0)、外部中断 1(INT1)、外部中断 2(INT2)、外部中断 3(INT3);定时器中断有三个,分别是定时器 0中断(Timer0)、定时器 1中断(Timer1)、定时器 2中断(Timer2);串口中断一个,就叫串口中断(UART)

        中断和中断之间还是有”三六九等的“,就像我们需要做的事情是有一个优先级的,比方说我们正在吃饭,但是这个时候,厨房的水烧开了,我们去把这个水处理一下,但是我们不小心摔倒了,这个时候我们优先处理的事情应该是从”处理烧开的水“变成”先爬起来“,这个就叫做中断的嵌套,先处理优先级更高的那个。我们应该要去处理中断优先级更高的那件事,就算我们正在处理应该中断的过程中,我们还是要去先处理更高优先级的中断请求,这也是中断嵌套的基本规则。

        这里有一张表格,写的就是中断的优先级:

我们可以看到,中断优先级的基本排序是:外部中断0(INT0) > 定时器 0中断(Timer0)>外部中断 1(INT1) > 定时器 1中断(Timer1) > 串口中断(UART)>定时器 2中断(Timer2)>外部中断 2(INT2)>外部中断 3(INT3)

1.2定时器

1.2.1定时器简介

  • 最初始的51单片机有两组定时器/计数器,因为既可以定时,又可以计数,故称之为定时器/计数器。T0T1与传统的51单片机兼容,T2是此型号单片机增加的资源
  • 定时器/计数器和单片机的 CPU是相互独立的。定时器/计数器工作的过程是自动完成的,不需要 CPU的参与。
  • 51单片机中的定时器/计数器是根据机器内部的时钟或者是外部的脉冲信号对寄存器中的数据加 1。

        有了定时器/计数器之后,可以增加单片机的效率,一些简单的重复加 1的工作可以交给定时器/计数器处理。CPU转而处理一些复杂的事情。同时可以实现精确定时作用。

        所以我们一般会使用定时器来代替之前的Delay,Delay的使用是对CPU执行的,在这段时间里,CPU都无法执行任何任务,而是在Delay函数中执行循环。所以我们现在可以采用定时器去把我们的Delay替换,转而把我们的CPU留出更多的时间去处理更加高效的事情。

1.2.2定时器大致原理及其配置

        大部分情况下,我们使用的最多的还是定时器0,这里是定时器的大致原理图

        我上图所示的C/T中T上有一个横线表示低电平有效,C表示高电平有效,C又是Clock的缩写,也就是说C/T = 1的话,我们使用的是计数器,如果C/T = 0,则说明我们使用的是计时器系统,这里的SYSclk叫做系统时钟,即晶振周期。我们一般使用的是12T mode运行。

        而则是一个控制开关,有这个小系统输出的值为高电平时,开关才会闭合,才会继续往后面执行操作。

        这里有必要介绍一下的是是非门电路,输入1则输出0,输入0则输出1;是或门,输入两个数有一个为1则输出1,都是0时才输出0;是与门,输入两个都是1时输出的才是1,否则输出的是0。

        这里我们需要反向推理一下,假设我们想要最终输出1,那么与门的两个输入口需要都是高电平1,所有这里TR0必须是1,然后就是这个或门的输出要是1,则说明这个门的输入只要有一个1就可以完成任务,或门连接的是 和,即门控端GATE取反值和外部中断0的值,我们要实现输出有一个为1即可,假如我们需要只靠外部中断0控制整个电路的通闭,那么我们就要把GATE设为1,即输出的为0,这样就只靠外部中断0实现控制电路,但是我们这里不需要依靠外部中断支配,所以我们这里直接把门控端GATE设为0就好了,这样无论外部中断0输出的是什么都不会影响我们的电路闭合。

        配置好了前面的部分,我们来配置一下后面的,这里要分成两部分,第一部分是 表示的是定时器/计数器0的计数数值,计数数值的高8bit位存在寄存器TH0中,后8bit位存在TL0中,最大可以表示到65535,每个单元一般时1us,直到超出了这个最大值,计数就会溢出,来到溢出标志位,这个就是一个判断定时器溢出的标志位,通过判断TF0来判断计数是否溢出,如果溢出,就会进入到中断中去。这就是上面的图的流程。

        我们配置的是定时器0,即T0的话,我们的流程就是这样的:

        经过刚刚的一系列计数,溢出,到达中断允许位,我们就来到了中断,这部分统称为IE,我们使用T0就要配置ET0为1,EA为1,才可以使这部分闭合,这部分也叫做“使能”,也就是这部分不闭合,我们就无法实现中断。然后就是到达IP选择PT0 = 1或者PT0 = 0,这就是选择高优先级和低优先级的,其实选择哪个都没有太大的影响,主要是完成前面的配置,保证电路通畅即可。

1.2.3定时器所需的所有配置总介

 

        这里写了两个寄存器列表,我们实现中断,所以从中断寄存器出发,我们必须要配置的是IE使能和IP/IPH的高低优先级选择。

        然后后面的进行分类,定时器T0和T1实现TCON的配置即可,我们实现T0定时器,就只要关关心TCON这个控制寄存器,然后我们需要实现的是T0,所以我们看到定时器0相关的寄存器列表中正好有TCON控制寄存器,然后我们还要实现TMOD模式寄存器的配置和TL0与TH0计数存放计数数值的初始化即可。

        总而言之,我们实现T0,需要配置IE使能(ET0和EA都配置为1),IP/IPH(即PT0)高低优先级选择,TCON控制寄存器,TMOD模式寄存器,TH0和TL0计数数值初始化。

        需要主要介绍的是TCON和TMOD这两个寄存器:

        这里TCON是“可位寻址”而TMOD是“不可位寻址”,意思就是TCON的每一位的配置可以单独配置,比如里面的IE0,IR0,而不用影响到IE1和IR1,但是TMOD就不一样,只能整体赋值,我们不能把里面的单个数拉出来赋值,只可以给一个十六进制的数把八位同时配置完成。

  TCON:   我们需要配置TCON,就只要让TR0 = 1让计数开始,IE0= 1使能让电路接通,IT0 = 1让

的控制只由TR0掌控。

        至于TF0标志位的置位和清零,可以说可有可无,初始置为0就好了,后面也不用再管。

TMOD:

        这里把IT0配置为1了,所以其实在TMOD中的门控端GATE是多少都不重要了

由于是不可位寻址,我们只能整体赋值,按照前面分析,我们操作定时器0的话需要把C/T = 0,GATE最好也设为0。

        M1和M0是模式的选择,主要的区别如下:

  • M1 = 0, M0 = 0: 13位定时/计数模式

    • 定时器/计数器0 使用 TH0 和 TL0 寄存器的所有位进行计数。
  • M1 = 0, M0 = 1: 16位定时/计数模式

    • 定时器/计数器0 使用 TH0 和 TL0 寄存器的所有位进行计数。
  • M1 = 1, M0 = 0: 8位自动重装定时/计数模式

    • 定时器/计数器0 先使用 TL0 寄存器计数,当 TL0 计数溢出时,自动从 TH0 中重新装载计数值,然后继续计数。
  • M1 = 1, M0 = 1: 2个8位定时/计数模式

    • 定时器/计数器0 分为两个独立的8位定时/计数器:T0 高位和 T0 低位。TH0 用作高8位计数器,TL0 用作低8位计数器。

我们一般默认选择两个8位的计数器,也就是M1 = 0, M0 = 1的16位定时/计数模式

所以综上所述,我们配置TMOD寄存器的最后四位,而且是配置为0001,前四位与定时器1有关,我们一般不作处理。

但是这里又只能整体赋值,所以TMOD的配置T0可以先把后四位清零,前四位不动,再把前四位不动,后四位变成0001,我们可以使用按位与(&)和按位或(|)两个操作符。

        先让TMOD &= 0xf0;就让前四位不变,后四位变成0000,再使用TMOD |= 0xf1;就让前四位不变,后四位变成0001,然后我们的TMOD配置就大功告成。

2.定时器0实现LED闪烁

        学习了配置定时器,我们就要学习怎么使用定时器,这里使用定时器配置间隔时长为1s的LED闪烁。

        这里我们就要写一个定时器初始化函数,把寄存器配置好,再使用中断实现功能。

        首先,我们需要配置模式寄存器TMOD,让TMOD选用定时器0并使用16位计时,所以我们就可以写出

TMOD &= 0xf0;
TMOD |= 0xf1;

然后是TCON寄存器

        这里主要是注意我们需要的是1s也就是1000*1000us,但是由于计数器限制,我们只能得到1ms的计时,就像Delay函数那样可以使用以1ms为基本单位的计时,累加起来就可以组成自己想要的时间

        这里就配置一个1000us,那么距离计数值溢出(65535)就相差1000,所以我们初始值为64535,TH0高四位为64535/256,TL0第四位为64535%256.

TL0 = 64535%256;	//设置定时初值
TH0 = 64535/256;//设置定时初值
TF0 = 0;		//清除TF0标志
TR0 = 1;		//定时器0开始计时
PT0 = 0;        //选择低优先级
ET0 = 1;        //使能配置
EA = 1;         //使能配置

这样就写完了我们的定时器0初始化程序:

void Timer0_Init()
{
    TMOD &= 0xf0;
    TMOD |= 0xf1;
    TL0 = 64535%256;	//设置定时初值
    TH0 = 64535/256;//设置定时初值
    TF0 = 0;		//清除TF0标志
    TR0 = 1;		//定时器0开始计时
    PT0 = 0;        //选择低优先级
    ET0 = 1;        //使能配置
    EA = 1;         //使能配置
}

配置完初始化程序之后,我们就开始配置中断程序:

        中断程序的命名参照这张图:

具体的流程就是这样,我们在中断函数中实现一下我们的代码:

void Timer0_Rountine() interrupt 1
{
	static int count = 0;//只有函数第一次被调用的时候才会初始化
	count++;
	TL0 = 64535%256;
	TH0 = 64535/256;//重新设置时间,否则默认设置为0
	if(count >= 1000)//到达1s
	{
		count = 0;//归0
		P2_0 = ~P2_0;//开关灯
	}
}

这样我们的代码就完全写完了:

#include <REGX52.H>
void Timer0_Init()
{
    TMOD &= 0xf0;
    TMOD |= 0xf1;
    TL0 = 64535%256;
    TH0 = 64535/256;
    TF0 = 0;
    TR0 = 1;
    PT0 = 0;
    ET0 = 1; 
    EA = 1; 
}

void main()
{
	Timer0_Init();
	while(1)
	{
		//主程序
	}
}

void Timer0_Rountine() interrupt 1
{
	static int count = 0;//只有函数第一次被调用的时候才会初始化
	count++;
	TL0 = 64535%256;
	TH0 = 64535/256;//重新设置时间,否则默认设置为0
	if(count >= 1000)//到达1s
	{
		count = 0;//归0
		P2_0 = ~P2_0;//开关灯
	}
}

这里我们并没有需要使用CPU执行主程序,所以while循环中的程序就不写了,还有一个要注意的点,就是头文件#include <REGX52.H>中才有我们需要配置的寄存器的地址,所以要包含这个头文件我们才可以使用这个定时器并配置程序。

到这里我们的定时器实现LED闪烁就算结束了。

3.使用软件生成定时器初始化程序

        我们的一个软件中可以生成定时器初始化程序:

我们设置好之后就可以得到一个定时器的较为准确的一个代码:

void Timer0Init(void)		//1毫秒@11.0592MHz
{
	AUXR |= 0x80;		//定时器时钟1T模式
	TMOD &= 0xF0;		//设置定时器模式
	TL0 = 0xCD;		//设置定时初值
	TH0 = 0xD4;		//设置定时初值
	TF0 = 0;		//清除TF0标志
	TR0 = 1;		//定时器0开始计时
}

我们的单片机上没有AUXR这个配置的选项,不需要配置它,然后就是这里还有一些代码我们需啊哟自己配置,比如IE使能和优先级选择。我们全部修改完成之后就是这样:

void Timer0Init(void)		//1毫秒@11.0592MHz
{
	TMOD &= 0xF0;		//设置定时器模式
	TL0 = 0xCD;		//设置定时初值
	TH0 = 0xD4;		//设置定时初值
	TF0 = 0;		//清除TF0标志
	TR0 = 1;		//定时器0开始计时
	
	PT0 = 0;		//优先级配置 
    ET0 = 1; 		//使能配置 
    EA = 1; 		//使能配置 
}

然后我们就可以快乐地使用定时器了!

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

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

相关文章

选择企业邮箱,扬帆迈向商务新纪元!

企业邮箱和个人邮箱不同&#xff0c;它的邮箱后缀是企业自己的域名。企业邮箱供应商一般都提供手机app、桌面端、web浏览器访问等邮箱使用途径。那么什么是企业邮箱&#xff1f;如何选择合适的企业邮箱&#xff1f;好用的企业邮箱应具备无缝迁移、协作、多邮箱管理等功能。 企…

(一)小案例银行家应用程序-介绍

案例示例如下所示&#xff1a; 登录之后就会出现下面所示&#xff1a; 项目案例流程图如下 ● 首先我们建立四个账号对象&#xff0c;用于登录 const account1 {owner: ItShare,movements: [200, 450, -400, 3000, -650, -130, 70, 1300],interestRate: 1.2, // %pin: 11…

算法学习系列(四十七):IDA*

目录 引言一、概念二、例题1.排书2.回转游戏 引言 之前觉得这个IDA*算法、迭代加深算法很神秘&#xff0c;感觉很难&#xff0c;其实自己学下来感觉其实不难&#xff0c;相反思路非常的简单&#xff0c;清晰明了&#xff0c;我觉得难是因为我之前从来都不写暴力&#xff0c;就…

发布自己的github项目

git下载 git关网&#xff1a;https://git-scm.com/ 下载后是exe文件 git安装 除了选安装地址&#xff0c;其他都是下一步下一步傻瓜式安装 安装好之后随便一个地方右键多了两个东西 git gui here 和git bash here git测试配置及创建github项目 右键git bash here 测试…

C语言之指针的指向地址和指针的内容总结(八十九)

简介&#xff1a; CSDN博客专家&#xff0c;专注Android/Linux系统&#xff0c;分享多mic语音方案、音视频、编解码等技术&#xff0c;与大家一起成长&#xff01; 优质专栏&#xff1a;Audio工程师进阶系列【原创干货持续更新中……】&#x1f680; 优质专栏&#xff1a;多媒…

全国加油站分布数据/停车场分布/公园分布/景区分布/保护区分布/poi感兴趣点

加油站是指为汽车和其它机动车辆服务的、零售汽油和机油的补充站&#xff0c;一般为添加燃料油、润滑油等。由于加油站所销售的石油商品具有易燃爆、易挥发、易渗漏、易集聚静电荷的特性&#xff0c;故加油站以“安全”为第一准则。在加油站内严禁烟火&#xff0c;严禁从事可能…

SpringMVC --- 老杜

1、什么是SpringMVC&#xff1f; SpringMVC是一个基于Java实现了MVC设计模式的请求驱动类型的轻量级Web框架&#xff0c;通过把Model&#xff0c;View&#xff0c;Controller分离&#xff0c;将web层进行职责解耦&#xff0c;把复杂的web应用分成逻辑清晰的及部分&#xff0c;…

java中大型医院HIS系统源码 Angular+Nginx+SpringBoot云HIS运维平台源码

java中大型医院HIS系统源码 AngularNginxSpringBoot云HIS运维平台源码 云HIS系统是一款满足基层医院各类业务需要的健康云产品。该产品能帮助基层医院完成日常各类业务&#xff0c;提供病患预约挂号支持、病患问诊、电子病历、开药发药、会员管理、统计查询、医生工作站和护士工…

Gson的用法

1. 导入依赖 <dependency><groupId>com.google.code.gson</groupId><artifactId>gson</artifactId><version>2.8.6</version> </dependency> 2. 使用Gson进行解析 2.1 Gson解析普通对象 package com.jiang.partnetbackend.…

Studio One 6注册机下载安装激活教程

一、Studio One 6安装 StudioOne6 下载&#xff1a;https://souurl.cn/Y6ZWCY StudioOne6 Win/Mac版注册机下载&#xff1a; rack百度网盘&#xff1a;https://pan.baidu.com/s/1zX3DqXt-wsy510L1lDI7Xg 提取码&#xff1a;3phh 1.双击Studio One6安装包&#xff0c;如下图&…

Qt中的事件学习笔记

视频链接 https://www.bilibili.com/video/BV18B4y1K7Cs/?spm_id_from333.999.0.0&vd_sourcefa4ef8f26ae084f9b5f70a5f87e9e41b事件 Qt主要用来开发带窗口的应用程序&#xff0c;我们使用的窗口的应用程序都是基于时间&#xff08;比如安卓中的点击事件&#xff09;&…

【机器学习】机器学习创建算法第4篇:K-近邻算法,学习目标【附代码文档】

机器学习&#xff08;算法篇&#xff09;完整教程&#xff08;附代码资料&#xff09;主要内容讲述&#xff1a;机器学习算法课程定位、目标&#xff0c;K-近邻算法定位,目标,学习目标,1 什么是K-近邻算法,1 Scikit-learn工具介绍,2 K-近邻算法API。K-近邻算法&#xff0c;1.4 …

手术麻醉系统源码 医疗信息管理系统源码C#.net6.0+ vs2022,vscode+BS网页版 手麻系统源码

手术麻醉系统源码 医疗信息管理系统源码C#.net6.0 vs2022,vscodeB/S网页版 手麻系统源码 手术麻醉管理系统是应用于医院手术室、麻醉科室的计算机软件系统。该系统针对整个围术期&#xff0c;对病人进行全程跟踪与信息管理&#xff0c;自动集成病人HIS、LIS、RIS、PACS信息&…

第四百四十三回

文章目录 1. 概念介绍2. 思路与方法2.1 整体思路2.2 使用方法 3. 示例代码4. 内容总结 我们在上一章回中介绍了"自定义Action菜单"相关的内容&#xff0c;本章回中将介绍如何获取屏幕相关参数.闲话休提&#xff0c;让我们一起Talk Flutter吧。 1. 概念介绍 我们在本…

【面试八股总结】进程(一)

参考资料 &#xff1a;小林Coding、阿秀、代码随想录 一、什么是进程&#xff1f; 1. 基本概念 进程是具有独立功能的程序在一个数据集合上运行的过程&#xff0c;是系统进行资源分配和调度的一个独立单位。 2. 进程控制块 系统通过进程控制块PCB描述进程的进本情况…

[Spring Cloud] gateway全局异常捕捉统一返回值

文章目录 处理转发失败的情况全局参数同一返回格式操作消息对象AjaxResult返回值状态描述对象AjaxStatus返回值枚举接口层StatusCode 全局异常处理器自定义通用异常定一个自定义异常覆盖默认的异常处理自定义异常处理工具 在上一篇章时我们有了一个简单的gateway网关 [Spring C…

vue3中实现文本显示省略号和tooltips提示框

前言 在 B 端业务中&#xff0c;我们经常会遇到文本内容超出容器区域需显示省略号的需求。当鼠标移入文本时&#xff0c;会出现 Tooltip 显示完整内容。最近&#xff0c;我也遇到了这样的场景。为了提高业务通用性&#xff0c;我已将其封装为组件、Hook 和指令等形式供使用。 …

从0到1实现RPC | 04 负载均衡和静态注册中心

一、Router的定义 Router路由用于预筛选&#xff0c;Dubbo有这样的设计&#xff0c;SpringCloud没有。 二、LoadBanlancer定义 负载均衡器&#xff1a;默认取第一个 当前支持随机和轮询两种负载均衡器。 随机&#xff1a;从所有provider中随机选择一个。 轮询&#xff1a;每…

如何选择优质的静动态住宅代理IP提供商

在从事跨境电商业务时选择优质的静动态住宅代理IP提供商是一个涉及多个方面考量的过程。在进行选择时&#xff0c;需要综合考虑多种因素&#xff0c;以确保选择的提供商能够满足您的需求并提供稳定、可靠的服务。以下是一些建议&#xff0c;以帮助您进行选择&#xff1a; 第一…

js中使let关键字报错,改用var关键字解决

js中使let关键字报错,改用var关键字解决 项目场景&#xff1a;问题描述原因分析&#xff1a;解决方案&#xff1a;总结 项目场景&#xff1a; 使用 let 关键字报错&#xff0c;报错信息为&#xff1a; Uncaught ReferenceError: maxNum is not defined at getMaxNum (4-3.htm…