2.5 通用寄存器组与I/O寄存器
全面熟练地理解、掌握AVR单片机的通用寄存器组与I/O寄存器的性能、特点、功能、设置和使用,是精通和熟练使用AVR单片机的关键。由于AVR单片机有32个通用寄存器和64个I/O寄存器,其功能、特点及使用方法涉及整个AVR单片机的全部功能和特性,因此相对复杂。读者不可能一下就全部掌握它们的应用,只有通过边学习、边实践,逐步深入,加深理解。本节仅给一个总体的介绍,各个不同寄存器具体的使用将在以后相关的章节中加以详细描述。
2.5.1 通用寄存器组
图2-11所示为AVR单片机中32个通用寄存器的结构图。在AVR单片机指令集中,所有的通用寄存器操作指令均带有方向,并能在单一时钟周期中访问所有的寄存器。
用户在使用汇编语言编写程序时,应注意如何正确使用AVR单片机中32个通用的寄存器。因为这32个通用寄存器的功能还是有一定的区别。尤其是R16~R31这16个寄存器能实现的操作比R0~R15要多,如SBCI、SUBI、CPI、ANDI、ORI以及LDI和乘法指令仅适用于寄存器组中后半部分的寄存器(R16~R31)。另外,R26~R31还构成3个16位的地址指针寄存器X、Y、Z,所以一般情况下不要作为他用。
图2-12 寄存器X、Y、Z
如图2-11所示,每个通用寄存器还被分配在AVR单片机的数据存储器空间中,它们直接映射到数据空间的前32个地址,因此也可以使用访问SRAM的指令对这些寄存器进行访问,但此时在指令中应使用该寄存器在SRAM空间的映射地址。通常情况下,最好是使用专用的寄存器访问指令对通用寄存器组进行操作,因为这类寄存器专用操作指令不仅功能强大,而且执行周期也短。
AVR单片机寄存器组最后的6个寄存器R26~R31具有特殊的功能,这些寄存器每两个合并成一个16位的寄存器,作为对数据存储器空间(使用寄存器X、Y、Z)以及程序存储器空间(仅使用寄存器Z)间接寻址的地址指针寄存器。这3个间接寄存器X、Y、Z由图2-12定义。在不同指令的寻址模式下,利用地址寄存器可实现地址指针的偏移、自动增量和减量(参考不同的指令)等不同形式的间
图2-11 通用寄存器组结构图
址寻址操作。
2.5.2 I/O寄存器
表2-1列出了ATmega16单片机的I/O寄存器的地址空间分配、名称和功能。
表2-1 ATmega16 I/O寄存器空间分配表
(续)
AVR系列单片机所有I/O口及外围接口的功能和配置均通过I/O寄存器进行设置和使用。CPU访问I/O寄存器可以使用两种不同的方法,使用对I/O寄存器访问的IN、OUT专用指令,以及使用对SRAM访问的指令。
所有的I/O寄存器可以通过IN(I/O口输入)和OUT(输出到I/O口)指令访问,这些指令是在32个通用寄存器与I/O寄存器空间之间传输交换数据,指令周期为1个时钟周期。此外,I/O寄存器地址范围在$00~$1F之间的寄存器(前32个)还可通过指令实现位操作和位判断跳转。SBI(I/O寄存器中指定位置1)和CBI(I/O寄存器中指定位清零)指令可直接对I/O寄存器中的每一位进行位操作。使用SBIS(I/O寄存器中指定位为1跳行)和SBIC(I/O寄存器中指定位为0跳行)指令能够对这些I/O寄存器中每一位的值进行检验判断,实现跳过一条指令执行下一条指令的跳转。
在I/O寄存器专用指令IN、OUT、SBI、CBI、SBIS和SBIC中使用I/O寄存器地址$00~$3F。
当以SRAM方式寻址I/O寄存器时,必须将其地址加上$0020,映射成在数据存储器空间的地址。本书中I/O寄存器地址均给出了两种地址表示:I/O寄存器空间地址以及在数据存储器空间中的映射地址(在圆括号中)。
2.5.3 状态寄存器和堆栈指针寄存器
以下面首先介绍两个在AVR单片机中起着非常重要作用的I/O寄存器,它们是状态寄存器(SREG)和堆栈指针寄存器(SP)。
1.状态寄存器(SREG)
状态寄存器(SREG)是一个8位标志寄存器,用来存放指令执行后的有关状态和结果的标志。SREG中各位状态通常是在指令的执行过程中自动形成,但也可以由用户根据需要用专用指令加以改变。
状态标志位的作用很大,每一位都代表着不同的含义。许多指令的运行将对寄存器中的某些位置1或清零,它反映了CPU运算、操作结果的状态。与状态寄存器(SREG)中的位操作有关的指令有置1、清零、为1转移、为0转移等,共有36条指令与状态寄存器(SREG)相关联。由此可见它的重要性。
AVR单片机的状态寄存器(SREG)在I/O空间的地址为$3F($005F),其各标志位的意义如下:
(1)位7—Ⅰ:全局中断使能位
该标志位为AVR单片机中断总控制开关,当Ⅰ位被置位(“1”)时,表示CPU可以响应中断请求,而当Ⅰ位被清零(“0”),则所有的中断被禁止,CPU不响应任何的中断请求。除了该标志位用于AVR单片机中断的总控制,各个单独的中断触发控制还由其所在的中断屏蔽寄存器(GIMSK、TIMSK)控制。如果全局中断触发寄存器被清零(“0”),则全局(所有的)中断被禁止,但单独的中断触发控制在GIMSK和TIMSK中的值保持不变。在中断发生后,I位由硬件清除,并由RETI(中断返回)指令置位,从而允许子序列的中断响应。
(2)位6—T:位复制存储
位复制指令BLD和BST使用T标志位作为源和目标。通用寄存器组任何一个寄存器的一位可以通过BST指令被复制到T中,而用BLD指令则可将T中的位值复制到通用寄存器组的任何一个寄存器的一位中。
(3)位5—H:半进位标志位
半进位标志位H表示在一些运算操作过程中有无半进位(低4位向高4位进、借位)的产生,该标志对于BCD码的运算和处理非常有用。
(4)位4—S:符号标志位,S=N⊕V
S位是负数标志位N和2的补码溢出标志位V两者的异或值。在正常运算条件下(V=0,不溢出)S=N,即运算结果最高位作为符号是正确的。而当产生溢出时V=1,此时N已不能正确指示运算结果的正负,但S=N⊕V还是正确的。对于单(或多)字节有符号数据来说,执行减法或比较操作后,S标志能正确指示参与相减或比较的两个数的大小。
(5)位3—V:2补码溢出标志位
2的补码溢出标志位V,支持2的补码运算,为模2补码加、减运算溢出标志。溢出表示运算结果超过了正数(或负数)所能表示的范围。加法溢出表现为正+正=负,或负+负=正;减法溢出表现为正-负=负,或负-正=正。溢出时,运算结果最高位(N)取反才是真正的结果符号。
(6)位2—N:负数标志位
负数标志位直接取自运算结果的最高位,N=1时表示运算结果为负,否则为正。但发生溢出时不能表示真实的结果(见上面对溢出标志位的说明)。
(7)位1—Z:零值标志位
零值标志位表明在CPU运算和逻辑操作之后,其结果是否为零,当Z=1时表示结果为零。
(8)位0-C:进/借位标志
进/借位标志位表明在CPU的运算和逻辑操作过程中有无发生进/借位。
以上这些标志位非常重要,对运算结果的判断处理,要以相应的标志位为依据。标志位也是分支、循环控制的依据。采用汇编语言编写程序时,要注意指令对标志位的影响,以及正确地使用判断指令。
2.堆栈指针寄存器(SP)
堆栈是数据结构中所使用的专用名词,它是由一块连续的SRAM空间和一个堆栈指针寄存器组成,主要应用于快速便捷地保存临时数据、局部变量和中断调用或子程序调用的返回地址。堆栈在系统程序的设计和运行中起着非常重要的作用,只要程序中使用了中断和子程序调用,就必须正确地设置堆栈指针寄存器(SP),在SRAM空间建立堆栈区。
堆栈是一种特殊的线性数据结构,数据的进出在堆栈的顶部进行,并遵循后进先出(Last in First out,LIFO)的原则。堆栈指针实际上就是堆栈顶部的地址,它随着堆栈中数据的进出而变化。堆栈指针寄存器(SP)中保存着堆栈指针,即堆栈顶部的地址。
处在I/O地址空间$3E($005E)和$3D($005D)的两个8位寄存器构成了AVR单片机的16位堆栈指针寄存器(SP)。AVR单片机复位后堆栈寄存器的初始值为SPH=$00、SPL=$00,因此建议用户程序必须首先对堆栈指针寄存器(SP)进行初始化设置。
AVR单片机的堆栈区是建立在SRAM空间的,16位的SP寄存器可以寻址的空间为64KB。但在实际应用中,还必须考虑所使用AVR单片机芯片SRAM空间的实际情况和所配备的SRAM容量的大小。首先,堆栈区应该避开寄存器区域所对应的SRAM空间,防止堆栈操作时改变了寄存器的设置。由于AVR单片机的堆栈是向下增长的,即新数据进入堆栈时栈顶指针的数据将减小(注意:这里与51单片机不同,51单片机的堆栈是向上增长的,即进栈操作时栈顶指针的数据将增加),所以尽管原则上堆栈可以在SRAM的任何区域中,但通常初始化时将SP的指针设在SRAM最高处。
对于具体的ATmega16芯片,堆栈指针必须指向高于$0060的SRAM地址空间,因为低于$0060的区域为寄存器空间。ATmega16片内集成有1KB的SRAM,不支持外部扩展SRAM,所以堆栈指针寄存器(SP)的初始值应设在SRAM的最高端$045F处(参考图2-10)。
AVR单片机的堆栈有自动硬件进栈(执行调用指令、响应中断)、自动硬件出栈(执行调用返回指令(RET)、执行中断返回指令(RETI))和人工进出栈(进栈(PUSH)、出栈(POP))等指令。AVR单片机堆栈采用SP-1或SP-2的进栈操作。