乐读文学

编码:隐匿在计算机软硬件背后的语言

乐读文学 > 科普学习 > 编码:隐匿在计算机软硬件背后的语言

第14章 反馈与触发器

书籍名:《编码:隐匿在计算机软硬件背后的语言》    作者:Charles Petzold




人人都知道电可以使物体运动。随便看一眼就会发现,很多家用电器中都装了电动机,  如钟、风扇,食品加工机、  CD机等等。电也能使扬声器中的磁芯振动,从而使音响设备、电  视机产生了声音、话音和音乐。不过,电使物体运动的一个最简单、最神奇的例子可能是电  子蜂鸣器和电铃。

将继电器、电池、开关按如下形式连接:



如果你觉得它看起来很奇怪,则你还没有发挥出你的想像力。我们还从未见过如此连接  的继电器。原来的继电器中,输入和输出通常是分开的,这里却构成一个闭环。当闭合开关  时,电路连通了:



接通的电路使电磁铁把金属簧片拉下来(电流的作用):



当金属簧片改变位置后,电路不再完整,电磁铁失去了磁性,金属簧片又弹回原来的位  置:



这样,电路便又一次接通了。可见,只要开关是闭合的,金属簧片就会上下跳动—使电  路闭合或断开  —  并制造一种声音。如果金属簧片制造了一种刺耳的声音,它就构成了一个  蜂鸣器。如果金属簧片附上一把小锤子,再加一个金属锣,它就构成了一个电铃。

有两种方法可用来连接继电器以构造一个蜂鸣器,下面是另一种方法的描述:



你可能从上述图中认出了这是第  11章介绍过的反向器,所以电路可以简化为:



输出



对于反向器而言,当输入为  0时,输出为  1;输入为  1时,输出为  0。在该电路中闭合开关  会使反向器中的继电器间断地闭合和断开。如果去掉开关,可以使反向器连续地工作,如下  图示:



输出



这幅图似乎在演示一种逻辑矛盾,反向器的输出是和其输入相反的,但是在这里,其输  出同时又是其输入。需要特别指出的是,反向器实际上是一个继电器,而继电器从一个状态  转换到另一个状态是需要时间的。所以,即使输入和输出是相等的,输出也会很快地改变,  成为输入的倒置(当然,随即输出也就改变了输入,如此反复)。

电路的输出是什么呢?其实就是提供电压和不提供电压之间的变换。或者说输出要么是  0,  要么是1。



这个电路称为  振荡器  ,它和我们以前见到的每样东西都有本质上的区别。以前,所有的  电路都靠手动地断开或闭合开关来改变状态,而振荡器却不需要人的干涉,它可以自主地工  作。

当然,单独的一个振荡器不会有什么用,但在本章的后面及接下去的几章里,你会看到  这个电路和其他电路连接后构成了自动控制中一个十分关键的部分。所有计算机都靠某种振  荡器来使其他部件同步工作。

振荡器的输出是  0和1的交替序列,可以用下图形象地来表示它:



图中,水平轴表示时间,垂直轴表示输出是  0或1:



时间



此图表示随着时间的变化,振荡器的输出在  0和1之间交替变化。基于这个原因,振荡器  有时称为  时钟(clock),因为通过对振荡次数记数还可确定时间。

那么,振荡器运行的速度有多快呢?也就是说,金属簧片上下跳动的频率是多少?每秒  有多少次呢?很明显,这依赖于继电器是如何构造的。容易想到,一个大的、笨重的继电器  只能迟钝地上下摆动;而一个小的、轻巧的继电器可以迅速地跳动。

我们把振荡器从某个时间的输出开始,经历一段变化又回到同样输出的这一段间隔称为  振荡器的一个循环(cycle):



一个循环



时间



一个循环所需要的时间称为振荡器的周期。假设一个振荡器的周期是  0.05秒,则可以在水  平轴上标出时间:



一个循环



0  0.025  0.05  0.075  0.10  0.125  0.15  时间



振荡器的频率是周期的倒数。本例中,若振荡器的周期是  0.05秒,则其频率是  1÷0.05秒,  即每秒钟  20个循环。这表明振荡器的输出每秒钟改变  20次。

