嵌入式开发基础从启动例程到硬件之时间控制问题(同步和异步调用)
概述
在嵌入式软件中实现目标功能时,需要的是与时间相关的控制。而且,在很好地设计与时间相关的问题时,有用的是“非同步调用”这一技术。
实际上,在设计笨拙的情况下,不需要这种技术。希望各位读者一定要掌握优秀的设计技术,在此进行说明。
在嵌入式系统中,(从计算机上看)有很多根据外部世界的状态和状态的变化来决定下一个动作的场景。例如,家用空调,
即使100V通电,平时也什么都不做.除了显示室温以外,一直在等待.只有按下驾驶按钮,才开始冷暖气的动作.。
像这样,在编入系统中需要“待机直到发生外界的变化”这一动作。同步/非同步调用是安装该动作的前阶段的设计概念。
同步调用
在涉及时间的说明之前,让我们考虑一下与时间无关的设计。例如,用电脑等处理数学计算问题时,通常要等到计算所需的第一步数据齐全后才启动程序。在这种情况下,
没有必要考虑在启动后再次等待某种变化(在发生变化之前什么都不做)的状况。
计算的公式很复杂,在计算的步骤中在几个地方应用相同的公式时,在C语言中将相同的公式总结为函数,记述为从程序中调用该函数。之前的文章“嵌入式开发基础从启动例程到硬件之程序是如何运行的?”中出现的阶乘计算就是很好的例子。
以下是多次调用阶乘计算函数fact的函数foo的例子。
long foo(a,b){
...
x=fact(a);
y=fact(b);
z=x/y;
return z;
}
在这个例子中,代入x的阶乘计算值在fact(A)被呼出的同时被计算。这个计算被推迟从C语言的规格来说是不可能的。也就是说,在执行求z的计算的x/y的时候,
x和y的值是确定的。用结构化设计方法对其进行图示,如图5-1所示。
像这样,在执行调用函数fact的公式的同时执行函数fact的约定中的调用,作为设计上的用语被称为“同步调用”。
同步调用是从父功能到子功能的实线箭头来表示。伴随调用的参数,在0符号上加上小的箭头,与名称一起表示(将其称为情侣)。返回值也同样用情侣来表示。
异步调用
所谓“非同步调用”,是指在某个执行场景中即使调用特定的函数foo,其实际执行也有可能在别的时机进行的情况下使用的表现。也就是说,由于调用的时期和执行的时期不同步,所以称为非同步调用。
在开头列举的空调的例子中,产生被按下按钮的外部事件后,想要执行暖气运转的函数(例如heating())的情况是理所当然的(图5-2)。
如果这样说明的话,知道C语言的大家可能会认为“反复检查检测按钮按下的输入寄存器,知道被按下后再叫heating()就可以了,所以不需要非同步调用”。另外,
“我不知道这与使用中断函数的声明有什么不同。”
accept_command函数在控制转移到该行的同时被执行(同步调用)。另一方面,heating函数在开头只允许通过中断调用,实际上是在准备就绪后调用(异步调用)。
像这样,在详细之前设计整体的方法称为自上而下设计。而且,在自上而下设计时,无论安装检测结构的手段(周期性轮询、硬件中断、OS委托等)是什么,共同使用的表现是非同步调用(图5-3)。让我们改变说法吧。仅仅按照代码的顺序执行计算和输入输出有可能不能实现设计意图时,就用非同步调用来表现。
非同步调用只是表示最初的调用和执行的开始不在同一时刻,不明示执行持续到什么时候,和其他的执行并列进行等。关于具体的操作,
- 在制作设计图的模块规格书时决定
- 写程序时决定
等等,只要在后面的时机决定、记录就可以了。先决定细微的部分是失败的根源。即使打算用Java安装,在编码阶段也可能需要做C。细微部分的决定尽量在后面进行。
这是一个安全的“拖延”的想法。
非同步调用在用图表示时使用虚线箭头,与实线箭头所示的同步调用相区别。有2条纵线的长方形模块是程序库模块(已经进行了设计和涂层的模块)。六角形的模块是数据只读模块(只有数据的模块)。
结束语
一旦习惯了编程,即使不好好设计也是能运行的东西。但是,如果想开发需要非同步处理且高品质的嵌入式软件的话,在设计工程上花费时间是很大的一件事。