---
schema_version: "library-reader-v1"
source_type: "original_book"
title: "编码 隐匿在计算机软硬件背后的语言"
author: null
edition: null
publisher: null
year: null
isbn: "9787121181184"
library_document_id: "38270854-596f-4a26-8183-db8c968c6020"
source_sha256: "249786274d83909f0bddc34d77f81ed8f0b14d1eac8843c772a37a3ecbfe2cfc"
pdf_physical_page_count: 438
pdf_physical_page_index_base: 0
range_start: 180
range_count: 10
html_url: "https://workshop.closeclaw.top/api/ai/read/38270854-596f-4a26-8183-db8c968c6020?start=180&limit=10"
markdown_url: "https://workshop.closeclaw.top/api/ai/read/38270854-596f-4a26-8183-db8c968c6020.md?start=180&limit=10"
previous_url: "https://workshop.closeclaw.top/api/ai/read/38270854-596f-4a26-8183-db8c968c6020.md?start=170&limit=10"
next_url: "https://workshop.closeclaw.top/api/ai/read/38270854-596f-4a26-8183-db8c968c6020.md?start=190&limit=10"
---

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

> 页码规则：PDF_PHYSICAL_PAGE_INDEX 是从 0 开始的权威文件物理页索引；PRINTED_PAGE 是页面中识别出的印刷页码，可能为空，二者不得混用。

## PDF_PHYSICAL_PAGE_INDEX=180 | PRINTED_PAGE=164

一个循环所占用的时间就是该振荡器的周期（period)。假设我们使用的振荡器的周期恰好是0.05s，任取一个时间点，将其设置为起始状态点，我们把它标注为零点，就可以在水平轴上标出相应的时间。

周期的倒数就是振荡器的频率(frequency)。在这个例子中振荡器的周期是0.05s，那么其频率就是1÷0.05s，即振荡器每秒钟产生20次循环，而相应的输出每秒钟也变化20次。

每秒钟的循环次数与每小时穿越的英里数、每平方英尺的重量、每份食物的卡路里数等概念一样都是很容易理解的，但这种描述方法已不常用。为了纪念发送和接收无线电波的第一人—亨利希·鲁道夫·赫兹（1857-1894)，后人使用“赫兹”这个词来表示这一概念。这种用法起源于20世纪20年代的德国，几十年之后逐渐被其他国家所广泛采纳。

这样，上述振荡器的频率就是20赫兹，记做20Hz。

目前为止，我们还只是在猜测一个振荡器的速度。在本章后面我们将构建一种可以测量振荡器速度的元件。

在此之前，让我们先来看看采用特殊方式连接的一对或非门。或非门的特点是只有在两个输入端都没有电压时，输出端才产生电压。

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

164

## PDF_PHYSICAL_PAGE_INDEX=181 | PRINTED_PAGE=165

下面是一个包含两个或非门、两个开关和一个灯泡的电路。

值得注意的是这种特殊的弯曲的连线方式：左边或非门的输出是右边或非门的输入，而右边或非门的输出是左边或非门的输入。这种连接方式我们称之为反馈（feedback)。系统的输出返回给输入这种形式和我们在振荡器中讨论的情况很相似。接下来你将会看到，本章大部分电路都具备这种特质。

在初始状态下，电路中只有左边的或非门输出电流，这是因为其两个输入均为 $0 _ { \circ }$ 让我们闭合上面的开关，左边或非门将立刻输出0，右边或非门的输出也会随之变为1，这时灯泡将被点亮。

奇妙的是，这时一旦你关闭上边的开关，灯炮依然闪闪发光。这是因为由于左边或非门的输入中有一个为1，其输出依然是0，因而左边或非门的输出不变，所以灯泡仍然亮着。

14 反馈与触发器

165

## PDF_PHYSICAL_PAGE_INDEX=182 | PRINTED_PAGE=166

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

难道你不觉得有点奇怪吗？两个开关都断开—和第一幅场景描述的是一模一样一一但这里的灯泡却仍发光。这与我们先前所见过的所有情况都完全不同。先前遇到的电路其输出依赖且仅依赖于其输入，这次的结论与以前的大相径庭。无论上面的开关怎么调整其状态，灯泡总是亮着。这个开关对电路毫无影响，究其原因可以发现这是由于左边或非门的输出一直为0。

现在来试试闭合下面的开关。我们会发现右边或非门的输入中有一个立刻变为1，其输出就相应地变为0，灯泡随之熄灭。左边或非门的输出此刻变为1。

这时你再去断开下面的开关就会发现，灯泡一直处在熄灭状态。

此时的电路状态与初始时是一样的。但是这次无论你怎么改变下面开关的状态，灯泡丝毫不受影响。我们将先前的情况一起总结一下：

