大道至简--跑马灯程序设计的新思路

学过单片机的人大都知道“流水灯”或“跑马灯”之类的名称,具体实现的效果就是按固定规律地循环地显示某组变化。如用一个字节长度的空间来实现“跑马灯”,可以是使该字节的值的变化过程为:

“0000 0001B” -> "0000 0010B” -> "0000 0100B” -> "0000 1000B” -> "0001 0000B” -> "0010 0000B” -> "0100 0000B” -> "1000 0000B” -> "0000 0001B” (循环)


假设,现在需要实现将一个int类型变量中的值从0至9的“跑马灯”变化过程,那么一般的方法是:

初版:

int val = 0;
while(1)
{
	val++;
	if( val > 9 )
	val = 0;
}//End;

在Keil uv3环境中使用ATMEL 89C51配置,编译后的汇编代码为:

C:0x0000    020010   LJMP     C:0010
     2: void main() 
     3: { 
     4:         unsigned char val = 0; 
     5:          
C:0x0003    E4       CLR      A
C:0x0004    FF       MOV      R7,A
     6:         while(1) 
     7:         { 
     8:                 val++; 
C:0x0005    0F       INC      R7
     9:                 if( val > 9 ) 
C:0x0006    EF       MOV      A,R7
C:0x0007    D3       SETB     C
C:0x0008    9409     SUBB     A,#0x09
C:0x000A    40F9     JC       C:0005
    10:                         val = 0; 
C:0x000C    E4       CLR      A
C:0x000D    FF       MOV      R7,A
    11:         } 
C:0x000E    80F5     SJMP     C:0005
C:0x0010    787F     MOV      R0,#0x7F
C:0x0012    E4       CLR      A
C:0x0013    F6       MOV      @R0,A
C:0x0014    D8FD     DJNZ     R0,C:0013
C:0x0016    758107   MOV      SP(0x81),#0x07
C:0x0019    020003   LJMP     main(C:0003)


精简修改版:

int val = 0;
while(1)
{
	if( (++val) > 9 )
	val = 0;
}

在Keil uv3环境中使用ATMEL 89C51配置,编译后的汇编代码为:

C:0x0000    020010   LJMP     C:0010
     2: void main() 
     3: { 
     4:         unsigned char val = 0; 
     5:          
C:0x0003    E4       CLR      A
C:0x0004    FF       MOV      R7,A
     6:         while(1) 
     7:         { 
     8:                 if( (++val) > 9 ) 
C:0x0005    0F       INC      R7
C:0x0006    EF       MOV      A,R7
C:0x0007    D3       SETB     C
C:0x0008    9409     SUBB     A,#0x09
C:0x000A    40F9     JC       C:0005
     9:                         val = 0; 
C:0x000C    E4       CLR      A
C:0x000D    FF       MOV      R7,A
    10:         } 
C:0x000E    80F5     SJMP     C:0005
C:0x0010    787F     MOV      R0,#0x7F
C:0x0012    E4       CLR      A
C:0x0013    F6       MOV      @R0,A
C:0x0014    D8FD     DJNZ     R0,C:0013
C:0x0016    758107   MOV      SP(0x81),#0x07
C:0x0019    020003   LJMP     main(C:0003)


从上面两个例子来看,KeilC51对源文件进行编译后,生成的汇编代码一模一样,也就是说,前面两个编程方法,虽然从C语言的角度看有些许差异,但最终编译为机器码后,前后两个代码的执行效率是一样的。


以上两种C语言格式的编程方法,是目前为止笔者所掌握的方法,但是今日学习张孝祥所著的《JAVA就业培训教程》时,了解至一种新的编程方法或者说是编程思路,用来实现此例中的”跑马灯“效果过程如下:

unsigned char val = 0;
while(1)
{
	val = (val+1)%10;
}
在Keil uv3环境中使用ATMEL 89C51配置,编译后的汇编代码为:

C:0x0000    020010   LJMP     C:0010
     2: void main() 
     3: { 
     4:         unsigned char val = 0; 
     5:          
C:0x0003    E4       CLR      A
C:0x0004    FF       MOV      R7,A
     6:         while(1) 
     7:         { 
     8:                 val = (val+1)%10; 
C:0x0005    0F       INC      R7
C:0x0006    EF       MOV      A,R7
C:0x0007    D3       SETB     C
C:0x0008    9409     SUBB     A,#0x09
C:0x000A    40F9     JC       C:0005
     9:         } 
C:0x000C    E4       CLR      A
C:0x000D    FF       MOV      R7,A
    10: }
C:0x000E    80F5     SJMP     C:0005
C:0x0010    787F     MOV      R0,#0x7F
C:0x0012    E4       CLR      A
C:0x0013    F6       MOV      @R0,A
C:0x0014    D8FD     DJNZ     R0,C:0013
C:0x0016    758107   MOV      SP(0x81),#0x07
C:0x0019    020003   LJMP     main(C:0003)

结果是笔者发现,对上面三种C语言风格的不同的编程方法(或称过程),经过KeilC51编译器编译为汇编代码后,汇编代码竟然一模一样。既然汇编代码一样,那么相应的机器代码也就一样,最终表现出来的代码执行效率、时间就是一样的。

至此,笔者惊讶于Keil公司的编译器竟是如此"高效“和”智能化“,为同一目标而编写的,但使用不同风格的编程方法编写出来的程序,代码经过编译后,最终的执行效率竟然几乎一致。

由此得出,Keil对C语言的源代码有非常高效的编译方法,使同一目的但不同编程方法实现的代码,最终在硬件上实现非常高效的执行效率。

那么,既然编译器如此高效,是否意味着:用户可以随意编程,而不考虑编译效率的问题呢?这个问题,有待继续学习、研究!




posted @ 2013-04-24 00:15  TechStone  阅读(320)  评论(0编辑  收藏  举报