首页 > 编程语言 >AVR汇编(四):数据传送指令

AVR汇编(四):数据传送指令

时间:2023-08-11 21:55:25浏览次数:55  
标签:R16 汇编 传送 R0 LDI AVR 指令 0xAA 寄存器

AVR汇编(四):数据传送指令

AVR指令主要分为五类:算术和逻辑指令、分支指令、位操作指令、数据传送指令、MCU控制指令,今天我们先来认识其中最常用的数据传送指令。

汇编程序的编写、编译和调试

学习任何技术都离不开实践,汇编语言也是如此。在正式学习指令前,我们先来体验一下汇编程序从编写到编译,再到调试的整个过程。

伪指令

根据百度百科:伪指令(Pseudo Instruction)是用于对汇编过程进行控制的指令,该类指令并不是可执行指令,没有机器代码,只用于汇编过程中为汇编程序提供汇编信息。

下面是几个常用的伪指令:

伪指令 说明 举例
.section 定义一个段 .section .text
.section .data
.global 定义一个全局符号 .global _start
.byte 定义一个字节数据 .byte 0x01
.word 定义一个字数据 .word 0x3412
.ascii 定义一个字符串数据 .ascii "hello"
.align 设置对齐方式 .align 4
.equ 定义一个符号常量,类似于C宏定义 .equ INT8_MAX, 0xFF

第一个汇编程序

.equ PINB, 0x03
.equ DDRB, 0x04
.equ PORTB, 0x05

.section .text        ; 定义text段
.global _start        ; 定义一个全局符号_start

_start:
    LDI R16, 0x20     ; R16 = 0x20
    OUT DDRB, R16     ; 设置PB5为输出
    OUT PORTB, R16    ; PB5初始输出高电平
loop:
    OUT PINB, R16     ; 翻转PB5电平
    RJMP loop         ; 跳转到loop处继续执行

上述程序实现的功能很简单,就是不断翻转PB5的电平状态。

使用下面的命令进行编译,生成elf文件:

avr-gcc -mmcu=atmega328p -x assembler-with-cpp -g -Og -Wall -c -o hello.o hello.s
avr-gcc -mmcu=atmega328p -nostartfiles -o hello.elf hello.o

其中, -x assembler-with-cpp 表示编译汇编程序, -nostartfiles 表示不添加默认启动文件,启动文件的作用是初始化MCU,创建C语言运行环境,由于这里编写的是汇编程序,所以不需要它,否则编译时会提示找不到 main 函数。

为了以后每次重新编译的时候不用都输一遍命令,可以写一个 Makefile 文件:

.PHONY: all clean
TARGET := hello

all: $(TARGET).elf

%.o: %.s
        avr-gcc -mmcu=atmega328p -x assembler-with-cpp -g -Og -Wall -c -o $@ $<

$(TARGET).elf: $(TARGET).o
        avr-gcc -mmcu=atmega328p -nostartfiles -o $@ $<

clean:
        rm -f *.o $(TARGET).elf

调试程序

使用 simavr 对上面生成的elf文件进行仿真:

simavr -f 16000000 -m atmega328p --gdb hello.elf

为了方便,可以在 Makefile 中添加一个 run 伪目标,将上面的命令添加进去:

.PHONY: all clean run

...

run: $(TARGET).elf
        simavr -f 16000000 -m atmega328p --gdb $<

之后需要仿真时,直接执行 make run 即可。

使用 avr-gdb 对程序进行调试, simavr 的GDB端口是 1234

avr-gdb -ex "target remote localhost:1234" -ex "layout split" -q --tui hello.elf

image.png

在GDB窗口中,可以输入 s 进行单步执行。

为了观察 PINBDDRBPORTB 寄存器的值,可以借助 x/<n/f/u> <addr> 命令,其中 n 表示要查看的值的个数; f 指定显示格式,如果要十六进制显示,这里就要指定 xu 表示值的单位,如果单位是字节,这里就要指定 b 。这条命令的具体使用方法可以通过 help x 命令查看。

这里我们查看从I/O地址0x03开始的3个字节:

x/3xb 0x03      # 注意,这里的地址是错误的!

结果如下:

image.png

