在汇编中对 Arduino 进行编程?

Programming the Arduino in assembly?

我知道我可以用 C 语言对 Arduino 进行编程,但是对于我当前的项目(一个很小的 ​​Arduino 内核),我真的更愿意在某些部分使用 Assembly 来学习 Assembly 并可能提高效率。

我可以使用 __ASM__() 之类的东西吗?我真的只能在网上找到有人试图说服问过类似问题的人学习 C,而不是真正回答问题。

谢谢!

我很久以前写和贴的。

.device ATmega168
.equ  DDRB       = 0x04
.equ  PORTB      = 0x05

.org 0x0000
    rjmp RESET

RESET:
    ldi R16,0x20
    out DDRB,R16

    ldi R18,0x00
    ldi R17,0x00
    ldi R20,0x20
Loop:

    ldi R19,0xE8
aloop:
    inc R17
    cpi R17,0x00
    brne aloop

    inc R18
    cpi R18,0x00
    brne aloop

    inc R19
    cpi R19,0x00
    brne aloop

    eor R16,R20
    out PORTB, R16
    rjmp Loop

我使用了 avra 并且可能编写了我自己的 arduino 加载器

blinker01.s.hex : blinker01.s
    avra -fI blinker01.s

clean :
    rm -f blinker01.s.*

你当然可以使用 avr_dude。

gnu 有点不同:

.globl _start
_start:
    rjmp RESET

RESET:
    ldi R18,0x00
    ldi R17,0x00
    ldi R20,0x20
Loop:

    ldi R19,0xE8
aloop:
    inc R17
    cpi R17,0x00
    brne aloop

    inc R18
    cpi R18,0x00
    brne aloop

    inc R19
    cpi R19,0x00
    brne aloop

    rjmp Loop

你真的不需要头文件来定义端口,你可以自己声明。

MEMORY
{
    rom : ORIGIN = 0x00000000, LENGTH = 0x1000
}

SECTIONS
{
    .text : { *(.text*) } > rom
}

avr-as so.s -o so.o
avr-ld -T so.ld so.o -o so.elf
avr-objdump -D so.elf > so.list
avr-objcopy so.elf -O ihex so.hex

使用 apt-got avr-gcc(和 binutils)可能与 arduino 沙箱使用的工具相同,应该可以直接访问,但我不使用沙箱,所以不知道。

编辑

另一种方法是有限的,但使用工具链更有可能成功,因为您从一个工作的 C 应用程序和环境开始,然后添加一个对象,也有助于汇编基础知识,看看编译器做了什么,然后继续阅读它:

unsigned short fun ( unsigned short x, unsigned short y )
{
    return(x+y+5);
}

avr-gcc -c -O2 so.c -o so.o
avr-objdump -D so.o

00000000 <fun>:
   0:   6b 5f           subi    r22, 0xFB   ; 251
   2:   7f 4f           sbci    r23, 0xFF   ; 255
   4:   86 0f           add r24, r22
   6:   97 1f           adc r25, r23
   8:   08 95           ret

所以

创建so.s

.globl fun
fun:
    subi r22, 0xFB  ; 251
    sbci r23, 0xFF  ; 255
    add  r24, r22
    adc  r25, r23
    ret



avr-as so.s -o so.o
avr-objdump -D so.o

00000000 <fun>:
   0:   6b 5f           subi    r22, 0xFB   ; 251
   2:   7f 4f           sbci    r23, 0xFF   ; 255
   4:   86 0f           add r24, r22
   6:   97 1f           adc r25, r23
   8:   08 95           ret

然后不是在 C 生成的对象中 link,而是在程序集生成的对象中 link,您必须学习通过实验可以弄清楚的调用约定。

unsigned char fun ( unsigned char x, unsigned char y )
{
    return(x+(y<<1));
}
00000000 <fun>:
   0:   66 0f           add r22, r22
   2:   86 0f           add r24, r22
   4:   08 95           ret

在这种情况下,r22 中的第二个参数首先在 r24 中,return r24 中的值。所以 22/23 可能是第一个参数,用于较大的项目,如短裤,第二个参数是 24/25。它也会在某个地方记录下来,编译器符合它,会有例外,所以制作一个合适的例子来查看编译器做了什么而不是仅仅假设一个例子中的一切都是关键的,即使你阅读了文档它可能是模糊的或使用在您进行实验之前可能没有意义的术语。