本文是探讨并发和中断概念的系列文章中的篇。本系列的大部分内容将直接处理微控制器和 GPIO 中断。
在初的这篇文章中,我们将讨论这些概念的基本定义,并考虑它们与为微控制器编写代码的相关性。
什么是并发?
让我们用一个我们都熟悉的例子来谈谈并发。通常,当您上床睡觉时,您想在特定时间醒来。你在这里有两个目标:上床睡觉,这样你就可以休息,但也要确保你不会睡到你想要的起床时间。
确保您不会错过起床时间的一种方法是保持清醒并看时钟,但这会破坏您想要上床睡觉的目的。为了帮助补救这个问题,我们通常使用闹钟(一个设备或受信任的人,到那时已经醒了)在特定时间叫醒我们,这样我们就可以专注于睡眠,同时仍然实现我们的目标时间。
并发性是我们用来描述您同时处理两个或多个进程但在任何时间点只能物理处理其中一个进程的能力的场景。
在上面的示例中,要注意的两个过程是睡眠和跟踪时间(因此我们会在所需时间醒来)。同一个人同时做这两件事在物理上是不可能的。
通常,我们只对与我们正在处理的过程相关的特定事件感兴趣。正如您在上面注意到的,从时间的角度来看,我们关心的事件是是否该起床了。处理并发的典型方法是让另一个物理资源(闹钟或人)监视我们感兴趣的事件,然后提醒(或打断)我们事件已经发生的事实,以便我们可以处理它。
图 1 显示了这方面的时间线图解。
图 1.上床睡觉并让闹钟在特定时间叫醒您的时间线图示。
嵌入式和网络物理系统中的并发
嵌入式和网络物理系统通常必须处理并发性。
这个概念的一个例子是微波炉。该设备需要能够处理按钮按下或检测您在食物加热时打开门的时间。按下暂停或取消按钮或打开门将导致食物停止加热。
微控制器——您通常将其编程为系统“大脑”的计算机——在设计时就考虑到了并发性。
除了通用 CPU 之外,它们还包含许多用于与外界交互的专用硬件设备(称为外围设备),因此您可以连接诸如按钮和显示器之类的东西以及实现系统所需的其他外部硬件。通常,这些外设具有中断机制,因此 CPU 可以要求它们监视特定事件,然后在该事件发生时中断 CPU。
中断和并发程序的概述
微控制器上的中断就像我之前讨论的睡眠和闹钟示例一样工作。
您可以编写一个程序,将外设配置为监视某个事件并在该事件发生时中断 CPU——例如,当 GPIO 输入值从 0 变为 1 时。当您的程序运行时,CPU 会执行您的程序片段主程序。当您等待的事件发生时,外围设备向 CPU 发出事件已经发生的信号。如果一切配置正确,CPU 将停止它在主程序中所做的任何事情,执行一个称为中断服务例程 (ISR) 或中断处理程序的特殊函数,然后返回主程序从中断的地方继续当它完成时。
您必须将 ISR 编写为代码的一部分。假设您正在使用 C 编写程序,这意味着您必须在源代码中的某处声明和定义它,该源代码将作为微控制器将运行的可执行文件的一部分构建。
但是,您永远不会自己调用 ISR。所有微控制器开发工具都有一种特定的方式让您告诉 C 编译器某个函数是 ISR 以及它与哪个特定中断相关联。正确完成此操作后,当特定中断发生时,CPU 将自动跳转到该函数并执行它。
C 代码中的中断示例
由于中断的工作方式,一开始在编程中处理并发似乎有点不直观。
下图展示了用 C 语言编写的具有 ISR 的代码将如何运行,以帮助提供一种思考并发程序的好方法。它假定所有中断配置都已正确完成。
图 2.带有中断的 C 代码
CPU 在 main 函数的 while 循环中执行代码。
感兴趣的事件(从 1 变为 0)发生在为中断配置的引脚上。
CPU停止执行while循环中的代码,转而执行中断服务程序。
中断服务程序执行完毕后,CPU 从中断处继续执行主循环。
CPU 正在 while 循环中执行代码。
感兴趣的事件再次发生。
CPU停止执行while循环中的代码,转而执行中断服务程序。
中断服务程序执行完毕后,CPU 从中断处继续执行主循环。
外围设备和 GPIO 的中断
本系列的大部分内容都集中在微控制器的并发和中断概念上。接下来,我们将讨论GPIO 中断及其工作原理。