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单片机有两组定时器/计数器,因为既可以定时,又可以计数,故称之为定时器/计数器。T0和T1与传统的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; //使能配置
}
然后我们就可以快乐地使用定时器了!
相关文章:
51之定时器与中断系统
目录 1.定时器与中断系统简介 1.1中断系统 1.2定时器 1.2.1定时器简介 1.2.2定时器大致原理及其配置 1.2.3定时器所需的所有配置总介 2.定时器0实现LED闪烁 3.使用软件生成定时器初始化程序 1.定时器与中断系统简介 1.1中断系统 首先,我们需要来了解一下什么…...
C语言中的内存函数
相比于内存函数,字符串函数和字符函数是对字符串和字符进行操作,内存函数是对内存进行操的。下面跟大家分享我学到的几个内存函数。 memcpy函数 void* memcpy(void* dest, const void* sour, size_t num); dest是目标地址,sour要拷贝的源地…...
JS继承与原型、原型链
在 JavaScript 中,继承是实现代码复用和构建对象关系的重要概念。本文将讨论原型链继承、构造函数继承以及组合继承等几种常见的继承方式,并提供相应的示例代码,并分析它们的特点、优缺点以及适用场景。 在开始讲解 JavaScript 的继承方式之…...
C#基础知识总结
C语言、C和C#的区别 ✔ 面向对象编程(OOP): C 是一种过程化的编程语言,它不直接支持面向对象编程。然而,C 是一种支持 OOP 的 C 的超集,它引入了类、对象、继承、多态等概念。C# 是完全面向对象的ÿ…...
机器学习模型——决策树
决策树的定义: 决策树利用树形数据结构来展示决策规则和分类结果,它是一种归纳学习算法,可以将复杂数据转化为可以预测未知数据的模型。每一条从根节点到叶节点的路径都代表一条决策规则。 决策树内的一些重要名词: 信息熵&am…...
【HTML】制作一个简单的三角形动态图形
目录 前言 开始 HTML部分 CSS部分 效果图 总结 前言 无需多言,本文将详细介绍一段HTML和CSS代码,具体内容如下: 开始 首先新建文件夹,创建两个文本文档,其中HTML的文件名改为[index.html],CSS的文件名…...
Acwing.504 转圈游戏(带取余的快速幂)
题目 n个小伙伴(编号从 0到 n−1)围坐一圈玩游戏。 按照顺时针方向给 n个位置编号,从 0到 n−1。 最初,第 0号小伙伴在第 0号位置,第 1号小伙伴在第 1号位置,…,依此类推。 游戏规…...
pair作为unordered_map的key报错
问题 pair作为unordered_map的key报错,编译时会报错 原因 因为pair没有哈希函数 解决方法 定义哈希函数 template <typename T> inline void hash_combine(std::size_t &seed, const T &val) {seed ^ std::hash<T>()(val) 0x9e3779b9 (…...
Windows提权—数据库提权-mysql提权mssql提权Oracle数据库提权
目录 Windows 提权—数据库提权一、mysql提权1.1 udf提权1.1.2 操作方法一 、MSF自动化--UDF提权--漏洞利用1.1.3 操作方法二、 手工导出sqlmap中的dll1.1.4 操作方法三、 moon.php大马利用 1.2 mof提权1.3 启动项提权1.4 反弹shell 二、MSSQL提权MSSQL提权方法1.使用xp_cmdshe…...
为什么android创建Fragment推荐用newInstance
FullScreenDialogFragment使用newInstance方法不是因为它是一个单例,而是因为这是创建DialogFragment实例并同时提供参数的一种标准模式。这种模式通常称为静态工厂方法模式,在Android开发中被广泛使用,尤其是用于Fragment的实例化。 newIns…...
MyBatis的xml实现方式
1、该项目引入的依赖 <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0" xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation"http://maven.apache.o…...
大模型prompt技巧——思维链(Chain-of-Thought)
1、Zero-shot、One-shot、Few-shot 与fintune prompt的时候给出例子答案,然后再让模型回答。 2、zero-shot-CoT “Let’s think step by step”有奇迹效果 3、多数投票提高CoT性能——自洽性(Self-consistency) 多个思维链,然后取…...
内网穿透的应用-如何在Android Termux上部署MySQL数据库并实现无公网IP远程访问
文章目录 前言1.安装MariaDB2.安装cpolar内网穿透工具3. 创建安全隧道映射mysql4. 公网远程连接5. 固定远程连接地址 前言 Android作为移动设备,尽管最初并非设计为服务器,但是随着技术的进步我们可以将Android配置为生产力工具,变成一个随身…...
面试算法-133-区间子数组个数
题目 给你一个整数数组 nums 和两个整数:left 及 right 。找出 nums 中连续、非空且其中最大元素在范围 [left, right] 内的子数组,并返回满足条件的子数组的个数。 生成的测试用例保证结果符合 32-bit 整数范围。 示例 1: 输入ÿ…...
物联网实战--入门篇之(八)嵌入式-空气净化器
目录 一、风扇调速 二、通讯协议 三、净化器运行逻辑 一、风扇调速 单片机是不能直接驱动电机的,因为主芯片的驱动电流比较小(50mA左右),他们之间正常还要有个电机驱动器,常用的有TB6612、L298和L9110等,目前项目用的这个电机它…...
macOS上QT打开麦克风和摄像头的权限问题
同样的代码在Windows上可以轻松操作麦克风和摄像头,特别是用QT这种跨平台的框架。但是对macOS这种权限要求完善的系统还需要进行一些配置,那就是增加Info.plist属性配置文件。如果是之前的早期5.x版本的QTCreator因为使用的是qmake构建系统,估…...
鸿蒙手机cordova-plugin-camera不能拍照和图片不显示问题
鸿蒙手机cordova-plugin-camera不能拍照和图片不显示问题 一、运行环境 1、硬件 手机型号:NOVA 7 系统:HarmonyOS版本 4.0.0 2、软件 android SDK platforms:14.0(API Level 34)、13.0(API Level 33) SDK Build-T…...
Spring源码解析上
spring源码解析 整体架构 defaultListableBeanFactory xmlBeanDefinitionReader 创建XmlBeanFactory 对资源文件进行加载–Resource 利用LoadBeandefinitions(resource)方法加载配置中的bean loadBeandefinitions加载步骤 doLoadBeanDefinition xml配置模式 validationMode 获…...
第九题:最大间隙
题目描述 给定一个序列 a1,a2,⋯ ,an。其中 a1≤a2≤⋯≤an。 相邻两个数之间的差(后一个数减前一个数)称为它们的间隙。 请问序列中最大的间隙值是多少? 输入描述 输入的第一行包含一个整数 n,表示序列的长度。 第二行包含…...
【随笔】Git -- 高级命令(中篇)(七)
💌 所属专栏:【Git】 😀 作 者:我是夜阑的狗🐶 🚀 个人简介:一个正在努力学技术的CV工程师,专注基础和实战分享 ,欢迎咨询! 💖 欢迎大…...
MODBUS TCP转CANopen 技术赋能高效协同作业
在现代工业自动化领域,MODBUS TCP和CANopen两种通讯协议因其稳定性和高效性被广泛应用于各种设备和系统中。而随着科技的不断进步,这两种通讯协议也正在被逐步融合,形成了一种新型的通讯方式——开疆智能MODBUS TCP转CANopen网关KJ-TCPC-CANP…...
Module Federation 和 Native Federation 的比较
前言 Module Federation 是 Webpack 5 引入的微前端架构方案,允许不同独立构建的应用在运行时动态共享模块。 Native Federation 是 Angular 官方基于 Module Federation 理念实现的专为 Angular 优化的微前端方案。 概念解析 Module Federation (模块联邦) Modul…...
unix/linux,sudo,其发展历程详细时间线、由来、历史背景
sudo 的诞生和演化,本身就是一部 Unix/Linux 系统管理哲学变迁的微缩史。来,让我们拨开时间的迷雾,一同探寻 sudo 那波澜壮阔(也颇为实用主义)的发展历程。 历史背景:su的时代与困境 ( 20 世纪 70 年代 - 80 年代初) 在 sudo 出现之前,Unix 系统管理员和需要特权操作的…...
Unsafe Fileupload篇补充-木马的详细教程与木马分享(中国蚁剑方式)
在之前的皮卡丘靶场第九期Unsafe Fileupload篇中我们学习了木马的原理并且学了一个简单的木马文件 本期内容是为了更好的为大家解释木马(服务器方面的)的原理,连接,以及各种木马及连接工具的分享 文件木马:https://w…...
初探Service服务发现机制
1.Service简介 Service是将运行在一组Pod上的应用程序发布为网络服务的抽象方法。 主要功能:服务发现和负载均衡。 Service类型的包括ClusterIP类型、NodePort类型、LoadBalancer类型、ExternalName类型 2.Endpoints简介 Endpoints是一种Kubernetes资源…...
【无标题】路径问题的革命性重构:基于二维拓扑收缩色动力学模型的零点隧穿理论
路径问题的革命性重构:基于二维拓扑收缩色动力学模型的零点隧穿理论 一、传统路径模型的根本缺陷 在经典正方形路径问题中(图1): mermaid graph LR A((A)) --- B((B)) B --- C((C)) C --- D((D)) D --- A A -.- C[无直接路径] B -…...
站群服务器的应用场景都有哪些?
站群服务器主要是为了多个网站的托管和管理所设计的,可以通过集中管理和高效资源的分配,来支持多个独立的网站同时运行,让每一个网站都可以分配到独立的IP地址,避免出现IP关联的风险,用户还可以通过控制面板进行管理功…...
STM32---外部32.768K晶振(LSE)无法起振问题
晶振是否起振主要就检查两个1、晶振与MCU是否兼容;2、晶振的负载电容是否匹配 目录 一、判断晶振与MCU是否兼容 二、判断负载电容是否匹配 1. 晶振负载电容(CL)与匹配电容(CL1、CL2)的关系 2. 如何选择 CL1 和 CL…...
【学习笔记】erase 删除顺序迭代器后迭代器失效的解决方案
目录 使用 erase 返回值继续迭代使用索引进行遍历 我们知道类似 vector 的顺序迭代器被删除后,迭代器会失效,因为顺序迭代器在内存中是连续存储的,元素删除后,后续元素会前移。 但一些场景中,我们又需要在执行删除操作…...
pycharm 设置环境出错
pycharm 设置环境出错 pycharm 新建项目,设置虚拟环境,出错 pycharm 出错 Cannot open Local Failed to start [powershell.exe, -NoExit, -ExecutionPolicy, Bypass, -File, C:\Program Files\JetBrains\PyCharm 2024.1.3\plugins\terminal\shell-int…...
