1.5 8051单片机编程语言
如图1.11所示,从系统结构来说,8051单片机语言分为四个不同的层次,包括:微指令控制序列、机器语言、汇编语言和高级语言。
图1.11 单片机编程语言体系结构
1.微指令控制序列
微指令控制序列存在于CPU内部,单片机应用开发人员无法微指令控制序列。本质上,CPU就是通过由有限的自动状态机所构成的微指令控制器对其内部的寄存器、存储器和ALU等参与具体数据处理的功能单元“发号施令”。例如,要实现对8051单片机CPU内的两个寄存器的数据进行相加的操作,CPU内的微指令控制器会发出一系列的控制序列,这些控制序列在CPU主时钟的控制下,按顺序先后给出,这就是时序。微指令控制序列属于数字逻辑中组合逻辑和时序逻辑的范畴。只有设计8051单片机芯片的工程师,才会接触到微指令控制序列。
下面给出微指令控制序列控制两个数据相加过程的形式化描述:
(1)选择某个寄存器,读取加数;
(2)选择另一个寄存器,读取被加数;
(3)将这两个操作数送到ALU;
(4)根据功能,选择ALU执行加法运算;
(5)ALU产生运算的结果和标志,比如:零标志、符号标志、进位标志和溢出标志等;
(6)根据指令的要求,将运算的结果保存到寄存器或者存储器中。
可以看出,一个简单的加法运算,要产生一系列的控制序列。这也是通常所说的译码和执行指令的过程。
2.机器语言
从上文可以知道,使用单片机从事开发的应用工程师根本不需要知道微指令控制序列,他只要告诉CPU执行加法操作即可,也就是不需要掌握CPU内部结构的具体实现方式。保存在单片机内程序存储器中的由0和1构成的序列,称为机器语言(也称为机器代码)。通过取出相应的机器指令(机器代码),就可以实现加法运算。
在8051单片机中,ACC累加器和一个常数(立即数)相加的机器语言的格式,如图1.12所示。从图中可以看出,机器语言是由0和1构成的二进制序列。这个序列(机器指令)中包含操作码和操作数两个部分。
图1.12 单片机机器语言格式
1)操作码
操作码告诉CPU需要执行的操作。该指令的操作码用二进制表示为(00100100)2,用十六进制表示为(24)16。操作码部分包含了操作的类型编码,同时也包含了一部分的操作数,指明了参与加法运算的一个数来自ACC寄存器中。
2)操作数
操作数是操作的对象。操作对象包括:立即数(常数)、寄存器和存储器等。在图1.12中,immediate data表示立即数(常数),占用了1字节(8比特),表示参与加法运算的另一个数的具体取值。
但是,纯粹意义上的机器语言对程序员太难理解了,这是因为使用单片机从事开发的应用工程师是CPU的使用者,而不是CPU的设计者,他们根本不可能从二进制代码的排列中看出机器语言所描述的逻辑操作行为。而且,他们很难记住这些0和1组成的二进制机器语言序列。
3.汇编语言
为了帮助应用工程师从更抽象的行为级上理解CPU所执行的操作,计算机软件设计人员开发了一套基于助记符描述CPU指令系统的方法。通过汇编语言助记符指令,软件应用开发人员可以将这些助记符所表示的CPU指令组合在一起,构成一个复杂的称为“程序”的软件代码来控制CPU的运行。
通过汇编器(软件工具),可以将使用汇编语言助记符描述的指令转换成使用机器语言描述的机器指令。用汇编助记符描述机器指令的完整的格式为:
[标号:] 助记符 [操作数] [;注释]
其中,标号用来表示一行指令;助记符表示CPU所要执行的操作;操作数为与操作行为有关的操作对象。
现在用汇编语言来描述图1.12给出的机器指令:
ADD A,#25
其中:ADD表示数据相加操作;A表示目的操作数,即ACC累加器;#25表示源操作数。
这个助记符汇编指令所表示的是,将立即数(常数)25和ACC累加器内所保存的数相加,并将得到的结果保存在ACC累加器中。可以看到,在汇编语言(助记符)级上理解CPU的指令操作,更加直观,而且无须知道指令二进制的具体表示形式。因此,显著降低了软件程序开发人员基于单片机开发应用程序的难度。
但是,由于汇编语言下面是机器语言,所以使用汇编语言开发具体软件应用的工程师必须很清楚CPU的指令集、寄存器单元和存储器映射等烦琐的硬件规则。虽然其执行效率与机器语言相当,但是使用汇编语言开发复杂应用的效率很低。由于很多软件开发人员根本不了解CPU的具体内部结构,所以对他们而言,使用汇编语言开发应用并不比直接使用机器语言编程有更多的优势。
但是,汇编语言仍然非常重要。重要性体现在:
(1)对理解CPU内部的结构和运行的原理非常重要。
(2)很多与CPU打交道的软件驱动程序,尤其是操作系统的初始引导代码必须用汇编语言开发,这是因为以C语言为代表的高级语言的语法并不能一一对应到机器指令,也就是无法实现某些机器指令的功能。
(3)一些对程序执行时间比较苛刻的场合也需要使用汇编语言进行开发,这样能显著减少程序的运行时间,提高代码的执行效率。
4.高级语言
值得高兴的是,目前,MCU的软件集成开发工具(如KeilμVision)支持使用C语言对单片机的程序进行开发。C语言不能直接运行在CPU上,它必须通过编译器和连接器(软件工具)的处理,最终生成可执行代码,也就是转换成机器语言,才能在CPU上运行。
从图1.11中可以看出,与C语言相比,汇编语言更接近于机器语言。因此,使用以C语言为代表的高级语言所编写的代码的运行效率不可能比用汇编语言编程的运行效率高。所以,如果想让用C语言所编写的代码和用汇编语言编写的代码有一样高的代码执行效率,需要C语言程序员使用各种程序设计技巧提高C语言代码的设计效率,并且调整编译工具的优先级设置选项,以满足代码长度和运行时间的双重要求。
代码长度和运行时间是单片机程序设计的两个最基本的要求,即:
(1)要求程序代码尽可能地短,这样可以大大节省所占用的程序存储器的空间,减少对程序存储器空间的要求。
(2)程序代码的运行尽量满足实时性的要求,这样在程序的执行过程中可以实时地响应不同外设的要求。虽然对程序进行优化会让高级语言程序员耗费很多的精力,但是他们再也不用和底层硬件直接打交道了。
现在越来越多的厂商提供了硬件的应用程序接口(Application Program Interface,API)函数。这样,程序员可以不用知道更多的硬件实现细节,只需关心如何使用API来编写代码使硬件工作,这样就大大提高了应用开发的效率。
下面以两个8位数相加为例,说明C语言、汇编语言和机器语言之间的关系:
这段代码的反汇编代码(汇编语言)、机器指令(机器语言)与C语言之间的对应关系如图1.13所示。
图1.13 C语言、汇编语言与机器语言之间的关系
正如上面所提到的那样,8051单片机代码设计者必须能够很好地处理好汇编语言和C语言的关系。
思考与练习1-10:单片机编程语言的四个层次为___、___、___和___。
思考与练习1-11:机器语言/汇编语言指令中,包含___和___。
思考与练习1-12:请说明在单片机程序设计中,使用C语言编程/汇编语言编程的优势。
对于8051单片机而言,应该从电子系统的高层次来认知,而不仅仅只从单片机本身来认知。这是因为由8051单片机所构成的电子系统,包括了软件和硬件两大部分。软件包含汇编语言设计、C语言程序设计、操作系统、数据结构、算法(数字信号处理和控制理论)的知识,硬件包含了模拟电子技术、数字逻辑、处理器、接口、ADC和DAC、电路设计的知识。
本书的编写就是基于8051单片机系统这个层次,虽然单片机所涉及的知识点较多,但是仍然有一条主线,即正确认识处理器架构、处理器和指令集之间的关系、汇编语言和C语言之间的关系、接口与外设之间的关系。
在学习单片机这门课程的时候应该紧密围绕这三大主题,即软件和硬件的协同设计、软件和硬件的协同仿真、软件和硬件的协同调试,这样才能把握整个单片机的精髓。