在20 MHz(?)时钟上添加1秒延迟

时间:2012-04-29 19:01:38

标签: assembly pic

编辑:PIC 16F684

好的,我有一个简单的3 LED二进制时钟,从0到7,并希望在每个灯开启之间增加约1秒的延迟。

我已经知道每个灯需要处于一种循环中,我必须使用计数来测量刻度和翻转等。

认为时钟是4MHz,这是手册的截图:http://i.imgur.com/tJatQ.png

以下是我的代码中的相关摘录:

COUNT1 EQU 20h      ; Delay counter #1
COUNT2 EQU 21h      ; Delay counter #2

...

LOOP0
        MOVLW   TRIS_D0_D1      ; Move value defined in Constants to TRISA, to switch on LED 0.
        TRIS    PORTA           ;
        CLRF    PORTA           ; Clear all outputs.
        MOVLW   D0              ; Set the accumulator to the value of D0.
        MOVWF   PORTA           ; Move the accumulator to PORTA, to switch on LED 0.

    ; Using COUNTs to add a delay
        decfsz    COUNT1,1       ; Decrease COUNT1 by 1, and skip the next line if the result is 0.
        goto      LOOP0          ; If COUNT1 is 0, carry on. If not, go to LOOP0.   
        decfsz    COUNT2,1       ; Decrease COUNT2 by 1, and skip the next line if the result is 0.
        goto      LOOP0          ; If COUNT1 is 0, carry on. If not, go to LOOP0.

然而,我很确定我搞砸了时间,有人能帮我一把吗?

2 个答案:

答案 0 :(得分:4)

假设:LOOP0处的代码是您希望每延迟执行一次的代码,而不是在延迟期间执行的次数。我还假设您正在设置COUNT1COUNT2 - 您发布的代码声明了两个“变量”但未分配它们。

您目前使用的代码将在LOOP0 COUNT1 + COUNT2次重复执行代码。这是因为每个循环是分开的。这使您最多延迟510个周期。正如其他评论者所说,PIC16每个周期执行大约一条指令,因此您需要延迟1,000,000个周期才能在4MHz下等待一秒钟。

如果我们考虑我们想要等待196392个周期的情况,我们基本上需要实现一个16位计数器。我们通过在循环中递减一个计数器来完成此操作。每次循环退出时,我们减少另一个计数器。当两个计数器都为零时,循环返回。这是一个例子:

COUNT1 EQU 20h
COUNT2 EQU 21h

LOOP0
    ;do some stuff here
        ...

    ;delay loop starts here:
    ;assume COUNT1=0 and COUNT2=0
Delay_0
    decfsz COUNT1
    goto Delay_0
    decfsz COUNT2   ;COUNT1 = 0 so 0xff cycles have passed
    goto Delay_0
    goto LOOP0 ;both COUNT1 and COUNT2 = 0 - 196392 cycles have now passed

分支指令如果不跳过则需要1个周期,如果不跳过则需要2个。 goto总是需要2个周期,这意味着完成一个完整计数所需的实际时间是767个周期(255 * 3 + 2)。我们可以计算两者的时间为((255 * 3 + 2)+ 3)* 255 + 2。

在Dos4Ever上有一个很棒的explanation of delay routines。这将介绍延迟例程的工作原理以及如何计算延迟例程的计数器值和成本。

最后,如果您只是想要剪切和粘贴延迟例程,PIClist上的Delay routine generator非常完美。

答案 1 :(得分:1)

上述代码假设两个计数器初始设置为零时两个循环需要197119个循环(而不是196392)对吗?

我指的是代码:

  • Delay_0 decfsz COUNT1
  • 转到Delay_0
  • decfsz COUNT2
  • 转到Delay_0

原因是与count1相关的内部循环将循环255次,这意味着{255次3个指令循环}加上最后的decfsz需要额外的2个循环。因此,对于该内部循环循环的第一次,相关的延迟(d1F)将是d1F = 255 * 3 + 2 = 767个循环。这一切都发生在我们甚至到了count2的decfsz之前。接下来,当我们达到decfsz count2时,剩下的活动就会发生;以decfsz count2开头,然后是goto Delay_0,其中'goto'将调用另一个内部循环延迟(等于d1F)。因此,由decfsz count2,goto Delay_0和d1F组成的这个三重组合将与count2索引值255相关联。然后我们继续获得更多的三重组合...索引254,然后索引253 ...一直到count2 index of 1.所以这意味着我们得到255个三重组合。最后,我们以最终的decfsz count2(索引为0)终止。最后的decfsz count2'指令'需要2个周期而不是1.所以延迟的第二部分是(d1F + 3)* 255 + 2.'3'(指令周期)是由于正常情况下的decfsz加goto指令循环。

因此,当我们将延迟的第一部分和第二部分放在一起时,我们得到:

  • d2F = d1F +(d1F + 3)x255 + 2 = 767 +(767 + 3)x255 + 2 = 197119

现在如果我们有多个循环,那么我们可以使用方程式:

  • d(n)_F = d(n-1)_F + {d(n-1)_F + 3} x255 + 2 = 256xd(n-1)_F + 767

  • d(n)_C = d(n-1)_C + {d(n-1)_F + 3} x {count_n - 1} + 2

其中d(n)_F或d(n-1)_F中的'F'表示所有计数器用ZERO值初始化的条件。并且d(n)_C中的'C'表示第n个循环的计数器用我们最初选择的任何值初始化的条件。并且'n'与第n个循环相关联。并且'n-1'与第(n-1)个循环相关联。

因此,如果我们有2个循环,则d(1)_F是由于循环#1的延迟,具有“完整”循环次数(即.. counter1最初是ZERO或256);和d(2)_F是由于循环#1和循环#2引起的延迟,因为当counter1和counter2最初都等于ZERO或256时。

  • d(1)_C是由于循环#1导致的延迟,其中count1初始化为我们最初选择的任何值。
  • d(2)_C是由于循环#1和循环#2导致的延迟,其中count2初始化为我们最初选择的任何值。

请注意,count_n是第n个循环的INITIAL计数器值。 此外,如果最初使用ZERO值初始化特定计数器,则将该值视为“256”通常很方便。这当然是一个EIGHT位计数器。例如,如果count1 = 0,则可以方便地将其视为count1 = 256(而不是0)。

  • 我们还可以定义:d(0)_F = 0和d(0)_C = 0.

因此,对于一个3循环系统,count1 = 1,count2 = 4,count3 = 2,

  • d(1)_F = 256xd(0)_F + 767 = 256x0 + 767 = 767

  • d(1)_C = 0 + {0 + 3} x {1 - 1} + 2 = 2

  • d(2)_F = 256xd(1)_F + 767 = 256x767 + 767 = 197119

  • d(2)_C = d(1)_C + {d(1)_F + 3} x {4 - 1} + 2 = 2 + {767 + 3} x3 + 2 = 2314

  • d(3)_F = 256xd(2)_F + 767 = 256x197119 + 767 = 50463231

  • d(3)_C = d(2)_C + {d(2)_F + 3} x {2 - 1} + 2 = 199438

3循环系统就像:

  • Delay_0 decfsz count1
  • 转到Delay_0
  • decfsz count2
  • 转到Delay_0
  • decfsz count3
  • 转到Delay_0

Kenny Leong