每秒循环数与每小时英里数、每平方英寸磅数、每份食物(饮料)的卡路里数等毋需多  解释的术语一样是一个很容易理解的概念,但已不常用。为了纪念第一个发送和接收无线电  波的人  —鲁道夫·赫兹  (1857-1894),我们用“赫兹”这个词表示每秒的循环数。这个用法



始于20世纪20年代的德国,后来传到其他国家。  于是,我们可以说这个振荡器的频率是  20赫兹,或直接简写为  20Hz。

到目前为止,我们只是在假设一个振荡器的速度。到本章末尾,我们可以构造一种器件  来真正地测量一个振荡器的速度。

为了构造这个器件,先看一个用特殊方式连接的一对或非门。或非门的特点是只有两个  输入都为  0时,输出才为  1:

NOR



0



1



0



1



0



1



0



0



下图是含有两个或非门、两个开关和一个灯泡的电路:


注意图中奇特的连接方式:左边或非门的输出是右边或非门的输入,右边或非门的输出是左  边或非门的输入。这是一种反馈。事实上,这和在振荡器中类似,输出又返回作为一种输入。  这是本章中大部分电路的特点。

在上图电路中,一开始,只有左边或非门的输出有电流,因为它的两个输入均为  0。现在  闭合上面的开关,左边或非门的输出变为  0,于是右边或非门的输出变为  1,灯泡点亮:



神奇之处在于当你断开上面的开关时,由于或非门的输入中只要有一个为  1,其输出就是

0,因而左边或非门的输出不变,灯泡仍然亮着:



你不觉得奇怪吗?两个开关都断开着,和第一幅图一样,但灯泡却亮着。这种情形和以  前所见到的完全不同。通常,一个电路的输出仅仅依赖于输入,这里的情况却不一样。无论  断开或闭合上面的开关,灯泡总是亮着。这里开关对电路没有什么影响,原因是左边或非门  的输出一直是  0。

现在闭合下面的开关。由于右边或非门的输入中有一个是  1,则其输出变为  0,灯泡熄灭。  左边或非门的输出此刻变为  1:



现在,再断开下面的开关,灯泡仍旧不亮:



此电路和初始电路一样。然而这回却是下面开关的状态对灯泡没有什么影响。总结起来就是:

•  闭合上面的开关使灯泡点亮,当再断开时,灯泡仍然亮着。

•  闭合下面的开关使灯泡熄灭,当再断开时,灯泡仍然不亮。  电路的奇特之处是:有时当两个开关都断开时,灯泡亮着;而有时,当两个开关都断开

时,灯泡却不亮。当两个开关都断开时,电路有两个稳定状态,这样的一个电路称为触发器。  触发器是  1918年在英国射电物理学家  William  Henry  Eccles(1875-1966)和F.W.Jordan的工作中  发明的。

触发器电路可以保持信息,换句话说,它有记忆性。它可以“记住”最近一次是哪个开  关先闭合的。如果你遇到这样一个触发器,它的灯泡亮着时,你可以确定最近闭合的是上面  的开关;而灯泡灭着时则是下面的开关。

触发器和跷跷板很像。跷跷板有两个稳定状态,它不会长期停留在不稳定的中间位置。  你只要一看跷跷板就知道哪边是最近被压下来的。

触发器是十分关键的工具,尽管你现在可能还没看出来。它们赋予电路“记忆”,使其知  道以前曾有过的状态。想像一下,如果你没有记忆力,你该如何去数数,你记不住你刚数过  的数,当然也无法确定下一个数是什么。同样,一个能计数的电路(本章后面要提到)必定  需要触发器。

触发器有很多种,刚才所看到的是最简单的一种,称为  R-S(或  Reset-Set,复位  /置位)  触发器。下面以对称的方式把它重新绘出来:



用于点亮灯泡的输出称为  Q,另一个输出-Q是Q的倒置。如果  Q是0,-Q就是1,反之亦然。  两个输入端  S(Set)和R(Reset)分别表示  置位和复位。你可以把“置位”理解为把  Q设为1,  而“复位”是把  Q设为0。当S为1时(对应于前面图中闭合上面开关的情况),Q变为1而Q-变为  0;当  R为1时(对应于前面图中闭合下面开关的情况),Q变为0而-Q变为  1。当S和R都为  0时,  输出保持  Q原来的状态。输入与输出的关系小结于下表中:

