蓝桥杯单片机学习5——外部中断

2023-10-30

上期我们学习了独立按键&矩阵按键,这次我们来学习外部中断。

中断

当CPU正在处理某个事件的时候,外界发生了紧急事件请求,CPU需要暂停当前的工作,转而去处理这个紧急事件,处理完之后,再次回到之前被中断的地方,继续执行原来的工作,这样的过程就叫做中断。
举个栗子:你现在正在家里面看电视,这个时候,你妈妈让你去把水果洗掉,这个时候你就需要去把水果洗掉,洗完之后再回来继续看电视。看电视就是当前正在处理的事情,洗水果就是中断请求,或者叫中断源,你洗完水果回来继续看电视这个过程就是中断。
在这里插入图片描述

1.中断请求源

我们把引起中断的原因,或者能够发出中断请求信号的来源统称为中断源。洗水果是一种中断源,拿外卖也一样可以,也就是说中断源可以有多个
在这里插入图片描述
STC15F2K60S2系列单片机的中断源也一样有多个,最主要的有外部中断0(INT0)、定时器0中断、外部中断1(INT1)、定时器1中断、串口1中断这五个,本篇我们先介绍外部中断0、1,其他的后面再讲。

2.外部中断

在这里插入图片描述

单片机的P3.2/INT0和P3.3/INT1引脚除了作为IO口使用外,还分别对应着外部中断0和外部中断1,当检测到对应引脚的电平发生变化时,可以产生中断请求,进而执行相应的中断函数。
举个栗子:这两个引脚在单片机上分别连接按键S5和S4,当我们按下或松开按键时,会在对应引脚上产生一个电平变化,进而在单片机内部产生中断请求,单片机就可以选择是否要产生中断去处理相应的事件。

3.中断寄存器

我们要使用中断,那就就需要对中断相关的寄存器进行配置。
比较常用的中断寄存器有以下几个:
1.中断允许寄存器IE(可以位寻址)
在这里插入图片描述

很明显:我们需要使用外部中断0、1,就需要吧EX0(外部中断0允许位)和EX1(外部中断1允许位)都置为1,同时要把EA(总中断允许控制位)置为1。
PS:中断允许可以理解为单片机检测到了对应引脚的到底电平的变化,但这个电平变化是否需要我们产生中断去响应它,这些是根据我们程序来决定的,因此存在中断允许位来决定是否需要产生中断。

2.定时器/计数器控制寄存器TCON(可位寻址)
在这里插入图片描述
PS:前面我们讲过单片机可以检测对应引脚的电平变化,那么究竟时怎样的电平变化呢?
这里提供了两种选择:当IT0/IT1为0时,对应的触发方式为上升沿和下降沿都可以触发。
当为1时,则只可以下降沿触发。

3.中断优先级控制寄存器IP/IP2
在这里插入图片描述
前面我们讲过,中断源是有多个的,那么,单片机同时面对多个中断时,究竟该先相应哪一个请求呢?这个时候就需要用到我们的优先级控制寄存器。当对应位置为1时,可以设计其优先级为高优先级。当同时存在多个中断请求时,单片机会首先响应优先级高的中断,在处理完优先级高的中断之后再去处理优先级低的中断请求,最后在处理完所有的中断请求之后再去处理主函数。

中断优先级的特点:
1.低优先级的中断可以被高优先级的中断所中断(中断嵌套),反之则不可以。
2.任何一个中断,一旦被响应之后,就不可以被同优先级的中断所打断。

4.中断优先级

前面我们提到了中断优先级控制寄存器,可以设置中断的优先级。
但是在面对比较复杂的程序时,往往会出现同时存在多个中断优先级相同的情况,那么在我面对多个优先级相同的中断请求时,单片机该如何应对呢?

在这里插入图片描述

在单片机的内部存在一个辅助优先级结构,在面对相同优先级的中断请求时,会按照如图所示的顺序进行响应。

5.中断结构

在这里插入图片描述
讲了那么多,一个完整的中断流程时怎么样的?
在使用中断之前,我们需要:
1.选择中断触发方式
2.开启中断允许
3.设置中断优先级(这一步在中断比较少的情况下可以省略)
4.编写中断服务函数。

前三步可以在中断初始化函数中实现,第四步则需要编写单独的中断服务函数。

6.中断函数

1.初始化函数

//外部中断0初始化函数
void IT0_Init(void)
{
    EX0 = 1;    //开启外部中断0允许
    EA=1;       //开启中断总允许
    IT0=1;      //设置触发方式为下降沿触发,为0时触发方式为下降沿和上升沿都触发
    PX0 = 0;    //设置低优先级,为1时为高优先级
}


