在51单片机上写出最优代码
来源:互联网 发布:日本书法 知乎 编辑:程序博客网 时间:2024/06/03 19:44
列举一些如何在8051单片机上写出高性能代码的方法,高性能指的是编译出的代码具有更小的size和更快的执行速度。以下的方法在大多数情况下都是能够起作用的。
- 存储模式(Memory Model)
存储模式最能够影响最终产生代码的大小和执行速度。编译时采用SMALL模式可以产生最小、最快的代码。在SMALL模式下所有的变量,除非特别说明,都会存放在8051内部存储区。单片机访问内部存储区的速度非常看(通常是1~2个时钟周期),产生的代码尺寸也比使用COMPACT或LARGE模式产生的代码小很多。比如以下代码
void do_nothing(void);void main(){ unsigned char i; for (i=0; i<100; i++) { do_nothing(); }}void do_nothing(void){ ;}
若使用SMALL模式进行编译,生成的汇编代码如下:
; FUNCTION main (BEGIN) ; SOURCE LINE # 3 ; SOURCE LINE # 4 ; SOURCE LINE # 60000 E4 CLR A0001 F500 R MOV i,A0003 ?C0001: ; SOURCE LINE # 7 ; SOURCE LINE # 80003 120000 R LCALL do_nothing ; SOURCE LINE # 90006 0500 R INC i0008 E500 R MOV A,i000A C3 CLR C000B 9464 SUBB A,#064H000D 40F4 JC ?C0001 ; SOURCE LINE # 10000F ?C0004:000F 22 RET ; FUNCTION main (END) ; FUNCTION do_nothing (BEGIN) ; SOURCE LINE # 12 ; SOURCE LINE # 13 ; SOURCE LINE # 150000 22 RET ; FUNCTION do_nothing (END)
在SMALL模式中,变量i保存在内部存储区。访问i的指令MOV A, i 和 INC i 只需要两个字节的空间。另外,执行这些指令只需要一个时钟周期。生成的代码size总共为17bytes。若使用LARGE模式,则生成下面的汇编指令
; FUNCTION main (BEGIN) ; SOURCE LINE # 3 ; SOURCE LINE # 4 ; SOURCE LINE # 60000 E4 CLR A0001 900000 R MOV DPTR,#i0004 F0 MOVX @DPTR,A0005 ?C0001: ; SOURCE LINE # 7 ; SOURCE LINE # 80005 120000 R LCALL do_nothing ; SOURCE LINE # 90008 900000 R MOV DPTR,#i000B E0 MOVX A,@DPTR000C 04 INC A000D F0 MOVX @DPTR,A000E E0 MOVX A,@DPTR000F C3 CLR C0010 9464 SUBB A,#064H0012 40F1 JC ?C0001 ; SOURCE LINE # 100014 ?C0004:0014 22 RET ; FUNCTION main (END) ; FUNCTION do_nothing (BEGIN) ; SOURCE LINE # 12 ; SOURCE LINE # 13 ; SOURCE LINE # 150000 22 RET ; FUNCTION do_nothing (END)
在LARGE模式中,变量i存放在外部存储区。为了访问变量i,编译器需要先加载该变量的地址,然后执行外部数据访问操作(offset为0001h~0004h), 执行这两条执行需要花费4个时钟周期。0008h~000dh是i++的指令。这些指令占用了6bytes内存空间,执行时间是7个时钟周期。在LARGE模式下,生成的代码大小总共为22bytes。
2. 变量存储方式
由于CPU访问内部存储区比外部存储区效率更高,所以需要频繁擦写的变量需要存放在内部存储区更好一些。内部存储区包括register, bit,stack以及存储类型为data的变量。
由于8051的内部存储区有限(128字节或256字节),所以程序中使用的变量不一定都能放到内部存储区中。此时你需要把一些变量分配到其他存储区。这里介绍两种方法。
2.1 在keil中设置memory model,让编译器去做这个工作。这个方法最简单,但生成的代码的不是最优的。
2.2 使用xdata存储类型声明将一些不经常使用的变量放置到外部存储区,而频繁擦写的变量放置到内部存储区。这样就能够合理的使用单片机的资源,生成最优的代码。
3. 定义变量的类型
8051家族都是8位单片机。使用8位的数据类型(char/unsigned char)会比使用 int/long类型的数据参与运算更有效率。基于此,我们在代码中尽量使用8位的数据类型。
4. 无符号类型
如果使用有符号类型变量,编译器会产生跟多的代码,所以尽量使用无符号类型变量。
5. 局部变量
在做代码优化时,编译器会尝试将局部变量放置到寄存器中,寄存器访问是最快的内存访问方式,所以我们尽可能使用局部变量。
如将变量i改为signed char类型
1 void do_nothing(void); 2 3 void main() 4 { 5 1 signed char i; 6 1 for (i=0; i<100; i++) 7 1 { 8 2 do_nothing(); 9 2 } 10 1 } 11 12 void do_nothing(void) 13 { 14 1 ; 15 1 }
生成的汇编代码为
; FUNCTION main (BEGIN) ; SOURCE LINE # 3 ; SOURCE LINE # 4 ; SOURCE LINE # 60000 E4 CLR A0001 F500 R MOV i,A0003 ?C0001: ; SOURCE LINE # 7 ; SOURCE LINE # 80003 120000 R LCALL do_nothing ; SOURCE LINE # 90006 0500 R INC i0008 C3 CLR C0009 E500 R MOV A,i000B 6480 XRL A,#080H000D 94E4 SUBB A,#0E4H000F 40F2 JC ?C0001 ; SOURCE LINE # 100011 ?C0004:0011 22 RET ; FUNCTION main (END) ; FUNCTION do_nothing (BEGIN) ; SOURCE LINE # 12 ; SOURCE LINE # 13 ; SOURCE LINE # 150000 22 RET ; FUNCTION do_nothing (END)
通过比较,可以看出,i改为signed char类型后,汇编中多了一条指令
000B 6480 XRL A,#080H
致使最终生成的代码size为19bytes,大于i为unsigned char的情况。
6. 算法的影响
有些时候,更好的算法也会提高代码的速度,减小代码的存储空间。
以上参考自keil编译手册。
- 在51单片机上写出最优代码
- java代码在AIX上写出的中文是乱码
- ucos ii在spca061a单片机上移植代码
- 写出高效优美的C语言代码(单片机)
- 写出高效优美的C语言代码(单片机)
- 如何写出高效优美的单片机C语言代码
- 写出高效优美的单片机C语言代码
- 如何写出高效优美的单片机C语言代码?
- 写出高效优美的单片机C语言代码
- 写出高效优美的单片机C语言代码
- 51单片机串口通信,网络上摘取的代码片段
- 在单片机上点亮LED
- 在CSDN上写出漂亮博文
- 在CSDN上写出漂亮博文
- 在51系列单片机上移植uCOS-II
- 在51系列单片机上移植uCOS-II
- 在51系列单片机上移植uCOS-II
- 在51系列单片机上移植uCOS-II
- 修改input的text 通过jquery的html获取值 未变化
- Git系列一之安装管理
- (4)MyBatis之一对一关联
- 0001-Verilog语言学习笔记/20170314
- Ubuntu 14.04下安装有道词典
- 在51单片机上写出最优代码
- [LeetCode OJ]Container With Most Water
- Java多线程相关知识记录
- java静态代码块执行顺序
- 弹出键盘,textfield上移,搜罗总结
- ud730深度学习(一)——卷积模型
- 获取Oracle连接对象代餐构造,select需要提交事务
- C++通过HTTP请求Get或Post方式请求Json数据
- (5)MyBatis之一对多关联