输入  输出



禁止



这张表称为功能表  、逻辑表  或真值表  。它指明不同的输入组合能产生不同的输出结果。由于

R-S触发器有两个输入端,因而不同的输入组合有  4种,分别对应于表中的  4行。  注意表中倒数第  2行中  S和R均为零,而输出标识为  Q和-Q。这表示当  S和R输入均为零时,

Q和-Q端的输出保持  S、R同时设为  0以前的输出值。表中最后一行说明  S和R输入都为  1是非法  的、禁止的。这是因为  S、R同时为  1时,两个输出  Q和-Q均为零,这与  Q和Q-互为倒置的关系相  矛盾。所以,当你用  R-S触发器设计电路时,要避免使  R、S输入同时为  1的情况。

R-S触发器通常画成有两个输入,两个输出的方块图,如下图所示:



R-S触发器能够记住哪一个输入端最近被输入高电位,这确实很有趣。但更有用的电路应  该能记住某个特定时间点上上一个信号是  0还是1。

在实际构造这种电路之前,先来思考一下它的行为功能。它需要两个输入,其中一个称

为数据端  (Data)。像所有数字信号一样,数据端输入可以是  0或1。另一个输入称为  保持位

(Hold  that  bit)。通常情况下,保持位设为  0,这时,数据端对电路没什么影响。当保持位置  为1时,电路就反映出数据端的值。接着,保持位又置为  0,这时,电路将记住数据端输入的  最近一个值。数据端信号的任何改变不会对电路再有影响。

换句话说,它的功能表可以这样写:



输入  输出

数据端  保持位



在前两种情况下,保持位置为  1,Q端输出和数据端输入相同;后两种情况下,当保持位  置为0时,Q端输出和它以前的值相同,即保持原状态。注意,后两种情况中当保持位为  0时,  Q端输出不再受数据端输入的影响,功能表可以简化表示为:

输入  输出

数据端  保持位



X表示不关心其取值情况,它的值对于电路输出没有影响。

基于R-S  触发器来实现保持位的功能要求在输入端增加两个与门,如下图所示:



复位



保持位



置位



要使与门输出为  1,两个输入端必须同时为  1。在上图中,  Q输出为0,而-Q输出为1。  只要保持位置为  0,置位信号对于输出就没有影响:



复位



保持位



置位



同样,复位信号对电路输出也没有影响:



复位



保持位



置位



只有当保持位信号是  1时,电路的功能才和前述的  R-S触发器相同:



复位



保持位



置位



这时,由于上面与门的输出和复位端输入相同,而下面与门的输出和置位端输入相同,  所以此电路的功能就和普通的  R-S触发器是一样的了。

但我们还没有达到目标,我们只想要两个输入,而不是三个,怎么办呢?前面讲过  R-S触  发器中两个输入同时为  1的情况是禁止的;而两个输入同时为零的情况没有什么意义,因为那  只是输出保持不变的简单情况。这里,只要将保持位置为  0,就可以完成同样的功能。

可见,真正有意义的输入是  S为0,R为1或R为0,S为1。把数据端信号当作置位信号,它  取反后的值就是复位端信号,如下图示:



保持位



数据端



在这种情况下,  S和R输入以及输出  Q均为0,Q-为1。只要保持位为  0,数据端输入对于电  路输出就没有影响:



保持位



数据端



当保持位为  1时,电路反映出数据端输入的值:



保持位



数据端



Q端输出现在和数据端输入是一致的,Q-则相反。现在,保持位又回到  0:



保持位



数据端



这时,电路会记得当保持位最后一次置为  1时数据端输入的值。数据端以后的变化对电路  的输出没有影响:



保持位



数据端



这个电路称为电平触发的  D型触发器  ,D(Data)表示数据端输入。所谓电平触发  是指当  保持位输入为某一特定电平(本例中为“  1”)时,触发器才对数据端的输入值进行保存。(很  快,你将会看到另一种形式的触发器。)

