1. 深入了解汇编指令和常用程序结构,以周期性点亮LED灯的延时函数为例,掌握:
(1)通过多重循环计数的定时方法 ;
我们首先要了解什么是汇编语言:
汇编语言(assembly language)是一种用于电子计算机、微处理器、微控制器或其他可编程器件的低级语言,亦称为符号语言。在汇编语言中,用助记符(Mnemonics)代替机器指令的操作码,用地址符号(Symbol)或标号(Label)代替指令或操作数操作数的地址。在不同的设备中,汇编语言对应着不同的机器语言指令集,通过汇编过程转换成机器指令。普遍地说,特定的汇编语言和特定的机器语言指令集是一一对应的,不同平台之间不可直接移植。
了解完后我们再看到如下汇编语言:
TIMER_LED:
MOV R7, #10 ; 外层循环计数器,控制点亮和熄灭LED的周期
OUTER_LOOP:
MOV R6, #1000 ; 内层循环计数器,控制LED点亮时间
INNER_LOOP_ON:
; 点亮LED的操作,例如将LED端口的相应位设置为1
DJNZ R6, INNER_LOOP_ON ; 内层循环,LED点亮时间
MOV R6, #1000 ; 重置内层循环计数器
INNER_LOOP_OFF:
; 熄灭LED的操作,例如将LED端口的相应位设置为0
DJNZ R6, INNER_LOOP_OFF ; 内层循环,LED熄灭时间
DJNZ R7, OUTER_LOOP ; 外层循环,控制整个周期
RET
在这个代码中,外层循环控制整个周期的间隔,内层循环控制LED点亮和熄灭的时间。你可以根据需要调整R7和R6的值来改变LED点亮和熄灭的周期和持续时间。
(2)通过 循环+ nop 指令的方法;
NOP指令(No Operation)是一个空操作指令,也是汇编语言中的一种指令,它不执行任何操作,仅占用一个CPU周期。在汇编语言中,NOP指令通常用于延时或者填充代码的空闲区域。在一些情况下,NOP指令也可以用于调试或者占位符。
CYCLIC_LED_DELAY:
MOV R5, #10 ; 外层循环计数器,可以根据需要调整
OUTER_LOOP:
MOV R6, #250 ; 内层循环计数器,可以根据需要调整
INNER_LOOP:
NOP ; 空操作,用于延时
NOP
NOP
NOP
DJNZ R6, INNER_LOOP ; 内层循环
DJNZ R5, OUTER_LOOP ; 外层循环
RET
这段代码会循环执行内层NOP指令,以产生一个延时,然后通过外层循环控制延时的周期。你可以根据需要调整R5和R6的值来调整延时的时间。在延时期间,你可以在LED控制寄存器中设置相应的位来点亮LED灯。
2. 掌握汇编语言用查表法完成求平方数的程序;
; 寄存器定义
R0 EQU 0
R1 EQU 1
R2 EQU 2
ORG 0x00 ; 程序起始地址
START:
MOV R0, #5 ; 设置要求平方的数值,例如5
MOV R1, R0 ; 将要求平方的数值存储到寄存器R1中
MOV R2, #0 ; 将平方结果初始化为0
SQUARE_LOOP:
ADD R2, R1 ; 将平方结果加上要求平方的数值
SUB R0, #1 ; 将要求平方的数值减1
JZ SQUARE_DONE ; 如果要求平方的数值为0,则跳转到结束标签
JMP SQUARE_LOOP ; 否则继续循环求平方
SQUARE_DONE:
; 在这里可以使用平方结果R2
; 比如将结果输出到某个输出端口或者存储到内存中
; 你的其他操作...
; 退出程序
HALT
END START ; 程序结束标签
这段代码首先将要求平方的数值存储到寄存器R1中,然后将平方结果初始化为0。接着通过循环将平方结果不断累加,直到要求平方的数值减为0。最后,在SQUARE_DONE标签处,你可以对平方结果进行后续操作,比如将结果输出到某个输出端口或者存储到内存中。
3. 掌握普中单片机实验开发板的开发使用方法,在板子上完成LED周期性点灯的C程序实验;
4.一个LED周期性闪烁的汇编程序例子。
(1)请查阅汇编指令 “MOV R6,#250”和“DJNZ R6,D2”的指令周期数,计算其对应的时钟周期 us值;然后计算 Delay函数的总的循环次数和对应的时钟周期总数us, 说明这个LED灯大约每隔多少毫秒(ms)或秒(s)才变化一次亮灭状态;
首先,我们需要了解这些指令的执行周期。在常见的8051系列单片机中,MOV指令和DJNZ指令通常执行需要1个机器周期。然后,我们可以使用单片机的时钟频率来计算时钟周期的时间。假设单片机的时钟频率为1 MHz(1微秒一个时钟周期)。
MOV R6,#250 指令的执行周期数为1,对应的时钟周期为1微秒。
DJNZ R6,D2 指令的执行周期数为2,对应的时钟周期为2微秒。
接下来,我们计算 Delay 函数的循环次数和对应的时钟周期总数:
Delay 函数中,R7 循环 250 次(MOV R7, #250),每次循环 R6 循环 250 次(D1:MOV R6,#250 和 D2:DJNZ R6,D2),所以总共循环次数为 250 * 250 = 62500。
每次 R6 循环需要 250 * 2 = 500 个时钟周期(MOV R6, #250 和 DJNZ R6, D2),所以总的时钟周期数为 62500 * 500 = 31250000 微秒。
最后,我们计算 LED 灯每隔多少毫秒或秒变化一次亮灭状态:
假设每次循环 LED 灯亮灭一次,那么 LED 灯变化一次状态需要的时间为 31250000 微秒,换算成毫秒为 31250 毫秒,或者换算成秒为 31.25 秒。
(2)如果要求你实现准确的LED 每隔1s亮灭的周期性变化,上面程序如何修改?请给出完整代码。
为了实现 LED 每隔 1 秒亮灭的周期性变化,我们需要修改内部循环的计数值,以及增加适当的延时来保证准确的周期性变化。下面是修改后的完整代码:
DOUBLE_LOOP:
MOV R7, #100 ; 设置外层循环次数,以实现每隔1秒变化一次状态
OUTER_LOOP:
MOV R6, #250 ; 设置内层循环次数,以增加适当的延时
INNER_LOOP:
; 在这里放置内层循环的操作
DJNZ R6, INNER_LOOP ; 内层循环
DJNZ R7, OUTER_LOOP ; 外层循环
RET ; 返回
在这个修改后的程序中,我们将外层循环的计数值设置为 100,这相当于每隔 1 秒变化一次 LED 的亮灭状态。同时,内层循环的计数值设置为 250,以增加适当的延时,确保 LED 的亮灭状态变化平滑和准确。
对于本次博客的编写,我也是参考了其他大佬的博客,并且也在网上查了一些资料;如果你发现有什么不对的地方,我很希望大佬能够指出。
参考资料: https://blog.csdn.net/fuhanghang/article/details/84260199