接通上面的开关，灯泡被点亮，断开此开关灯泡仍然亮着。

接通下面的开关，灯泡被熄灭，断开此开关灯泡仍然不亮。

电路的奇怪之处是：同样是在两个开关都断开的状态下，灯泡有时亮着，有时却不亮。当两个开关都断开时，电路有两个稳定态，这类电路统称为触发器（Flip-Flop)，Flip-Flop这个单词也可以有“沙滩鞋”或者是“政治策略”的意思。触发器是在1918年被发明的，发明者是英国无线电物理学家威廉姆·亨利·艾克里斯（1875-1966）和F.W.乔丹（信息不详）。

166

## PDF_PHYSICAL_PAGE_INDEX=183 | PRINTED_PAGE=167

触发器电路可以保持信息，它可以“记住”某些信息。特别地，对于本章先前所讲述的触发器，它可以记住最近一次是哪个开关先闭合。如果你遇到这样一种触发器，如果它的灯泡是亮着的，你就可以推测出最后一次连通的是上面的开关；而如果灯泡不亮则可推测出最后一次连通的是下面的开关。

触发器和跷跷板有着很强的相似性。跷跷板也有两个稳定状态，它不会长期停留在不稳定的中间位置。通过观察跷跷板，我们很容易推测出哪边最后一次被压下来。

尽管你现在可能还没感受到这一点，但触发器的的确确是一种必不可少的工具。它们可以让申路“记住”之前发生了什么事情。想象一下，如果你没有了记忆力，该如何去数数，我们不记得刚刚数过的数，当然也就无法确定下一个数是什么！同理，一个能计数的电路（本章后面要讲到）必定需要触发器。

触发器种类繁多，先前所讲述的是最简单的一种R-S(Reset-Set，复位/置位)触发器。我们通常把两个非或门绘制成另一种形式，加上标识符就得到了下面这幅图。

我们通常用Q来表示用于点亮灯泡的输出的状态。另一个输出 $\overline { { \mathbf { Q } } }$ （读做Q反）是对Q的取反。Q是0， $\overline { { \mathbf { Q } } }$ 就是1，反之亦然。输入端S（Set）用来置位，R（Reset）用来复位。你可以把“置位”理解为把Q设为1，而“复位”是把Q设为 $0 _ { \circ }$ 当状态 S为1时(对应于先前触发器中上面的开关闭合的情况)，此时Q变为1而 $\overline { { \mathbf { Q } } }$ 变为0；当R状态为1时（对应于前面图中闭合下面的开关的情况)，此时Q变为0而 $\overline { { \mathbf { Q } } }$ 变为 $1 _ { \circ }$ 当S和R均为0时，输出保持Q原来的状态不变。我们把结论总结如下表所示。

14 反馈与触发器

167

## PDF_PHYSICAL_PAGE_INDEX=184 | PRINTED_PAGE=168

这类表称为功能表（function table)、逻辑表（logic table）或真值表（truth table)。它表达了不同输入组合所对应的不同输出结果。因为R-S触发器仅有两个输入端，所以不同的输入组合共有4种，分别对应于表中的4行。

注意表中倒数第2行，这一行输入S和R均为0，而输出标识为Q和 $\overline { { \mathbf { Q } } }$ 。这表示当S和R输入均为0时，Q和 $\overline { { \mathbf { Q } } }$ 端的输出保持为S、R同时被设为0以前的输出值。表中最后一行表示S和R均为1的输入组合是被禁止或者不合法的。不要误解为你会因此被逮捕，而是说如果S、R状态同时为1时，Q和 $\overline { { \mathsf { Q } } }$ 均会为零，这与Q和 $\overline { { \mathbf { Q } } }$ 互反的假设关系相矛盾。所以当使用R-S触发器进行电路设计时，R、S输入同时为1的情况一定要避免。

R-S触发器可以简化为带有输入和输出标志的小框图，就像下面画的这样。

R-S触发器最突出的特点在于，它可以记住哪个输入端的最终状态为1。但是有时候我们需要一种记忆能力更加强大的电路，例如能记住在某个特定时间点上的--个信号是0还是1。

在构造具备这种功能的电路之前，让我们先来思考-下它的具体行为。这个电路存在两个输入。其中一个我们称之为数据端（Data)。j所有数字信号一样，数据端取值为0或1；另一个输入被称为保持位(HoldThat Bit)，保持位的作用就是使当前的状态被“记住”，通常情况下保持位被设置为0，在这种情况下数据端对电路不产生影响。当保持位置1时，数据端的值就会在电路系统中被“记住”。随后保持位又置为 $\mathrm { \dot { \boldsymbol { 0 } } }$ ，这时电路已经“记住”了数据端的最后一次输入，而之后数据端的输入无论如何变化都不会对电路产生影响。