发现读取的值并不符合我们的预期,这是因为上面命令中的地址设置错了,有两个因素:

  1. PINBDDRBPORTB 在I/O空间的地址是0x03开始,而在数据空间中的地址需要加上0x20;
  2. AVR的程序空间和数据空间是分别独立编址的,因此地址存在重叠情况。通过 avr-readelf -S hello.elf 查看,可以发现 .data 段的地址是从0x800100开始的,而实际的SRAM地址是从 0x0100 开始的,因此可以知道elf文件中数据空间的地址还需要加上0x800000,如果不加,则代表的是 .text 段(Flash)的地址。

image.png

通过上面的分析,将命令中的地址改为0x800023即可正确查看 PINBDDRBPORTB 中的内容:

x/3xb 0x800023

结果如下:

image.png

这样显示的结果与我们的程序逻辑是一致的。

数据传送指令

由于AVR具有多种寻址方式,因此数据传送指令也对应有多种。

空间 指令
寄存器堆 MOV
数据空间 LD / ST
程序空间 LPM / SPM
I/O空间 IN / OUT
栈空间 PUSH / POP

一般而言,AVR指令如果有两个操作数,则第一个是目的操作数,第二个是源操作数。

MOV

image.png

MOV 指令用于寄存器之间的数据传送(一个字节),后缀如果加 W 表示传送一个字的数据。

例如:

LDI  R16, 0x10    ; R16 = 0x10
MOV  R0, R16      ; R0 = 0x10

LDI  R16, 0x20    ; R16 = 0x20
LDI  R17, 0x30    ; R17 = 0x30
MOVW R0, R16      ; R0 = 0x20, R1 = 0x30

LD

image.png

LD 指令用于将数据从数据空间加载到寄存器中,后缀加 I 表示加载立即数,加 D 表示偏移量寻址,加 S 表示直接寻址。

X / Y / Z 寄存器可以用于间接寻址,如果前缀加 - ,表示执行操作前寄存器的值自减一,如果后缀加 + ,表示执行操作后寄存器的值自加一。

Y / Z 寄存器可以用于偏移量寻址(注意不包括 X 寄存器),后面加 +q 表示偏移量为 q

例如:

LDI R16, 0xAA    ; R16 = 0xAA
LDI XL, 0x00
LDI XH, 0x01     ; X = 0x0100
ST  X, R16       ; (0x0100) = 0xAA
LD  R0, X+       ; R0 = 0xAA, X = 0x0101

LDI ZL, 0xF1
LDI ZH, 0x00     ; Z = 0x00F1
LDD R1, Z+0xF    ; R1 = 0xAA

LDS R2, 0x0100   ; R2 = 0xAA

ST

image.png

ST 指令用于将数据从寄存器写入到数据空间中,后缀加 D / S 的意义同 LD ,注意 ST 不支持立即寻址,即没有 STI 这样的指令!

例如:

LDI R16, 0x55    ; R16 = 0x55
LDI XL, 0x80
LDI XH, 0x01     ; X = 0x0180
ST  X, R16       ; (0x0180) = 0x55
LD  R0, X        ; R0 = 0x55

LDI R16, 0xAA    ; R16 = 0xAA
LDI ZL, 0x50
LDI ZH, 0x01     ; Z = 0x0150
STD Z+0x30, R16  ; (0x0180) = 0xAA
LD  R1, X        ; R1 = 0xAA

LDI R16, 0xA5    ; R16 = 0xA5
STS 0x0180, R16  ; (0x0180) = 0xA5
LD  R2, X        ; R2 = 0xA5

LPM / SPM

image.png

LPM / SPM 指令用于将数据从程序空间加载到寄存器/从寄存器写入到程序空间。

例如:

LDI ZL, lo8(const)
LDI ZH, hi8(const)      ; Z = const
LPM R0, Z+              ; R0 = 0xA5, Z = CONST + 1
LPM R1, Z+              ; R1 = 0x5A, Z = CONST + 2
LPM R2, Z+              ; R2 = 0x55, Z = CONST + 3
LPM R3, Z               ; R3 = 0xAA

const:
.byte 0xA5
.byte 0x5A
.word 0xAA55

SPM 指令的用法较为特殊,后面有机会再来介绍。

IN / OUT

image.png

IN / OUT 用于从I/O空间读入数据到寄存器/向I/O空间写入寄存器中的数据,注意 P 为I/O空间的地址,此命令不能访问扩展I/O空间。

例如:

OUT DDRB, 0x00    ; DDRB = 0xAA
IN  R0, DDRB      ; R0 = 0xAA

PUSH / POP

image.png

PUSH / POP 用于将数据压入/弹出栈,使用时需要注意SP的初始值要设置正确(AVR是空减栈),并要避免出现栈溢出的情况。

