文章目录
一、主要任务
-
本篇文章的主要任务以周期性点亮LED灯的延时函数为例,掌握 1)通过软件多重循环软件计数的定时方法 ;2)通过 循环+ nop 指令的方法;
-
掌握汇编语言用查表法完成求平方数的程序;
-
掌握普中单片机实验开发板的开发使用方法,在板子上完成LED周期性点灯的C程序实验。
二、51单片机汇编延时函数分析
1. 周期
(1)单片机执行一条指令所需要的时间是一个指令周期。
(2)完成一个基本操作所用的时间是一个机器周期,如读操作、写等操作。当晶振频率为12MHz时,1个机器周期为1us。
2. 单重循环短暂延时
DJNZ RN,REL 是一条件转移指令,先将工作寄存器 Rn 中的数减 “ 1 ” ,判断结果是否为 “ 0 ”,不为 “ 0 ” 程序就跳转到行标为 REL 的地方执行,否则,为 “ 0 ” 就不转移,继续执行下一条指令。DJNZ 运行的机器周期为2。
如果需要短暂的延时,我们可以通过单重循环来实现。
例如,下面为延时250μs的程序。
DELAY:
MOV R7,#125
DELAY1:
DJNZ R7,DELAY1
RET
MOV的指令周期为一个机器周期,即执行一条MOV指令需要1μs
DJNZ的指令周期为两个机器周期,即执行一条DJNZ指令需要2μs,每执行一次寄存器R7的值减 1 ,不断重复,到R7值为 0 的时候,跳转到 RET 指令结束,即执行 DJNZ 指令125次。
即可以实现延时大约250μs的目的。
3. 多重循环长延时
3.1 以实现LED周期性闪烁的汇编程序为例
LOOP:SETB 90H ;led0置1
LCALL DELAY ;调用延时函数
CLR 90H ;led0置0
LCALL DELAY
AJMP LOOP ;跳转到LOOP
DELAY: MOV R7,#250 ;延时函数
D1: MOV R6,#250
D2: DJNZ R6,D2
DJNZ R7,D1
RET ;返回主函数
END ;指令结束
延时函数中第一句是定义一个延时函数标号,并将250传到R7。
第二句是放置一个标号,并把250放到R6。“MOV R6,#250”的指令周期数为1个时钟周期,需要1μs。
第三句是放置一个标号,并判断R6的值是否为0,不为0的话转到后面标号对应处执行。“DJNZ R6,D2”的指令周期数为2个时钟周期,需要2μs。
而D2的标号也是第三条语句,因此只要R6不为0,则一直执行本条语句,又知R6=250,因此,这条语句将执行250次后结束。
第四句是先将R7减1 ,然后判断R7是否为0 ,不为0的话转到后面的标号对应处执行。标号D1,即第二句,执行第二句之后,又将执行第三句,执行250次后,再次执行语句四,如此循环即在第四句执行了250次后执行第五句,即结束函数。
第五句是函数结束。
共执行了:
第一句:1次;第二句:251次;第三句:250*250次;第四句:250次;第五句:1次
因此,此函数所用时间大约在第三条语句,时间为125000μs。
即这个LED灯大约每隔0.125s才变化一次亮灭状态。
3.2 实现LED 每隔1s亮灭的周期性变化
(1)通过软件多重循环软件计数的定时方法
此子程序采用3重循环结构。
LOOP:SETB 90H ;led0置1
LCALL DELAY ;调用延时函数
CLR 90H ;led0置0
LCALL DELAY
AJMP LOOP ;跳转到LOOP
DELAY: MOV R5,#20
D1: MOV R6,#250
D2: MOV R7,#100
DJNZ R7,$
DJNZ R6,D2
DJNZ R5,D1
RET
由上述分析可知,为了计算上的简便,可以忽略赋值语句的时间,即只计算“DJNZ R7,$"语句的执行时间,该指令执行一次需2μs。执行的次数为R5、R6和R7值的乘积,即:
总延时=2μs x 20 x 250 x 10=1000000μs=1s
(2)通过 循环+ nop 指令的方法
NOP指令
NOP指令是汇编语言中的一条空指令,通常用于延时或者在程序中占位。NOP指令本身不执行任何操作,只是让处理器执行一个空操作,不改变寄存器状态,也不影响程序流程。在大多数处理器架构中,NOP指令的执行时间非常短,通常只占用一个时钟周期。
在实际应用中,NOP指令可以用于以下几个方面:
延时:通过多次执行NOP指令来实现简单的延时效果。
占位:在程序中插入NOP指令,以便将来填充其他指令或代码。
调试:在调试过程中,可以在需要观察的地方插入NOP指令,以便暂停程序执行。
总的来说,NOP指令在汇编语言中是一个非常简单且常用的指令,虽然本身不执行任何有用的操作,但在某些情况下却具有一定的作用。
汇编程序:
DELAY: MOV R7,#250 ;延时函数
D1: MOV R6,#250
D2:
NOP
;此处需要有14个NOP指令
DJNZ R6,D2
DJNZ R7,D1
RET ;返回主函数
END ;指令结束
由上述分析可知若不采用NOP的延时函数,只能延时0.125s,若想延时1s,NOP指令就额外需要延时大约875000μs,根据NOP所在位置,我们可知一个NOP指令就可以延时250 x 250 x 1=62500μs,所以需要NOP的个数为875000/62500=14
三、查表法查找平方数的汇编程序
1、汇编程序
ORG 0000H
LB:DB 0,1,4,9,16,25,36
MOV DPTR,#LB
MOV R1,#5
MOV A,R1
MOVC A,@A+DPTR
MOV R2,A
RET
END
这段汇编程序是一个简单的查表法来查找平方数的程序。下面是这段程序的逐行解释:
ORG 0000H: 程序起始地址为 0000H。
LB: DB 0,1,4,9,16,25,36: 定义了一个存储平方数的表 LB,包含了 0 到 6 的平方数。
MOV DPTR, #LB: 将表 LB 的起始地址加载到数据指针 DPTR 中。
MOV R1, #5: 将要查找的数 5 存储在寄存器 R1 中。
MOV A, R1: 将要查找的数 5 存储在累加器 A 中。
MOVC A, @A+DPTR: 使用 MOVC 指令,通过查表法找到索引为 5 的平方数,并将结果存储在累加器 A 中。
MOV R2, A: 将找到的平方数从累加器 A 复制到寄存器 R2 中。
RET: 程序结束并返回。
END: 程序结束。
这段程序的逻辑比较简单,首先将要查找的数存储在 R1 寄存器中,然后通过查表法在表 LB 中查找对应的平方数,并将结果存储在 R2 寄存器中。最后程序返回。
MOVC 指令是一种特殊的指令,用于将数据从表中移动到累加器 A 中。在指令 MOVC A, @A+DPTR 中,它的作用是从表中读取数据,并将其存储在累加器 A 中。
具体来说,@A+DPTR 的含义是将累加器 A 中的值作为偏移量,加上数据指针 DPTR 指向的地址,然后从该地址读取数据。在这个特定的情况下,累加器 A 中存储着一个偏移量,用来在表中查找对应的数据。
DB 指令是汇编语言中用来定义数据的伪指令。在汇编语言中,程序员通常需要定义一些常量、变量或者数据,DB 指令就是用来完成这个任务的。
DB 指令的全称是 “Define Byte”,它的作用是定义一个或多个字节的数据。在汇编程序中,可以使用 DB 指令来为程序中的变量分配空间,并初始化这些变量的值。
2、验证结果
Edsim51仿真验证
四、在普中单片机开发板完成LED灯周期性闪烁及流水灯
1、LED灯周期性闪烁
汇编程序
LOOP:SETB P2.0
LCALL DELAY ;
CLR P2.0
LCALL DELAY
AJMP LOOP ;
DELAY: MOV R5,#20
D1: MOV R6,#250
D2: MOV R7,#100
DJNZ R7,$
DJNZ R6,D2
DJNZ R5,D1
RET
注:开发板上只有P2口的LED灯,需要将接口改为接入P2
c语言程序
#include<reg51.h>
sbit LED0=P2^0;
void Delay(unsigned int t);
void main (void)
{
while (1)
{
LED0=0;
Delay(10000);
LED0=1;
Delay(10000);
}
}
void Delay(unsigned int t)
{
while(--t);
}
在PZ-ISP软件中导入hex文件
结果:
2、流水灯
汇编程序
ORG 000H
LJMP MAIN
ORG 0030H
MAIN:
MOV A,#0FEH
LOOP:
MOV P2,A
LCALL DELAY
RL A
SJMP LOOP
DELAY:
MOV R7,#255
D1:
MOV R6,#250
DJNZ R6,$
DJNZ R7,D1
RET
END
c语言程序
#include <reg51.h>
#include <intrins.h>
void delay_ms(int a)
{
int i,j;
for(i=0;i<a;i++)
{
for(j=0;j<1000;j++) _nop_();
}
}
void main(void)
{
while(1)
{
P2=0xfe;
delay_ms(50);
P2=0xfd;
delay_ms(50);
P2=0xfb;
delay_ms(50);
P2=0xf7;
delay_ms(50);
P2=0xef;
delay_ms(50);
P2=0xdf;
delay_ms(50);
P2=0xbf;
delay_ms(50);
P2=0x7f;
delay_ms(50);
}
}
五、总结
本次任务让我学习到了更多关于汇编语言的知识,也对单片机开发板的应用有了初步的了解,文章也有不足的地方,希望大家多多包涵。
参考资料:
https://blog.csdn.net/xinzhiya001/article/details/55001751?spm=1001.2014.3001.5506