51之定时器与中断系统

目录

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;//重新设置时间,否则默认设置为0if(count >= 1000)//到达1s{count = 0;//归0P2_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;//重新设置时间,否则默认设置为0if(count >= 1000)//到达1s{count = 0;//归0P2_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.mzph.cn/news/794652.shtml

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

相关文章

深入浅出 -- 系统架构之单体到分布式架构的演变

一、传统模式的技术改革 在很多年以前&#xff0c;其实没有严格意义上的前后端工程师之分&#xff0c;每个后端就是前端&#xff0c;同理&#xff0c;前端也可以是后端&#xff0c;即Ajax、jQuery技术未盛行前的年代。 起初&#xff0c;大部分前端界面很简单&#xff0c;显示的…

AcWing1402.星空之夜

【题目链接】1402. 星空之夜 - AcWing题库 夜空深处&#xff0c;闪亮的星星以星群的形式出现在人们眼中&#xff0c;形态万千。 一个星群是指一组非空的在水平&#xff0c;垂直或对角线方向相邻的星星的集合。 一个星群不能是一个更大星群的一部分。 星群可能是相似的。 如…

【蓝桥杯】GCD与LCM

一.概述 最大公约数&#xff08;GCD&#xff09;和最小公倍数&#xff08;Least Common Multiple&#xff0c;LCM&#xff09; 在C中&#xff0c;可以使用 std::__gcd(a, b)来计算最大公约数 1.欧几里德算法/辗转相除法 int gcd(int a,int b){return b?gcd(b, a%b):a; } 2…

Tensorboard以及Transforms初步学习

一.前情提要 1.本文是代码结合知识点&#xff0c;注释即为知识点 2.主要详细讲解Tensorboard以及Transforms代码以及基础知识 3.若想深入学习&#xff0c;建议阅读 P3. Python学习中的两大法宝函数&#xff08;当然也可以用在PyTorch&#xff09;_哔哩哔哩_bilibili 二.简述…

抖音运营技巧

1、视频时长 抖音的作品是否能够继续被推荐&#xff0c;取决于综合数据&#xff0c;包括完播率、点赞率、评论率、转发率和收藏率等。其中&#xff0c;完播率是最容易控制的因素。对于新号来说&#xff0c;在没有粉丝的初期&#xff0c;发布过长的视频可能会导致无人观看。因此…

金田金业带你一文了解现货黄金开户注意事项

现货黄金作为一种受欢迎的投资品种&#xff0c;吸引了越来越多的投资者。然而&#xff0c;在进行现货黄金开户时&#xff0c;有一些重要的注意事项需要牢记。本文将为您详细介绍现货黄金开户的九大关键要点&#xff0c;确保您能够在投资过程中做出明智的决策。 第一&#xff0c…

Java- maven下载jar包,提示找不到,Could not find artifact

1、执行下面命令行 mvn install:install-file -Dfile/home/quangang/桌面/isv-sdk-2.0.jar -DgroupIdcom.jd -DartifactIdisv-sdk -Dversion2.0 -Dpackangjar 2、然后这里要加上jar包

No dashboards are active for the current data set.

再次记录一下这个离谱的问题 之前出现这个问题是因为目录没写对 今天遇到这个问题的原因是目录是对的&#xff0c;跟目录是否带有中文也没关系 是writer写入的时候写的是空的&#xff0c;离谱的是写入是空的情况下也会生成events日志文件&#xff0c;看起来好像成功写入了一样&…

Spring源码解析上

spring源码解析 整体架构 defaultListableBeanFactory xmlBeanDefinitionReader 创建XmlBeanFactory 对资源文件进行加载–Resource 利用LoadBeandefinitions(resource)方法加载配置中的bean loadBeandefinitions加载步骤 doLoadBeanDefinition xml配置模式 validationMode 获…

2024-04-05 问AI: 介绍一下深度学习中的Leaky ReLU函数