通常情况下,当这样一个电路出现在书中时,输入并不被标为保持位,而是标为“时钟”。  当然,这个信号并不是一个真的时钟,但它有时却具有类似钟一样的属性,即在  0和1之是有  规律地来回变化。但是现在时钟只是用来指示什么时候保存数据:



时钟



数据端



把数据端简写为  D,时钟端简写为  Clk,其功能表如下所示:



输入  输出



这个电路就是所谓的电平触发的  D型锁存器  ,它表示电路锁存住一位数据并保持至将来使  用。它也可以称为  1位存储器。本书将在第  16章中说明如何将多个  1位存储器连起来以构成多  位存储器。

在锁存器中保存多位值是很有用的。假如你想用第  12章中的加法机把三个  8位数加起来,  你可以在第  1行开关上输入第一个加数,在第  2行开关上输入第二个加数,但是你必须把第一  次加法运算的结果记录下来,然后以同样方式把记下来的结果和第三个加数再用开关输入。  这是十分麻烦的。

使用锁存器可以解决这个问题。让我们把  8个锁存器集成到一个盒子里,形成一个  8位锁  存器  。每个锁存器用到两个或非门、两个与门和  1个反向器。时钟端输入是互相连在一起的。  结果如下图所示:



Clk  8位锁存器



这个锁存器一次可以保存  8位数。上面的  8个输入标为  D  ~D  ,下面的  8个输出标为  Q  ~Q  。左

0  7  0  7



边的输入是时钟(  Clk),时钟信号通常为  0。当时钟信号为  1时,D端输入被送到  Q端输出。当

时钟信号变为  0时,  8位输出值保持不变,直到时钟信号再次被置为  1。8位锁存器也可以画成  下面的样子:



8位锁存器



下面是8位加法器  :



8位加法器



通常(先不考虑上一章的减法),8个A输入和  8个B输入是连在开关上的,  CI(进位输入)  端接地,  8个S(和输出)和  CO(进位输出)端连着灯泡。

经修改,  8位加法器的输出既与灯泡相连,也作为  8位锁存器的数据端  (D)输入。标为“保  存”(Save)的开关是锁存器的时钟输入,用于保存加法器的运算结果:


开关  开关



8位锁存器

保存



A  B

2-1选择器  输出



来自锁存器



8位加法器



灯泡  灯泡



标识为  2-1选择器的方块是让你用一个开关来选择加法器的  B端输入是取自第  2排开关还是  取自锁存器的  Q端输出。当选择开关闭合时,就选择了用  8位锁存器的输出作为  B端输入。  2-1  选择器用了  8个如下电路:



B

选择

输出

A



如果选择(  Select)端输入为  1,或门的输出和  B端输入是一样的。这是因为上面与门的输  出和B端输入是一样的,而下面与门的输出是  0。同样,如果选择端输入是  0,或门的输出则和  A端输入是一样的。总结起来如下表所示:



输入  输出

输出端  A  B



修改后的加法机中包含了  8个这样的  1位选择器。所有选择端的信号输入是连在一起的。  改进过的加法机不能很好地处理进位输出  (CO)信号。如果两个数的相加使进位输出信号

为1,则当下一个数再加进来时,这个信号就被忽略了。一个可能的解决方法是使加法器、锁  存器、选择器均为  16位宽度,或者至少比你可能遇到的最大的和的位数多一位。这个问题会  在第17章中专门讲述。

对加法机一个更好的改进方法是完全去掉一排开关,但是这需要先对  D触发器做一点儿小  的改进,对它加一个或门和一个称为清零(Clear)的输入信号。清零信号通常为  0,但当它为  1时,Q输出为0,如下图所示:



清零



时钟



数据端



无论其他信号是什么,清零信号总迫使  Q输出为0,起到了给触发器清零的作用。  你也许还不明白为什么要设置这个信号,为什么不能通过把数据端输入置  0和时钟端输入

置1来使触发器清零呢?这也许因为我们并不能控制数据端的输入。下图中,  8个锁存器连着  8

位加法器的输出:



开关



8位加法器



8位锁存器

清零  相加



灯泡

