Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/assembly/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Loops AVR组件BRNE延迟环路如何工作?_Loops_Assembly_Delay_Avr - Fatal编程技术网

Loops AVR组件BRNE延迟环路如何工作?

Loops AVR组件BRNE延迟环路如何工作?,loops,assembly,delay,avr,Loops,Assembly,Delay,Avr,An给了我一个运行在16MHz的芯片0.5s的延时循环 我脑子里的问题是: 如果寄存器变为负数,分支是否保持分支 如何准确计算开始时加载的值 ldi r18, 41 ldi r19, 150 ldi r20, 128 L1: dec r20 brne L1 dec r19 brne L1 dec r18 brne L1 如何准确计算开始时加载的值 ldi r18, 41 ldi r19, 150

An给了我一个运行在16MHz的芯片0.5s的延时循环

我脑子里的问题是:

  • 如果寄存器变为负数,分支是否保持分支
  • 如何准确计算开始时加载的值

        ldi  r18, 41
        ldi  r19, 150
        ldi  r20, 128
    L1: dec  r20
        brne L1
        dec  r19
        brne L1
        dec  r18
        brne L1
    
  • 如何准确计算开始时加载的值

        ldi  r18, 41
        ldi  r19, 150
        ldi  r20, 128
    L1: dec  r20
        brne L1
        dec  r19
        brne L1
        dec  r18
        brne L1
    
    计算循环总量=>0.5s*16000000=8000000

    知道r20和r19循环的总周期(从零到零),AVR寄存器为8位,因此完整循环为256次(
    dec0=255
    dec
    为1个周期
    brne
    条件(分支)发生时为2个周期,不发生时为1个周期

    因此,最内部的循环:

    L1: dec  r20
        brne L1
    
    从零到零(
    r20=0
    ):255*(1+2)+1*(1+1)=767个周期(255次分支执行,1次分支通过)


    然后,使用
    r19
    的第二个换行循环是:255*(767+1+2)+1*(767+1+1)=197119个循环

    当执行分支时,单个
    r18
    循环为197119+1+2=197122个循环。(197121当未执行分支=延迟循环的最终退出时,我将在下一步中使用技巧避免-1)

    现在,这几乎足以计算初始
    r18
    ,让我们首先通过O(1)代码调整总周期,即三次
    ldi
    指令,需要1个周期:total2=8000000-(1+1+1)+1=7999998。。。等等,最后一个+1是什么?这是一个额外的延迟周期,使最终
    r18
    循环假装成本与非最终相同,即197122个周期


    就是这样,初始的
    r18
    必须足够等待至少
    7999998个周期:
    r18=(7999998+197122-1)div197122=41
    。“+197122-1”部分将确保丰富的循环符合约束条件:
    0准确回答您的问题:

    1:指令不知道“有符号”的数字,它只是对8位寄存器进行递减。Two补码算法的奇迹使其在环绕(0x00->0xFF,是与0->1相同的位模式)下工作。DEC指令还在状态寄存器中设置Z标志,用于确定是否应该发生分支

    2:您可以从AVR手册中看到DEC是单周期指令。BRNE在不分支时也是一个周期,分支时是两个周期。因此,要计算循环的时间,需要计算每条路径的使用次数

    考虑单个DEC/BRNE循环:

        ldi r8 0
    L1: dec r8
        brne L1
    
    该循环将执行256次,即DEC的256个周期,BRNE的512个周期,总共768个周期。在16MHz时,即48us

    将其包装在外部延迟环路中:

        ldi r7 10
        ldi r8 0
    L1: dec r8
        brne L1
        dec r7
        brne L1
    
    您可以看到,每当内循环计数器达到0时,外循环计数器将递减。因此,在我们的示例中,外循环DEC/BRNE将发生10次(768个循环),内循环将发生10 x 256次,因此该循环的总时间为10 x 48us+48us(528us)。对于3个嵌套循环也是如此


    从这里开始,计算每个循环应该执行多少次以达到所需的延迟是很简单的。这是外部循环可以执行的最大迭代次数,少于所需的时间,然后将该时间取出,对下一个嵌套循环执行相同的操作,依此类推,直到最内部的循环填满剩余的少量。

    1。在指令集参考中查找
    brne
    的功能。我假设当结果为非零时,不管是正的还是负的。因此,只需将循环看作使用无符号计数器。另请参阅,您必须计算指令周期来计算此循环所消耗的时间。此循环循环标签
    L1:
    0x00299680(272504)次。(0x29=41d,0x96=150d,0x80=128d)。如果在循环期间执行ISR(中断子程序),则使用循环计算的时间无效;您可以使用适当的指令在延迟循环期间禁用ISR。显然,此计算仅在MCU不执行ISR时有效…:)@SergioFormiggini是的,没有简单的解决办法,只要时间管理是幼稚的循环计数,它就是没有希望的。需要某种类型的片上定时器数据来创建精度较低但更可靠的延时环路。同样,如果这是一种非常专门的系统,只执行一项任务,需要绝对完美的计时,那么禁用所有中断并只让这个完美计时的代码运行是一种有效的方法,那么精度将与CPU中的crystal freq精度相同(这可能不太好?我可能不会在任何重要的事情上使用它)。AVR MCU有很多设置的好计数器。程序员可以使用的一个功能是设置计数数,当计数消失时触发ISR…;)在使用AVR时禁用ISR并不难!在一些AVR(我记得不是全部)中有
    CLI
    SEI
    指令。如果不存在这些指令,则可以在SREG寄存器上设置/重置一个位,该位指示全局ISR已启用或未启用!:)