7回答

0收藏

[原创] 51中获得长整型高字节的方法的效率对比

51单片机 51单片机 4300 人阅读 | 7 人回复 | 2013-03-04

  前两周刚搞好一个labview的作品,这几天又开始忙做单片机课设,没想到开学开始这么忙。不过今天在做课设过程中有所收获,所以特地花点时间和大家分享分享。
  因为课设要做的涉及到SD卡,所以函数参数中长整型用到比较多。51是8位,不知道处理32位数据上效率怎么样,于是今天特地做了下测试,顺便复习下汇编语言。想要知道一条C代码执行效率怎么样,还是得用反汇编窗口看看汇编后的代码是什么。说了这么多好像大家都不知道我在说些什么。额,好像确实没有逻辑。我还是另起一段,有条理的讲述下问题吧。
  我用51实现SPI模式读取SD卡,因为SD卡的函数参数是32位长整型,而SPI以字节为单位传输,于是就涉及到如何获得长整型的各个字节。我目前已知的方法有两种,一种是用移位来获得高位字节,如:SDWriteByte((uint8)(arg >> 24));还有一种是指针的方法,如:SDWriteByte(((unsigned char *)&arg)[0]);以上两句代码实现的是一样的功能(arg是32位无符号长整型,这里其值为0x00000095),但是哪种的效率高呢?我们可以打开keil的反汇编窗口看看汇编后的代码就知道了。
  对于第一种方法,汇编代码如:
  1.    253:         SDWriteByte((uint8)(arg >> 24));
  2. C:0x26A8    7818     MOV      R0,#0x18
  3. C:0x26AA    1228A8   LCALL    C:28A8
复制代码
这里调用了地址C:28A8的函数,所以我们转到C:28A8看一下代码:
  1. C:0x28A8    900289   MOV      DPTR,#0x0289
  2. C:0x28AB    E0       MOVX     A,@DPTR
  3. C:0x28AC    FC       MOV      R4,A
  4. C:0x28AD    A3       INC      DPTR
  5. C:0x28AE    E0       MOVX     A,@DPTR
  6. C:0x28AF    FD       MOV      R5,A
  7. C:0x28B0    A3       INC      DPTR
  8. C:0x28B1    E0       MOVX     A,@DPTR
  9. C:0x28B2    FE       MOV      R6,A
  10. C:0x28B3    A3       INC      DPTR
  11. C:0x28B4    E0       MOVX     A,@DPTR
  12. C:0x28B5    FF       MOV      R7,A
  13. C:0x28B6    121118   LCALL    C?ULSHR(C:1118)
  14.   ......(这里是SDWriteByte函数)
复制代码
这是0x28A8处的代码,以上部分是参数传递部分,后面省略的是SDWriteByte函数。可以看到前面 12句是将arg复制到寄存器中。(可以看到arg在内存中的地址正是0x0289)

  那最后一句呢?老实说我汇编很烂,看到C?ULSHR还以为那问号是乱码呢?不过等看完代码后终于知道这里调用的是一个函数:无符号长整型右移函数(ULSHR),在C:1118可以看到函数代码:
  1.                  C?ULSHR:
  2. C:0x1118    E8       MOV      A,R0
  3. C:0x1119    600F     JZ       C:112A
  4. C:0x111B    EC       MOV      A,R4
  5. C:0x111C    C3       CLR      C
  6. C:0x111D    13       RRC      A
  7. C:0x111E    FC       MOV      R4,A
  8. C:0x111F    ED       MOV      A,R5
  9. C:0x1120    13       RRC      A
  10. C:0x1121    FD       MOV      R5,A
  11. C:0x1122    EE       MOV      A,R6
  12. C:0x1123    13       RRC      A
  13. C:0x1124    FE       MOV      R6,A
  14. C:0x1125    EF       MOV      A,R7
  15. C:0x1126    13       RRC      A
  16. C:0x1127    FF       MOV      R7,A
  17. C:0x1128    D8F1     DJNZ     R0,C:111B
  18. C:0x112A    22       RET
复制代码
17句代码实现了长整型的右移位,老实说,平时没用汇编,看懂了上面的代码后才发现汇编是多么精妙的东西,简单,却强大。
  不过,汇编好归好,要是评估起这个移位传参的方法好像效率不是很高哦。一个右移函数的循环部分有14条指令,像这里移位24,算起来要执行300多条指令才能搞定。一句看起来简单的arg>>24竟然要执行这么多指令来完成,那样速率一定有很大影响。
   我们再来看第二种方法,汇编代码如下:
  1. 254:         SDWriteByte(((unsigned char *)&arg)[0]);
  2. C:0x26A8    900289   MOV      DPTR,#0x0289
  3. C:0x26AB    E0       MOVX     A,@DPTR
  4. C:0x26AC    FF       MOV      R7,A
  5. C:0x26AD    1228AB   LCALL    SDWriteByte(C:28AB)
复制代码
可以看到这种方法代码很少,只用了3条指令就完成了参数的传递 ,效率之高就不用说了。
  综上,我个人认为在51在进行长移位并不是一个效率很高的方法,用指针的方法应该更好。不知道大家有什么看法,或者有其他更好的方法可以分享下。


分享到:
回复

使用道具 举报

回答|共 7 个

倒序浏览

沙发

sagitattoo

发表于 2013-3-4 19:25:08 | 只看该作者

这应该还要考虑在不同IDE下的情况
Don't Worry.

Be Happy!
板凳

ming1006

发表于 2013-3-4 19:34:18 | 只看该作者

sagitattoo 发表于 2013-3-4 19:25
这应该还要考虑在不同IDE下的情况

比较常见的是keil,不知道其他IDE能汇编出效率更高的代码吗
地板

mcp2013

发表于 2013-3-4 21:08:11 | 只看该作者

效率bu怎么样
5#

ming1006

发表于 2013-3-4 22:13:12 | 只看该作者

mcp2013 发表于 2013-3-4 21:08
效率bu怎么样

?什么意思?
6#

mcp2013

发表于 2013-3-4 23:12:03 | 只看该作者

keil里面有一个编译选项 可以调节编译效率等级的
7#

E08610225

发表于 2013-3-5 19:49:31 | 只看该作者

恩恩~这个研究很不错~
①人生最重要的三件事:一孝顺;二行善;三学习。
②人欲立业,首要立德。做自己想做的人,一个用心听事、用心做事的人。
③树欲静而风不止,子欲养而亲不待。父母养我育我,他们能够再等多久?
④切记戒骄戒躁。
8#

ming1006

发表于 2013-3-8 19:01:10 | 只看该作者

mcp2013 发表于 2013-3-4 23:12
keil里面有一个编译选项 可以调节编译效率等级的

我的是等级8时编译的,应该优化度比较高了
您需要登录后才可以回帖 注册/登录

本版积分规则

关闭

站长推荐上一条 /2 下一条