我们可以把状态转化的过程以真值表的形式表示如下。

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

168

## PDF_PHYSICAL_PAGE_INDEX=185 | PRINTED_PAGE=169

在前两种情况下，保持位为1，输出Q与数据端输入相同；后面两种情况下，保持位为0，输出端Q和其前一个状态保持一致。值得注意的是，保持位为0意味着输出将不再变化，也就是说不再被数据端所影响，我们可以进一步将真值表简化为如下所示。

X表示“其取值情况与结果无关”，只要保持位的值为0，那么数据位对电路的输出没有影响，电路的输出和其前一个状态相同。

如果使用先前学过的R-S触发器来实现这种具有保持位的功能系统，那么我们的电路需要在输入端增加两个与门，下图所给出了该系统的实现电路。

回忆一下与门，它的特点是只有在输入端都为1的状态下，输出才为 $1 _ { \circ }$ 在上面这幅图中，输出端Q为0， $\overline { { \mathbf { Q } } }$ 为1。

只要保持位为0，则置位端对于输出结果不会有任何影响。

14 反馈与触发器

169

## PDF_PHYSICAL_PAGE_INDEX=186 | PRINTED_PAGE=170

同样，复位信号对输出也无任何影响。

当保持位信号为1时，这套电路系统就和先前讲过的R-S触发器功能一致。

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

但是我们离目标还差一点。我们只想要两个输入，而不是三个，怎么解决这个问题呢？先回忆一下R-S触发器的功能表：两个输入端同时为1是非法的，要尽量避免；而两个输入端同时为0是无意义的，因为那种情况下输出就会保持不变。我们只要将保持位设置为0，就完全可以实现相同的功能。

由此可以总结出，真正有意义的输入可以是S为0，R为1或者是R为0，S为1的情形。如果把数据端信号看做置位信号，把它取反后的值看做复位端信号，我们可以画出相应的电路图如下所示。

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

170

## PDF_PHYSICAL_PAGE_INDEX=187 | PRINTED_PAGE=171

在上图所表示的情况下，所有输入均为0，而输出Q也为0（此时 $\overline { { \mathsf { Q } } }$ 为1)。可以看出只要保持位为0，电路输出就丝毫不受输入端的影响。

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

现在Q端的输出和数据输入是一致的，而 $\overline { { \mathbf { Q } } }$ 端则正好相反。现在保持位又回到0，如下图所示。

14 反馈与触发器

171

## PDF_PHYSICAL_PAGE_INDEX=188 | PRINTED_PAGE=172

这时，电路会“记得”当保持位最后一次置1时数据端输入的值，数据端的变化对此没有影响。例如，数据端再置回0对输出将不会产生影响。

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

通常情况下，当这种电路出现在书中的时候，输入端是不会被标记为保持位的，而是被标记为时钟（clock）。当然，这种信号并不是真正的时钟，但是在某些情况下它却具有类似时钟的属性，即它可以在0和1之间有规律地来回变化。但是现在时钟仅仅用来指示什么时候保存数据。

通常把数据端简写为D，时钟端简写为Clk，其功能表如下所示。

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

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

172

## PDF_PHYSICAL_PAGE_INDEX=189 | PRINTED_PAGE=173

在锁存器中保存多位值通常是很有用的。假如你想用第12章的加法器把3个8位数相加，可以在开关的第1行中存入第1个加数，以同样的方式把第2个加数存入第2行，但是必须记下第一次相加的结果。然后你需要把这个结果输入到开关的一行中，再把第3个加数输入到开关的另一行中。而你实际上不必输入中间结果，你应该能够在第一次计算之后直接使用它。

可以使用锁存器来解决这个问题。我们在一个小盒子里布置8个锁存器，如前所述，每个锁存器包括两个或非门、两个与门以及一个反相器。所有的时钟输入端都互相连在一起。结果如下图所示。

这个锁存器可以一次保存8位数。上面的8个输入端依次标记为 ${ \bf D } _ { 0 } \sim { \bf D } _ { 7 }$ ，下面的8个输出端被标记为 $\mathrm { Q } _ { 0 } \sim \mathrm { Q } _ { 7 }$ 。左边的输入是时钟（Clk)，时钟信号通常为 $\mathbf { 0 } _ { \circ }$ 当时钟信号为1时，D端输入的8位值被送到Q端输出。当时钟信号为0时，这8位值将保持不变，直到时钟信号再次被置1。

也可以将8位锁存器的8个数据输入端和8个Q输出端画为两组线，如下图所示。

下面是8位加法器的图示。

14 反馈与触发器

173

下一段：[继续读取](https://workshop.closeclaw.top/api/ai/read/38270854-596f-4a26-8183-db8c968c6020.md?start=190&limit=10)