例如:

LDI  R16, 0xA5    ; R16 = 0xA5
PUSH R16          ; (SP) = 0xA5, SP -= 1
POP  R0           ; R0 = 0xA5, SP += 1

参考资料

  1. ATmega328P Datasheet
  2. AVR Instruction Set Manual
  3. 百度百科 - 伪指令

标签:R16,汇编,传送,R0,LDI,AVR,指令,0xAA,寄存器
From: https://www.cnblogs.com/chinjinyu/p/17624021.html

相关文章

  • AVR汇编(二):AVR架构介绍
    AVR汇编(二):AVR架构介绍ATmega328P介绍ATmega328P是Atmel公司(现Microchip公司)推出的一个基于AVR架构的高性能低功耗单片机,拥有32KB的Flash、1KB的EEPROM以及2KB的SRAM等资源,具体如下表:资源主要特征Flash32KB频率16MHzEEPROM1024B定时器2个8bit,1个16bitP......
  • AVR汇编(一):搭建交叉编译环境
    AVR汇编(一):搭建交叉编译环境几年间,陆陆续续接触了很多热门的单片机,如STC、STM8S、STM32、ESP32等。但一直都是抱着急功近利的心态去学习他们,基本上都是基于库函数和第三方组件进行开发,很少静下心来去研究这些不同内核单片机的底层工作原理。因此我打算接下来一段时间好好研究一番,......
  • 汇编-xor异或
     XOR指令在两个操作数的对应位之间进行(按位)逻辑异或(XOR)操作如果两个位值相同(同为0或同为1),则结果位等于0;否则结果位等于1【相同为0,不同为1】      ......
  • 汇编语言开发环境搭建
    汇编语言开发环境搭建简述学习汇编的意义:汇编语言有着简单的语法,它更加贴近硬件,而不像高级语言有着自己的语言抽象层关于主引导扇区主引导扇区:处理器上电或复位后,如果系统由硬盘启动,那么ROM-BIOS将试图读取硬盘0面0道1扇区,这块就是主引导扇区(MainBootSector)缩写:M......
  • 正点原子ARM裸机开发003----汇编LED驱动实验1-原理分析
    一、汇编LED原理分析为什么要学习Coretex-A汇编?需要用汇编初始化一些SOC外设使用汇编初始化DDR,IMX6U不需要设置sp指针,一般指向DDR,设置好C语言运行环境ALPHA开发板LED灯硬件原理分析:STM32 IO初始化流程:使能GPIO时钟设置IO复用,将其复用为GPIO配置GPIO的电气属性使用G......
  • 【汇编随笔】在汇编中使用数据
    在内存中怎么存储数据需要将数据放在连续的内存单元中。DWdw0123h,0456hdw是定义字型数据,这里定义了2个字型数据,4个字节。如何寻得数据地址assumecs:codecodesegmentdw0123h,0456h...codeendsend因为数据定义在代码段中,代码段的所有数据都存放在CS中,定义......
  • 恶意c2家族反汇编
     协议当日家族TOP5及数量HTTPtrojan:win32/emotetcrypt:2162trojan:win32/emotet:453trojan:win32/wacatac:342trojan:win32/smokeloader:181trojan:win32/woreflint:164HTTPStrojan:win32/smokeloader:744virtool:win32/ceeinject:118trojan:win32/wacatac:6......
  • idea查看java代码汇编指令
    将下列jar包放入到jre的bin目录下面   hsdis-amd64.dll指定java的jvm参数-server-Xcomp-XX:+UnlockDiagnosticVMOptions-XX:+PrintAssembly-XX:CompileCommand=compileonly,*VolitaleDemo.main运行......
  • 汇编语言初识
    汇编语言初识8086所有的编程语言都是一种解决问题的方法如果说java,C++,go,python之类的编程语言是面向对象的编程语言C,Pasical之类的编程语言是面向过程的编程语言那么像汇编这样的底层编程语言,应该就是所谓的面向CPU的编程语言因为它从头到尾都是和CPU在打交道万物皆......
  • 汇编-彩色字符模式显示缓冲区结构
      80×25彩色字符模式显示缓冲区的结构:1.内存地址空间中,B8000H~BFFFFH共32KB的空间,为80×25彩色字符模式的显示缓冲区。向这个地址空间写入数据,写入的内容将立即出现在显示器上2.在80×25彩色字符模式下,显示器可以显示25行,每行80个字符,每个字符可以有256种属性(背景色、前景......