注意,标识为“相加”  (Add)的开关此刻控制着锁存器的时钟输入。  你可能会发现这个加法器比前面那个好用,尤其是当你需要加上一长串数字时。刚开始

时,按下清零开关,这个操作使锁存器输出为  0,并熄灭了所有的灯泡,同时使加法器的  B端  输入全为  0。接着,通过开关输入第一个加数,闭合“相加”开关,则此加数反映在灯泡上。  再输入第二个数并再次闭合“相加”开关,由开关输入的  8位操作数加到前面的结果上,其和  输出到灯泡。如此反复,可以连加很多数。

触发器是电平触发式的,意思是说只有在时钟端输入从  0变到1后(即高电平时),数据端  输入的值才能保存在锁存器中。注意,在时钟端输入为  1期间  ,数据端输入的任何改变都将反  应在Q或Q-端的输出值上。

对一些应用而言,电平触发时钟输入已经足够用了;但对另外一些应用来说,  边沿触发  时钟输入更为适用。对于边沿触发器而言,只有当时钟从  0变到1的瞬间,输出才会改变。在  电平触发器中,当时钟输入为  0时,数据端输入的任何改变都不会影响输出;而在边沿触发器  中,当时钟输入为  1时,数据端输入的改变也不会影响输出。只有在时钟输入从  0变到1的瞬间,  数据端的输入才会影响边沿触发器的输出。

边沿触发的  D型触发器是由两级  R-S触发器按如下方式连接而成的:



数据端



时钟



这时,时钟输入既控制着第一级,也控制着第二级。但是应该注意到时钟信号在第一级中取  了反,这意味着除了当时钟信号为零时保存数据外,第一级工作原理和  D型触发器完全相同。  第二级的输出是第一级的输入,当时钟信号为  1时,它们被保存。总的结论就是只有当时钟信  号从0变为1时,数据端输入才会保存下来。

让我们进一步分析。下面是处于非工作状态的触发器,其数据端、时钟输入均为  0,Q端  输出也是  0:



数据端



时钟



现在,使数据端输入为  1:



数据端



时钟



这改变了第一级触发器状态,因为时钟信号取反后为  1。但第二级仍保持不变,因为时钟  端输入仍为  0。现在把时钟输入变为  1:



数据端



时钟



这就引起第二级触发器改变,使  Q端输出变为  1。与前面不同的是现在无论数据端输入如  何变化(如变为  0),它也不会影响  Q端的输出值:



数据端


时钟



Q和Q-端输出只有在时钟输入从  0变到1的瞬间才发生改变。

边沿触发的  D型触发器的功能表需要一个新符号来表示这种从  0到1的瞬时变化,即用一个  向上指的箭头(↑)表示:

输入  输出



箭头表示当  Clk信号从  0变到1时,Q端输出和数据端输入是一样的,这称为  Clk信号的“正  跳变”(“负跳变”是从  1到0的转换)。触发器的符号图如下所示:



图中的小三角符号表示触发器是边沿触发的。  现在向你展示一个使用边沿触发器的电路。先回忆一下本章开始构造的振荡器,振荡器

的输出是在  0和1之间变化的:



输出



把振荡器的输出连到边沿触发的  D型触发器的时钟输入端,并把  Q  端输出连到自己的  D输  入端:



触发器的输出同时又是它自己的输入。(实际上,这种构造可能是有问题的。振荡器是由  来回迅速转变状态的继电器构成的。振荡器的输出和构成触发器的继电器相连,而这些继电  器不一定能跟上振荡器的速度。为了避免这些问题,这里假设振荡器中继电器的速度比这个  电路中其他地方的继电器的速度都慢。)

观察下面的功能表,就可以明白电路中发生的情况了。刚开始时,  Clk输入和  Q端输出都  是0,则  Q  端输出为  1,而它和  D输入是相连的:



输入  输出



当Clk输入从0变到1后,Q端输出就和  D输入一样了:

输入  输出



但是因为  -端输出变为  0,因而D输入也变为  0。Clk输入现在是  1:

Q



输入  输出



当Clk信号变回为  0时,不会影响输出:

输入  输出



现在Clk信号再变为  1。由于D输入为0,则Q为0且-  1:

