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
Assembly 写一个延迟子程序?_Assembly_Microcontroller_8051 - Fatal编程技术网

Assembly 写一个延迟子程序?

Assembly 写一个延迟子程序?,assembly,microcontroller,8051,Assembly,Microcontroller,8051,我需要写一个延迟子程序。它应该延迟大约1秒。它必须适用于8051环境,DS89C430微控制器11.0592 MHz XTAL。如何编写这个子程序 Delay1sec: ... .... ... .... ... 该微控制器有三个板载定时器(参见第11节)连接到系统时钟除以12,因此需要对它们进行编程,以便在时间到期时生成中断。由于分频输入刚好低于1MHz,最大计数器为16位,如果我计算正确,至少需要计算14次中断才能达到1秒。要获得在中断期间也能工作的精确1秒延迟,需要使用硬件计时器,而不是

我需要写一个延迟子程序。它应该延迟大约1秒。它必须适用于8051环境,DS89C430微控制器11.0592 MHz XTAL。如何编写这个子程序

Delay1sec: ...
....
...
....
...

该微控制器有三个板载定时器(参见第11节)连接到系统时钟除以12,因此需要对它们进行编程,以便在时间到期时生成中断。由于分频输入刚好低于1MHz,最大计数器为16位,如果我计算正确,至少需要计算14次中断才能达到1秒。

要获得在中断期间也能工作的精确1秒延迟,需要使用硬件计时器,而不是软件计时器。我建议您使用一个可用的车载计时器

这是一种涉及内置计时器和计数计时器溢出的方法。由于运行计时器默认每12个时钟周期更新一次,以保持与8051的兼容性,因此将每秒更新921600次。一个乘法位告诉我们从0到46080的计数需要50毫秒,这也告诉我们我们可以在19456启动一个16位计时器,等待它溢出20次以延迟1秒*

代码可能如下所示:

        CLR     T0M          ; set timer 0 to use a divide-by-12 of
                             ; the crystal frequency (default)

        MOV     R0,TMOD      ; set timer 0 to 16-bit mode without
        ORL     R0,#01h      ; affecting the setup of timer 1
        MOV     TMOD,R0

        LCALL   Delay1sec    ; call the delay subroutine

Delay1sec:
        MOV     R0,#20d      ; set loop count to 20

loop:   CLR     TR0          ; start each loop with the timer stopped
        CLR     TF0          ; and the overflow flag clear. setup
        MOV     TH0,#4Ch     ; timer 0 to overflow in 50 ms, start the
        MOV     TL0,#00h     ; timer, wait for overflow, then repeat
        SETB    TR0          ; until the loop count is exhausted
        JNB     TF0,$
        DJNZ    R0,loop
        RET   
Delay1sec:                   ; <------------------------------+
;       LCALL   Delay1sec    ; 3 cycles                       |
        MOV     R2,#42d      ; 2 cycles                       |
        MOV     R1,#00d      ; 2 cycles                       |
        MOV     R0,#00d      ; 2 cycles                       |
loop:   DJNZ    R0,loop      ; 4 cycles <-- l1 <- l2 <- l3    Delay1sec
        DJNZ    R1,loop      ; 4 cycles <---------+     |     |
        DJNZ    R2,loop      ; 4 cycles <---------------+     |
        RET                  ; 3 cycles <---------------------+
注意:示例中不包括指令执行时间的开销。 *数学是如何分解的: 11059200 / 12 = 921600 0.05 * 921600 = 46080 65536-46080=19456=0x4C00

软件延迟循环浪费处理器时间,并受到中断的干扰。也就是说,你可以用硬编码的方式来做

一种方法涉及了解每个机器周期的时钟周期数以及各种指令执行所需的机器周期数。根据,DS89C430通常对每个指令字节使用一个机器周期,并且需要一个执行周期。中提供了每条指令的周期数

由于您的晶体频率为11.0592 MHz,因此您的例程需要延迟11059200个时钟周期。这通常是通过已知长度的嵌套循环完成的,然后包括任何额外的循环设置以及可能的子程序调用和返回指令*

该函数可以如下所示:

        CLR     T0M          ; set timer 0 to use a divide-by-12 of
                             ; the crystal frequency (default)

        MOV     R0,TMOD      ; set timer 0 to 16-bit mode without
        ORL     R0,#01h      ; affecting the setup of timer 1
        MOV     TMOD,R0

        LCALL   Delay1sec    ; call the delay subroutine

Delay1sec:
        MOV     R0,#20d      ; set loop count to 20

loop:   CLR     TR0          ; start each loop with the timer stopped
        CLR     TF0          ; and the overflow flag clear. setup
        MOV     TH0,#4Ch     ; timer 0 to overflow in 50 ms, start the
        MOV     TL0,#00h     ; timer, wait for overflow, then repeat
        SETB    TR0          ; until the loop count is exhausted
        JNB     TF0,$
        DJNZ    R0,loop
        RET   
Delay1sec:                   ; <------------------------------+
;       LCALL   Delay1sec    ; 3 cycles                       |
        MOV     R2,#42d      ; 2 cycles                       |
        MOV     R1,#00d      ; 2 cycles                       |
        MOV     R0,#00d      ; 2 cycles                       |
loop:   DJNZ    R0,loop      ; 4 cycles <-- l1 <- l2 <- l3    Delay1sec
        DJNZ    R1,loop      ; 4 cycles <---------+     |     |
        DJNZ    R2,loop      ; 4 cycles <---------------+     |
        RET                  ; 3 cycles <---------------------+
让我们看看数学是如何分解的**:

l1=4*256=1024个周期 l2=1024+4*256=263168个周期 l3=263168+4*42=11053224个周期 Delay1sec=11072668+3+2+2+3=11053236个周期

11053236个周期*1/11059200秒/周期=999.461毫秒

*如有必要,可以省略子程序调用和返回指令。
**我使用Microsoft Excel来帮助计算与确定循环计数器有关的数据。

参考硬件计时器

B参考CPU定时器。一些处理器有一个非常宽的计时器,即64位宽,以时钟为单位运行

C软件循环。为了获得最佳结果,代码和所有数据都应该驻留在具有可预测定时的内部内存中。从SDRAM运行可能会导致计时问题

这样做不需要计算装配周期。相反,你可以在引脚上画一个脉冲,在环路前拉高,在环路后拉低,用逻辑分析仪测量脉冲宽度,然后改变环路计数来调整你的计时。为了获得最佳效果,您应该使用频率计数器测量外部CPU时钟/晶体,然后补偿偏离中心频率的情况,因为大多数便宜的晶体不会死机


您可以通过使用计时器来计算循环计时来进行自我校准。

我没有阅读手册,也不太熟悉该芯片,但通常通过不使用计数器的全量程,可以在多次中断时获得更精确的计时器,即,在1MHz频率下数到50000二十次应该比数到65535大约十四次更准确。@Zooba:一般来说,你是对的,不过在这种情况下,数到65536十四次会给出一个时间,幸运的是,根据大约一秒钟的时间,它确实非常准确,可能比他所关心的更准确。