//外部中断1初始化函数
void IT1_Init(void)
{
    EX1 = 1;    //开启外部中断0允许
    EA=1;       //开启中断总允许
    IT1=1;      //设置触发方式为下降沿触发,为0时触发方式为下降沿和上升沿都触发
    PX1 = 1;    //设置低优先级,为1时为高优先级
}

2.中断服务函数

中断服务函数的写法,不同于普通的函数,具体写法如下:
void 函数名(void) interrupt 中断号
{
//函数内容
}

中断服务函数的特点:
1.中断服务函数不能带有参数和返回值。
2.中断服务函数后面需要带有 interrupt关键字 ,并且标注中断号

使用时需要注意的点:
1.中断函数讲究的时快进快出,不要进行延时,大量浮点运算等耗时操作。
2.不能够再中断函数中递归,调用自身。
3.中断函数中不宜写太多的代码,否则可能导致中断服务函数还未执行完,因为符合条件,又触发了一次中断,程序就一直卡在中断服务程序中,导致整个系统崩溃;
4.当系统有多个中断时,为防止在执行当前中断服务函数时,被另一个不必要的中断打断,一个可以参考的解决方法时在进入中断时关闭其他中断,并在中断服务函数的最后一句再次开启中断开关

//外部中断0服务函数
void External_Hander0() interrupt 0
{
    //函数内容
}



//外部中断1服务函数
void External_Hander2() interrupt 2
{
    //函数内容
}  

不同中断对应的中断号如下:
在这里插入图片描述

6.中断嵌套

中断嵌套是指 中断系统 正在执行一个中断服务时,有另一个优先级更高的中断提出 中断请求 ,这时会暂时终止当前正在执行的级别较低的 中断源 的服务程序,去处理级别更高的中断源,待处理完毕,再返回到被中断了的 中断服务程序 继续执行的过程。
在这里插入图片描述
举个栗子:你现在再看看电视,如你妈妈叫你去洗水果,在你洗水果的时候,你定的外卖到了,这个时候,你要停下洗水果,去拿外卖,拿完外卖之后再去继续洗水果,洗完水果才能去继续看电视。
看电视就是主程序,洗水果就是低级的中断,拿外卖就是高级的中断。

实战环节

1.任务要求

  • 通过数码管显示一个数字(初始值为0,最大值为9999),使用外部中断INT0,和INT1分别控制数字的加减,即当S5按下时,数字加一,按下S4,数字减一。

2.代码实现

1.main.c

#include <STC15F2K60S2.H>
#include "LS138.h"
#include "Interrupt.h"

static unsigned int Count = 0;

void main()
{
    IT0_Init();
    IT1_Init();
    LS138_Init();
	while(1)
	{
        if(Count>= 9999)
        {
            Count=9999;
        }
		SEG_Write_Num(Count);
	}
}


//外部中断0服务函数
void External_Hander0() interrupt 0
{
    Delayxms(20);
    if(P3^2==0)
    {
        Count++;
    }
}

//外部中断1服务函数
void External_Hander2() interrupt 2
{
    Delayxms(20);
    if(P3^3==0)
    {
        Count--;
    }
}   
  

PS:SEG_Write_Num(Count)这个函数在LS138.h头文件中,不过时我自己后面加上去的,可在数码管上显示一个四位数的数字,
具体代码如下:

//在数码管的前四位上显示对应的数字
//显示数字大小为0~9999
void SEG_Write_Num(unsigned int Data)
{
	unsigned char i =0;
    unsigned char arr[4];
    arr[0]=Data/1000%10;
    arr[1]=Data/100%10;
    arr[2]=Data/10%10;
    arr[3]=Data%10;
    for(i=0;i<4;i++)
	{
		LS138_Clear();
		LS138_Set(7);	//ls138译码器位选为数字输入
		P0 = NixieTube[arr[i]];
		LS138_Set(6);		//ls138译码器位选为管脚选择,对应位为1,则对应的数码管亮起
		P0 = (unsigned char )0x01<<i;
        LS138_Clear();
		Delayxms(2);
		P0=0xFF;  
	}
}

2.Interrupt.h

#ifndef __INTERRUPT_H_
#define __INTERRUPT_H_
#include <STC15F2K60S2.H>

//外部中断0初始化函数
void IT0_Init(void);

//外部中断1初始化函数
void IT1_Init(void);


外部中断0服务函数
//void External_Hander0() interrupt 0
//{
//    
//}

外部中断1服务函数
//void External_Hander2() interrupt 2
//{
//    
//}  

#endif  /*__INTERRUPT_H_*/

3.Interrupt.c

#include "Interrupt.h"

