历史上的今天
今天是:2025年06月17日(星期二)
2021年06月17日 | C51优化设计之使用DJNZ循环指令提高执行效率
2021-06-17 来源:eefocus
C51有三种循环语句即while,do-while和for,这三种循环都可以用来处理同一问题,基本上三者可以相互替换.但由于C51是针对51汇编语言的编译器,如果不注意51汇编指令的特点,不同的编程方式可能得到不同的程序性能(执行速度和代码长度).以计算1+2+3+...+9+10为例,下面做一对比.
程序1:
unsigned char i;
unsigned char sum;
for(i=1,sum=0;i<11;i++)
{
sum+=i;
}
汇编代码为:
C:0x0003 7F01 MOV R7,#0x01
C:0x0005 E4 CLR A
C:0x0006 FE MOV R6,A
C:0x0007 EF MOV A,R7
C:0x0008 2E ADD A,R6
C:0x0009 FE MOV R6,A
C:0x000A 0F INC R7
C:0x000B BF0BF9 CJNE R7,#0x0B,C:0007
代码长度(字节):11,执行周期(机器周期):63
程序2:
unsigned char i;
unsigned char sum;
for(i=10,sum=0;i;i--)
{
sum+=i;
}
汇编代码为:
C:0x000F 7F0A MOV R7,#0x0A
C:0x0011 E4 CLR A
C:0x0012 FE MOV R6,A
C:0x0013 EF MOV A,R7
C:0x0014 2E ADD A,R6
C:0x0015 FE MOV R6,A
C:0x0016 DFFB DJNZ R7,C:0013
代码长度(字节):9,执行周期(机器周期):53
程序3:
unsigned char i=11;
unsigned char sum=0;
while(i--)
{
sum+=i;
}
汇编代码为:
C:0x0003 7F0A MOV R7,#0x0B
C:0x0005 E4 CLR A
C:0x0006 FE MOV R6,A
C:0x0007 AD07 MOV R5,0x07
C:0x0009 1F DEC R7
C:0x000A ED MOV A,R5
C:0x000B 6005 JZ C:0012
C:0x000D EF MOV A,R7
C:0x000E 2E ADD A,R6
C:0x000F FE MOV R6,A
C:0x0010 80F5 SJMP C:0007
代码长度(字节):15,执行周期(机器周期):130
从以上三个不同程序可以看出,其运算结果都是0x37(55),但最短代码为9,最长代码为15,最快速度为53,最慢速度为130,可见三个程序的性能差异较大.
如何编出占用空间小运行效率高的循环代码呢?在C51编译环境下要写出优秀的循环代码必须熟悉51汇编语言的指令系统.观察程序2,循环控制指令使用了DJNZ循环转移指令,该指令同时完成计数和循环判断两种操作,而且只占用两个字节,是51指令系统中最为高效的循环指令,因此在设计循环程序时,应尽可能使C51将DJNZ用于循环程序中.当然DJNZ指令的循环次数是确定的,主要用在有确定循环次数的情况.
DJNZ指令的一个最大特点是递减计数,因此循环程序必须采用递减方式才有可能编译出DJNZ指令,如以上程序2.DJNZ指令的另一个特点是先减后判断,因此设计循环程序也必须坚持先减后判断的原则,否则得不到DJNZ指令,如以上程序3.如果将程序3改写为:
unsigned char i=10;
unsigned char sum=0;
while(i)
{
sum+=i;
i--;
}
就可以得到与程序2相同的汇编代码.若i--后还有其它操作,比如改为:
unsigned char i=10,j=0;
unsigned char sum=0;
while(i)
{
sum+=i;
i--;
j++;
}
也得不到DJNZ汇编指令,也就是说,循环语句在执行过程中,减1与判断必须是连续的,且减1在前,判断在后.对于while循环,当将减1与判断合成一步时,应当采用while(--i).按照以上所述,do-while循环同样可以汇编出DJNZ指令,不再一一列举.
但是当循环变量不是通过常数赋值语句完成,而是来自于另一个变量时,for和while语句无论采用何种控制流程都不能产生DJNZ指令,因为这两种循环都是先判断后执行的控制逻辑,而DJNZ的执行过程是先执行循环体后进行循环判断.按照DJNZ的控制流程,只有do-while语句符合这个条件,因此当循环次数不是常量而是变量时,就必须使用do-while循环语句了.
综上所述,若要使用DJNZ指令提高程序效率,在设计循环程序中应坚持以下三大原则:
① 采用递减计数;
② 先减后判断,减与判断连续进行;
③ 循环次数为变量时,采用do-while循环.
上一篇:IC卡读写接口的可靠性设计
史海拾趣
|
今天突然想起以前的一个设想,能不能用水做能源呢? 这个不是没有根据乱想的,当时是看到了电解水,于是想到了这个。 如果汽车只要加水做燃料那将是一件多么好的事啊,石油都不用采了...是不是有点夸张了。 我是这么想的 水>>电解>>分离成 氢 ...… 查看全部问答> |
|
我知道, sbit是定义一个可以位寻址的变量如: P00代表了一个可以位寻址的变量P0.0, 疑问,上述定义中,那个尖尖“^ ”,是不是异或运算,还有,尖尖后面的那个数“0”,可不可以用一个变量代替。 如 [code]unsigned char index = 0; &nbs ...… 查看全部问答> |
|
一个版友MSP430驱动SST25VF016B程序一直有问题,特贴出我自己使用无问题的版本。 固件中,自己更改所使用的SPI口和初始化好SPI就行。 固件SST25_Init中, u8 SST25_Init(void) { u8 m; &nb ...… 查看全部问答> |
|
关于Atheros几款wifi芯片 AR9344 AR9331 AR9341 有谁知道Atheros这几款wifi芯片性能上的异同点,包括芯片的整个框架,wifi指标等,越详细越好,非常感谢!!! … 查看全部问答> |
|
刚刚开始学arm,希望用KEIL中提供的RL-FLASHFS编写一个读写SD卡的程序, 我是根据KEIL的帮助文档编写的,所用的单片机是LPC1343,sd卡用SPI通讯。 现在SD卡可以初始化,可以在SD卡中创建文件,但不能读写文件,百思不得解。 从调试结果来看,Ret ...… 查看全部问答> |




