周期性点亮LED灯的延时函数
1.通过软件多重循环软件计数的定时方法周期性点亮LED灯
ORG 0000H ; 程序起始地址
MAIN: ; 主程序标签
SETB P1.0 ; 将P1.0设置为高电平,点亮LED
ACALL DELAY ; 调用延时函数
CLR P1.0 ; 将P1.0设置为低电平,熄灭LED
ACALL DELAY ; 再次调用延时函数
SJMP MAIN ; 无限循环
DELAY: ; 延时函数标签
MOV R0, #1 ; 外层循环计数器
OUTER_LOOP:
MOV R1, #1 ; 内层循环计数器
INNER_LOOP:
DJNZ R1, INNER_LOOP ; 内层循环
DJNZ R0, OUTER_LOOP ; 外层循环
RET ; 返回主程序
END
2.通过 循环+ nop 指令的方法
ORG 0000H
MAIN:
SETB P1.0
ACALL DELAY
CLR P1.0
ACALL DELAY
SJMP MAIN
DELAY:
MOV R0, #1
DELAY_LOOP: NOP ; 插入多个NOP指令来增加延时 NOP
NOP ; ...更多NOP指令...
DJNZ R0, DELAY_LOOP
RET
END
在edsim51上面仿真成功
使用汇编语言用查表法完成 求平方数的程序
ORG 0000H
; 平方数表
SQUARE_TABLE:
DB 0, 1, 4, 9, 16, 25, 36, 49, 64, 81, 100, 121, 144, 169, 196, 225
; 主程序
MAIN:
MOV A, #5 ; 假设我们要计算5的平方
MOV R0, A ; 将A的值移动到R0,用作表索引
MOV DPTR, #SQUARE_TABLE ; 设置数据指针到平方数表
MOVC A, @A+DPTR ; 查表得到平方数
; 此时,A寄存器中存储的是5的平方,即25
; ...其他代码...
END
例
SETB 90H
LCALL DELAY
CLR 90H
LCALL DELAY
AJMP LOOP
DELAY:
MOV R7,#250
D1:MOV R6,#250
D2:DJNZ R7,D1
RET
END
汇编指令 “MOV R6,#250”和“DJNZ R6,D2”的指令周期数,计算其对应的时钟周期 us值;
对于指令 MOV R6,#250
,这是一个2字节的指令,对于8051,它通常需要1个机器周期来执行,即12个时钟周期。
对于指令 DJNZ R6,D2
,这是一个3字节的指令,通常需要2个机器周期来执行,即24个时钟周期。但是,当R6不为0时,它会跳转,这个跳转会增加额外的2个时钟周期,所以总共是26个时钟周期
现在,假设微控制器的时钟频率为12MHz,那么一个时钟周期的时间是 1/(12 * 10^6) 秒,或者大约 0.0833 微秒。
对于 MOV R6,#250
指令: 1 指令周期 * 12 时钟周期/指令周期 * 0.0833 微秒/时钟周期 = 1 微秒
对于 DJNZ R6,D2
指令: 26 时钟周期 * 0.0833 微秒/时钟周期 = 2.166 微秒
然后计算 Delay函数的总的循环次数和对应的时钟周期总数us, 说明这个LED灯大约每隔多少毫秒(ms)或秒(s)才变化一次亮灭状态
对于 DELAY
函数的总循环次数,有两个嵌套的循环,外层循环R7从250减到0,内层循环R6也是从250减到0。所以,总的循环次数是 250 * 250 = 62500。每次循环包括一个 MOV R6,#250
指令和250次 DJNZ R6,D2
指令。
总的时钟周期数是: (1 + 250 * 26) * 62500 * 0.0833 微秒 = 32687500 微秒 = 32.6875 秒
上述计算是基于单次 DELAY
函数调用的,但在程序中 DELAY
函数被调用了两次,一次用于LED开启的延时,一次用于LED关闭的延时。因此,LED灯的一次亮灭变化周期是两次 DELAY
函数调用的总和,即大约65.375秒。
要实现LED每隔1秒亮灭的周期性变化,需要根据实际的时钟频率调整延时循环的次数。如果我们假设时钟频率为12MHz,需要计算出使 DELAY
函数的延时大约为500毫秒的循环次数。
要求你实现准确的LED 每隔1s亮灭的周期性变化,上面程序如何修改?
ORG 0000h ; 程序起始地址
MAIN:
SETB P1.0 ; 将P1.0设置为高电位,点亮LED
ACALL DELAY_1S ; 调用1秒延时函数
CLR P1.0 ; 将P1.0设置为低电位,熄灭LED
SJMP MAIN ; 无限循环 ; 假设单片机的时钟频率为12MHz ; 1机器周期 = 12个时钟周期 = 1μs ; 假设每个循环迭代大约需要1μs
DELAY_1S:
MOV R1, #20 ; 外层循环计数器,假设大约为20次
OUTER_LOOP: MOV R2, #250 ; 内层循环计数器1,假设大约为250次
INNER_LOOP1: MOV R3, #250 ; 内层循环计数器2,假设大约为250次
INNER_LOOP2: NOP ; 执行一个空操作 (NOP) 以消耗时间
DJNZ R3, INNER_LOOP2 ; 循环直到R3为0
DJNZ R2, INNER_LOOP1 ; 循环直到R2为0
DJNZ R1, OUTER_LOOP ; 循环直到R1为0 RET ; 返回到调用DELAY_1S的地方
END ; 程序结束
在普中单片机开发板上重新完成上述实验
使用stc软件;
最终实验完成。
作者水平有限,不足之处欢迎指正。