//外部中断0初始化函数
void IT0_Init(void)
{
    EX0 = 1;    //开启外部中断0允许
    EA=1;       //开启中断总允许
    IT0=1;      //设置触发方式为下降沿触发,为0时触发方式为下降沿和上升沿都触发
    PX0 = 0;    //设置低优先级,为1时为高优先级
}
//外部中断1初始化函数
void IT1_Init(void)
{
    EX1 = 1;    //开启外部中断0允许
    EA=1;       //开启中断总允许
    IT1=1;      //设置触发方式为下降沿触发,为0时触发方式为下降沿和上升沿都触发
    PX1 = 1;    //设置低优先级,为1时为高优先级
}

3.代码思路

在这里插入图片描述

4.外部中断的按键消抖

之前我们在独立按键&矩阵按键中提到过按键抖动的问题,由于我们的外部中断依然是通过按键的按下和弹起带来的电平变化引起中断的,所以,我们还是毫不意外的遇到的按键抖动的问题。
之前我们都是通过软件延时或者频繁的进入按键扫描函数来消抖的,但是我们前面讲到过,最好不要在中断函数里面进行延时等耗时操作,同时,中断服务函数是在中断触发之后才能进入的,不允许我们随意的调用,这一下就给我难住了…
左思右想,我也没有想出一个好的解决方案,只能等后面学习了定时器再看看有没有解决方法,或者有没有大佬能够评论区指点一二。

总结

外部中断最主要的就是要理解中断的含义,并且会配置中断相关的寄存器,这一期我们也只是简单的介绍了一下中断的相关概念,其实还有相当多的中断内容没有提及到,毕竟我的能力也有限,其他的内容,感兴趣的可以自己去找资料学习,我这里就不再继续讲下去了。
在这里插入图片描述

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

蓝桥杯单片机学习5——外部中断 的相关文章

  • MySQL子查询

    子查询指一个查询语句嵌套在另一个查询语句内部的查询 这个特性从MySQL 4 1开始引入 SQL 中子查询的使用大大增强了 SELECT 查询的能力 因为很多时候查询需要从结果集中获取数据 或者需要从同一个表中先计算得出一个数据结果 然后与
  • 微信小程序和百度的语音识别接口

    介绍 因为项目需要 使用到了微信小程序和百度的语音接口 现在将项目中的一个小模块拿出来单独分享 技术关键字 微信小程序 百度语音接口 nodejs express fluent ffmegp 环境 windows 10 vs code 1
  • adb inputswipe shell_adb shell 基本使用

    连接远程设备 adb connect ip host 端口 获取设备 adb devices 显示adb连接设备列表 adb e d s xxx shell e 模拟器 d 外置设备 s 输入序列号 进入shell后 adb shell 就
  • Qt之NSIS打包

    一 Qt发布方式 Qt发布的时候 通常使用两种方式 1 静态编译 把相关联的库一并引入可执行程序 虽然发布简单 但可执行程序较大 2 动态编译 把相关联的库 以dll的形式引用 不包含到可执行程序 发布不方便 但可执行程序较小 二 NSIS

