单片机与嵌入式
51单片机的寻址方式
51单片机的汇编指令系统
51汇编语言的伪指令
51汇编语言程序结构与程序示例
Keil C51程序设计
Keil C51的库函数
PIC单片机的基本结构
PIC单片机的汇编语言指令
PIC单片机的C语言编程
ATmega16单片机基本结构
ATmega16单片机的汇编语言
ATmega128单片机的结构
STM32单片机基础
使用STM32CubeMX开发STM32单片机
uC/OS-II嵌入式操作系统
uC/OS-II在STM32F10xx上的移植
FreeRTOS系统介绍
Linux系统介绍
Linux系统编程
嵌入式Linux编程
AVR单片机是一种内置Flash的RISC(Reduced Instruction Set CPU) 精简指令集高速8位单片机,有一套独特的指令系统及汇编语言。
1. ATmega16单片机的指令系统:
AVR单片机是RISC结构精简指令集,共有131条指令,按功能可分为5大类:算术、逻辑运算和比较指令31条,跳转指令33条,数据传送指令35条,位操作和位测试指令28条,MCU控制指令4条。
AVR指令的一般格式为:
操作码 |
第1操作数或操作数地址 |
第2操作数或操作数地址 |
AVR指令中,有相当一部分只有操作码,或只有操作码和第一操作数或操作数地址。
指令的表示方法有二进制、十六进制和助记符3种。二进制是CPU识别和执行的方式,称为指令的机器码或汇编语言的目标代码,下载到AVR单片机中的代码必须是这种形式。十六进制方式是二进制表示方式的变型,将二进制代码每4位用一组十六进制数来描述,往往作为调试环境中的辅助方式和手段。
指令的助记符表示方式称为汇编形式,它是用英文单词或缩写字母以及数字来表征指令功能,比如容易识别和读写,也方便记忆和交流,是程序设计的一种常见方式,被称为汇编语言。汇编语言编写的程序,需要经相应的开发软件翻译成二进制的机器码,下载到目标板来运行。
在汇编指令描述中,除了操作码采用助记符外,还会用到一些符号代码:
Rd:目的(或源)寄存器,取值为R0~R31或R16~R31。
Rr:源寄存器,取值为R0~R31。
P:I/O寄存器,取值为0~63或0~31。
b:I/O寄存器中的指定位,常数(0~7)。
s:状态寄存器SREG中的指定位,常数(0~7)。
K:立即数,常数(0~255)。
k:地址常数,取值范围取决于指令。
q:地址偏移量常数(0~63)。
X、Y、Z:地址指针寄存器(X=R27:X26, Y=R29:R28, Z=R31:R30)。
STACK:作为返回地址和压栈寄存器的堆栈。
SP:堆栈STACK的指针。
状态寄存器SREG中每一位的定义如下:
C:进位标志位。
Z:结果为零标志位。
N:结果为负数标志位。
V:2的补码溢出标志位。
S:N⊕V,用于符号测试的标志位。
H:操作中产生半进位的标志位。
T:用于与BLD、BST指令进行位数据交换的位。
I:全局中断使能/禁止标志位。
AVR指令中,一类指令执行后要影响到状态寄存器中某些标志位,而另一类指令在执行后不会影响标志位。由于AVR的CPU响应中断时硬件不保护状态寄存器,所以在编写中断服务处理程序时应注意将状态寄存器进行保护(如用PUSH指令压入到堆栈),在中断返回前还要恢复状态寄存器在进入中断前时的标志位(如用POP指令从堆栈中断中弹出)。
2. AVR指令的寻址方式和寻址空间:
指令的一个重要组成部分是操作数。指令给出参与运算数据的方式称为寻址方式。CPU执行指令时,首先要根据地址获取参加操作的操作数,然后才能对操作数进行操作,操作的结果还要根据地址保存在相应的存储器或寄存器中。因此,CPU执行程序实际上是不断地寻找操作数并进行操作的过程。通常,指令的寻址方式有多种,寻址方式越多,指令的功能也就越强。AVR单片机指令操作数的寻址方式有以下15种:
1)单寄存器直接寻址:
由指令指定一个寄存器的内容作为操作数,在指令中给出寄存器的直接地址,这种寻址方式称为单寄存器直接寻址。单寄存器寻址的地址范围限制为通用工作寄存器组中的32个寄存器R0~R31,或后16个寄存器R16~R31(取决于不同指令)。示例:
INC Rd ;操作:Rd←Rd+1
INC R5 ;操作:R5←R5+1,即将寄存器R5内容加1回送
2)双寄存器直接寻址:
双寄存器直接寻址方式是将指令指出的两个寄存器Rd和Rr的内容作为操作数,而结果存放在Rd寄存器中,指令中同时给出两个寄存器的直接地址。双寄存器寻址的地址范围限制为通用工作寄存器组中的32个寄存器R0~R31,或后16个寄存器R16~R31,或后8个寄存器R16~R23(取决于不同指令)。示例:
ADD Rd, Rr ;操作:Rd←Rd+Rr
ADD R0, R1 ;操作:R0←R0+R1,即将寄存器R0和R1的内容加1回送R0
3)I/O寄存器直接寻址:
由指令指定一个I/O寄存器的内容作为操作数,在指令中直接给出I/O寄存器的地址,这种寻址方式称为I/O寄存器直接寻址。I/O寄存器直接寻址的地址使用I/O寄存器空间的地址$00~$3F,共64个,取值为0~63或0~31(取决于指令)。示例:
IN Rd, P ;操作:Rd←P
IN R5, $3E ;操作:R5←$3E,即将地址$3E寄存器(SPH)的内容放入寄存器R5
4)数据存储器空间直接寻址:
数据存储器空间直接寻址方式用于CPU直接从SRAM存储器中存取数据。指令为双字节指令,指令的低字节中指出一个16位SRAM地址。示例:
LDS Rd, k ;操作:Rd←(k)
LDS R18, $100 ;操作:R18←$3E,即将$100地址的SRAM中内容传送到寄存器R18
指令中16位SRAM的地址长度限定了地址空间为64kB,该地址空间也包括了32个通用寄存器和64个I/O寄存器,所以也可以用来读取通用寄存器或I/O寄存器中的内容,但效率降低,因为指令是双字节,指令周期为2个系统时钟。
5)数据存储器空间的寄存器间接寻址:
由指令指定某一个16位寄存器的内容作为操作数在SRAM中的地址,称为数据存储器空间的寄存器间接寻址。AVR单片机中使用16位寄存器X、Y或Z作为规定的地址指针寄存器,因此操作数的SRAM地址在间址寄存器X、Y或Z中。示例:
LD Rd, Y ;操作:Rd←(Y)
LD R16, Y ;操作:R16←(Y),即将Y为指针的SRAM的内容传送到寄存器R16中
6)带后增量的数据存储器空间的寄存器间接寻址:
类似于数据存储器空间的寄存器间接寻址,间址寄存器X、Y或Z中的内容仍为操作数在SRAM空间的地址,但指令在间接寻址操作后,再自动把间址寄存器中的内容加1。示例:
LD Rd, Y+ ;操作:Rd←(Y),Y←Y+1
LD R16, Y+ ;操作:R16←(Y),Y←Y+1
这种寻址方式特别适用于访问矩阵、查表等应用。
7)带预减量的数据存储器空间的寄存器间接寻址:
类似于数据存储器空间的寄存器间接寻址,间址寄存器X、Y或Z中的内容仍为操作数在SRAM空间的地址,但指令在间接寻址操作之前,先自动将间址寄存器中的内容减1,然后把减1后的内容作为操作数在SRAM空间的地址。示例:
LD Rd, -Y ;操作:Y←Y-1,Rd←(Y)
LD R16,- Y ;操作:Y←Y-1,R16←(Y)
这种寻址方式也特别适用于访问矩阵、查表等应用。
8)带位移的数据存储器空间的寄存器间接寻址:
由间址寄存器(Y或Z)中的内容和指令字中给出的地址偏移量共同决定操作数在SRAM空间的地址,偏移量的范围为0~63。示例:
LD Rd, Y+q ;操作:Rd←(Y+q),Y寄存器的内容不变
LD R16, Y+$31 ;操作:R16←(Y+$31)
9)程序存储器空间取常量寻址:
这种方式主要是从程序存储器Flash中读取常量,只用于指令LPM。程序存储器中常量字节的地址由地址寄存器Z的内容确定。Z寄存器的高15位用于选择字地址(程序存储器的存储单元为字),而最低位d0用于确定字地址的高/低字节。若d0=0,则选择字的低字节;若d0=1,则选择字的高字节。示例:
LPM ;操作:R0←(Z),即把以Z为指针的程序寄存器的内容送R0
LPM R16, Z ;操作:R16←(Z),即把以Z为指针的程序寄存器的内容送R16
10)带后增量的程序存储器空间取常量寻址:
主要是从程序存储器Flash中取常量,此种寻址方式只用于指令“LPM Rd, Z+”。程序存储器中常量字节的地址由地址寄存器Z的内容确定,Z寄存器的高15位用于选择字地址(程序存储器的存储单元为字),而最低位d0用于确定子地址的高/低字节。若d0=0,则选择字的低字节;若d0=1,则选择字的高字节。寻址操作后,Z寄存器的内容加1。示例:
LPM R16, Z+ ;操作:R16←(Z),Z←Z+1 把以Z为指针的程序寄存器的内容送R16,然后Z=Z+1
11)程序存储器空间写数据寻址:
主要用于可进行在系统自编程的AVR单片机,此种寻址方式只用于指令SPM。将寄存器R1和R0中的内容组成一个字R1:R0,然后写入由Z寄存器的内容作为地址(Z寄存器的最低位必须为0)的程序存储单元中(实际是写入到Flash的页缓冲区中)。例如:
SPM ;操作:(Z)←R1:R0,即把R1:R0内容写入以Z为指针的程序寄存器单元中
12)程序存储器空间直接寻址:
用于程序的无条件跳转指令JMP、CALL。指令中含有一个16位的操作数,指令将操作数存入程序计数器PC中,作为下一条要执行指令在程序存储器空间的地址。JMP类指令和CALL类指令的寻址方式相同,但CALL类的指令还包括了返回地址的压进堆栈和堆栈指针寄存器SP内容减2的操作。示例:
LMP $0100 ;操作:PC←$0100,程序计数器PC的值设置为$0100,接下来执行其中的代码
CALL $0100 ;操作:STACK←PC+2; SP←SP-2; PC←$0100
13)程序存储器空间Z寄存器间接寻址:
使用Z寄存器存放下一步要执行的指令代码程序地址,程序转到Z寄存器内容所指定程序寄存器的地址处继续执行,即用寄存器Z的内容代替PC的值。此寻址方式用于IJMP、ICALL指令。示例:
ILMP ;操作:PC←Z,即把Z的内容送程序计数器PC,接下来执行Z内容为地址的代码
ICALL ;操作:STACK←PC+1; SP←SP-2; PC←Z
14)程序存储器空间相对寻址:
指令中包含一个相对偏移量k,指令执行时首先将当前程序计数器PC值加1,然后再与偏移量k相加,作为程序下一条要执行指令的地址。此寻址方式用于RJMP、RCALL指令。示例:
RLMP $0100 ;操作:PC←PC+1+$0100
RCALL $0100 ;操作:STACK←PC+1; SP←SP-2; PC←PC+1+$0100
15)数据存储器空间堆栈寄存器SP间接寻址:
是将16位的堆栈寄存器SP的内容作为操作数在SRAM空间的地址。此寻址方式用于PUSH、POP指令。示例:
PUSH R0 ;操作:STACK←R0; SP←SP-1,即先把R0的内容送到堆栈指针单元,再将SP减1
POP R1 ;操作:SP←SP+1; R1←STACK,先将SP内容加1,再把堆栈指针单元内容送R1
此外,在CPU响应中断和执行CALL一类的子程序调用指令(SP=SP-2)及执行中断返回RETI和子程序返回RET一类的子程序返回指令(SP=SP+2),都隐含着使用堆栈寄存器SP间接寻址的方式。
3. 算术和逻辑指令:
AVR的算术运算指令有加法、减法、乘法、取反码、取补码、比较、增量和减量指令,逻辑运算指令有与、或和异或指令等。
1)加法指令:
①不带进位加法:
ADD Rd, Rr ;0≤d≤31, 0≤r≤31
操作:Rd←Rd+Rr PC←PC+1
说明:两个寄存器不带进位C相加,结果送目的寄存器Rd中。
影响标志位:H、S、V、N、Z和C。
②带进位加法:
ADC Rd, Rr ;0≤d≤31, 0≤r≤31
操作:Rd←Rd+Rr+C PC←PC+1
说明:两个寄存器和进位C相加,结果送目的寄存器Rd中。
影响标志位:H、S、V、N、Z和C。
③字加立即数:
ADIW Rdl, K ;dl为24,26,28,30, 0≤K≤63
操作:Rdh:Rdl←Rdh:Rdl+K PC←PC+1
说明:寄存器对(1字=16位)与立即数相加,结果送目的寄存器对中。
影响标志位:S、V、N、Z和C。
注:dl只能取24/26/28/30,即仅用于最后4个寄存器对。K为6位二进制无符号数0~63。
④增1指令:
INC Rd ;0≤d≤31
操作:Rd←Rd+1 PC←PC+1
说明:寄存器Rd的内容加1,结果送目的寄存器Rd中。不改变C标志位。
影响标志位:S、V、N和Z。
注:当对无符号数操作时,仅有BREQ(相等跳转,即Z标志位为1)和BRNE(不为0跳转,即Z标志位为0)指令有效;当对二进制补码值操作时,所有的带符号跳转指令都有效。
2)减法指令:
①不带进位减法:
SUB Rd, Rr ;0≤d≤31, 0≤r≤31
操作:Rd←Rd-Rr PC←PC+1
说明:两个寄存器不带进位C相减,结果送目的寄存器Rd中。
影响标志位:H、S、V、N、Z和C。
②带进位减法:
SBC Rd, Rr ;0≤d≤31, 0≤r≤31
操作:Rd←Rd-Rr-C PC←PC+1
说明:两个寄存器带进位C相减,结果送目的寄存器Rd中。
影响标志位:H、S、V、N、Z和C。
③减立即数(字节):
SUBI Rd, K ;16≤d≤31, 0≤K≤255
操作:Rd←Rd-K PC←PC+1
说明:一个寄存器和常数相减,结果送目的寄存器Rd中。
影响标志位:H、S、V、N、Z和C。
注:该指令工作在寄存器R16~R31之间,适合X、Y和Z指针的操作。
④带进位减立即数(字节):
SBCI Rd, K ;16≤d≤31, 0≤K≤255
操作:Rd←Rd-K-C PC←PC+1
说明:寄存器和立即数带C标志相减,结果送目的寄存器Rd中。
影响标志位:H、S、V、N、Z和C。
注:该指令工作在寄存器R16~R31之间,适合X、Y和Z指针的操作。
⑤字减立即数:
SBIW Rdl, K ;dl为24,26,28,30, 0≤K≤63
操作:Rdh:Rdl←Rdh:Rdl-K PC←PC+1
说明:寄存器对(1字=16位)与立即数相减,结果送目的寄存器对中。
影响标志位:S、V、N、Z和C。
注:dl只能取24/26/28/30,即仅用于最后4个寄存器对。K为6位二进制无符号数0~63。
⑥减1指令:
DEC Rd ;0≤d≤31
操作:Rd←Rd-1 PC←PC+1
说明:寄存器Rd的内容减1,结果送目的寄存器Rd中。不改变C标志位。
影响标志位:S、V、N和Z。
注:当对无符号数操作时,仅有BREQ(相等跳转,即Z标志位为1)和BRNE(不为0跳转,即Z标志位为0)指令有效;当对二进制补码值操作时,所有的带符号跳转指令都有效。
3)取反码指令:
COM Rd ;0≤d≤31
操作:Rd←$FF-Rd PC←PC+1
说明:寄存器Rd的内容取反码。
影响标志位:S、N、Z、V(0)和C(1)。
4)取补码指令:
NEG Rd ;0≤d≤31
操作:Rd←$00-Rd PC←PC+1
说明:寄存器Rd的内容取补码。
影响标志位:H、S、V、N、Z和C。
5)比较指令:
①寄存器比较:
CP Rd, Rr ;0≤d≤31, 0≤r≤31
操作:Rd-Rr PC←PC+1
说明:两个寄存器进行比较,只影响SREG,而寄存器的内容不改变。
影响标志位:H、S、V、N、Z和C。
注:该指令后能使用所有条件跳转指令。
②带进位比较:
CPC Rd, Rr ;0≤d≤31, 0≤r≤31
操作:Rd-Rr-C PC←PC+1
说明:寄存器Rd的值与寄存器Rr加C相比较,只影响SREG,而寄存器的内容不改变。
影响标志位:H、S、V、N、Z和C。
注:该指令后能使用所有条件跳转指令。
③与立即数(字节)比较:
CPI Rd, K ;16≤d≤31, 0≤K≤255
操作:Rd-K PC←PC+1
说明:寄存器Rd与常数比较,只影响SREG,而寄存器的内容不改变。
影响标志位:H、S、V、N、Z和C。
注:该指令后能使用所有条件跳转指令。
6)逻辑与指令:
①寄存器逻辑与:
AND Rd, Rr ;0≤d≤31, 0≤r≤31
操作:Rd←Rd∧Rr PC←PC+1
说明:寄存器Rd和寄存器Rr的内容逻辑与,结果送目的寄存器Rd。
影响标志位:S、V(0)、N和Z。
注:用于清0某位,用0与该位逻辑与;用于保留某位,用1与该位逻辑与。
②与立即数(字节):
ANDI Rd, K ;16≤d≤31, 0≤K≤255
操作:Rd←Rd∧K PC←PC+1
说明:寄存器Rd的内容与常数K逻辑与,结果送目的寄存器Rd。
影响标志位:S、V(0)、N和Z。
注:用于清0某位,用0与该位逻辑与;用于保留某位,用1与该位逻辑与。
③寄存器位清0:
CBR Rd, K ;16≤d≤31, 0≤K≤255
操作:Rd←Rd∧($FF-K) PC←PC+1
说明:利用寄存器Rd的内容与常数K的反码逻辑与清除其中指定位,结果送寄存器Rd。
影响标志位:S、V(0)、N和Z。
④测试寄存器为零或负:
TST Rd ;0≤d≤31
操作:Rd←Rd∧Rd PC←PC+1
说明:利用寄存器Rd的内容自己与自己逻辑与测试寄存器为0或负,寄存器内容不变。
影响标志位:S、V(0)、N和Z。
7)逻辑或指令:
①寄存器逻辑或:
OR Rd, Rr ;0≤d≤31, 0≤r≤31
操作:Rd←Rd∨Rr PC←PC+1
说明:寄存器Rd和寄存器Rr的内容逻辑或,结果送目的寄存器Rd。
影响标志位:S、V(0)、N和Z。
注:用于置1某位,用1与该位逻辑或;用于保留某位,用0与该位逻辑或。
②或立即数(字节):
ORI Rd, K ;16≤d≤31, 0≤K≤255
操作:Rd←Rd∨K PC←PC+1
说明:寄存器Rd的内容与常数K逻辑或,结果送目的寄存器Rd。
影响标志位:S、V(0)、N和Z。
注:用于置1某位,用1与该位逻辑或;用于保留某位,用0与该位逻辑或。
③寄存器位置1:
SBR Rd, K ;16≤d≤31, 0≤K≤255
操作:Rd←Rd∨K PC←PC+1
说明:利用寄存器Rd的内容与常数K的逻辑或置1其中指定位,结果送寄存器Rd。
影响标志位:S、V(0)、N和Z。
④置寄存器为$FF:
SER Rd ;16≤d≤31
操作:Rd←$FF PC←PC+1
说明:直接装入$FF到寄存器Rd中。
影响标志位:无。
8)逻辑异或指令:
①寄存器逻辑异或:
EOR Rd, Rr ;0≤d≤31, 0≤r≤31
操作:Rd←Rd⊕Rr PC←PC+1
说明:寄存器Rd和寄存器Rr的内容逻辑异或,结果送目的寄存器Rd。
影响标志位:S、V(0)、N和Z。
②寄存器清0:
CLR Rd ;0≤d≤31
操作:Rd←Rd⊕Rd PC←PC+1
说明:寄存器Rd的内容自己与自己逻辑异或实现寄存器所有位清0。
影响标志位:S(0)、V(0)、N(0)和Z(1)。
9)乘法指令:
①无符号数乘法:
MUL Rd, Rr ;0≤d≤31, 0≤r≤31
操作:R1:R0←Rd×Rr PC←PC+1
说明:寄存器Rd和寄存器Rr的内容进行8位无符号数的乘法,结果保存在寄存器R1:R0中,R1为高8位,R0为低8位。如果操作数为寄存器R1和R0,原操作数会被覆盖。
影响标志位:Z和C。
②有符号数乘法:
MULS Rd, Rr ;16≤d≤23, 16≤r≤23
操作:R1:R0←Rd×Rr PC←PC+1
说明:寄存器Rd和寄存器Rr的内容进行8位有符号数的乘法,结果保存在寄存器R1:R0中,R1为高8位,R0为低8位。原操作数为寄存器R16~R23。
影响标志位:Z和C。
③有符号数与无符号数乘法:
MULSU Rd, Rr ;16≤d≤23, 16≤r≤23
操作:R1:R0←Rd×Rr PC←PC+1
说明:寄存器Rd(8位有符号数)和寄存器Rr(8位无符号数)的内容相乘,结果为16位有符号数,保存在寄存器R1:R0中,R1为高8位,R0为低8位。原操作数为寄存器R16~R23。
影响标志位:Z和C。
④无符号定点小数乘法:
FMUL Rd, Rr ;16≤d≤23, 16≤r≤23
操作:R1:R0←Rd×Rr (unsigned(1.15)=unsigned(1.7)×unsigned(1.7)) PC←PC+1
说明:寄存器Rd和寄存器Rr的内容进行8位无符号数的乘法,结果为16位无符号数,左移1位后保存在寄存器R1:R0中,R1为高8位,R0为低8位。原操作数为寄存器R16~R23。
影响标志位:Z和C。
注:(n.q)表示一个小数点左边有n个二进制数位,右边有q个二进制数位的小数。以(n1.q1)和(n2.q2)为格式的两个小数相乘,产生格式为((n1+n2).(q1+q2))的结果。对于要有效保留小数位的处理应用,输入的数据通常采用(1.7)的格式,产生的结果为(2.14)格式。因此,将结果左移一位以使高字节的格式与输入的相一致。FMUL指令的执行周期与MUL指令相同,但比MUL增加了左移操作。被乘数Rd和乘数Rr是两个包含无符号定点小数的寄存器,小数点固定在第7位和第6位之间;结果为16位无符号定点小数,小数点固定在第15位和第14位之间。
⑤有符号定点小数乘法:
FMULS Rd, Rr ;16≤d≤23, 16≤r≤23
操作:R1:R0←Rd×Rr (signed(1.15)=signed(1.7)×signed(1.7)) PC←PC+1
说明:寄存器Rd和寄存器Rr的内容进行8位有符号数的乘法,结果为16位有符号数,左移1位后保存在寄存器R1:R0中,R1为高8位,R0为低8位。原操作数为寄存器R16~R23。
影响标志位:Z和C。
注:(n.q)表示一个小数点左边有n个二进制数位,右边有q个二进制数位的小数。以(n1.q1)和(n2.q2)为格式的两个小数相乘,产生格式为((n1+n2).(q1+q2))的结果。对于要有效保留小数位的处理应用,输入的数据通常采用(1.7)的格式,产生的结果为(2.14)格式。因此,将结果左移一位以使高字节的格式与输入的相一致。FMULS指令的执行周期与MULS指令相同,但比MULS增加了左移操作。被乘数Rd和乘数Rr是两个包含有符号定点小数的寄存器,小数点固定在第7位和第6位之间;结果为16位无符号定点小数,小数点固定在第15位和第14位之间。
⑥有符号定点小数和无符号定点小数乘法:
FMULSU Rd, Rr ;16≤d≤23, 16≤r≤23
操作:R1:R0←Rd×Rr (signed(1.15)=signed(1.7)×unsigned(1.7)) PC←PC+1
说明:寄存器Rd(8位有符号数)和寄存器Rr(8位无符号数)的内容相乘,结果为16位有符号数,左移1位后保存在寄存器R1:R0中,R1为高8位,R0为低8位。原操作数为寄存器R16~R23。
影响标志位:Z和C。
注:(n.q)表示一个小数点左边有n个二进制数位,右边有q个二进制数位的小数。以(n1.q1)和(n2.q2)为格式的两个小数相乘,产生格式为((n1+n2).(q1+q2))的结果。对于要有效保留小数位的处理应用,输入的数据通常采用(1.7)的格式,产生的结果为(2.14)格式。因此,将结果左移一位以使高字节的格式与输入的相一致。FMULSU指令的执行周期与MULSU指令相同,但比MULSU增加了左移操作。被乘数Rd是一个个包含有符号定点小数的寄存器,乘数Rr是一个包含无符号定点小数的寄存器,小数点固定在第7位和第6位之间;结果为16位有符号定点小数,小数点固定在第15位和第14位之间。
4. 跳转指令:
1)无条件跳转指令:
①相对跳转:
RJMP k ;-2048≤k≤2047
操作:PC←(PC+1)+k
说明:相对跳转到(PC-2048)~(PC+2047)字范围内的地址。
影响标志位:无。
注:在汇编语言中,用目的地址的标号替代相对跳转字k。
②间接跳转:
IJMP
操作:PC←Z(15~0)
说明:间接跳转到Z指针寄存器指向的16位地址。
影响标志位:无。
注:Z指针是16位宽,允许在64K字内跳转,范围大。但作为子程序模块,移植时需修改跳转指针,所以一般在子程序中不要使用。
③直接跳转:
JMP k ;0≤k≤4194303
操作:PC←k
说明:直接跳转到k地址处。
影响标志位:无。
注:在汇编语言中,用目的地址的标号替代跳转字k。
2)条件跳转指令:
条件跳转指令是依照某种特定的条件而跳转的指令,条件满足时跳,条件不满足则顺序执行下面的指令。
①测试条件符合跳转指令:
⑴状态寄存器中位为1跳转:
BRBS s, k ;0≤s≤7 -64≤k≤63
操作:if SREG(s)=1, then PC←(PC+1)+k; else PC←PC+1
说明:PC先加1,再测试SREG的s位。如果该位为1,则跳转k个字;否则顺序执行。
影响标志位:无。
注:k为7位带符号数,最多可向前跳63个字,向后跳64个字。在汇编语言中,用目的地址的标号替代跳转字k。
⑵状态寄存器中位为0跳转:
BRBC s, k ;0≤s≤7 -64≤k≤63
操作:if SREG(s)=0, then PC←(PC+1)+k; else PC←PC+1
说明:PC先加1,再测试SREG的s位。如果该位为0,则跳转k个字;否则顺序执行。
影响标志位:无。
注:k为7位带符号数,最多可向前跳63个字,向后跳64个字。在汇编语言中,用目的地址的标号替代跳转字k。
⑶相等跳转:
BREQ k ;-64≤k≤63
操作:if (Z=1), then PC←(PC+1)+k; else PC←PC+1
说明:测试零标志位Z。如果该位为1,则跳转k个字;否则顺序执行。
影响标志位:无。
注:如果在执行CP、CPI、SUB或SUBI指令后立即执行该指令,则当寄存器Rd中数与寄存器Rr中数相等时发生跳转。这条指令相当于指令“BRBS 1,k”。
⑷不相等跳转:
BRNE k ;-64≤k≤63
操作:if (Z=0), then PC←(PC+1)+k; else PC←PC+1
说明:测试零标志位Z。如果该位为0,则跳转k个字;否则顺序执行。
影响标志位:无。
注:如果在执行CP、CPI、SUB或SUBI指令后立即执行该指令,则当寄存器Rd中数与寄存器Rr中数不相等时发生跳转。这条指令相当于指令“BRBC 1,k”。
⑸进位标志位C为1跳转:
BRCS k ;-64≤k≤63
操作:if (C=1), then PC←(PC+1)+k; else PC←PC+1
说明:测试进位标志位C。如果该位为1,则跳转k个字;否则顺序执行。
影响标志位:无。
注:这条指令相当于指令“BRBS 0,k”。
⑹进位标志位为0跳转:
BRCC k ;-64≤k≤63
操作:if (C=0), then PC←(PC+1)+k; else PC←PC+1
说明:测试进位标志位C。如果该位为0,则跳转k个字;否则顺序执行。
影响标志位:无。
注:如果在执行CP、CPI、SUB或SUBI指令后立即执行该指令,则当寄存器Rd中数与寄存器Rr中数不相等时发生跳转。这条指令相当于指令“BRBC 0,k”。
⑺大于或等于跳转(对无符号数):
BRSH k ;-64≤k≤63
操作:if (C=0), then PC←(PC+1)+k; else PC←PC+1
说明:测试进位标志位C。如果该位为0,则跳转k个字;否则顺序执行。
影响标志位:无。
注:如果在执行CP、CPI、SUB或SUBI指令后立即执行该指令,则当寄存器Rd中无符号二进制数大于或等于寄存器Rr中无符号二进制数时发生跳转。这条指令相当于指令“BRBC 0,k”。
⑻小于跳转(对无符号数):
BRLO k ;-64≤k≤63
操作:if (C=1), then PC←(PC+1)+k; else PC←PC+1
说明:测试进位标志位C。如果该位为1,则跳转k个字;否则顺序执行。
影响标志位:无。
注:如果在执行CP、CPI、SUB或SUBI指令后立即执行该指令,则当寄存器Rd中无符号二进制数小于寄存器Rr中无符号二进制数时发生跳转。这条指令相当于指令“BRBS 0,k”。
⑼结果为负跳转:
BRMI k ;-64≤k≤63
操作:if (N=1), then PC←(PC+1)+k; else PC←PC+1
说明:测试负号标志位N。如果该位为1,则跳转k个字;否则顺序执行。
影响标志位:无。
注:这条指令相当于指令“BRBS 2,k”。
⑽结果为正跳转:
BRPL k ;-64≤k≤63
操作:if (N=0), then PC←(PC+1)+k; else PC←PC+1
说明:测试负号标志位N。如果该位为0,则跳转k个字;否则顺序执行。
影响标志位:无。
注:这条指令相当于指令“BRBC 2,k”。
⑾大于或等于跳转(带符号数):
BRGE k ;-64≤k≤63
操作:if (N⊕V=0), then PC←(PC+1)+k; else PC←PC+1
说明:测试符号标志位S。如果该位为0,则跳转k个字;否则顺序执行。
影响标志位:无。
注:如果在执行CP、CPI、SUB或SUBI指令后立即执行该指令,且当寄存器Rd中带符号二进制数大于或等于寄存器Rr中带符号二进制数时发生跳转。这条指令相当于指令“BRBC 4,k”。
⑿小于跳转(带符号数):
BRLT k ;-64≤k≤63
操作:if (N⊕V=1), then PC←(PC+1)+k; else PC←PC+1
说明:测试符号标志位S。如果该位为1,则跳转k个字;否则顺序执行。
影响标志位:无。
注:如果在执行CP、CPI、SUB或SUBI指令后立即执行该指令,且当寄存器Rd中带符号二进制数小于寄存器Rr中带符号二进制数时发生跳转。这条指令相当于指令“BRBS 4,k”。
⒀半进位标志为1跳转:
BRHS k ;-64≤k≤63
操作:if (H=1), then PC←(PC+1)+k; else PC←PC+1
说明:测试半进位标志位H。如果该位为1,则跳转k个字;否则顺序执行。
影响标志位:无。
注:这条指令相当于指令“BRBS 5,k”。
⒁半进位标志为0跳转:
BRHC k ;-64≤k≤63
操作:if (H=0), then PC←(PC+1)+k; else PC←PC+1
说明:测试半进位标志位H。如果该位为0,则跳转k个字;否则顺序执行。
影响标志位:无。
注:这条指令相当于指令“BRBC 5,k”。
⒂T标志为1跳转:
BRTS k ;-64≤k≤63
操作:if (T=1), then PC←(PC+1)+k; else PC←PC+1
说明:测试标志位T。如果该位为1,则跳转k个字;否则顺序执行。
影响标志位:无。
注:这条指令相当于指令“BRBS 6,k”。
⒃T标志为0跳转:
BRTC k ;-64≤k≤63
操作:if (T=0), then PC←(PC+1)+k; else PC←PC+1
说明:测试标志位T。如果该位为0,则跳转k个字;否则顺序执行。
影响标志位:无。
注:这条指令相当于指令“BRBC 6,k”。
⒄溢出标志为1跳转:
BRVS k ;-64≤k≤63
操作:if (V=1), then PC←(PC+1)+k; else PC←PC+1
说明:测试溢出标志位V。如果该位为1,则跳转k个字;否则顺序执行。
影响标志位:无。
注:这条指令相当于指令“BRBS 3,k”。
⒅溢出标志为0跳转:
BRVC k ;-64≤k≤63
操作:if (V=0), then PC←(PC+1)+k; else PC←PC+1
说明:测试溢出标志位V。如果该位为0,则跳转k个字;否则顺序执行。
影响标志位:无。
注:这条指令相当于指令“BRBC 3,k”。
⒆中断标志为1跳转:
BRIE k ;-64≤k≤63
操作:if (I=1), then PC←(PC+1)+k; else PC←PC+1
说明:测试全局中断允许标志位I。如果该位为1,则跳转k个字;否则顺序执行。
影响标志位:无。
注:这条指令相当于指令“BRBS 7,k”。
⒇中断标志为0跳转:
BRID k ;-64≤k≤63
操作:if (I=0), then PC←(PC+1)+k; else PC←PC+1
说明:测试全局中断允许标志位I。如果该位为0,则跳转k个字;否则顺序执行。
影响标志位:无。
注:这条指令相当于指令“BRBC 7,k”。
②测试条件符合跳行跳转指令:
⑴相等跳行:
CPSE Rd, Rr ;0≤d≤31, 0≤r≤31
操作:if (Rd=Rr), then PC←PC+2(or 3); else PC←PC+1
说明:两个寄存器Rd与Rr的内容比较,如果相等则跳一行执行指令;否则顺序执行。
影响标志位:无。
⑵寄存器位为0跳行:
SBRC Rd,b ;0≤d≤31 0≤b≤7
操作:if Rd(b)=0, then PC←PC+2(or 3); else PC←PC+1
说明:测试寄存器Rd的第b位。如果该位为0则跳一行执行指令;否则顺序执行。
影响标志位:无。
⑶寄存器位为1跳行:
SBRS Rd,b ;0≤d≤31 0≤b≤7
操作:if Rd(b)=1, then PC←PC+2(or 3); else PC←PC+1
说明:测试寄存器Rd的第b位。如果该位为1则跳一行执行指令;否则顺序执行。
影响标志位:无。
⑷I/O寄存器位为0跳行:
SBIC P,b ;0≤P≤31 0≤b≤7
操作:if P(b)=0, then PC←PC+2(or 3); else PC←PC+1
说明:测试I/O寄存器P的第b位。如果该位为0则跳一行执行指令;否则顺序执行。
影响标志位:无。
注:该指令只在低32个I/O寄存器内操作,地址为I/O寄存器空间的0~31。
⑸I/O寄存器位为1跳行:
SBIS P,b ;0≤P≤31 0≤b≤7
操作:if Rd(b)=1, then PC←PC+2(or 3); else PC←PC+1
说明:测试I/O寄存器P的第b位。如果该位为1则跳一行执行指令;否则顺序执行。
影响标志位:无。
注:该指令只在低32个I/O寄存器内操作,地址为I/O寄存器空间的0~31。
5. 子程序调用和返回指令:
在程序设计中,通常把具有一定功能模块的公用程序段定义为子程序。为了实现调用子程序的功能,指令系统中都有调用子程序指令。调用子程序时,把下一条指令地址PC值保留到堆栈中,即断点保护,然后把子程序的起始地址置入PC;子程序执行完毕返回时,将断点由堆栈弹出到PC,然后从断点处继续执行原程序。在每个子程序中,都必须有返回指令,功能就是把调用前压入堆栈的断点弹出置入PC,恢复执行调用子程序前的原程序。
在一个程序中,子程序中还会调用别的子程序,称为嵌套。每次调用子程序时,必须将下条指令地址保存起来,返回时按后进先出原则依次取出相应的PC值。堆栈就是按后进先出规则存取数据的,调用指令和返回指令具有自动保存和恢复PC内容的功能,即自动进栈和自动出栈。
1)相对调用:
RCALL k ;-2048≤k≤2047
操作:STACK←PC+1 SP←SP-2; PC←(PC+1)+k
说明:将PC+1后的值(RCALL指令后的下一条指令地址)压入堆栈,然后调用在当前PC前或后k+1处地址的子程序。
影响标志位:无。
2)间接调用:
ICALL
操作:STACK←PC+1 SP←SP-2; PC←Z
说明:间接调用由Z寄存器(16位指针寄存器)指向的子程序。地址指针寄存器Z为16位,允许调用在当前程序存储空间64K字(128KB)内的子程序。
影响标志位:无。
3)直接调用:
CALL k ;0≤k≤65535
操作:STACK←PC+2 SP←SP-2; PC←k
说明:将PC+2后的值(CALL指令后的下一条指令地址)压入堆栈,然后直接调用k处地址的子程序。
影响标志位:无。
4)从子程序返回:
RET
操作:SP←SP+2 PC←STACK
说明:从子程序返回,返回地址从堆栈中弹出。
影响标志位:无。
5)从中断程序返回:
RETI
操作:SP←SP+2 PC←STACK
说明:从中断子程序中返回,返回地址从堆栈中弹出,且全局中断标志置位。
影响标志位:I(1)。
注:主程序应通过中断向量区,防止给修改、补充中断程序带来麻烦。应在中断向量区中不用的中断入口地址写上RETI,有抗干扰作用。
6. 数据传送指令:
数据传送指令是编程中使用最频繁的一类指令。数据传送指令包括寄存器与寄存器、寄存器与数据存储器SRAM、寄存器与I/O端口之间的数据传送指令,从程序寄存器取数装入寄存器指令LPM(ELPM)以及进栈指令PUSH和出栈指令POP等。所有的传送指令的操作对标志位均无影响。
1)直接寻址数据传送指令:
①工作寄存器间传送数据:
MOV Rd, Rr ;0≤d≤31, 0≤r≤31
操作:Rd←Rr PC←PC+1
说明:该指令将一个寄存器内容传送到另一个寄存器中,源寄存器Rr的内容不改变。
影响标志位:无。
②SRAM数据直接送寄存器:
LDS Rd, k ;0≤d≤31, 0≤k≤65535
操作:Rd←(k) PC←PC+2
说明:把SRAM中一个存储单元的内容(字节)装入到寄存器中,其中k为该存储单元的16位地址。
影响标志位:无。
③寄存器数据直接送SRAM:
STS k, Rr ;0≤r≤31, 0≤k≤65535
操作:(k)←Rd PC←PC+2
说明:将寄存器的内容直接存储到SRAM中,其中k为该存储单元的16位地址。
影响标志位:无。
④立即数送寄存器:
LDI Rd, K ;16≤d≤31, 0≤K≤255
操作:Rd←K PC←PC+1
说明:将一个8位立即数传送到寄存器R16~R31中。
影响标志位:无。
⑤寄存器字复制(扩展指令,部分AVR芯片支持):
MOVM Rd+1:Rd, Rr+1:Rr ;RdЄ(0,2,...,30), RrЄ(0,2,...,30)
操作:Rd+1:Rd←Rr+1:Rr PC←PC+1
说明:将一个寄存器对的内容复制到另外一个寄存器对中(16位传送)。
影响标志位:无。
2)间接寻址数据传送指令:
使用X、Y、Z指针寄存器特别适用于访问矩阵表和堆栈指针等。
①使用X指针寄存器间接寻址传送数据:
⑴使用地址指针寄存器X间接寻址将SRAM内容装入到指定寄存器:
a) LD Rd, X ;0≤d≤31
操作:Rd←(X) PC←PC+1
说明:将指针为X的SRAM中的数送寄存器,X指针不变。
影响标志位:无。
b) LD Rd, X+ ;0≤d≤31
操作:Rd←(X) X←X+1 PC←PC+1
说明:先将指针为X的SRAM中的数送寄存器,然后X指针加1。
影响标志位:无。
c) LD Rd, -X ;0≤d≤31
操作:X←X-1 Rd←(X) PC←PC+1
说明:先将X指针减1,然后将指针为X的SRAM中的数送寄存器。
影响标志位:无。
⑵使用地址指针寄存器X间接寻址将寄存器内容存储到SRAM:
a) ST X, Rr ;0≤r≤31
操作:(X)←Rr PC←PC+1
说明:将寄存器内容送X为指针的SRAM中,X指针不变。
影响标志位:无。
b) ST X+, Rr ;0≤r≤31
操作:(X)←Rr X←X+1 PC←PC+1
说明:先将寄存器内容送X为指针的SRAM中,然后X指针加1。
影响标志位:无。
c) ST -X, Rr ;0≤r≤31
操作:X←X-1 (X)←Rr PC←PC+1
说明:先将X指针减1,然后将寄存器内容送指针为X的SRAM中。
影响标志位:无。
②使用Y指针寄存器间接寻址传送数据:
⑴使用地址指针寄存器Y间接寻址将SRAM内容装入到指定寄存器:
a) LD Rd, Y ;0≤d≤31
操作:Rd←(Y) PC←PC+1
说明:将指针为Y的SRAM中的数送寄存器,Y指针不变。
影响标志位:无。
b) LD Rd, Y+ ;0≤d≤31
操作:Rd←(Y) Y←Y+1 PC←PC+1
说明:先将指针为Y的SRAM中的数送寄存器,然后Y指针加1。
影响标志位:无。
c) LD Rd, -Y ;0≤d≤31
操作:Y←Y-1 Rd←(Y) PC←PC+1
说明:先将Y指针减1,然后将指针为Y的SRAM中的数送寄存器。
影响标志位:无。
d) LDD Rd, Y+q ;0≤d≤31, 0≤q≤63
操作:Rd←(Y+q) PC←PC+1
说明:将指针为Y+q的SRAM中的数送寄存器,Y指针不变。
影响标志位:无。
⑵使用地址指针寄存器Y间接寻址将寄存器内容存储到SRAM:
a) ST Y, Rr ;0≤r≤31
操作:(Y)←Rr PC←PC+1
说明:将寄存器内容送Y为指针的SRAM中,Y指针不变。
影响标志位:无。
b) ST Y+, Rr ;0≤r≤31
操作:(Y)←Rr Y←Y+1 PC←PC+1
说明:先将寄存器内容送Y为指针的SRAM中,然后Y指针加1。
影响标志位:无。
c) ST -Y, Rr ;0≤r≤31
操作:Y←Y-1 (Y)←Rr PC←PC+1
说明:Y指针减1,然后将寄存器内容送指针为Y的SRAM中。
影响标志位:无。
d) STD Y+q, Rr ;0≤r≤31, 0≤q≤63
操作:(Y+q)←Rr PC←PC+1
说明:将寄存器内容送指针为Y+q的SRAM中,Y指针不变。
影响标志位:无。
③使用Z指针寄存器间接寻址传送数据:
⑴使用地址指针寄存器Z间接寻址将SRAM内容装入到指定寄存器:
a) LD Rd, Z ;0≤d≤31
操作:Rd←(Z) PC←PC+1
说明:将指针为Z的SRAM中的数送寄存器,Z指针不变。
影响标志位:无。
b) LD Rd, Z+ ;0≤d≤31
操作:Rd←(Z) Z←Z+1 PC←PC+1
说明:先将指针为Z的SRAM中的数送寄存器,然后Z指针加1。
影响标志位:无。
c) LD Rd, -Z ;0≤d≤31
操作:Z←Z-1 Rd←(Z) PC←PC+1
说明:先将Z指针减1,然后将指针为Z的SRAM中的数送寄存器。
影响标志位:无。
d) LDD Rd, Z+q ;0≤d≤31, 0≤q≤63
操作:Rd←(Z+q) PC←PC+1
说明:将指针为Z+q的SRAM中的数送寄存器,Z指针不变。
影响标志位:无。
⑵使用地址指针寄存器Z间接寻址将寄存器内容存储到SRAM:
a) ST Z, Rr ;0≤r≤31
操作:(Y)←Rr PC←PC+1
说明:将寄存器内容送Z为指针的SRAM中,Z指针不变。
影响标志位:无。
b) ST Z+, Rr ;0≤r≤31
操作:(Z)←Rr Z←Z+1 PC←PC+1
说明:先将寄存器内容送Z为指针的SRAM中,然后Z指针加1。
影响标志位:无。
c) ST -Z, Rr ;0≤r≤31
操作:Z←Z-1 (Z)←Rr PC←PC+1
说明:Z指针减1,然后将寄存器内容送指针为Z的SRAM中。
影响标志位:无。
d) STD Z+q, Rr ;0≤r≤31, 0≤q≤63
操作:(Z+q)←Rr PC←PC+1
说明:将寄存器内容送指针为Z+q的SRAM中,Z指针不变。
影响标志位:无。
3)从程序存储器中取数装入寄存器指令:
①从程序存储器中取数装入寄存器R0:
LPM
操作:R0←(Z) PC←PC+1
说明:将Z指向的程序存储器空间的1字节装入寄存器R0。
影响标志位:无。
注:由于程序存储器的地址是以字(双字节)为单位的,因此16位地址指针寄存器Z的高15位为程序存储器的字地址。最低位LSB为0时指字的低字节,为1时指字的高字节。该指令能寻址程序存储器空间为64KB(32K字)。
②从程序存储器中取数装入寄存器Rd:
LPM Rd, Z ;0≤d≤31
操作:Rd←(Z) PC←PC+1
说明:将Z指向的程序存储器空间的1字节装入寄存器Rd。
影响标志位:无。
注:由于程序存储器的地址是以字(双字节)为单位的,因此16位地址指针寄存器Z的高15位为程序存储器的字地址。最低位LSB为0时指字的低字节,为1时指字的高字节。该指令能寻址程序存储器空间为64KB(32K字)。
③带后增量的从程序寄存器中取数装入寄存器Rd:
LPM Rd, Z+ ;0≤d≤31
操作:Rd←(Z) Z←Z+1 PC←PC+1
说明:先将Z指向的程序存储器空间的1字节装入寄存器Rd,然后Z指针加1。
影响标志位:无。
注:由于程序存储器的地址是以字(双字节)为单位的,因此16位地址指针寄存器Z的高15位为程序存储器的字地址。最低位LSB为0时指字的低字节,为1时指字的高字节。该指令能寻址程序存储器空间为64KB(32K字)。
④从程序存储器中取数装入寄存器R0(扩展指令,部分AVR芯片支持,ATmega16不支持):
ELPM
操作:R0←(RAMPZ:Z) PC←PC+1
说明:将RAMPZ:Z指向的程序存储器空间的1字节装入寄存器R0。
影响标志位:无。
注:由于程序存储器的地址是以字(双字节)为单位的,因此RAMPZ寄存器的最低位加上Z的高15位组成16位的程序存储器字寻址地址,能寻址128KB(64K字)。最低位LSB为0时指字的低字节,为1时指字的高字节。
⑤从程序存储器中取数装入寄存器(扩展指令,部分AVR芯片支持,ATmega16不支持):
ELPM Rd, Z ;0≤d≤31
操作:Rd←(RAMPZ:Z) PC←PC+1
说明:将RAMPZ:Z指向的程序存储器空间的1字节装入寄存器Rd。
影响标志位:无。
注:由于程序存储器的地址是以字(双字节)为单位的,因此RAMPZ寄存器的最低位加上Z的高15位组成16位的程序存储器字寻址地址,能寻址128KB(64K字)。最低位LSB为0时指字的低字节,为1时指字的高字节。
⑥带后增量的从程序存储器中取数装入寄存器(扩展指令,部分AVR芯片支持,ATmega16不支持):
ELPM Rd, Z+ ;0≤d≤31
操作:Rd←(RAMPZ:Z) RAMPZ:Z←RAMPZ:Z+1 PC←PC+1
说明:将RAMPZ:Z指向的程序存储器空间的1字节装入寄存器Rd,然后RAMPZ:Z加1。
影响标志位:无。
注:由于程序存储器的地址是以字(双字节)为单位的,因此RAMPZ寄存器的最低位加上Z的高15位组成16位的程序存储器字寻址地址,能寻址128KB(64K字)。最低位LSB为0时指字的低字节,为1时指字的高字节。
4)写程序存储器指令:
SPM
操作:(Z)←R1:R0 PC←PC+1
说明:将寄存器对R1:R0的内容(16位字)写入Z指向的程序存储器空间。
影响标志位:无。
注:该指令用于具有在应用自编程性能的AVR单片机。应用这一特性,单片机系统程序可以在运行中更改程序,实现动态修改系统程序的功能。由于程序存储器的地址是以字(双字节)为单位的,因此16位地址指针寄存器Z的高15位为程序存储器的字地址。最低位LSB为0时指字的低字节,为1时指字的高字节。该指令能寻址程序存储器空间为64KB(32K字)。
5)I/O口数据传送指令:
①I/O口数据装入寄存器:
IN Rd, P ;0≤d≤31, 0≤P≤63
操作:Rd←P PC←PC+1
说明:将I/O空间(口、定时器、配置寄存器等)的数据传送到寄存器Rd中。
影响标志位:无。
②寄存器数据送I/O口:
OUT P, Rr ;0≤r≤31, 0≤P≤63
操作:P←Rd PC←PC+1
说明:将寄存器Rd中的数据传送到I/O空间(口、定时器、配置寄存器等)。
影响标志位:无。
6)堆栈操作指令:
AVR单片机的特殊功能寄存器中有一个16位堆栈指针寄存器SP,它指出栈顶的位置。
①进栈指令:
PUSH Rd ;0≤d≤31
操作:STACK←Rd SP←SP-1 PC←PC+1
说明:该指令将寄存器Rd的内容压入堆栈。
影响标志位:无。
②出栈指令:
POP Rd ;0≤d≤31
操作:SP←SP+1 Rd←STACK PC←PC+1
说明:该指令将堆栈中的字节装入到寄存器Rd中。
影响标志位:无。
7.位操作和位测试指令:
AVR单片机指令系统中有1/4的指令是位操作和位测试指令,极大地提高了系统的逻辑控制和处理能力。
1)带进位逻辑操作指令:
①寄存器逻辑左移:
LSL Rd ;0≤d≤31
操作:C←b7b6b5b4b3b2b1b0←0 PC←PC+1
说明:寄存器Rd中所有位左移1位,第0位清0,第7位移到SREG中的C标志位。
影响标志位:H、S、V、N、Z和C。
注:该指令相当于完成一个无符号数乘以2的操作。
②寄存器逻辑右移:
LSR Rd ;0≤d≤31
操作:0→b7b6b5b4b3b2b1b0→C PC←PC+1
说明:寄存器Rd中所有位右移1位,第7位清0,第0位移到SREG中的C标志位。
影响标志位:S、V、N(0)、Z和C。
注:该指令相当于完成一个无符号数除以2的操作,C标志用于结果舍入。
③带进位的寄存器逻辑循环左移:
ROL Rd ;0≤d≤31
操作:C←b7b6b5b4b3b2b1b0←C PC←PC+1
说明:寄存器Rd中所有位左移1位,C标志位移入第0位,第7位移到C标志位。
影响标志位:H、S、V、N、Z和C。
④带进位的寄存器逻辑循环右移:
ROR Rd ;0≤d≤31
操作:C→b7b6b5b4b3b2b1b0→C PC←PC+1
说明:寄存器Rd中所有位右移1位,C标志位移入第7位,第0位移到C标志位。
影响标志位:S、V、N、Z和C。
⑤寄存器算术右移:
ASR Rd ;0≤d≤31
操作:b7→b7b6b5b4b3b2b1b0→C PC←PC+1
说明:寄存器Rd中所有位右移1位,而第7位保持原值,第0位移入C标志位。
影响标志位:S、V、N、Z和C。
注:该指令相当于完成一个补码除以2的操作,不改变符号,C标志用于结果舍入。
⑥寄存器半字节交换:
SWAP Rd ;0≤d≤31
操作:b7b6b5b4←→b3b2b1b0 PC←PC+1
说明:寄存器Rd中高半字节与低半字节交换。
影响标志位:无。
2)位变量传送指令:
①寄存器中的位存储到SREG中的T标志:
BST Rd, b ;0≤d≤31, 0≤b≤7
操作:T←Rd(b) PC←PC+1
说明:把寄存器Rd中的位b存储到SREG状态寄存器中的T标志位。
影响标志位:T。
②SREG中的T标志位值装入寄存器Rd中的某一位:
BLD Rd, b ;0≤d≤31, 0≤b≤7
操作:Rd(b)←T PC←PC+1
说明:复制SREG状态寄存器中的T标志位到寄存器Rd中的位b。
影响标志位:无。
3)位变量修改指令:
⑴状态寄存器SREG的指定位置1:
BSET s ;0≤s≤7
操作:SREG(s)←1 PC←PC+1
说明:状态寄存器SREG中某一标志位置1。
影响标志位:I、T、H、S、V、N、Z和C。
⑵状态寄存器SREG的指定位清0:
BCLR s ;0≤s≤7
操作:SREG(s)←0 PC←PC+1
说明:状态寄存器SREG中某一标志位清0。
影响标志位:I、T、H、S、V、N、Z和C。
⑶I/O寄存器的指定位置1:
SBI P, b ;0≤P≤31, 0≤b≤7
操作:I/O(P,b)←1 PC←PC+1
说明:对P指定的I/O寄存器的指定位置1。
影响标志位:无。
注:该指令只在低32个I/O寄存器内操作,I/O寄存器地址为0~31。
⑷I/O寄存器的指定位清0:
CBI P, b ;0≤P≤31, 0≤b≤7
操作:I/O(P,b)←0 PC←PC+1
说明:对P指定的I/O寄存器的指定位清0。
影响标志位:无。
注:该指令只在低32个I/O寄存器内操作,I/O寄存器地址为0~31。
⑸进位标志位置1:
SEC
操作:C←1 PC←PC+1
说明:状态寄存器SREG中的进位标志位C置1。
影响标志位:C(1)。
⑹进位标志位清0:
CLC
操作:C←0 PC←PC+1
说明:状态寄存器SREG中的进位标志位C清0。
影响标志位:C(0)。
⑺负标志位置1:
SEN
操作:N←1 PC←PC+1
说明:状态寄存器SREG中的负标志位N置1。
影响标志位:N(1)。
⑻负标志位清0:
CLN
操作:N←0 PC←PC+1
说明:状态寄存器SREG中的负标志位N清0。
影响标志位:N(0)。
⑼零标志位置1:
SEZ
操作:Z←1 PC←PC+1
说明:状态寄存器SREG中的零标志位Z置1。
影响标志位:Z(1)。
⑽零标志位清0:
CLZ
操作:Z←0 PC←PC+1
说明:状态寄存器SREG中的零标志位Z清0。
影响标志位:Z(0)。
⑾使能全局中断位:
SEI
操作:I←1 PC←PC+1
说明:状态寄存器SREG中的全局中断标志位I置1。
影响标志位:I(1)。
⑿禁止全局中断位:
CLI
操作:I←0 PC←PC+1
说明:状态寄存器SREG中的全局中断标志位I清0。
影响标志位:I(0)。
⒀S标志位置1:
SES
操作:S←1 PC←PC+1
说明:状态寄存器SREG中的符号标志位S置1。
影响标志位:S(1)。
⒁S标志位清0:
CLS
操作:S←0 PC←PC+1
说明:状态寄存器SREG中的符号标志位S清0。
影响标志位:S(0)。
⒂溢出标志位置1:
SEV
操作:V←1 PC←PC+1
说明:状态寄存器SREG中的溢出标志位V置1。
影响标志位:V(1)。
⒃溢出标志位清0:
CLV
操作:V←0 PC←PC+1
说明:状态寄存器SREG中的溢出标志位V清0。
影响标志位:V(0)。
⒄T标志位置1:
SET
操作:T←1 PC←PC+1
说明:状态寄存器SREG中的标志位T置1。
影响标志位:T(1)。
⒅T标志位清0:
CLT
操作:T←0 PC←PC+1
说明:状态寄存器SREG中的标志位T清0。
影响标志位:T(0)。
⒆半进位标志位置1:
SEH
操作:H←1 PC←PC+1
说明:状态寄存器SREG中的半进位标志位H置1。
影响标志位:H(1)。
⒇半进位标志位清0:
CLH
操作:H←0 PC←PC+1
说明:状态寄存器SREG中的半进位标志位H清0。
影响标志位:H(0)。
8. MCU控制指令:
主要用于控制MCU的运行方式及清0看门狗定时器,只有3条指令。
1)空操作指令:
NOP
操作:无 PC←PC+1
说明:该指令完成一个单周期空操作。
影响标志位:无。
注:用于抗干扰、延时等待、产生方波等。其中,抗干扰处理为在空的程序存储器单元中写上空操作,空操作指令最后加一跳转指令,转到$0000。
2)进入休眠方式:
SLEEP
操作:PC←PC+1
说明:该指令使MCU进入休眠方式运行。
影响标志位:无。
注:休眠模式由MCU控制寄存器定义,当MCU在休眠状态下由一个中断唤醒时,在中断程序执行后,紧跟在休眠指令后的指令将被执行。
3)清0看门狗计数器:
WDT
操作:WDT清0
说明:该指令清0看门狗定时器。
影响标志位:无。
注:在允许使用看门狗定时器情况下,系统程序在正常运行中必须在WDT预定比例器给出的限定时间内执行一次该指令,以防止看门狗定时器溢出而造成系统复位。
9. AVR汇编器与伪指令:
用汇编语言编写程序比二进制的机器语言更容易学习和掌握,用汇编语言编写的程序称为汇编语言程序。但是单片机不能直接识别和执行汇编语言程序,需要使用一个专用的软件将汇编语言翻译成二进制的机器语言--目标程序(执行代码)。这种专用软件就是汇编语言编译软件。ATMEL公司提供免费的AVR开发平台--AVR Studio集成开发环境,其中就包括AVR Assembler汇编编译器。
用汇编语言编写程序,必须按汇编工具软件所规定的语法和规则进行,其中不仅有汇编指令,还定义了一些用于编写汇编程序的伪指令及使用表达式等。
1)汇编语言语句格式:
汇编语言是由一系列汇编语句组成。AVR的汇编语句的标准有以下4种:
[标号;] 伪指令 [操作数][;注释]
[标号;] 指令 [操作数][;注释]
[;注释]
空行
(注:汇编语句中不使用中括号“[”和“]”,格式中的中括号中内容表示可以缺省)
⑴标号:是语句地址的标记符号,用于引导对该语句的访问和定位。使用标号的目的是为了跳转和分支指令,以及在程序存储器、数据存储器SRAM和EEPROM中定义变量名。
标号的相关规定为:
·标号一般由ASCII字符组成,第一个字符为字母。
·同一标号在一个独立的程序中只能定义一次。
·不能使用汇编语言中已定义的符号(保留字),如指令字、寄存器名、伪指令字等。
⑵伪指令:伪指令不属于CPU指令集,编译时并不产生实际的目标机器代码,只是用于在汇编程序中对地址、寄存器、数据、常量等进行定义说明,以及对编译过程进行某种控制等。伪指令由汇编软件给出。
⑶指令:指令是汇编程序的主要部分,汇编程序中使用AVR指令集中给出的全部指令。
⑷操作数:操作数是指令操作时所需要的数据或地址,汇编程序完全支持指令系统所定义的操作数格式。但指令系统采用的操作数格式通常为数字形式,编写程序时使用往往不太方便,而编译软件可以使用多种形式的操作数,如数字、标识符、表达式等。
⑸注释:注释部分仅用于对程序和语句进行说明,帮助程序设计人员阅读=理解和修改程序。“;”后面即为注释部分,内容长度不限,换行时开头部分要用“;”。编译软件对注释内容不予理会,不产生任何代码。
⑹其他字符:汇编语句中,“:”用于标号后;空格用于指令字和操作数的分隔;指令有两个操作数时用“,”分隔两个操作数;“;”用于注释之前。
2)编译器伪指令:
AVR编译器使用一些伪指令。伪指令并不直接转换生成操作执行代码,而只是用于指示编译生成目标程序的起始地址或常数表格的起始地址,或为工作寄存器定义符号名称,定义外设口地址,规定SRAM工作区,规定编译器的工作内容等。因此,伪指令有间接产生机器码,控制机器代码空间的分配,对编译器工作过程进行控制等作用。
AVR编译器使用18条伪指令,见下表:
序号 |
伪指令 |
说明 |
|
序号 |
伪指令 |
说明 |
1 |
BYTE |
在RAM中定义预留存储单元 |
|
10 |
EXIT |
退出文件 |
2 |
CSEG |
声明代码段 |
|
11 |
INCLUDE |
包含指定的文件 |
3 |
DB |
定义字节常量 |
|
12 |
MACRO |
宏定义开始 |
4 |
DEF |
定义寄存器符号名 |
|
13 |
ENDMACRO |
宏定义结束 |
5 |
DEVICE |
指定为何器件生成汇编代码 |
|
14 |
LISTMAC |
列表宏表达式 |
6 |
DSEG |
声明数据段 |
|
15 |
LIST |
列表文件生成允许器 |
7 |
DW |
定义字常数 |
|
16 |
NOLIST |
关闭列表文件生成 |
8 |
EQU |
定义标识符常量 |
|
17 |
ORG |
设置程序起始位置 |
9 |
ESEG |
声明EEPROM段 |
|
18 |
SET |
赋值给标识符 |
⑴.BYTE:为变量预留字节型存储单元。
BYTE伪指令,是从指定的地址开始,在SRAM中预留若干字节的存储空间备用。BYTE伪指令前应使用一个标号,该标号既作为变量名称,又作为符号地址以标记备用存储空间在SRAM中的起始位置。该伪指令有一个参数,表示保留存储空间的字节数,但并不给这些SRAM单元赋值。BYTE伪指令仅能用在数据段内。
语法:LABEL:.BYTE 表达式
示例:
.DSEG ;RAM数据段(SRAM)
var1: .BYTE 1 ;保留1字节的存储单元,用var1标识
table: .BYTE tab_size ;保留tab_size字节的存储空间
.CSEG ;代码段开始(Flash)
LDI R30,low(var1) ;将保留存储单元var1起始地址的低8位装入Z
LDI R31,high(var1) ;将保留存储单元var1起始地址的高8位装入Z
LD R1,Z ;将保留存储单元的内容读到寄存器R1
⑵.CSEG:声明代码段(Flash)。
CSEG伪指令用于声明代码段的起始(在Flash中),即CSEG之后是要写入程序存储器中的指令代码,常数表格等。一个汇编程序可包含几个代码段,这些代码段在编译时被连接成一个代码段,每个代码段内部都有自己的字定位计数器。可使用ORG伪指令定义该字定位计数器的初始值,作为代码段在程序存储器中的起始位置。CSEG伪指令不带参数。代码段中不能使用BYTE伪指令。
语法:.CSEG
⑶.DB:在程序存储器或EEPROM中定义字节常数。
DB伪指令是从程序存储器或EEPROM的某个地址单元开始,存入一组规定的8位二进制常数(字节常数)。DB伪指令前应使用一个标号,以标记所定义的字节常数区域的起始位置,DB伪指令只能出现在代码段或EEPROM段中。
DB伪指令要带表达式列表,表达式之间用逗号分开,并至少要含有一个表达式。每个表达式值的范围必须在-128~255之间,如果为负数要用8位2的补码表示。
语法:LABEL:.DB 表达式表
⑷.DEF:定义寄存器符号名。
DEF伪指令给寄存器定义一个替代的符号名,后续程序中就可以使用定义的符号名来表示被定义的寄存器。可以给一个寄存器定义多个符号名,定义过的符号名还可以在后续的程序中重新定义。编译时,凡遇到符号名,都以相应被定义的寄存器替代。
语法:.DEF 符号名=寄存器
⑸.DEVICE:指定为何器件生成汇编代码。
DEVICE伪指令告知编译器为什么型号器件产生执行代码。如果在程序中使用该伪指令指定了器件型号,那么在编译过程中存在指定器件不支持的指令就会给出警告。如果代码段或EEPROM段所使用的存储器空间大于指定器件本身所能提供的存储器容量,编译器也会给出警告。如果不使用DEVICE伪指令,则假定器件支持所有的指令,也不限制存储容量大小。
语法:.DEVICE Atmega16
⑹.DSEG:声明数据段(SRAM)。
DSEG伪指令声明数据段的起始。一个汇编程序文件可以包含几个数据段,这些数据段在汇编过程中被连接成一个数据段。在数据段中,通常仅由BYTE伪指令(和标号)组成。每个数据段内部都有自己的字节定位计数器。可使用ORG伪指令定义该字节定位计数器的初始值,作为数据段在SRAM中的起始位置。DSEG伪指令不带参数。
语法:.DSEG
⑺.DW:在程序存储器或EEPROM中定义字常数。
DW伪指令是从程序存储器或EEPROM的某个地址单元开始,存入一组规定的16位二进制常数(字常数)。DW伪指令前应使用一个标号,以标记所定义的字常数区域的起始位置,DW伪指令只能出现在代码段或EEPROM段。
DW伪指令要带表达式列表,表达式之间用逗号分开,并至少要含有一个表达式。每个表达式值的范围必须在-32768~65535之间,如果为负数要用16位2的补码表示。
语法:LABEL:.DW 表达式表
⑻.EQU:定义标识符常量。
EQU伪指令将表达式的值赋给一个标识符,该标识符为一个常量标识符,可以 用于后面的指令表达式中,在汇编时凡遇到该标识符都以其等值表达式替代。在编写程序时,只要修改此表达式,就修改了程序中多处涉及该表达式的地方,减少了程序的修改量。但该标识符定义后不能重新定义或改变。
语法:.EQU 标识符=表达式
⑼.ESEG:声明EEPROM段。
ESEG伪指令声明EEPROM段的起始。一个汇编程序可包含几个EEPROM段,这些EEPROM段在编译时被连接成一个EEPROM段,每个EEPROM段内部都有自己的字定位计数器。可使用ORG伪指令定义该字定位计数器的初始值,作为EEPROM段在EEPROM中的起始位置。ESEG伪指令不带参数。EEPROM段中不能使用BYTE伪指令。
语法:.ESEG
⑽.EXIT:退出文件。
EXIT伪指令告诉汇编编译器停止汇编该文件。在正常情况下,汇编编译器的编译过程一直到文件的结束,如果中间出现EXIT,则编译器放弃对其后语句的编译。
如果EXIT出现在所包含文件中,则汇编编译器将结束对包含文件的编译,然后从本文件当前INCLUDE伪指令的下一行处开始继续编译。
语法:.EXIT
⑾.INCLUDE:包含指定的文件。
INCLUDE伪指令告诉汇编编译器开始从一个指定的文件读入程序语句,并对读入的语句进行编译,直到该包含文件结束或遇到该文件中的EXIT伪指令,然后再从本文件当前INCLUDE伪指令的下一行语句处继续开始编译。在一个包含文件中,也可以使用INCLUDE伪指令来包含另外一个指定的文件。
语法:.INCLUDE “文件名”
⑿.MACRO:宏开始。
MACRO伪指令将宏程序名作为参数,告诉编译器一个宏程序的开始,当后面的程序中使用宏程序名时,表示在该处调用宏程序。宏程序有些像子程序或公式,它是一段含有形式参数(亚元)的程序。一个宏程序中可带10个形式参数,这些参数在宏定义中用@0~@9来代表,参数之间用逗号分隔。当调用一个宏程序时,必须以实参代形参。
默认情况下,在汇编编译器生成的列表文件中仅给出宏的调用。如果要在列表文件中给出宏的表达式,则必须使用LISTMAC伪指令。在列表文件的操作码域中,宏带有“a+”的记号。
语法:.MACRO 宏名
⒀.ENDMACRO:宏结束。
ENDMACRO伪指令指示宏定义的结束,该指令不带参数。
语法:.ENDMACRO
示例:
.MACRO SUBI16 ;宏定义开始,定义一个16位减法
subi @1,low(@0) ;减低8位字节
sbci @2,high(@0) ;带借位减高8位字节
.ENDMACRO ;宏定义结束
... ...
.CSEG ;代码段开始
SUBI16 0x1234,r16,r17 ;调用宏完成r17:r16=r17:r16-0x1234
⒁.LISTMAC:列表时输出宏表达式。
LISTMAC伪指令告诉编译器,在生成的列表清单文件中,显示所调用宏的内容。默认情况下,仅在列表文件中显示所调用的宏名和参数。
语法:.LISTMAC
⒂.LIST:启动生成列表清单文件功能。
LIST伪指令告诉汇编编译器在对源文件编译后,产生一个机器语言与源文件相对照的列表清单文件。正常情况下,汇编编译器在编译过程中将生成一个由汇编源代码、地址和机器操作码组成的列表文件。默认时为允许生成列表清单文件。该伪指令可以与NOLIST伪指令配合使用,以选择仅使某一部分的汇编源文件产生列表清单文件。
语法:.LIST
⒃.NOLIST:关闭列表清单文件生成功能。
NOLIST伪指令告诉汇编编译器关闭列表清单文件生成的功能。正常情况下,汇编编译器在编译过程中将生成一个由汇编源代码、地址和机器操作码组成的列表文件,默认情况下为允许生成列表清单文件。当使用该伪指令时,将禁止列表清单文件的产生。该伪指令与LIST伪指令配合使用,可以选择使某一部分的汇编源文件产生列表清单文件。
语法:.NOLIST
⒄.ORG:定义代码起始位置。
ORG伪指令设置定位计数器为一个绝对数值,该数值为表达式的值,作为代码的起始位置。如果该伪指令出现在数据段中,则设定SRAM定位计数器;如果该伪指令出现在代码段中,则设定程序存储器计数器;如果该伪指令出现在EEPROM段中,则设定EEPROM定位计数器。如果该伪指令前带有标号(在相同的语句行),则标号的定位由ORG的参数值定义。
代码段和EEPROM段定位计数器的默认值是0;而当汇编编译器启动时,SRAM定位计数器的默认值是32(因为寄存器占有地址为0~31)。EEPROM和SRAM定位计数器按字节计数,而程序存储器定位计数器按字计数。
文件中可以出现多处ORG伪指令,但后面ORG所带的地址不能小于前一个ORG所带的地址,也不能落在由前一个ORG定位的代码段空间。
语法:.ORG
⒅.SET:设置标识符与一个表达式值相等。
与EQU作用类似,SET伪指令将表达式的值赋值给一个标识符。该标识符为一个常量标识符,可以用于后面的指令表达式。在汇编时,凡遇到该标识符都以其等值表达式替代。与EQU不同的是,用SET伪指令赋值的标识符能在后面使用SET伪指令重新设置改变。在SET改变后的代码使用新的等值表达式值,直到遇到下一个重新的SET定义为止。
语法:.SET 标识符=表达式
3)器件定义头文件m16def.inc :
在AVR的器件手册中,对所有的内部寄存器进行了标称化的定义,如32个通用寄存器组用R0~R31表示,系统状态寄存器用SREG表示,A口输出I/O寄存器用PORTA表示等,这样便于记忆、理解和使用。而当编写程序时,在指令中实际出现的应该是这些寄存器的空间地址,这就给编写程序造成了麻烦。为了能让程序员编写程序时不去使用那些不易记忆的寄存器地址,而是直接使用这些寄存器的标称名称,在AVR的开发软件平台中都含有各个AVR器件的标称定义头文件。
在ATMEL公司提供的AVR开发平台AVR Studio中,含有很多的“器件型号.inc”文件,这些inc文件已将该器件所有的I/O寄存器、标志位、中断向量地址等进行了标称化的定义。这些定义的标称化符号与硬件结构中寄存器的命名是相同的,同时定义了它们所代表的地址值,这样在程序中就可以直接使用标称化的符号,而不必去记住它的实际地址。例如,使用PORTA来代替A口I/O输出寄存器的地址$1b。ATmega16器件定义头文件m16def.inc中的部分内容如下:
;* * * * * Specify Device
.device ATmega16
;* * * * * I/O Register Definitions
.equ SREG = $ 3f
.equ SPH = $ 3e
.equ SPL = $ 3d
... ...
.equ PORTA = $ 1b
.equ DDRA = $ 1a
.equ PINA = $ 19
... ...
.def XL =r26
.def XH =r27
.def YL =r28
.def YH =r29
.def ZL =r30
.def ZH =r31
.equ RAMEND = $ 45F
... ...
可以看出,在器件定义文件中,大量使用了汇编伪指令EQU、DEF等,并定义了各个寄存器标称名所对应的地址值。因此,当编写AVR汇编程序时,在程序的开始处,需要先使用伪指令.INCLUDE,调用编译系统中的器件标识定义文件“****def.inc”。由于该文件已将该器件所有的I/O寄存器、标志位等进行了标称化的符号定义,这样在程序中就可以直接使用标称化的符号,而不必去使用它的实际地址了。示例:
.INCLUDE “m16def.inc” ;
.DEF TEMP1= r20 ;
... ...
.ORG $0000 ;
jmp RESET ;
.ORG $002A ;
;
;
;
RESET: idi r16, high(RAMEND) ;
out SPH, r16 ;
ldi r16, low(RAMEND) ;
out SPL, r16 ;
ser temp1 ;
out DDRA, temp1 ;
... ...
汇编程序示例1:延时子程序。
delay: push r16 ;延时子程序,压栈(1t)
del1: push r16 ;压栈(2t)
del2: push r16 ;压栈(2t)
del3: dec r16 ;r16=r16-1(1t)
brne del3 ;不为0跳转,为0顺序执行(2t/1t)
pop r16 ;出栈(2t)
dec r16 ;r16=r16-1(1t)
Brne del2 ;不为0跳转,为0顺序执行(2t/1t)
pop r16 ;出栈(2t)
dec r16 ;r16=r16-1(1t)
brne del1 ;不为0跳转,为0顺序执行(2t/1t)
pop r16 ;出栈(2t)
ret ;子程序返回(4t)
上述软件延时子程序采用2次嵌套,最多可以产生2s延时(4MHz时钟),如果3次嵌套则可产生140s延时(4MHz),而且代码短使用的寄存器少。
4MHz时钟下,AVR的每个指令周期为t=0.25us,则二次嵌套的总机器周期数为:
式中:x为R16的初始设置值;第一项数值11为调用子程序指令rcall、第1条压栈指令push、最后1条出栈指令pop和子程序返回指令ret需要的机器周期数(3+2+2+4);7x-1为del1循环(外围循环)需要的机器周期数;后面两项分别为内循环del2和del3需要的机器周期数。总的延时时间为T×0.25s。
下表给出了R16设置不同初始值情况下的总机器周期数及得到的延时时间:
x |
T |
延时 |
|
x |
T |
延时 |
|
x |
T |
延时 |
1 |
25 |
6.25us |
|
20 |
6010 |
1.5ms |
|
90 |
401860 |
100.465ms |
2 |
52 |
13.0us |
|
22 |
7732 |
1.933ms |
|
114 |
800404 |
200.101ms |
3 |
94 |
23.5us |
|
23 |
8704 |
2.176ms |
|
131 |
1202590 |
300.648ms |
4 |
154 |
38.5us |
|
26 |
12100 |
3.025ms |
|
144 |
1587754 |
396.939ms |
5 |
235 |
58.75us |
|
29 |
16279 |
4.07ms |
|
156 |
2009290 |
502.323ms |
6 |
340 |
85.0us |
|
31 |
19540 |
4.885ms |
|
166 |
2412920 |
603.205ms |
7 |
472 |
118us |
|
32 |
21322 |
5.33ms |
|
175 |
2819260 |
704.815ms |
8 |
634 |
158.5us |
|
40 |
39610 |
9.9ms |
|
183 |
3216784 |
804.196ms |
9 |
829 |
207.25us |
|
41 |
42445 |
10.61ms |
|
191 |
3650020 |
912.505ms |
10 |
1060 |
265us |
|
46 |
58660 |
14.67ms |
|
197 |
3999307 |
999.827ms |
13 |
1999 |
500us |
|
51 |
78550 |
19.64ms |
|
249 |
8000629 |
2.000157s |
17 |
3937 |
984us |
|
52 |
83002 |
20.75ms |
|
... |
... |
... |
18 |
4564 |
1.14ms |
|
71 |
202360 |
50.59ms |
|
0(256) |
8686090 |
2.1715225s |
(注:使用4MHz晶振情况下,设置R16中的常数从1~255,延时时间在6.25us~2.17s)
10. AVR汇编器的表达式:
在标准的指令系统中,操作数通常只能使用纯数字格式,这给程序的编写带来了许多不便。但在编译系统的支持下,在编写汇编程序时允许使用表达式,以方便程序的编写。AVR编译器支持的表达式由操作数、函数和运算符组成,所有的表达式内部都是32位的。
1)操作数:
AVR汇编器使用的操作数有以下几种形式:
①用户定义的标号,该标号给出了放置标号位置的定位计数器的值。
②用户用SET伪指令定义的常量。
③用户用EQU伪指令定义的常数。
④整数常数,包括下列几种形式:
·十进制数(默认),如10、255;
·十六进制数,如0x0A、$0A、0xFF、$FF;
·二进制数,如0b00001010、0b11111111.
⑤PC--程序存储器定位计数器的当前值。
2)函数:
AVR汇编器定义了下列函数:
LOW(表达式) 返回一个表达式值的最低字节。
HIGH(表达式) 返回一个表达式值的第2字节。
BYTE2(表达式) 返回一个表达式值的第2字节。
BYTE3(表达式) 返回一个表达式值的第2字节。
BYTE4(表达式) 返回一个表达式值的第4字节。
LWRD(表达式) 返回一个表达式值的0~15位。
HWRD(表达式) 返回一个表达式值的16~31位。
PAGE(表达式) 返回一个表达式值的16~21位。
EXP2(表达式) 返回一个表达式的2次幂的值。
LOG2(表达式) 返回一个表达式以2为底的对数值的整数部分。
3)运算符:
汇编器提供的部分运算符如表:
序号 |
运算符 |
名称 |
优先级 |
说明 |
1 |
! |
逻辑非 |
14 |
一元运算符。表达式是0返回1,表达式是1返回0 |
2 |
~ |
逐位非 |
14 |
一元运算符。将表达式的值按位取反 |
3 |
- |
负号 |
14 |
一元运算符。使表达式为算术负 |
4 |
* |
乘法 |
13 |
二进制运算符。两个表达式相乘 |
5 |
/ |
除法 |
13 |
二进制运算符。左边的表达式除以右边的表达式,取整数的商 |
6 |
+ |
加法 |
12 |
二进制运算符。两个表达式相加 |
7 |
- |
减法 |
12 |
二进制运算符。左边的表达式减去右边的表达式 |
8 |
<< |
左移 |
11 |
二进制运算符。左边表达式值左移右边表达式给出的次数 |
9 |
>> |
右移 |
11 |
二进制运算符。左边表达式值右移右边表达式给出的次数 |
10 |
< |
小于 |
10 |
二进制运算符。左边带符号表达式值小于右边带符号表达式值,则为1;否则为0 |
11 |
<= |
小于或等于 |
10 |
二进制运算符。左边带符号表达式值小于或等于右边带符号表达式值,则为1;否则为0 |
12 |
> |
大于 |
10 |
二进制运算符。左边带符号表达式值大于右边带符号表达式值,则为1;否则为0 |
13 |
>= |
大于或等于 |
10 |
二进制运算符。左边带符号表达式值大于或等于右边带符号表达式值,则为1;否则为0 |
14 |
== |
等于 |
9 |
二进制运算符。左边带符号表达式值等于右边带符号表达式值,则为1;否则为0 |
15 |
!= |
不等于 |
9 |
二进制运算符。左边带符号表达式值不等于右边带符号表达式值,则为1;否则为0 |
16 |
& |
逐位与 |
8 |
二进制运算符。两个表达式值之间逐位与 |
17 |
^ |
逐位异或 |
7 |
二进制运算符。两个表达式值之间逐位异或 |
18 |
| |
逐位或 |
6 |
二进制运算符。两个表达式值之间逐位或 |
19 |
&& |
逻辑与 |
5 |
二进制运算符。两个表达式值之间逻辑与,全非0则为1;否则为0 |
20 |
|| |
逻辑或 |
4 |
二进制运算符。两个表达式值之间逻辑或,非0则为1;全0为0 |
表达式可以用小括号“(”“)”括起来,并且与括号外其他任意的表达式再组合成表达式。
11.ATMEGA16指令集汇总:
1)算术和逻辑指令:
指令 |
操作数 |
功能 |
执行的操作 |
影响的标志位 |
周期 |
ADD |
Rd, Rr |
无进位加法 |
Rd=Rd+Rr |
Z C N V H S |
1 |
ADC |
Rd, Rr |
带进位加法 |
Rd=Rd+Rr+C |
Z C N V H S |
1 |
ADIW |
Rd, K |
双字节加法 |
Rd+1:Rd, K |
Z C N V S |
2 |
SUB |
Rd, Rr |
无进位减法 |
Rd=Rd-Rr |
Z C N V H S |
1 |
SUBI |
Rd, K8 |
立即数减法 |
Rd=Rd-K8 |
Z C N V H S |
1 |
SBC |
Rd, Rr |
带进位减法 |
Rd=Rd-Rr-C |
Z C N V H S |
1 |
SBCI |
Rd, K8 |
带进位立即数减法 |
Rd=Rd-K8-C |
Z C N V H S |
1 |
AND |
Rd, Rr |
逻辑与 |
Rd=Rd&Rr |
Z N V S |
1 |
ANDI |
Rd, K8 |
立即数逻辑与 |
Rd=Rd&K8 |
Z N V S |
1 |
OR |
Rd, Rr |
逻辑或 |
Rd=Rd∨Rr |
Z N V S |
1 |
ORI |
Rd, K8 |
立即数逻辑或 |
Rd=Rd∨K8 |
Z N V S |
1 |
EOR |
Rd, Rr |
逻辑异或 |
Rd=Rd⊕Rr |
Z N V S |
1 |
COM |
Rd |
求补数 |
Rd=$FF-Rd |
Z N V S |
1 |
NEG |
Rd |
求负数 |
Rd=$00-Rd |
Z C N V H S |
1 |
SBR |
Rd, K8 |
置寄存器中的位 |
Rd=Rd∨K8 |
Z C N V S |
1 |
CBR |
Rd, K8 |
清除寄存器中的位 |
Rd=Rd&($FF-K8) |
Z C N V S |
1 |
INC |
Rd |
寄存器加1 |
Rd=Rd+1 |
Z N V S |
1 |
DEC |
Rd |
寄存器减1 |
Rd=Rd-1 |
Z N V S |
1 |
TST |
Rd |
测试寄存器是否为0或负数 |
Rd=Rd&Rd |
Z C N V S |
1 |
CLR |
Rd |
清除寄存器 |
Rd=0 |
Z C N V S |
1 |
SER |
Rd |
置寄存器 |
Rd=$FF |
|
1 |
SBIW |
Rd1, K6 |
用双字节做减法 |
Rdh:Rdl=Rdh:Rdl-K6 |
Z C N V H S |
2 |
MUL |
Rd, Rr |
无符号数乘法 |
R1:R0=Rd*Rr |
Z C |
2 |
MULS |
Rd, Rr |
有符号数乘法 |
R1:R0=Rd*Rr |
Z C |
2 |
MULSU |
Rd, Rr |
有符号数乘无符号数 |
R1:R0=Rd*Rr |
Z C |
2 |
FMUL |
Rd, Rr |
浮点无符号数乘法 |
R1:R0=(Rd*Rr)<<1 |
Z C |
2 |
FMULS |
Rd, Rr |
浮点符号数乘法 |
R1:R0=(Rd*Rr)<<1 |
Z C |
2 |
FMULSU |
Rd, Rr |
浮点符号数乘无符号数 |
R1:R0=(Rd*Rr)<<1 |
Z C |
2 |
2)分支指令:
指令 |
操作数 |
功能 |
执行的操作 |
影响的标志位 |
周期 |
RJMP |
K |
相对跳转 |
PC=PC+K+1 |
- |
2 |
IJMP |
|
非直接跳转到Z |
PC=Z |
- |
2 |
JMP |
K |
跳转 |
PC=K |
- |
3 |
RCALL |
K |
调用进程子程序 |
STACK=PC+1, PC=PC+K+1 |
- |
3/4 |
ICALL |
|
非直接调用,跳到Z |
STACK=PC+1, PC=Z |
- |
3/4 |
CALL |
K |
调用子程序 |
STACK=PC+2, PC=K |
- |
4/5 |
RET |
|
子程序返回 |
PC=STACK |
- |
4/5 |
RETI |
|
中断返回 |
PC=STACK |
I |
4/5 |
CPSE |
Rd, Rr |
比较,如果相等则忽略 |
If Rd=Rr, PC=PC+2或PC+3 |
- |
1/2/3 |
CP |
Rd, Rr |
比较 |
Rd-Rr |
Z C N V H S |
1 |
CPC |
Rd, Rr |
带进位比较 |
Rd-Rr-C |
Z C N V H S |
1 |
CPI |
Rd, K8 |
与立即数比较 |
Rd-K |
Z C N V H S |
1 |
SBRC |
Rd, b |
如果寄存器中的位清除则忽略 |
If Rr(b)==0, PC=PC+2或PC+3 |
- |
1/2/3 |
SBRS |
Rr, b |
如果寄存器中的位置位则忽略 |
If Rr(b)==1, PC=PC+2或PC+3 |
- |
1/2/3 |
SBIC |
P, b |
如果I/O寄存器中的位清除则忽略 |
If IO(P, b)==0, PC=PC+2或PC+3 |
- |
1/2/3 |
SBIS |
P, b |
如果I/O寄存器中的位置位则忽略 |
If IO(P, b)==1, PC=PC+2或PC+3 |
- |
1/2/3 |
BRBC |
S, K |
如果状态标志清除则跳转 |
If(SREG(s)==0), PC=PC+k+1 |
- |
1/2 |
BRBS |
S, K |
如果状态标志置位则跳转 |
If(SREG(s)==1), PC=PC+k+1 |
- |
1/2 |
BREQ |
K |
如果相等则跳转 |
If(Z==0), PC=PC+k+1 |
- |
1/2 |
BRNE |
K |
如果不等则跳转 |
If(Z==1), PC=PC+k+1 |
- |
1/2 |
BRCS |
K |
如果进位置位则跳转 |
If(C==1), PC=PC+k+1 |
- |
1/2 |
BRCC |
K |
如果进位清除则跳转 |
If(C==0), PC=PC+k+1 |
- |
1/2 |
BRSH |
K |
如果相等或大于则跳转 |
If(C==0), PC=PC+k+1 |
- |
1/2 |
BRLO |
K |
如果小于则跳转 |
If(C==1), PC=PC+k+1 |
- |
1/2 |
BRMI |
K |
如果负数则跳转 |
If(N==1), PC=PC+k+1 |
- |
1/2 |
BRPL |
K |
如果正数则跳转 |
If(N==0), PC=PC+k+1 |
- |
1/2 |
BRGE |
K |
如果大于等于则跳转 |
If(S==0), PC=PC+k+1 |
- |
1/2 |
BRLT |
K |
如果小于则跳转 |
If(S==1), PC=PC+k+1 |
- |
1/2 |
BRHS |
K |
如果半进位置位则跳转 |
If(H==1), PC=PC+k+1 |
- |
1/2 |
BRHC |
K |
如果半进位清除则跳转 |
If(H==0), PC=PC+k+1 |
- |
1/2 |
BRTS |
K |
如果T标志置位则跳转 |
If(T==1), PC=PC+k+1 |
- |
1/2 |
BRTC |
K |
如果T标志清除则跳转 |
If(T==0), PC=PC+k+1 |
- |
1/2 |
BRVS |
K |
如果溢出标志置位则跳转 |
If(V==1), PC=PC+k+1 |
- |
1/2 |
BRVC |
K |
如果溢出标志清除则跳转 |
If(V==0), PC=PC+k+1 |
- |
1/2 |
BRIE |
K |
如果中断使能则跳转 |
If(I==1), PC=PC+k+1 |
- |
1/2 |
BRID |
K |
如果中断禁止则跳转 |
If(I==0), PC=PC+k+1 |
- |
1/2 |
3)数据传送指令:
指令 |
操作数 |
功能 |
执行的操作 |
影响的标志位 |
周期 |
MOV |
Rd, Rr |
复制寄存器 |
Rd=Rr |
- |
1 |
MOVW |
Rd, Rr |
双字节复制寄存器 |
Rd+1:Rd=Rr+1:Rr |
- |
1 |
LDI |
Rd, K8 |
立即数赋值 |
Rd=K |
- |
1 |
LDS |
Rd, K |
直接地址赋值 |
Rd=(K) |
- |
2 |
LD |
Rd, X |
非立即数赋值 |
Rd=(X) |
- |
2 |
LD |
Rd, X+ |
非立即数赋值且X值加1 |
Rd=(X), X=X+1 |
- |
2 |
LD |
Rd, -X |
非立即数赋值且X预减1 |
X=X-1, Rd=(X) |
- |
2 |
LD |
Rd, Y |
非立即数赋值 |
Rd=(Y) |
- |
2 |
LD |
Rd, Y+ |
非立即数赋值且Y值加1 |
Rd=(Y), Y=Y+1 |
- |
2 |
LD |
Rd, -Y |
非立即数赋值且Y预减1 |
Y=Y-1, Rd=(Y) |
- |
2 |
LDD |
Rd, Y+q |
带偏移的非立即数赋值 |
Rd=(Y+q) |
- |
2 |
LD |
Rd, Z |
非立即数赋值 |
Rd=(Z) |
- |
2 |
LD |
Rd, Z+ |
非立即数赋值且Z值加1 |
Rd=(Z), Z=Z+1 |
- |
2 |
LD |
Rd, -Z |
非立即数赋值且Z预减1 |
Z=Z-1, Rd=(Z) |
- |
2 |
LDD |
Rd, Z+q |
带偏移的非立即数赋值 |
Rd=(Z+q) |
- |
2 |
STS |
K, Rr |
地址存储 |
(K)=Rr |
- |
2 |
ST |
X, Rr |
非直接存储 |
(X)=Rr |
- |
2 |
ST |
X+, Rr |
非直接存储且X值加1 |
(X)=Rr, X=X+1 |
- |
2 |
ST |
-X, Rr |
非直接存储且X预减1 |
X=X-1, (X)=Rr |
- |
2 |
ST |
Y, Rr |
非直接存储 |
(Y)=Rr |
- |
2 |
ST |
Y+, Rr |
非直接存储且X值加1 |
(Y)=Rr, Y=Y+1 |
- |
2 |
ST |
-Y, Rr |
非直接存储且X预减1 |
Y=Y-1, (Y)=Rr |
- |
2 |
ST |
Y+q, Rr |
带偏移的非直接存储 |
(Y+q)=Rr |
- |
2 |
ST |
Z, Rr |
非直接存储 |
(Z)=Rr |
- |
2 |
ST |
-Z, Rr |
非直接存储且X预减1 |
Z=Z-1, (Z)=Rr |
- |
2 |
ST |
Z+q, Rr |
带偏移的非直接存储 |
(Z+q)=Rr |
- |
2 |
LPM |
|
调入程序存储器 |
R0=(Z) |
- |
3 |
LPM |
Rd, Z |
调入程序存储器 |
Rd=(Z) |
- |
3 |
LPM |
Rd, Z+ |
调入程序存储器且Z加1 |
Rd=(Z), Z=Z+1 |
- |
3 |
SPM |
|
保存入程序存储器 |
(Z)=R1:R0 |
- |
- |
IN |
Rd, P |
端口输入 |
Rd=P |
- |
1 |
OUT |
P, Rr |
端口输出 |
P=Rr |
- |
1 |
PUSH |
Rr |
将寄存器入栈 |
STACK=Rr |
- |
2 |
POP |
Rd |
将寄存器出栈 |
Rd=STACK |
- |
2 |
4)位与位测试指令:
指令 |
操作数 |
功能 |
执行的操作 |
影响的标志位 |
周期 |
LSL |
Rd |
逻辑左移 |
Rd(n+1)=Rd(n), Rd(0)=0, C=Rd(7) |
Z C N V H S |
1 |
LSR |
Rd |
逻辑右移 |
Rd(n)=Rd(n+1), Rd(7)=0, C=Rd(0) |
Z C N V S |
1 |
ROL |
Rd |
带进位逻辑左移 |
Rd(0)=C, Rd(n+1)=Rd(n), C=Rd(7) |
Z C N V H S |
1 |
ROR |
Rd |
带进位逻辑右移 |
Rd(7)=C, Rd(n)=Rd(n+1), C=Rd(0) |
Z C N V S |
1 |
ASR |
Rd |
算术右移 |
Rd(n)=Rd(n+1), n=0, ......, 6 |
Z C N V S |
1 |
SWAP |
Rd |
高低位交换 |
Rd(3..0)=Rd(7..4), Rd(7..4)=Rd(3..0) |
- |
1 |
BSET |
s |
标志置位 |
SREG(s)=1 |
SREG(s) |
1 |
BCLR |
s |
标志清除 |
SREG(s)=0 |
SREG(s) |
1 |
SBI |
P, b |
I/O寄存器置位 |
I/O(P, b)=1 |
- |
2 |
CBI |
P, b |
I/O寄存器清除 |
I/O(P, b)=0 |
- |
2 |
BST |
Rr, b |
从寄存器存入T |
T=Rr(b) |
T |
1 |
BLD |
Rd, b |
从T存入寄存器 |
Rr(b)=T |
- |
1 |
SEC |
|
设置进位标志 |
C=1 |
C |
1 |
CLC |
|
清除进位标志 |
C=0 |
C |
1 |
SEN |
|
设置负数标志 |
N=1 |
N |
1 |
CLN |
|
清除负数标志 |
N=0 |
N |
1 |
SEZ |
|
设置零标志 |
Z=1 |
Z |
1 |
CLZ |
|
清除零标志 |
Z=0 |
Z |
1 |
SEI |
|
设置中断标志 |
I=1 |
I |
1 |
CLI |
|
清除中断标志 |
I=0 |
I |
1 |
SES |
|
设置符号标志 |
S=1 |
S |
1 |
CLN |
|
清除符号标志 |
S=0 |
S |
1 |
SEV |
|
设置溢出标志 |
V=1 |
V |
1 |
CLV |
|
清除溢出标志 |
V=0 |
V |
1 |
SET |
|
设置T标志 |
T=1 |
T |
1 |
CLT |
|
清除T标志 |
T=0 |
T |
1 |
SEH |
|
设置半进位标志 |
H=1 |
H |
1 |
CLH |
|
清除半进位标志 |
H=0 |
H |
1 |
NOP |
|
无操作 |
- |
- |
1 |
SLEEP |
|
睡眠 |
|
- |
1 |
WDR |
|
看门狗复位 |
|
- |
1 |