文心一言 Leaky ReLU&#xff08;Leaky Rectified Linear Unit&#xff09;函数是深度学习领域中的一种激活函数&#xff0c;主要用于解决ReLU&#xff08;Rectified Linear Unit&#xff09;函数在负值区域为零的问题。ReLU函数在输入为正时保持原样&#xff0c;而在输入为负…

nodejs实现TCP端口转发并截包的小工具

近期我正致力于开发一个基于 Go-CQHTTP 的 QQ 机器人应用程序项目&#xff0c;该项目现已成功实现了 Go-CQHTTP 的容器化部署&#xff0c;利用 Docker 技术确保其运行环境的一致性与便捷性。随着项目推进&#xff0c;接下来的工作重心转向部署配套的签名服务器&#xff08;qsig…

软考111-上午题-【计算机网络】-URL和DNS

一、URL解析 org&#xff1a;各类组织结构&#xff08;非盈利团队&#xff09; 1-1、顶级域 顶级域名是域名的最后一个部分&#xff0c;即是域名最后一点之后的字母&#xff0c;例如&#xff1a;www.baidu.com这个域名中&#xff0c;顶级域是.com&#xff08;或.COM&#xff…

数据结构系列-队列的结构和队列的实现

&#x1f308;个人主页&#xff1a;羽晨同学 &#x1f4ab;个人格言:“成为自己未来的主人~” 队列 队列的概念及结构 队列&#xff1a;只允许在一端进行插入数据操作&#xff0c;在另一端进行删除删除数据操作的特殊线性表&#xff0c;队列具有先进先出FIFO&#xff0c;…

全面解析找不到msvcr110.dll,无法继续执行代码的解决方法

MSVCR110.dll的丢失可能导致某些应用程序无法启动。当用户试图打开依赖于该特定版本DLL文件的软件时&#xff0c;可能会遭遇“找不到指定模块”的错误提示&#xff0c;使得程序启动进程戛然而止。这种突如其来的故障不仅打断了用户的正常工作流程&#xff0c;也可能导致重要数据…

基于SpringBoot+微信小程序的农产品销售平台

一、项目背景介绍&#xff1a; 随着人们收入的不断增加、生活水平的普遍提高,对生活质量的要求也日益凸显。而作为关乎每个人的生命、健康安全的食品卫生、质量无疑更被人们所重视。所以,… 2. 其他国家的绿色有机食品所占其国家食品市场比重比较大,如德国在99年便已达到40%,美…

Mac反编译APK

文章目录 第一种方式: brew installapktool 使用说明dex2jar 使用说明 第二种方式: 下载安装包apktool 使用说明 (根据官方介绍没有操作成功,后续成功再更新这里)dex2jar 使用说明 安装 JD-GUI 查看jar包中的class文件JD-GUI 使用说明 第一种方式: brew install 安装过程可能很…

使用 mitmproxy 抓包 grpc

昨天在本地执行 grpc 的 quick start&#xff08;python版本的&#xff09;&#xff0c;我了解 grpc 内部使用的是 HTTP2&#xff0c;所以我就想着抓包来试试&#xff0c;下面就来记录一下这个过程中的探索。 注意&#xff1a;我的电脑上面安装了 Fiddler Classic&#xff0c;…

微信小程序生命周期管理:从数据初始化到事件绑定

作为一个独立的应用开发平台,微信小程序提供了自己的生命周期机制,与我们熟悉的Vue.js框架有一些差异。掌握小程序生命周期的特点和使用技巧,对于开发高质量的小程序应用至关重要。深入理解和掌握小程序生命周期的使用技巧,将有助于我们构建出更加健壮和可维护的小程序应用。 小…

可视化大屏 - 项目1

文章目录 技术栈echarts 可视化需求分析代码实现 技术栈 flexible.js rem 实现不同终端下的响应式布局&#xff0c;根据不同屏幕宽度&#xff0c;自适配布局&#xff1b; html中引入index.js&#xff0c;可以改名为flexible.js&#xff1b;默认划分10份&#xff0c;可以自己修…