PIC ASM 中的延迟如何工作?我真的很困惑
我真的一点也不明白。我在网上看到的所有代码在评论中都以随机数字说明了为什么要执行这么多周期,但实际上没有解释为什么什么做什么或什么在哪里做什么。我真的不知道。
例如:
cblock
Delay1
Delay2
Delay3
endc
Start:
.
.
.
Delay
movlw .2
movwf Delay1 ;&&&&
movlw .3
movwf Delay2
movlw .4 <------ Important note here. For some reason it loops back to the
movwf Delay3 <------ "&&&&" mark when it reads this piece of code. NO IDEA why
DelayLoop
decfsz Delay1,f <----- Explain what this does. Where does it get the time from?
goto DelayLoop <----- Thanks
decfsz Delay2,f <-----
goto DelayLoop
end
任何帮助都会很棒。
I really don't understand it at all. All the code I see online somehow in the comments has random numbers of why it's doing that many cycles, but there is literally no explanation as to why what does what or where what does who. I really have no idea.
For example:
cblock
Delay1
Delay2
Delay3
endc
Start:
.
.
.
Delay
movlw .2
movwf Delay1 ;&&&&
movlw .3
movwf Delay2
movlw .4 <------ Important note here. For some reason it loops back to the
movwf Delay3 <------ "&&&&" mark when it reads this piece of code. NO IDEA why
DelayLoop
decfsz Delay1,f <----- Explain what this does. Where does it get the time from?
goto DelayLoop <----- Thanks
decfsz Delay2,f <-----
goto DelayLoop
end
Any help would be fantastic.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
“我真的完全不明白。我在网上看到的所有代码在评论中都以随机数字说明了为什么要执行这么多周期,但实际上没有解释为什么什么做什么或什么在哪里做什么。我真的不知道。”
“我理解这一点,但我喜欢,不知道你从哪里得到确切的计时。你如何计算它?这些数字从哪里来。如果我将 VAR1 设置为 15,会发生什么,会发生什么变化。如果我设置三个延迟变量为 4、16、12,这些时间从何而来?这些数字会发生什么情况导致循环达到某个时间?谢谢 – Jimmy Page”
如果我理解您的问题:
16F690 数据表说:
一个指令周期由四个振荡器周期组成,振荡器频率为 4 MHz,这给出了 1 μs 的正常指令执行时间。所有指令都在单个指令周期内执行,除非条件测试为真,或者程序计数器由于指令而改变。发生这种情况时,执行需要两个指令周期,第二个周期作为 NOP 执行。
因此,假设 Delay1 的值为 3,并且我们有这样的循环:
每次执行 decfsz 时,我们都会获得一个周期的库存。如果 f 为零并且我们必须跳过,那么它就变成了两个周期指令。每次执行 goto 时,pc 都会发生变化,因此它是一个 2 周期指令。因此,如果我们遍历循环,并使用
指令之前的 Delay1 值、指令、用于执行的周期、总周期
的格式来显示这一点,那么如果我们以 4mhz 运行,则从 3 开始的 Delay1 循环本身需要 8 个周期或 8us。重要的是首先计算周期,然后调整部件的时钟速率,相同的代码在 2MHz 下运行时可能是 16us,在 1MHz 下运行时可能是 32us。
因此,通过检查我们可以看到,对于不是 1 的 f 值,decfsz+goto 对是 2+1=3 个周期。当我们使用 decfsz 的值为 1 时,它将是 2 个周期。因此,从 Delay1 为 3 开始,将有 2 个非 1 条目值 (3,2)。最后一次点击 decfsz 并跳过时添加 2 个周期,总周期 ((3-1)*3)+2=8。
如果我们在 Delay1 设置为 11 的情况下进入此循环,则将是 ((11-1)*3)+2=32 个周期,7 将是 20 个周期。
如果您更进一步,将一个 decfsz 循环包裹在另一个循环周围,您将继续乘以执行的周期数。如果 Delay1 是 3 进入,Delay2 是 2
那么第一次通过 Delay1 decfsz,goto 循环我们知道是 8 个周期。第一个decfsz Delay2,f 因为Delay2 不是一个1 is 1 的循环,所以我们总共达到9。 goto 还有 2 个,总共 11 个。假设 f 内存是 8 位,那么第二次进入 Delay1 循环时,我们输入 0,将其视为 0x100 或 256,数学给出 ((256-1)3)+2=还有 767 个周期,到目前为止总共 778 个周期。 Delay2 现在是 1,因此这是最终的 decfsz Delay2,f,因此花费了 2 个周期,总共 780 个周期。我们可以想出一个算法来计算接近 ((Delay2-1)(((256-1)*3)+2))+(((Delay1)-1) 的周期*3)+2)+((Delay2-1)*3)+2 个周期。
虽然我的循环比你的小 1 decfsz 循环,但如果你让我的循环与你的相似,因为它以其他一些指令开头:
我们需要为两个 movlw 和两个 movwf 增加 4 个循环到循环数的总体方程中执行。
因此,从字面上看,有一个解释为什么它执行这么多周期。该解释位于该设备的数据表中。
让我们更进一步。让我们让 patrickmdnet 链接到的代码生成器生成 780 个周期:
这个循环的架构有点不同。
我们从加载 f 寄存器的 4 个周期开始,然后到达 Delay_0
内部 decfsz 循环 goto 不会直接分支到 Delay_0,正如您问题中的代码和我上面的解释,这个跳过了 decfsz d2,f。因此,对于非一通过该循环,decfsz 有 1 个周期,goto $+2 有 2 个周期,goto Delay_0 有 2 个周期,每个非 1 d1 总共有 5 个周期。当 d1 为 1 时,再添加两个周期。这样我们就得到了 ((0x9B-1)*5)+2 = 772 个周期,加上之前的 4 个周期,我们达到了 776 个周期。
有趣的是,最后一个 decfsz d1,f 命中了 decfsz d2,f,其中 d2 设置为 0x01,这意味着它肯定会跳过。这是 2 个周期,一个 goto $+2 和另一个 goto $+1 而不是 movlw/movwf 来加载 d2 会做同样的事情。无论如何,这条 2 个周期的指令总共使我们达到 778 个周期,
我们还需要两个周期才能达到 780 个周期,这是通过 goto $+1 完成的,goto 修改 pc,因此它们始终是 2 个周期。我们有我要求程序生成的 780 个周期。
"I really don't understand it at all. All the code I see online somehow in the comments has random numbers of why it's doing that many cycles, but there is literally no explanation as to why what does what or where what does who. I really have no idea."
"I understand that, but I like, don't know where you get EXACT timing from. How do you calculate it? Where do these numbers come from. If I set VAR1 to 15, what happens, what changes. If I set the three delay variables to 4, 16, 12, where does the the timing come from? What happens to those numbers to cause the loop to be a certain time? Thanks – Jimmy Page"
If I understand your questions then:
The 16F690 data sheet says:
One instruction cycle consists of four oscillator periods for an oscillator frequency of 4 MHz, this gives a normal instruction execution time of 1 μs. All instructions are executed within a single instruction cycle, unless a conditional test is true, or the program counter is changed as a result of an instruction. When this occurs, the execution takes two instruction cycles, with the second cycle executed as a NOP.
So lets say Delay1 has the value 3 and we have this loop:
Each time we execute decfsz we get the stock one cycle. IF f is zero and we have to skip then it becomes a two cycle instruction. Each time we execute the goto the pc changes so it is a 2 cycle instruction. So if we walk the loop and I show this using the format
Delay1 value before instruction, instruction, cycles used to execute, total cycles
So that loop by itself with Delay1 starting at 3 took 8 cycles or 8us if we were running at 4mhz. It is important to compute cycles first, then adjust for the clock rate of the part, that same code could be 16us when running at 2mhz or 32us when running at 1mhz.
So by inspection we can see that for f values that are not one the decfsz+goto pair are 2+1=3 cycles. The one time we hit decfsz with a value of 1 it will be 2 cycles. So starting with Delay1 of 3 there will be 2 non-one entry values (3,2). And add 2 cycles for the last time we hit decfsz and skip, total cycles ((3-1)*3)+2=8.
If we had entered this loop with Delay1 set to 11, it would be ((11-1)*3)+2=32 cycles, a 7 would be 20 cycles.
If you go further and wrap one decfsz loop around another you continue to multiply the number of executed cycles. If Delay1 is a 3 going in and Delay2 is a 2
Then the first time through the Delay1 decfsz,goto loop we know is 8 cycles. The first decfsz Delay2,f because Delay2 is not a 1 is 1 cycle, we are up to 9 total. the goto is 2 more, 11 total. Assuming the f memory is 8 bit, then the second time we hit the Delay1 loop we enter with a 0, think of it as a 0x100 or 256 for the math giving us ((256-1)3)+2=767 more cycles, 778 total so far. Delay2 is now a 1, so this is the final decfsz Delay2,f so that costs us 2, a total of 780 cycles. And we could come up with an algorithm for computing the cycles for that Something close to ((Delay2-1)(((256-1)*3)+2))+(((Delay1)-1)*3)+2)+((Delay2-1)*3)+2 cycles.
And although my loop is smaller by one decfsz loop than yours, if you make mine resemble yours in that it starts with some other instructions:
We need to add 4 more cycles for the two movlw's and two movwf's to the overall equation for number of cycles to execute.
So, literally, there is an explanation why it is executing so many cycles. And that explanation was in the datasheet for the device.
Lets take this further. Lets get the code generator that patrickmdnet linked to to generate 780 cycles:
This loop is architected a bit different.
we start with 4 cycles of loading the f registers before we get to Delay_0
The inner decfsz loops goto does not branch up to Delay_0 directly as the code in your question and my explanation above, this one skips over decfsz d2,f. So for the non-one passes through that loop there is 1 cycle for the decfsz, 2 cycles for the goto $+2 and 2 cycles for the goto Delay_0, total 5 cycles for each non-one d1. And add two more for the time that d1 is a 1. this gives us ((0x9B-1)*5)+2 = 772 cycles add the 4 cycles before this we are up to 776 cycles.
Interestingly that last decfsz d1,f hits a decfsz d2,f with d2 set to 0x01 which means it is guaranteed to skip. it is 2 cycles, a goto $+2 with another goto $+1 instead of the movlw/movwf to load d2 would have done the same thing. Anyway this single instruction of 2 cycles brings us up to a total of 778 cycles
We need two more cycles to get to 780 and that is done here with a goto $+1, gotos modify the pc so they are always 2 cycles. We have the 780 cycles that I asked the program to generate.
延迟循环背后的想法是燃烧与一定时间量相关的一定数量的周期。每个周期的时间量取决于 PIC CPU 的时钟速率。
您发布的是一个三级延迟循环,类似于此处生成的延迟循环:
http://www.piclist.com/techref/piclist/codegen/delay.htm
第一个指令块用计数器加载三个内存位置。使用上面的程序找到产生所需延迟的最佳值。
第二组指令是实际延迟。 "decfsz VAR,f" 会将 VAR 减 1;如果 VAR 为零,则跳过下一条指令。因此,在上述情况下,decfsz 将运行直到 Delay1 为零,然后跳过“goto DelayLoop”并启动“decfsz Delay2,f”。
我建议阅读此页面:
http://www.mstracey.btinternet.co.uk/pictutorial/progtut4.htm
还有这个页面:
http://www.piclist.com/techref/microchip/PIC16DelayTutorial.htm
有关 decfsz 和 goto 如何工作的更多帮助。
The idea behind delay loops is to burn a certain number of cycles that correlate to a certain amount of time. The amount of time per cycle depends on the clock rate of your PIC CPU.
What you posted is a three-stage delay loop similar to the ones generated here:
http://www.piclist.com/techref/piclist/codegen/delay.htm
The first block of instructions loads three memory locations with counters. Use the program above to find the optimal values to produce the delay you want.
The second set of instructions is the actual delay. "decfsz VAR,f" will decrement VAR by 1; if VAR is then zero, it skips the next instruction. So in the above case, decfsz will run until Delay1 is zero, then jump over the "goto DelayLoop" and start "decfsz Delay2,f".
I suggest reading this page:
http://www.mstracey.btinternet.co.uk/pictutorial/progtut4.htm
and also this page:
http://www.piclist.com/techref/microchip/PIC16DelayTutorial.htm
for more help on how decfsz and goto works.
内置 RC 振荡器的频率决定了时钟周期,进而决定了速度。
The frequency of the built in RC oscillator determines the clock cycle, which in turn determines the speed.