使用nop组装精确延迟Arduino?

时间:2014-10-08 02:32:18

标签: c assembly arduino arduino-uno

我希望在上升沿信号输入后制作一个非常短的脉冲。

这里的难点在于我想控制(达到高分辨率)脉冲前的延迟时间和脉冲持续时间。我可以通过自己将nops串联起来,硬编码延迟来轻松控制这一点,但是我不知道如何以一定的任意延迟来执行它,具有相同的准确度。

经过很多头痛追逐计时器,然后最终意识到我最终受到中断例程进入/退出时间的限制,我现在正试图通过nops来控制我的延迟。

我假设这个C开关语句将是我想要的(编译之后,希望它会变得高效并且只是将程序计数器更改为正确的位置),但它会产生一些非常奇怪的行为......

  switch(delayTime){
    case 10:
      __asm__ __volatile__("nop");
    case 9:
      __asm__ __volatile__("nop");
    case 8:
      __asm__ __volatile__("nop");
    case 7:
      __asm__ __volatile__("nop");
    case 6:
      __asm__ __volatile__("nop");
    case 5:
      __asm__ __volatile__("nop");
    case 4:
      __asm__ __volatile__("nop");
    case 3:
      __asm__ __volatile__("nop");
    case 2:
      __asm__ __volatile__("nop");
    case 1:
      __asm__ __volatile__("nop");
  }
  PORTD = 0x10;
 ...

理想情况下,我想基本上运行一些编译成这个的代码:(这是C和汇编的一些奇怪的伪代码,仍然不知道如何在汇编中做一些)

0x005 Reg1 = 0xFF-val1      %(where somehow 0xFF is known? / found out?)
0x006 Reg2 =0x1FF-val2
0x007 IJMP Reg1
0x008 NOP
0x009 NOP
0x00A NOP
...
0x0FF MOV 0x40, PORTD  % assign the value 0x40 to the static variable "PORTD"
0x100 IJMP Reg2
0x101 NOP
0x102 NOP
0x103 NOP
0x104 NOP
...
0x1FF MOV 0x00, PORTD   % assign the value 0x00 to the static variable "PORTD"

我总体上不确定如何在运行时/运行期间找到代码的内存位置,这样该程序的“0xFF”和“0x1FF”方面实际上并不是那么糟糕(看起来它是超级危险的只是,得到代码的汇编,然后硬编码...我宁愿不这样做)。另外,虽然很容易用200多个nops充满它,但是如何让IJMP cmd以我想要的方式运行? (老实说,我甚至不知道这是否是我想要的命令)..

我想我一般都在寻找一些汇编命令(我似乎无法找到),它允许我“将N添加到程序计数器”,我可以确保该命令在汇编中运行在它之前至少有N + 1个装配命令,硬编码。

作为旁注,所有这些都是在一个中断例程中执行的,所以我对使用PC感觉并不是那么糟糕...而且,我知道对于多达500次操作来说有点阻塞,但是对于手头的任务来说,时间比作为一个例程的阻塞程度更重要。

1 个答案:

答案 0 :(得分:1)

我不熟悉AVR指令集,但一般的想法是使用CALL指令将程序计数器(PC)放在堆栈上。然后使用POP将PC移动到Z寄存器。然后你可以ADD向Z寄存器输入一些数字,并使用IJMP跳转到结果地址。

沿着这些方向做点什么

delay:  call delay1             ; push the PC onto the stack
delay1: pop  r30                ; pop the PC into the Z registers
        pop  r31
        add  r30,r0             ; add some amount to the PC value
        addc r31,r1
        ijmp                    ; use IJMP to jump to the resulting address
        nop
        nop
        nop
        ...

随机想法:

  • 在8MB机器上,你需要第三个pop来删除第三个字节 堆栈中的PC。
  • Z只有16位,因此该代码必须在第一位 128KB的程序存储器。
  • 我不确定应该弹出哪个寄存器(r30或r31) 第一
  • delay1起,添加到Z的值必须相对于calldelay1的地址压入堆栈。换一种说法, 需要添加的最小金额是6,因为那是 从delay1到第一个nop
  • 的说明数量
  • 最小延迟由六个指令决定,最多为和 包括ijmp。你应该增加r1 / r0(减少数量 nops)相应的。

就像我说的那样,我不是AVR指令集的专家,所以你应该把它作为一般性的建议,并准备花一些时间来制定细节。祝你好运!