Q为



输入  输出



所以D输入也变为  1:

输入  输出



以上发生的情况总结起来就是:每当  Clk输入从0变到1时,Q端输出就发生改变,或者从  0

变到1,或者从  1变到0。看看下面的图,问题就更清楚了:



当Clk输入从  0变到1时,D的值(与  Q  的值是相同的)被输出到  Q端。当下一次  Clk信号从  0变到1时,同样会改变  D和  Q  的值。

若振荡器的频率是  20赫兹(即每秒  20次循环),则  Q的输出频率是它的一半,即  10赫兹。  由于这个原因,这种电路  (其中  Q  输出依循触发器的数据端输入  )称为分频器。

当然分频器的输出可以是另一个分频器的  Clk输入,并再一次进行分频。下面是三个分频  器连在一起的情况:



让我们来看一下上图顶部的  4个信号的变化规律:



这里只给出了这幅图的一部分,因为这个电路会周而复始地变化下去。从这个图中,有  没有发现使你眼熟的东西?

提示你一下,把这些信号标上  0和1:



现在看出来了吗?把这个图顺时针旋转  90度,读一读横向的  4位数字,每一组输出都对应  了十进制中  0~15中的一个数:



二进制



0000



十进制



0



0001



1



0010



2



0011



3



0100



4



0101



5



0110



6



0111



7



1000



8



1001



9



1010



10



1011


11



1100



12



1101



13



1110



14



1111



15



这个电路只具备了一个计数功能,如果再多加上几个触发器,它就可能计更多的数。第  8  章曾指出在一个递增的二进制数序列中,每一列数字在  0和1之间变化的频率是其右边那一列  数字变化频率的一半,这个计数器模仿了这一点。时钟信号每一次正跳变时,计数器的输出  就递加了  1。

可以把8个触发器集成于一个盒子里,构成一个  8位计数器:



8位行波计数量



这个计数器称为  8位行波(异步)计数器,因为每一个触发器的输出都成为下一个触发器  的时钟输入。变化是沿着触发器一级一级地传递的,最后一级触发器的变化必定要延迟一些。  更复杂的计数器是“并行(同步)计数器”,在这种计数器中,所有输出是同时改变的。

输出端信号已标识为从  Q  ~Q  ,Q  是第一个触发器的输出。如果把灯泡连到这些输出上,

0  7  0



就可以把  8位结果读出来。

这样一个计数器的时序图可以把  8个输出分开来表示,也可以把它们一起表示,如下图所  示:



时钟信号的每个正跳变发生时,一些  Q输出可能改变,另一些可能不改变,但总体上是使



原来的结果递增了  1。  本章前面曾提到过可以找到某种方法来确定振荡器的频率,现在这个方法已经找到了。

如果把振荡器连到  8位计数器的时钟输入上,计数器会显示出振荡器经历了多少次循环。当计

数器总和达到  11111111时,它又会返回到  00000000。使用计数器确定振荡器频率的最简单方  法是把计数器的输出连到  8个灯泡上。当所有输出为  0时(即没有一个灯泡点亮),启动一个秒  表;当所有灯泡都点亮时,停住秒表。这就是振荡器循环  256次所需要的时间。假设是  10秒钟,  则振荡器的频率就是  256÷10,或者说是  25.6赫兹。

当触发器功能增加时,它也变得更复杂。下面这个触发器称为具有预置(  Preset)和清零  功能的边沿触发的  D型触发器  。



清零



预置



时钟



通常情况下,预置和清零信号输入会忽视时钟和数据端输入,且均为  0。当预置信号输入  为1时,Q变为1,  Q  变为0。当清零信号为  1时,Q为0,  Q  变为1(同R-S触发器中的  S和R输入  一样,预置和清零信号不能同时为  1)。其他情况下,该触发器的行为和普通边沿触发的  D型触  发器是一样的。



输入  输出



电路图符号可以简化地用下图代替:



现在,我们已经知道如何用继电器来做加法、减法和计数,是不是很有成就感?因为我  们所用的硬件是  100多年以前就存在的东西,我们还有更多的空间去探索。但是先暂时休息一  下,不用再去构造什么,回过头来