随机推荐

  • leectode 合并二叉树 -- 递归

    0 题目描述 leetcode原题链接 617 合并二叉树 1 递归解法 可以使用深度优先搜索合并两个二叉树 从根节点开始同时遍历两个二叉树 并将对应的节点进行合并 两个二叉树的对应节点可能存在以下三种情况 对于每种情况使用不同的合并方式
  • 梯度下降(Gradient Descent)

    基本思想 梯度下降是一个用来求函数最小值的算法 本次 我们将使用梯度下降算法来求出代价函数的最小值 梯度下降背后的思想是 开始时我们随机选择一个参数的组合 计算代价函数 然后我们寻找下一个能让代价函数值下降最多的参数组合 我们持续这么做直到
  • Vue2的学习

    computed计算属性 概念 基于现有数据 计算出来的新属性 依赖的数据变化 会自动重新计算 语法 声明在computed配置项中 一个计算属性对应一个函数 这是一个属性 计算属性名 不是方法 注意不要忘记return div ul li
  • 抓取热门话题:获取热门话题及其讨论

    目录 1 抓取微博热门话题简介 2 准备工作 3 分析微博网站结构 4 编写微博热门话题爬虫
  • 【程序员面试金典】对于一个元素各不相同且按升序排列的有序序列,请编写一个算法,创建一棵高度最小的二叉查找树。

    题目描述 对于一个元素各不相同且按升序排列的有序序列 请编写一个算法 创建一棵高度最小的二叉查找树 给定一个有序序列int vals 请返回创建的二叉查找树的高度 class MinimalBST public int buildMinim
  • 简单的融合模型:基于keras 的少量样本集迁移学习 VGG16+MeanShift+PAC降维混合模型的苹果识别

    案例分析 更多是是一种思想 而不是具体实现 1 数据集 样本总数为30个 其中普通苹果和其他苹果各占一半 其中有10个苹果已经标注其他均无标签 2 数据集扩容 由于数据集中数据数量少无法满足模型训练 故而改变图片生成一部分模型 path o
  • 翻转字符串

    描述 写出一个程序 接受一个字符串 然后输出该字符串反转后的字符串 字符串长度不超过1000 示例1 输入 abcd 返回值 dcba 示例2 输入 返回值 法一 使用StringBulider public String solve St
  • UML实例

    以下内容摘自张海藩老师 软件工程导论 课件 UML实例 拟开发一软件 完成学校管理中的教务部门功能 包括班级管理 课程管理 帐户管理等 要求用UML建模 1 用例图设计 主用例图 班级管理子用例图 帐户管理子用例图 2 顺序图和用例图 可为
  • echarts图形销毁重新绘制

    echars在绘制图形的时候会给div添加属性 echarts instance 因此只需要将此属性移除并清空div内容即可重新绘制新的echarts图形 myChart removeAttr echarts instance empty
  • libevent库使用之二:深入理解使用

    目录 一 event base 1 创建event base 2 查看IO模型 3 销毁event base 4 事件循环 event loop 5 event base的例子 二 event 事件 1 创建一个事件event 2 释放ev
  • IE9下silverlight 里边MessageBox.Show 失效!

    今天刚刚安装了IE9 在用的时候发现之前用silverlight 做的一个页面里边 MessageBox Show 执行后看不到弹出的对话框 整个页面卡在哪儿没反应了 测试了一下发现是因为silverlight 所在的页面 是用 javas
  • 迁移wind to linux服务器EE网站--迁移说明步骤

    1 上传程序文件 htaccess上传 里面有特殊字符记得更改2 还原数据库从原数据库导出 SQL的命令mysqldump u用户名 p密码 default character set latin1 数据名 gt 数据名 sql3 修改配置
  • 用CSS画小猪佩奇,你就是下一个社会人!

    欢迎大家前往腾讯云 社区 获取更多腾讯海量技术实践干货哦 作者 江志耿 腾讯TEG网络工程师 我是佩奇 哼 这是我的弟弟乔治 呱呱 这是我的妈妈 嚯 这是我的爸爸 嚯 背景 小猪佩奇已经火了好一阵了 其实一开始我是不屑的 纵观小朋友的历届动
  • 网络安全-子域名收集

    本文为作者学习文章 按作者习惯写成 如有错误或需要追加内容请留言 不喜勿喷 本文为追加文章 后期慢慢追加 子域名 子域名指二级域名 二级域名是顶级域名 一级域名 的下一级比如mail heetian com和bbs heetian com是
  • Fusionstorage Cinder架构

    由于最近一个月加班开发一个云存储产品 fusionstorage cinder 之前也没有碰过云存储这方面的知识 于是花了很长一段时间去学习了解它的架构 首先我们要知道云存储是什么 云存储其实是在云计算概念上延伸出的一个新概念 通过集群应用
  • 创建线程四种方法详解;及说明ThreadPoolExecutor方式创建线程池

    一 继承Thread类的方式 创建一个线程 class MyThred extends Thread public MyThred String name super name Override public void run 线程内的操作
  • Files under the build folder are generated and should not be edited

    在类库里面写的 按ctrl z返回之前写的代码 然后rebuild project的时候就不行了 报资源文件错误 各种clean也不起作用 报的错误都是build文件下的错误 应该是没更新过来 然后我就 1 show history返回到没
  • sklearn.svm中LinearSVR(svm线性回归)、LinearSVC(svm线性分类)与SVC(svm分类)、SVR(svm回归)之间的区别

    区别 LinearSVC SVM线性分类器 用来实现线性的分类任务 鸢尾花数据集 执行一个分类问题 import numpy as np from sklearn pipeline import Pipeline from sklearn
  • AI大模型公开课来了!免费学习!

    Datawhale分享 课程 知乎AI大模型公开课 近几年AI发展迅猛 行业巨头争先布局AI领域 想切入大热的AI领域 却找不到方向 为了帮助大家零成本学习AI大模型技术 特邀一线大佬发起 AI大模型公开课 AI大模型进阶之旅 直播时间 9
  • 蓝桥杯单片机学习5——外部中断

    上期我们学习了独立按键 矩阵按键 这次我们来学习外部中断 蓝桥杯单片机学习 外部中断 中断 1 中断请求源 2 外部中断 3 中断寄存器 4 中断优先级 5 中断结构 6 中断函数 6 中断嵌套 实战环节 1 任务要求 2 代码实现 3 代