当前课程知识点:智能车制作:嵌入式系统 > 第三章 MCU基础 > 3.4 中断的概念和机制 > Video
各位同学大家好
我是清华大学工程物理系的曾鸣老师
欢迎继续大家回到我们
ARM微控制器与嵌入式系统的MOOC课程的学习
我们现在进入了第三章
基础知识的下半部分的学习
在前面几个单元里
我们认识了一个片上计算机系统
微控制器里的基本结构
尤其是专注于CPU 从8位 16位到32位
我们看了很多很多通用的内部结构
寄存器组 编程模型
乃至16位 32位的指定集
在上面实际运行的头脑体操
我们对这样一种
微控制器的运行
和它的程序理解越来越深
也越来越有信心
那么从这个下半部分开始
我们来从CPU逐渐地往外看
把视野拓展到整个片上系统
来理解这样一个片上计算机微控制器
它更多的运行机制的方方面面
那么这个单元
我们要接触一个难点
一个非常困难的难点
也就是中断
那么这是我们
与硬件有关的嵌入式开发
与普通计算机编程当中一个
非常明显有差异的部分
那么我们在这个单元里
要进行对于中断的学习
来理解什么是中断
为什么要有中断这种机制
以及中断的标志位使能
这样一些处理流程
还有一些关于它的优先级嵌套
潜伏期这样一些高阶段概念
我们会在这个单元的上 下两个部分
来给大家进行介绍
那么先说说中断
其实中断和轮询
是相互对应的
两个基本的编程的思想和概念
那么我们在进行计算机编程的时候
很多时候之前所接触的编程模式
都是轮询
它不仅仅限于计算机
更在我们的生活当中我们就可以理解
这样两种处理事情的不同思路
最典型的一件事情
就比如说
我们要找个人要打个电话
我们可能会有不同的做法
有的同学还比较内向
他会反复的打电话
隔一会就打电话问
请问谁谁谁在吗
不在 没事没事
我呆会再打 不停的打
这样一种反复打电话确认
一个人是否在
直到把一件事办成的方式
其实就是一种典型轮询
那什么是中断
可能会有一个很简单的比喻
也许不是那么的严谨 恰当
就是说我电话打过去说
请问谁在吗 不在
那么请等他来了以后给我回个电话
然后就把电话放在旁边
这个时候我就可以做作业
可以烤蛋糕 可以做烹饪 可以做料理
可以做各种各样的事情
电话铃响的时候
我去接这个电话
把刚才我计划要做的事情做了
打完了电话
电话一挂我接着做我手上
正在做的事情
这样一种方式其实就是中断
就跟英文里头一样
我们中断的英文是Interrupt打断
所以这样一种工作模式
跟轮询对应的英文Polling
是相互对应的两种不同处理事情的方式
那么用更严谨的语言来讲
说轮询 就是周期的连续的
检查外部事件是否发生
那么这样一种工作模式里头
我们会发现
用术语来讲它会
消耗大量CPU的处理时间
来反复的做一件查询的事情
那么这个代码可能写起来会比较简单
但是会耽误你这个CPU
去做其他事情所需要的时间
另外就是假设说我在这样一种机制里
我要同时查询和处理很多种不同的事情
那么CPU可能顾此失彼
忙着查这个的时候忽略了那个
忙着做那个的时候忽略了这个
这样是一种轮询的方式
这就是对我们刚才这样反复打电话
这样一种机制的一种更凝练的说法
中断是什么
中断是用一种类似于硬件的电路的机制
来判断一个外部的事件是否发生了
进而通知CPU去专门来处理这件事
并且在打断处理完这件事情之后
继续返回我们正常的流程继续我们的程序
那么这是不是对我们刚才那样一个比喻
做了一个进一步的概括
那么我们再进一步来讲
什么是中断
中断是一个需要CPU立刻处理的外部的事物
那么这些事物有很多很多种
我们所谓的外部是指CPU的外部
那么可能是我们
一个计算机系统 CPU的外部
计算机的内部的这些外设产生的一些事件
放在我们更具体的计算机编程的角度上来讲
我们大家如果做过一点编程
或者憧憬过编程
可以想像到的事情
比如说 我定了时
定了一个1分钟 定了个5毫秒
或长或短的时间到达了
比如说我采集一个数据
一个AD变换它结束了
或者我对外做了一个通讯
这个通讯 我的数据的发送完成了
那么这样一些事件的发生
可能需要我们做一些处理
那么这都可以构成一种中断的触发条件
然后如果说是对外
比如说是人机交互
或者说跟其它的网络设备
跟其它的计算机系统进行通讯
比方说我们有一个按键
在电路上引出来了
我的人进行了一些按键
那么这也是个外部事件
那么我们外面的计算机
给我发了一个通讯的数据包
我收到了
这也是个外部事件等等等等
这些对于CPU来讲在外部
但是可能在计算机内
也可能在计算机外的这样一些事件
都可以构成我们中断触发的事件条件
那么对于这样一系列的事情
绕回去说我们很多时候
可以用轮询的思路来加以处理
最典型的比如人的按键
我们要检查人有没有按键
我是不是可以在我的程序里头
main函数写一个大大的for循环
去反复查询这个键
有没有被按下
只要我查到足够快
我不会错过任何一个按键
为什么
我们以后编程会给大家讲
人按下键的反应时间
最短最短也应该在几十毫秒的量级
而我们的计算机编程可以轻而易举的
在微秒尺度去轮询
查询一件事情有没有发生
但是我们更加简单的方法
就是本门课程在这个单元所讲到的
用中断的机制来做
那么它的一个完整的处理流程是
外面的事情发生直接通过电路通知CPU
你所约定的这件事情发生了
而CPU应该有一个机制
打断当前正在执行的程序
这个时候大家已经慢慢的
越来越清晰什么是程序
就是那一条一条指令顺序执行的流水
把这样一个程序打断
跳转而去执行一个
跟我发生的事件所约定好应该做的操作
而做完了这个操作以后
CPU应该有个自动的机制
返回来继续执行我们原来的程序
而恢复到原来的流程与现状当中
那这就是一个中断的机制
那么把这样一个机制讲清楚了以后
我们接下来会详细的讲它究竟是
怎么操作 怎么发生 怎么编程的
那么我们拎起来看一看
中断和轮询有什么特点
就是中断显然这样一种机制
它诞生的原因是我们有可能
会适合于处理一些一旦发生
需要非常快速的响应和处理的事情
比如在一些飞行器
机器人这样的控制领域
包括我们的智能车
我们可能会一个信号一个信息采集进来
我们需要在非常短的时间内做出响应
比如智能车
如果我的转向响应的不及时
可能我的车就应该冲出赛道
这个时候你再要返回来就晚了
比如飞行器
它会一个最短响应时间
以避免飞行器处于一个
不可支 不可控的状态
此外中断会要求我们单次中断处理
希望尽可能在非常短的时间里完成
这个在以后会讲
而不是长时间在一个中断的状态里
让其他的事件无法得到处理
此外 中断的这样一种机制
它使我们的CPU
可以在集中的非常短的时间内
非常高效的去处理这些事情的应对
而在更多的长时间里
比如说我们确实没有
别的事情可能工作在一个低功耗的状态
使整个系统
只有1% 甚至1‰的时间处于运行状态
而更多的99% 999‰的时间
可能处于低功耗
而实现今天我们大家耳熟能详的
比如穿戴设备
像手环这样的设备
它的低功耗的设计
那它的代价就是要完成这样的设计
显然比只在一个main函数里
写一个for循环去轮询
查询一件事情
它在编程上在电路的实现上
要更加的复杂一些
是需要专门学习的
也是我们为什么说它是个难点
而相对于它 轮询的机制
方便于我们初学者
写一个非常简单的程序
用非常straightforward 非常直观的方式
去理解自己要做的事情
比如说我要查询人按键没有
我写个函数
不停的去检查这个键
有没有被按下
这是非常直观的
所以它的程序设计比较的简单
有利于初学者绕开一些雷
实现自己要的功能
但是做为这门课程的学习
大家对于嵌入式系统的学习
一定要越过中断这道坎
去理解这样一种机制
它不仅是实时高效的
去实现一些控制功能
包括智能车在内一个重要的技能
也是我们计算机学科
发展历程当中不断的演变
产生前 后台程序
产生操作系统的一个基础的知识
非常非常的重要
那么在这个单元里
我还会给大家讲一讲
中断发生的机制
因为是一种电路上的通知来告诉CPU
所以它一定会设计成一种逻辑的结构
我们站在一个设计者的角度来看
某一个事件一旦发生
一定会从电学上来产生一个信号
表征为逻辑量
一定是表征为一个0 或者一个1
那么通过一系列的控制
要让它有序的通知CPU
知道一件事情发生了
而剩下的问题在CPU
在计算机的架构里如何设计出一个机制
使这个事情能够自动的得到响应
那么这样一种中断的使能
中断的发生
我们抽象出来讲
就是这样一种与的逻辑
我们日后在真正的编程
会针对我们所要开发的实际的功能
一定会完成这样具体的设置
那么具体表现为它的功能设置
就是说根据不同的中断源
比如说是一个键按下了
还是一个通讯完成了
它一定会产生一个信号
来标志这件事情的完成
这样一种0或者1的信号
我们一般会把它称为中断标志位
也就是IF lnterrupt flag
Flag就是标志
来表证我们所约定的 所期待的
那样一件事发生了
那么与之相关的
我们还会有一个跟这一类信号
所对应的开关量
来表征在这样一个计算机系统里面
我们通过编程人员的设置
我允许这样一类的信号产生中断
也就是我将要使用这一类中断
比如说我允许按键 我允许通讯
所以这是一个允许的开关量
最后 对于整个CPU在各家各行
设计的CPU MCU里头
都会有一个中断总开关
我们称为中断的总的使能信号
然后这三个信号
刚才那张图里1 2 3捋在一起
才会条件满足于就是说
用更抽象 更逻辑的语言来讲
CPU总开关打开 允许使用中断
我们所要使用的那一种中断
那做为编程人员我心里很清楚
把它给打开 允许它发生中断
然后最后我设定那个事件确实发生了
键按下来了 通讯产生了
这三个条件同时满足
最终产生了一个对于CPU的通知信号
告诉CPU这个中断发生了
那么对于我们所学习的
ARM Cortex M的这样一种处理器
它的中断的总开关在哪呢
这是在这个单元里给大家讲的
就是在上一个单元所讲到的
在ARM的CPU的总的CPU内部寄存器里
我们有一个中断的使能位
就是那一个比特 置0或者置1
不知道大家还记不记得
来控制这个中断的开或者关
那么这样一种片内的中断的开或者关
体现在编程的角度
其实就是两句语言汇编指令
就是CPSIE和CPSID
那么这两条指令只要执行
打开或者关闭了总的中断开关
那么这个部分讲起来大家会觉得有点抽象
没有关系要给大家留下一个印象
就是做为编程人员
你可以使用的中断有很多种
那么如果有朝一日你要使用它
那大家先留下这么一个概念
你需要打开中断总开关
需要使能你所要用的中断
你要配置好你那个中断所发生的条件
当它发生的时候 三者具备
CPU就会接受到一个信号
你所设定这个事件发生了
而日后的单元的具体学习里
我会带着大家
从时钟的中断 按键的中断做为练习
来不断巩固翻滚来加深这样一种知识的认识
那么一旦这样一种中断的信号给了CPU
说这样一种事情发生了
不管这件事情是什么
CPU都要有一个机制去做跟这件事情
跟这个信息所对应的操作
那么在计算机设计构架里
这样一种过程我们称为中断的响应
那么在中断响应当中
会有这样一种工作流程
我们把它加以抽象
就体现成为这样一种图
我们把我们程序执行的流程横过来
我们之前都习惯竖着的
一条一条指令执行我们横过来
把它看成一个流水的流程
一条一条指令的程序往前运行
在某个时间点上
无论是哪一种中断
发生通知CPU
有一件你需要响应的事情发生了
这是不是我们中断的机制
就好像说电话铃响了一样
那么这个时候CPU得知了这个信息
这个信息是我们刚才所讲的
三个条件满足的
可能是按键 可能是通信
可能是电话铃响了 CPU需要按照约定
去知晓是那一种信号发生了
是人按键了 还是通讯了
从而跳转去执行一个与之呼应的
专用程序来处理这件事
跳转到另外一个程序里
而这段程序做了若干个操作来响应这件事情
比如说人来按键
在这个程序里把一个灯点亮
或者说一个通讯来了
在一段程序里把这个通讯的反馈给发送出去
做完这件事
那么CPU需要返回刚才的程序流程
继续往下执行
那么在这个过程当中
被中断 打断的程序
主流程和中断执行完返回的主流程
必须无缝的衔接
对于主程序而言
要好像什么事情都没有发生过一样
这才是一个真正的程序执行的流程
那么如何做到这一点
大家会想 那么我们会说
在函数调用里已经有了这种概念
就是我们在函数调用完毕返回的时候
要返回函数调用之后的那段代码继续执行
要保存函数的返回地址
而在中断调用的时候
我们会有一段程序执行得好好的
它会在使用寄存器
它会做很多运算
在任意可能发生的时刻被一个外来的信号打断
所以我们必须有一个机制
就是在任何时候打断它
都能还原它的运行
这样一种过程
我们用通俗的语言讲叫还原一个现场
就好像有的同学很调皮
你在家里干了坏事
或者说在做作业的时候假装在玩
但是妈妈回来了
你要假装这个东西还原成
我正在继续学习 我没有玩
我们要还原一个犯罪现场
那么对于这样一种CPU的机制来讲
因为中断是由硬件产生的
由外部信号产生
它可能在任意时刻
任意位置打断我们程序的运行
所以我们要试图把
程序运行的那样一个现场保留下来
最终成功的还原
而能够无缝的继续运行下去
不被这个中断程序所破坏
那么这样一种过程在计算机里
不称为还原现场
我们称为什么呢
我们称为context
也就是我们程序运行的一个上下文
从更具体的角度来讲
什么是程序运行的上下文
大家有了刚才上一个单元
之前上一个单元学习的这个头脑风暴
头脑计算机
这样一个头脑体操的一个过程
我们就知道 一条一条汇编指令的使用
最终保存的信息
就是我们的编程模型的寄存器的值
那些寄存器记录了
我们执行到了第几条指令
记录了我们堆栈用到了那里
记录了我们片内每个寄存器
被使用存储的一些值
那么是不是在这个打断的时间点上
我们保留CPU运行的所有寄存器的当前值
如果再考虑到内存状态的可恢复性
那么我们一旦在一个中断程序去执行完毕
使用了这些寄存器之后
把寄存器的值
把这些状态
还原到中断发生之前的那一个瞬间
是不是对于我们的主程序
对于绿色的这个正常的流程
就好像什么事情都没有发生过
所以如果我们有一个机制
能够在进入中断之前保留所有这些
而在退出中断 还原所有这些
是不是我们的主程序
就可以在任意位置
被打断 而不会出现错误
这个过程用一个更形象的比喻来讲
除了刚才说的犯罪现场
干了坏事的现场以外
我自己可以把它理解为
我们有时候玩游戏的时候
会有一个快速保存的功能
你按个键快速保存
你就可以出去干别的事
甚至关机
回来你快速load 它就回到了这个现场
那我们要保存的这个现场是什么
在计算机的领域
就是这样一个Register Context的上下文
最好的情况下包括了
我们CPU的所有寄存器
那么不同的CPU涉及各家各户
涉及的时候
它会选择把那些CPU的寄存器压入堆栈
出于效率的考虑
我们大多的程序运行
很有可能用不到所有的寄存器
所以它会有选择的压栈部分寄存器
比如在我们所使用的ARM Cortex的处理器
一旦有一个信号通知CPU中断发生
那么CPU要做的一件事情
就是如这张图所示
依次把这些寄存器自动的压入堆栈
进行保存 哪些呢 R0 R1 R2 R3
然后中间跳过了若干个寄存器
R12 我们的Link Register
R14 PC寄存器 R15
以及我们CPU的xPSR
32位的CPU的状态寄存器
会被自动压入堆栈
在有限个的指令周期里
然后去执行我们的中断函数
相应的这个中断函数
在执行完毕返回的时候
CPU也会自动的把这些寄存器
从堆栈倒序弹出来
还原一个CPU的现场
让这个CPU让主程序
好像什么事情都没有发生过一样往下运行
那有同学会说
老师如果我的中断函数
用到了这些寄存器之外的寄存器
破坏了额外的现场怎么办
那就是编程人员
也就是在座诸位的责任
你应该把你用到的寄存器
用一些额外的指令
压入堆栈进行保存
并且在退出中断程序的时候
把它加以还原
使这个现场完美的得到保护
那么可以想像为什么只压这些个寄存器
这是一种效率的平衡
那么压有限个节约大家的时间
如果你用到更多
你可以自己手动压
而如果你没有用到更多
你就避免了每次入栈
很多个寄存器来浪费中断响应的那个实时性
那么在这样一种机制下面
我们就可以理解
虽然我们在日后的学习当中
会更加深入理解中断真正怎么编程
那么我们理解了一个概念
中断工作的机制
以及在什么情况下
设定好的条件满足以电路的方式
通知CPU发生中断
而CPU一定要保存这样一个
Register Context上下文的现场
来打断现有的程序的运行
去执行一个约定好的程序
从而返回主程序
并且这种打断是可能发生在任意时间的
这些概念是核心的
希望通过这样一个单元的学习
给大家留下一个初步的印象
而下一个单元我们来看看
真正中断的函数
是如何运行和如何编写的
-1.1 课程概览
--Video
-1.2 进入嵌入式系统的世界
--Video
-1.3 如何学好嵌入式系统
--Video
-2.1 计算机的基本概念、发展历史
--Video
-2.2 从晶体管到CPU
--Video
-2.3 概念CPU、微控制器MCU和嵌入式系统
--Video
-2.4 八卦计算机史
--Video
-2.5 不同领域、不同系列的嵌入式系统
--Video
-2.6 ARM历史与MKL25Z128 MCU
--Video
-3.1 CPU的基本结构和运行机制
--Video
-3.2.1 堆栈的概念
--Video
-3.2.2 堆栈的概念-头脑体操
--Video
-3.3.1 ARM的体系结构
--Video
-3.3.2 ARM的体系结构-头脑体操
--Video
-3.4 中断的概念和机制
--Video
-3.5 中断子程的概念和编程
--Video
-3.6 复位、时钟、存储器和总线
--Video
-3.7 小结:MCU的总体结构和程序运行机制
--Video
-4.1 第一种外设:IO
--Video
-4.2 IO外设的编程实操-点亮LED
--Video
-4.3 IO外设的进阶知识
--Video
-4.4 嵌入式开发的基本概念与工具链
--Video
-4.5 嵌入式开发的进阶知识
--Video
-4.6 嵌入式开发中的C语言(上)
--Video
-4.7 嵌入式开发中的C语言(下)
--Video
-E0.1 实验零 开发板的初步认识与工具链的安装
--Video
-E0.2 实验零 体验一个例程的编译与下载
--Video
-E0.3 实验零 编写第一个程序:点亮核心板LED
--Video
-E1 实验一 点灯秘籍
--Video
-5 智能车视角的嵌入式设计
--Video