天天看点

d你好Arduino

有​

​两个​

​​选项可链接​

​ldc​

​​发出的​

​编译目标文件​

​​:用​

​avr-gcc​

​​的链接器,或用​

​llvm​

​​的内部链接器.​

​-gcc=avr-gcc​

​​参数告诉在哪查找​

​avr-gcc​

​​工具,或可用使用​

​llvm​

​​的内置链接器的​

​--link-internally​

​​.两者都会起作用.

使用​​

​-gcc​

​​相关的好处是可​

​arduino studio​

​​,因为它有​

​objcopy,avrdude​

​​等程序及其他有用的东西.让它正常工作,并更好地​

​集成​

​​与其他库和工具等一起使用,如​

​gcc​

​提供的C运行时.

$ PATH=/opt/arduino/arduino-1.8.10/hardware/tools/avr/bin:$PATH ldc2 -betterC -Oz -mtriple=avr -mcpu=atmega328p -gcc=avr-gcc delay.d
$ file delay
delay: ELF 32-bit LSB executable, Atmel AVR 8-bit, version 1 (SYSV), statically linked, with debug_info, not stripped
$ ls -l delay
-rwxr-xr-x 1 me users 2440 Sep 18 08:28      

使用​

​PATH​

​​中的​

​arduino​

​​工具,​

​-gcc=avr-gcc​

​​参数就可工作.

使用​​

​--link-internally​

​,你不需要这些,但是:

$ ldc2 -betterC -Oz -mtriple=avr -mcpu=atmega328p --link-internally delay.d
lld: warning: cannot find entry symbol _start; defaulting to 0x110B4
$ file delay
delay: ELF 32-bit LSB executable, Atmel AVR 8-bit, version 1 (SYSV), statically linked, not stripped
$ ls -l delay
-rwxr-xr-x 1 me users 708 Sep 18 08:31      

注意它​

​链接​

​​了,但它给出了关于丢失​

​_start​

​​的警告.还要注意​

​不同​

​​的文件大小.这是因为​

​gcc​

​​提供的C运行时,提供了调用你的​

​extern(C)main​

​​来执行一些​

​基本设置​

​​的​

​开始​

​​符号.没有它,你需要​

​自己​

​​做更多的事情.我敢肯定,你也可在链接命令中列举​

​lib/object​

​​文件来让​

​ldc​

​​链接,但是使用​

​-avr-gcc​

​​,可正常工作,因为它已知道​

​在哪​

​​可找到所有​

​这些东西​

​.

​​avr链接​​​,有点过时.

可用标准的​​

​ldc2​

​​安装,只需从​

​ldc​

​​网站获取​

​二进制​

​​.你不必自己编译它;正常下载中,​

​avr​

​​支持已有一段时间了.

得到​​

​ldc​

​​后,先安装​

​arduino​

​​工具.我直接安装​

​ArduinoStudio​

​​.我把文件放在​

​/opt/arduino/arduino-1.8.10/​

​​中.你可能要​

​调整​

​​该路径.在那里,你会看到​

​arduino​

​命令,硬件目录等.

me@arsd:/opt/arduino/arduino-1.8.10$ ls
arduino          arduino-linux-setup.sh  hardware    java  libraries  revisions.txt  tools-builder
arduino-builder  examples                install.sh  lib   reference  tools          uninstall.sh      

写个测试:

import ldc.llvmasm;

// delay_basic.h中的移植
void _delay_loop_1(ubyte __count) {
//该模板参数是必需的,以避免
//`!Call.getType()->isVoidTy()&&"Badinlineasm!"'`断定失败.
        __asm!ubyte (
                "1: dec $0\n\tbrne 1b",
                "=r,0", (__count)
        );
}
void _delay_loop_2(ushort __count) {
        __asm!ushort (`
    1: sbiw $0,1
    brne 1b
    `,
    `=w,0`,
    __count);
}

// arduino 中 delay.h 的端口
enum F_CPU = 1000000UL;

 // 这是`_delay_ms`,但我做错了,把`double`改成`int`,我还是不喜欢
