注解目录
第一章《振南当年入门 C 语言和单片机的那些事儿》
1、注定堕入单片机
1.1 懵懂好奇的我
(小时候好奇的性格经常让我屁股开花。初中开始对计算机产生兴趣,并一发不可收拾。)
1.2 我的 C 语言学习经历
(上大学后自学 C 语言。遇到“能人”加入 ACM 竞赛。感觉 C 语言乐趣多多,程序如人生。)
1.3 C 语言的顶级赛事
(ACM 国际程序设计竞赛在东北被我们发扬光大。ACM 竞赛浙大的一段传奇佳话。振南在关注的 IOCCC 国际混乱 C 代码大赛。网吧包宿学 C 语言惊呆室友。)
1.4 岔路口上选择单片机
(搞纯软件还是搞单片机,这是一个抉择。鬼才杜撰拉我进入单片机快车道。)
1.5 窗户纸破了
(入门阶段的困惑,看破 C 语言与单片机之间的鸿沟。)
2 、看穿单片机
2.1 CPU 模型
(CISC 与 RISC 指令集。CPU 如何执行指令。汇编不是第一代编程语言,打孔纸带才是。)
2.2 存储器模型
(存储器就是一个指令和数据的容器。)
2.3 总线模型
(地址、数据和控制三大总线。贯穿整个单片机芯片的通路。)
2.4 外设模型
3、单片机跑起来
3.1 时钟系统
(时钟是单片机激励和血液。时钟频率不能无限提高。)
3.2 二进制
(为什么单片机采用二进制?振南告诉你如果单片机使用十进制会怎样?)
3.3 中断机制
(中断不是在给 CPU 捣乱。中断对于单片机为什么如何重要?)
看穿单片机
经历了十多年的单片机开发,站在我现在的高度来回看单片机,可谓望眼欲穿。
下面振南要介绍的是“单片机的体系架构模型”,是超脱于任何一种具体型号的单片机芯片之上的(我感觉我要成仙),它具有很强的普适性。几乎所有的单片机,或是ARM、DSP以及更为高端的处理器都遵循这一模型。或者说,这一模型中的几大要素是必需的。我认为只有在这个层面上,午能真而“看深单片机”。
1.1 CPU模型
CPU,即中央处理单元,它是计算机系统的核心,占有至高无上的地位,拥有绝对的管理权与控制权,如图 1.5 所示。
图1.6 CPU在计算机系统中占有核心地位
CPU的核心要务是执行指令,比如计算两个数的和、读写寄存器、操作总线读写内存等等。每一个CPU都有自己事先设计好的一套指令集,或称指令系统,每一条指令完成一项具体的操作和功能。但是指令集并不是凭空存在的,每条指令必然都对应着一套电路。当CPU执行一条指令时,其实就是相应的电路在工作。所以,一个 CPU 的性能是否优异,一部分因素就在于指令集是否丰富,指令功能是否强大,指令电路是否强大而高效。从复杂程度上来说,CPU指令集主要分为两种:复杂指令集(CISC) 与精简指令集(RISC)。大多数的嵌入式CPU都是RISC的,这一方面表现在指令的数量上:指令少,则对应的电路就少,可以很大程度上降低CPU设计的难度,同时也降低了功耗;另一方面则表现在指令的功能量级上:指令本身一般不宜实现过于复杂的功能,这使得指令执行效率比较高CISC则不同(x86就是最为经典的CISC指集),它的指数量庞大(少的有300条左右,多的甚至超过500条,而 RISC通常不超过10 条),而且指令的功能都比较强大。这意味着采用CISC指令集的CPU在电路设计上的难度很大,研发周期比较长。但是它在功能和性能上都是RISC所无法企及的(一条 CISC指所完成的工作可能需要若干条RISC指令才能完成)。所以在大型服条器、工作站这些计算机系统中大多使用CISC指CPU实际上,CISC 与 RISC只是为了适应不同的需求而产生的,它们并非对立,反而是相互促进,取长补短的关系。CISC中已经开始加人部分RISC指令,而在嵌人式领域中也出现了一些CISC指令的CPU。融合了 CISC与RISC双重指集的新型CPU将是以后的发展趋势。上面是振南对CPU指令集的简要介绍,其实与指令集密切相关还有一些关键技术,比如流水线、指令预取、乱序执行等等,是它们让CPU的性能有了更大的提升(振南早期就职于In-tel 中国研究院,主要就是研究这方面技术,所以深有感触)。不过在这里振南不对其进行讲解,有兴趣的读者可以自行研究。
直到现在,仍然有很多人向我资询关于计算机基本原理、体系架构、硬件组成等等方面的问题,我在解答之余,也在问他们:“你们对计算机基础如此感兴趣,为什么起初不学计算机专业呢?”我其实明白,很多人在高考报志愿的时候,都是有些盲目的。
指令的实质是什么?是 C语言中的 a=0? 是汇编语言中的 MOV?不,大家看到的这些语句只是指令的一种表达形式而已。指令的实质上是一个有一定长度的二进制序列(比如0101111010101010 或 1011010111011011等)。CPU 在得到指今之后,首先由指令译码电路从中分离中操作码、操作数,如图 1.6 所示(以 51 的 MOV 指令为例进行说明)。
图1.7 对指令码的译码
01110100 即为指令 74H,它的功能是将后面的操作数(00010000,即10H)传送到 A 寄存器(51CPU中的累加器)。这条指令如果使用汇编语言来表示就是MOV A,# 10H,它通过汇编器翻译之后,就是上图中的16 位指令码(汇编语言的提出,只是对最原始的CPU二进制指令进行了封装,用一些便于记忆的标识,比如MOV、ADD、INC等对指令进行表示,经过汇编器翻译后,就是可直接进入CPU 进行执行的指令码序列了)。
振南经常想像在CPU问世初期人们是如何向 CPU输入指令的一“打孔纸带”,如图 1.7所示。
在汇编语言产生之前,程序指令的编制都要完全靠人工来完成。人们将编好的若干条指令通过纸带打孔方式输人到CPU中,让它可以依次执行,最终完成整个计算任务(纸带上的“孔’与“实’代表了1和 0)。从某种意义上来说,“纸带”才是第一代编程语言,然后“汇编语言”是第二代编程语言。它们都是离CPU指令最近的语言,所以我们称之为“低级语言”。最
图1.8 人们使用纸带打孔方式向CPU输入指令
后才产生了C语言,它与我们人类日常使用的自然语言(英语)已经非常接近,这意味着它离CPU指令很远了。它需要经过专门的编译器进行预处理、语义分析、编译等加工处理,生成中间代码(汇编),然后再进一步进行汇编,连接等处理才能得到真正可由CPU执行的指令码。所以,C 语言被称为“高级语言”。
综上所述,我们可以认为CPU就是一个取指令执行的机器,这就是CPU的主要功能和工作。但是CPU的体系结构又并非仅仅这么简单,如何协调取指令的过程,防止出错? 指令存储在哪里?CPU如何从存储器中取出指令?这些问题我们都要深刻理解,否则C语言和单片机是无法真正精通的。