一、几个基本概念 位(bit):是计算机所能表示的最小的、最基本的数据单位。由于计算机使用的是二进制数,因此一位就是一个二进制数。 字节(Byte):一个连续8位的二进制数码称为一个字节,即1Byte=8bit。 字(Word):一般由两个字节组成,即16位二进制数码组成,显然1Word=2Byte=16bit。 双字((Double Word):两个字组成,即四个字节(32位)。 字长:字长是计算机一次处理二进制的位数。(MCS-51是8位单片机,字长就是8位) 二、指令的执行过程指令执行过程可用如图所示:
单片机指令执行过程示意图
一条指令的执行过程包括以下几个环节: 1.取操作码:根据指令指针PC中的内容(操作码地址),取指令第一字节; 2.指令指针加1; 3.译码:对指令操作码进行翻译,指示控制器给出相应的控制信号; 4.取操作数:取出指令第二、三个字节。指令的第一个字节(操作码)会告诉CPU该指令的长度; 5.执行指令规定的操作。 随后,不断重复“取操作码→译码→取操作数→执行”的过程,执行后面的指令,直到程序结束或循环往复。 在指令取出过程中,程序计数器PC每输出一个地址编码到地址寄存器AR后,PC内容自动加1,指向下一个存储单元。 三、单片机的指令系统单片机种类繁多,设计时怎样表示操作码和操作数,都有各自的规定,指令代码也各不相同。各个系列的单片机虽然有不同的指令系统,但也有其共同性。MCS-51单片机应用广泛,派生品种多,具有代表性,这里以51系列的指令系统为例说明“指令”的组成和应用。 1、MOV A,#20H 这条指令表示把20H这个数送入累加器A中(一个特殊功能寄存器) 2、ADD A,70H 这条指令表示把累加器A中的内容(在上例中送入的#20H)和存贮器中地址为70H单元中的内容(也是一个数字),通过算术逻辑单元(英文缩写为ALU)相加,并将结果保留在A中。 这里MOV、ADD等称为操作码,而A、#20H、70H等均称为操作数。在汇编语言程序中,操作码通常由英文单词缩写而成,这样有助于**,所以又称助记符。如MOV就是英文单词MOVE的缩写,含有搬移的意思;而ADD即为英文单词,其意为相加。因此,对于略懂英语的用户,掌握单片机指令的含意是较为方便的。操作数有多种表示法,如以上的#20H称为立即数,即20H就是真正的操作数。而70H是存贮器中某个单元的地址,在该单元中,放着操作数(比如说是3AH),ADD A,70H不是将70H和A中的内容相加,而是从存贮器70H单元中将3AH取出和A中的内容相加。 MCS-51系列单片机指令系统表
四、汇编语言指令格式指令格式即指令的表示方式,它规定了指令的长度和内部信息的安排。一个完整的汇编语言指令格式如下: [标号:] 指令助记符 [操作数] [;注释] 其中方括号[ ]中为可选项。 标号:本条指令的起始地址的符号,也称为指令的符号地址,代表该条指令在程序编译时的具体地址,标号可以被其他语句调用。 指令助记符:即操作码,对应的英文构成,是指令语句的关键,不能缺少。 操作数:可以是具体数据,也可以是具体数据存放的地址。 特别说明:语句中的标点符号千万切记一定要用半角字符,我就经常吃全角字符的亏。 汇编语言指令系统中的常用符号: - Rn 当前寄存器区的8个工作寄存器R0~R7(n=0~7)。
- Ri 当前寄存器区中可作间接寻址寄存器的2个寄存器R0、R1(i=0,1)。
- Direct 直接地址,即8位的内部RAM或特殊功能寄存器的地址。
- #data 包含在指令中的8位立即数。
- #data16 包含在指令中的16位立即数。
- rel 相对转移指令中的偏移量,为8位的带符号补码数。
- DPTR 数据指针,可用作16位的数据地址寄存器。
- bit 内部RAM或特殊功能寄存器中的直接寻址位。
- C(或Cy) 进位标志位或位处理机中的累加器。
- addr11 11位目的地址
- addr16 16位目的地址
- @ 间接寻址寄存器前缀,如@Ri,@A+DPTR
- (X) X中的内容。
- ((X)) 由X寻址的单元中的内容。
- → 箭头右边的内容被箭头左边的内容所取代。
五、单片机的寻址方式指令由操作码和操作数组成,操作码通过指令指针PC找到,那么CPU是如何找到操作数的呢? 确定指令中操作数所在存储单元地址的方式,就是我们所说的寻址方式。对于只有操作码的指令,不存在寻址方式问题;对于双操作数指令来说,每一操作数都有自己的寻址方式。 例如,在含有两个操作数的指令中,第一操作数(也称为目的操作数)有自己的寻址方式;第二操作数(称为源操作数)也有自己的寻址方式。 指令中的操作数来源的规定:操作数只能是下列内容之一: (1)CPU内某一寄存器名,如累加器A、通用寄存器B、堆栈指针SP、程序状态字寄存器PSW以及工作寄存器组R7~R0。 (2)存储单元。存贮单元地址范围由CPU寻址范围以及实际安装的存储器容量、连接方式决定。 (3)I/O端口号。在通用微机系统中,I/O地址空间与存储器地址空间相互独立;不过在单片机系统中,I/O端口地址空间往往与外存储器地址空间连在一起,不再区分。 (4)常数。常数类型及范围与CPU类型有关。 找到实际操作数的过程称为寻址,MCS-51共有7种寻址方式,现介绍如下: 1.立即寻址当指令第二操作数(源操作数)为8位或16位常数时,就称为立即寻址方式,其中的常数称为立即数。操作数就写在指令中,和操作码一起放在程序存贮器中。把“#”号放在立即数前面,以表示该寻址方式为立即寻址,如: MOV A,#23H ;其中第二操作数“30H”就是立即数。 MOV DPTR, #1000H ;将立即数1000H送到数据指针DPTR(16位寄存器)寄存器中。 在立即寻址方式中,立即数包含在指令码中,取出指令码时也就取出了可以立即使用的操作数(也正因如此,该操作数被称为“立即数”,并把这一寻址方式形象地称为“立即寻址”方式)。 例如“MOV A,#23H”指令机器码为“74 23”,在存储器中的存放位置及执行结果可用图表示。
立即寻址示意图2.寄存器寻址操作数是CPU内的某一寄存器名。操作数放在寄存器中,在指令中直接以寄存器的名字来表示操作数的地址。例如: MOV A,23H ;在这条指令中,目的操作数是累加器A。因此,这条指令目的操作数采用寄存器寻址方式。 寄存器寻址方式可以用在目的操作数中,也可以用在源操作数中,如: MOV 23H,A ;在这条指令中,累加器A是源操作数。因此,这条指令源操作数采用寄存器寻址方式。 MOV A,R0; 即将R0寄存器的内容送到累加器A中。 说明:可用于寄存器寻址方式的寄存器有:累加器A、寄存器B(但仅限于乘法指令)、数据指针DPTR、位操作指令中的进位标志Cy、工作组寄存器R7~R0。 3.直接寻址操作数放在单片机的内部RAM的某个单元中,在指令中直接写出该单元的地址。操作数是某一存储单元的地址码。例如:MOV A,0023H ;直接使用存储单元地址作为源操作数。 将0023H存储单元中的内容传送到累加器A中,其中的“0023H”不是立即数,而是存储单元的地址编码。假设存储器中0023H单元的内容为55H,则该指令执行后,累加器A中的内容将变为55H,指令代码和执行结果可用图表示。
直接寻址示意图
4.寄存器间接寻址将寄存器内容作为指令中操作数所在存储单元地址编码的寻址方式,称为寄存器间接寻址方式。操作数放在RAM某个单元中,该单元的地址又放在寄存器R0、R1中。 如果RAM的地址大于256,则该地址存放在16位寄存器DPTR(数据指针)中,此时在寄存器名前加@符号来表示这种间接寻址。如: MOV A,@ R1 ; MOV A ,@DPTR; 第一条指令的含义是:将寄存器R1内容指定的内部RAM单元的内容传送到累加器A中。假设R1=40H,而内部RAM 40H单元的内容为5578H,则指令执行后,累加器A的内容将为78H。指令中的“@”是间接寻址标志,该指令与“MOV A,R1”不同,“MOV A,R1”指令源操作数采用寄存器寻址方式,含义是将寄存器R1内容传送到累加器中。 在MCS-51系列单片机中,只能使用寄存器R0、R1以及DPTR作为间接寻址寄存器。 5.变址寻址方式将某一寄存器作为基址寄存器,另一寄存器作为变址寄存器,两者相加后作为操作数所在存储单元地址的寻址方式就称为变址寻址方式。例如: MOVC A,@A+DPTR 数据指针寄存器DPTR(16位,作为基址寄存器)加上累加器A(作为变址寄存器)后获得存储器单元地址,并将该单元内容传送到累加器A中。在这一指令中,源操作数采用了变址寻址方式。 6.相对寻址方式以程序计数器PC的当前值加上指令中给出的相对偏移量rel作为程序计数器PC的值,这一寻址方式用在条件转移指令中。例如: JZ lable ;其中lable为转移的目标地址 7.位寻址方式按照位来进行寻址,这是51系列单片机所特有的一种寻址方式,例如: MOV C,20H ;指令中的“C”是进位标志Cy的简称,20H是位寻址空间内的位地址。 操作码与操作数不同寻址方式的组合就构成了特定CPU的指令系统,但在特定CPU指令系统内,操作码支持何种类型的寻址方式,由CPU决定。例如在MCS-51指令系统中,PUSH指令(将操作数压入堆栈)只支持直接寻址方式。 可能小伙伴会问,在指令中直接给出实际操作数,不是简单、明了吗?为什么还要这么复杂?这是因为在编制程序时有时很难一下子就给出具体的操作数,或者它是变化的,直接使用操作数有时会让程序过于冗长(比如大量数据运算)。寻址方式越多,编制程序就越方便、灵活,适用范围就越广。 寻址有如找人,寻址方式越多,找操作数越方便,单片机的功能就越强。前面介绍51系列单片机的寻址方式时,常遇到单片机内部的一些寄存器、累加器A、通用寄存器R0~R7、数据指针DPTR和存贮器等。在以后介绍指令时,数据就要在这些寄存器、存贮器之间传送,或者进行运算。因此,编制程序就需熟悉单片机的内部结构。
单片机拥有“位处理器”,可以对某个位进行寻址,寻找某位的内容,适于按位进行逻辑运算的位处理器。 除128字节RAM、4k字节ROM和中断、串行口及定时器模块外,还有4组I/O口P0~P3。 六、8051单片机存储器地址分配MCS-51的存储系统 MCS-51系列单片机在存储结构上采用哈佛(Har-Vard)结构,即将程序存储器和数据存储器分开,它们有各自的寻址机构和寻址方式。在物理上有4个存储器地址空间:片内程序存储器、片外程序存储器、片内数据存储器和片外数据存储器。 从逻辑上划分,有3个存储器地址空间:片内外统一编址的64KB的程序存储器地址空间(0000-FFFFH)、128B或256B(52系列)的片内数据存储器地址空间和64KB的片外数据存储器地址空间、片内128B的特殊功能寄存器(SFR)。 在访问这3个不同的逻辑空间时,应采用不同形式的指令。如图所示为MCS-51系列存储器的地址空间分配图。
图 51系列存储器地址空间分配图1.程序存储器空间程序存储器用于存放程序和预置数据。MCS-51单片机具有16位的程序计数器PC和16位的地址总线,使64KB的程序存储器空间连续统一。64kB程序存储器寻址空间。 当脚/EA接高电平时,程序从内部ROM开始执行。当PC值超过内部地址空间(0FFFH)时,会自动转到外部程序存储器的1000H~FFFFH地址空间上去执行程序。 当脚/EA接低电平时,程序从外部ROM开始执行。 1)对于内部无ROM的8031单片机,它的程序存储器必须外接,空间地址为64kB,此时单片机的使能端端必须接地。强制CPU从外部程序存储器读取程序。 2)对于内部有ROM的8051等单片机,正常运行时,则需接高电平,使CPU先从内部的程序存储中读取程序,当PC值超过内部ROM的容量时,才会转向外部的程序存储器读取程序。
8051片内有4kB的程序存储单元,其地址为0000H—0FFFH,单片机启动复位后,程序计数器的内容为0000H,所以系统将从0000H单元开始执行程序。但在程序存储中有些特殊的单元(入口地址),这在使用中应加以注意: 有7个入口地址具有特殊功能。0000H单元,它是程序的起始地址,一般在该单元中设置一条绝对转移指令,使之转向主程序处执行;其余6个特殊功能的入口地址分别对应6种中断源的中断服务程序入口地址,如表所示。
中断向量入口地址表一般在这些入口地址处放一条无条件转移指令,使之转移到相应的中断服务程序中执行。
特殊单元0000H—0002H单元:系统复位后,PC为0000H,单片机从0000H单元开始执行程序,如果程序不是从0000H单元开始,则应在这三个单元中存放一条无条件转移指令,让CPU直接去执行用户指定的程序。
特殊单元是0003H—002AH,这40个单元各有用途,它们被均匀地分为五段,它们的定义如下:
0003H—000AH 外部中断0中断地址区。
000BH—0012H 定时/计数器0中断地址区。
0013H—001AH 外部中断1中断地址区。
001BH—0022H 定时/计数器1中断地址区。
0023H—002AH 串行中断地址区。
这40个单元是专门用于存放中断处理程序的地址单元,中断响应后,按中断的类型,自动转到各自的中断区去执行程序。因此以上地址单元不能用于存放程序的其他内容,只能存放中断服务程序。但是通常情况下,每段只有8个地址单元是不能存下完整的中断服务程序的,因而一般是在中断响应的地址区安放一条无条件转移指令,指向程序存储器的其它真正存放中断服务程序的空间去执行。这样中断响应后,CPU读到这条转移指令,便转向其他地方去继续执行中断服务程序。 2.数据存储器数据存储器也称为随机存取数据存储器。51单片机的数据存储器在物理上和逻辑上都分为两个地址空间,一个是内部数据存储区和一个外部数据存储区。内部和外部数据存储器地址空间存在重叠,通过不同指令来区分。在访问内部RAM时,用MOV类指令;在访问外部RAM时,用MOVX类指令。 内部RAM有128或256个字节的用户数据存储(不同的型号有分别),它们是用于存放执行的中间结果和过程数据的。MCS-51的数据存储器均可读写,部分单元还可以位寻址。 8051内部数据存储空间大小为256B,但实际提供给用户使用的RAM为128B。这128B的RAM从功能上又分为3个不同的区域:工作寄存器区、位寻址区和用户区,如图1.5所示。
8051内部128字节RAM功能分区1) 通用寄存器区 00H—1FH共32个单元中被均匀地分为四块,每块包含八个8位寄存器,均以R0—R7来命名,我们常称这些寄存器为通用寄存器。这四块中的寄存器都称为R0—R7,那么在程序中怎么区分和使用它们呢?使用一个寄存器——程序状态字寄存器(PSW)来管理它们,CPU只要定义这个寄存的PSW的第3和第4位(RS0和RS1),即可选中这四组通用寄存器。 2)位寻址区 内部RAM的20H—2FH单元为位寻址区,既可作为一般单元用字节寻址,也可对它们的位进行寻址。位寻址区共有16个字节,128个位,位地址为00H—7FH。位地址分配如表1所示,CPU能直接寻址这些位,执行例如置“1”、清“0”、求“反”、转移,传送和逻辑等操作。我们常称MCS-51具有布尔处理功能,布尔处理的存储空间指的就是这些为寻址区。 表1 RAM位寻址区地址表 单元地址 MSB 位地址 LSB 2FH 7FH 7EH 7DH 7CH 7BH 7AH 79H 78H 2EH 77H 76H 75H 74H 73H 72H 71H 70H 2DH 6FH 6EH 6DH 6CH 6BH 6AH 69H 68H 2CH 67H 66H 65H 64H 63H 62H 61H 60H 2BH 5FH 5EH 5DH 5CH 5BH 5AH 59H 58H 2AH 57H 56H 55H 54H 53H 52H 51H 50H 29H 4FH 4EH 4DH 4CH 4BH 4AH 49H 48H 28H 47H 46H 45H 44H 43H 42H 41H 40H 27H 3FH 3EH 3DH 3CH 3BH 3AH 39H 38H 26H 37H 36H 35H 34H 33H 32H 31H 30H 25H 2FH 2EH 2DH 2CH 2BH 2AH 29H 28H 24H 27H 26H 25H 24H 23H 22H 21H 20H 23H 1FH 1EH 1DH 1CH 1BH 1AH 19H 18H 22H 17H 16H 15H 14H 13H 12H 11H 10H 21H 0FH 0EH 0DH 0CH 0BH 0AH 09H 08H 20H 07H 06H 05H 04H 03H 02H 01H 00H 3)用户区 用户区为一般的数据缓冲区,即30H~7FH共80个单元,这些单元只能按字节寻址。另外,堆栈区通常也设置在这个区域内。 4)特殊功能寄存器 特殊功能寄存器(SFR)也称为专用寄存器,反映单片机的运行状态。很多功能也通过特殊功能寄存器来定义和控制程序的执行。 51系列单片机共有26个特殊功能寄存器。每个SFR占用一个RAM单元,它们离散的分布在80H~FFH地址范围内,这些寄存的功能已作了专门的规定,用户不能修改其结构。不为SFR占用的RAM单元实际上并不存在,访问它们是没有意义的,如表所示。
特殊功能寄存器一览表在这些SFR中,用户可以通过直接寻址指令对它们进行字节存取,也可以对某些寄存器中的每一位进行位寻址。 程序计数器PC(Program Counter) 程序计数器在物理上是独立的,它不属于特殊内部数据存储器块中。PC是一个16位的计数器,用于存放一条要执行的指令地址,寻址范围为64kB,PC有自动加1功能,即完成了一条指令的执行后,其内容自动加1。PC本身并没有地址,因而不可寻址,用户无法对它进行读写,但是可以通过转移、调用、返回等指令改变其内容,以控制程序按我们的要求去执行。 累加器ACC(Accumulator) 累加器A是一个最常用的专用寄存器,大部分单操作指令的一个操作数取自累加器,很多双操作数指令中的一个操作数也取自累加器。加、减、乘、除法运算的指令,运算结果都存放于累加器A或AB累加器对中。大部分的数据操作都会通过累加器A进行,它形象于一个交通要道,在程序比较复杂的运算中,累加器成了制约软件效率的“瓶颈”,它的功能较多,地位也十分重要。以至于后来发展的单片机,有的集成了多累加器结构,或者使用寄存器阵列来代替累加器,即赋予更多寄存器以累加器的功能,目的是解决累加器的“交通堵塞”问题。提高单片机的软件效率。 七、单片机初始编程大多数情况下,程序通常是顺序执行的,所以程序中的指令也是一条条顺序存放的,单片机在执行程序时要能把这些指令一条条取出并加以执行,必须有一个部件能追踪指令所在的地址,这一部件就是程序计数器PC(包含在CPU中,16位指令指针寄存器)。在开始执行程序时,给PC赋以程序中第一条指令所在的地址,然后取得每一条要执行的命令,PC在中的内容就会自动增加,增加量由本条指令长度决定,可能是1、2或3,以指向下一条指令的起始地址,保证指令顺序执行。PC中存储的***都是下一步要执行的指令地址。改变PC的内容,就可以改变程序执行的顺序,从而实现跳转。 在编写软件之前,首先要确定一些常数、地址,事实上这些常数、地址在设计阶段已被直接或间接地确定下来了。如当某器件的连线设计好后,其地址也就确定了,当器件的功能被确定下来后,其控制字也就被确定了。 然后用文本编缉器(如Notepad、Winedt 等)写软件. 编写好后,用编译器对源程序文件编译,查错,直到没有语法错误,除了极简单程序外,一般应用仿真机对软件进行调试,直到程序运行正确为止。运行正确后, 就可以写(将程序固化在EPROM中)。在源程序被编译后,生成了扩展名为HEX的目标文件,一般编程器能够识别种格式的文件,只要将此文件调入即可写片。在此,为使大家对整个过程有个认识,举例说明: 程序的执行过程 单片机在通电复位后8051内的程序计数器(PC)中的值为‘0000?,所以程序总是从‘0000’单元开始执行,也就是说:在系统的ROM中一定要存在‘0000’单元,并且在‘0000’单元中存放的一定是一条长跳转指令。 ORG 0000H LJMP START ORG 040H START: MOV SP,#5FH ;设堆栈 LOOP: NOP LJMP LOOP ;循环 END ; 转自https://www.zhihu.com/tardis/bd/art/107152693
|