void _delay(int __ms) {
    ushort __ticks;
    ulong __tmp = (F_CPU * __ms) / 4000;
    if(__tmp < 1)
        __ticks = 1;
    else if(__tmp > 65535) {
        __ticks = cast(ushort) (__ms * 10.0);
        while(__ticks) {
            _delay_loop_2(cast(ushort) (((F_CPU) / 4e3) / 10));
            __ticks--;
        }
        return;
    } else
        __ticks = cast(ushort) __tmp;
    _delay_loop_2(__ticks);
}


 // 这是来自`WebFreak`在`Dwiki`上的示例代码

enum AVR_ARCH = 5; // MCU 的 AVR 架构

static if (AVR_ARCH >= 100) {
 enum SFR_OFFSET = 0x00;
} else {
 enum SFR_OFFSET = 0x20;
}

enum ubyte* MMIO_BYTE(ubyte memAddr) = cast(ubyte*) memAddr;
enum ubyte* SFR_IO8(ubyte ioAddr) = MMIO_BYTE!(ioAddr + SFR_OFFSET);

enum ubyte* PINB = SFR_IO8!(0x03);
enum ubyte* DDRB = SFR_IO8!(0x04);
enum ubyte* PORTB = SFR_IO8!(0x05);

extern(C) void main() {
  import core.volatile;

  volatileStore(DDRB, 0xFF);
    //端口所有B设置为输出

  // 我添加了延迟

  while (true) {
    volatileStore(PORTB, 0xFF);
    //端口所有B设置为高
    foreach(i; 0 .. 10)
        _delay(1000);
    volatileStore(PORTB, 0x00);
    //端口所有B设置为低
    foreach(i; 0 .. 20)
        _delay(1000);
  }
}      

先,​

​make​

​文件:

# Makefile
$ cat Makefile
all:
        ldc2 delay.d -betterC -Oz -mtriple=avr -mcpu=atmega328p -Xcc=-mmcu=atmega328p -gcc=avr-gcc
        avr-objcopy -O ihex -R .eeprom delay delay.hex
        avrdude -F -V -c arduino -p ATMEGA328P -P /dev/ttyACM0 -b 115200 -U flash:w:delay.hex -C /opt/arduino/arduino-1.8.10/hardware/tools/avr/etc/avrdude.conf      

请不要在​

​最后一行​

​​的路径,再次安装​

​arduino​

​​.

要运行它,请设置​​

​PATH​

​​为你的​

​arduino​

​​安装,并运行​

​make​

​,如下所示:

PATH=/opt/arduino/arduino-1.8.10/hardware/tools/avr/bin:$PATH make      

这编译​

​D代码​

​​,然后把它​

​复制​

​​到​

​arduino​

​​硬件并​

​开始​

​​运行它.灯(及连接到​

​引脚​

​​上的其他东西)闪烁.

如果查看上面链接的​​

​wiki​

​​页面,其中​

​大部分​

​​内容很熟悉.我随意​

​复制/粘贴​

​​.

需要注意的一些​​

​重要事项​

​​:

1,不能用​​

​extern(C)​

​​从​

​arduinoC​

​​的头文件中调用​

​delay_ms​

​​,因为它是按内联函数​

​定义​

​​的.库或目标文件中没有​

​内联函数​

​​;你必须​

​移植​

​​源.

​​​源​​​

​WebFreak​

​在此移植了源码,我解释下.

​gcc​

​和​

​ldc​

​中的内联​

​asm​

​略有不同.这是文件中的​

​_delay_loop_1​

​:

void _delay_loop_1(uint8_t __count)
{
    __asm__ volatile (
        "1: dec %0" "\n\t"
        "brne 1b"
        : "=r" (__count)
        : "0" (__count)
    );
}      

而,如下是​

​D​

​文件中:

import ldc.llvmasm;
// delay_basic.h中的移植
void _delay_loop_1(ubyte __count) {
//该模板参数是必需的,以避免
//`!Call.getType()->isVoidTy()&&"Badinlineasm!"'`断定失败.

    __asm!ubyte (
        "1: dec $0\n\tbrne 1b",
        "=r,0", (__count)
    );
}      

继续阅读