扫描关注一起学嵌入式,了解程序结构优化与标识符选取技巧

语言设计单片机应用系统程序时,首先要注意尽可能采用结构化的程序设计方法,这样可使整个应用系统程序结构清晰,便于调试和维护。各个模块可以分别编写,甚至还可以由不同的程序员编写,一般单个模块完成的功能较为简单,设计和调试也相对容易一些。语言中,一个函数就可以认为是一个模块。

扫描关注一起学嵌入式,了解程序结构优化与标识符选取技巧

程序结构优化

1.程序编写结构

虽然书写格式不会影响生成代码的质量,但是在实际编写程序时还是需要遵循一定的书写规则,清晰简洁的程序有利于日后的维护。

编写程序时,特别是对于 While、for、do…while、if…else、switch…case 等语句,或者这些语句的嵌套组合,应该使用“缩进”的书写格式。

2、程序中使用的用户标识符除了要遵循标识符的命名规则外,一般不要使用代数符号(如a、b、x1、y1)作为变量名,应选用具有相关含义的英文单词(或缩写)或汉语拼音作为标识符,以增加程序的可读性,如:count、number1、red、work等。

3. 程序结构

C语言是一种高级编程语言,提供了非常完善的标准化过程控制结构。因此,在利用C语言设计单片机应用系统程序时,首先应注意尽可能采用结构化的编程方法,使整个应用系统程序结构清晰,便于调试和维护。

对于一个较大的应用程序来说,通常将整个程序按照功能划分为若干个模块,不同的模块完成不同的功能。

各个模块可以单独编写,甚至可以由不同的程序员编写。一般单个模块完成的功能比较简单,设计和调试也比较容易。在C语言中,一个函数可以看作是一个模块。

所谓程序模块化,不仅仅是将整个程序分成若干个功能模块,更重要的是还要注意保持模块间变量的相对独立性,即保持模块的独立性,尽量少使用全局变量等。对于一些常用的功能模块,也可以将其封装为应用程序库,以便在需要的时候直接调用。

但是,在使用模块化的时候,如果将模块分成太多小的部分,程序的执行效率会降低(进入和退出函数时保护和恢复寄存器需要一些时间)。

4. 定义常量

在程序设计过程中,如果将一些经常使用的常量直接写入程序中,一旦常量的值发生变化,就必须逐个查找程序中的所有常量,逐个进行修改,这样势必会降低程序的可维护性。因此,要尽可能地采用预处理命令法来定义常量,这样也可以避免输入错误。

5.减少判断语句

尽可能使用条件编译(ifdef)代替if语句,这有助于减少编译生成的代码的长度。

6. 表达

对于表达式中各种运算的优先级不明确或容易混淆的地方,应该使用括号来明确规定它们的优先级。表达式不宜过于复杂。如果表达式太复杂,读了很久之后就很难理解,不利于以后的维护。

7. 功能

对于程序中的函数,在使用之前应该说明函数的类型。函数类型的说明必须保证与原先定义的函数类型一致。对于无参数和返回值类型的函数,应添加“void”说明。如果需要缩短代码长度,可以将程序中一些常用的程序段定义为函数。

如果需要缩短程序的执行时间,可以在程序调试完成后,用宏定义代替某些函数。注意,宏应该在程序调试完成后再定义,因为大多数编译系统只有在宏展开后才会报错,这会增加调试的难度。

8. 尽量少用全局变量,多用局部变量

由于全局变量是放在数据存储器中的,定义一个全局变量就意味着 MCU 少了一个可用的数据存储器空间,如果定义了太多的全局变量,编译器就会没有足够的内存来分配。局部变量在 MCU 内部大多位于寄存器中,在大多数 MCU 中,使用寄存器的运算速度比数据存储器快,指令也更加丰富灵活,有利于生成更高质量的代码。另外,局部变量占用的寄存器和数据存储器可以在不同的模块中重复使用。

9.设置适当的编译器选项

很多编译器都有几种不同的优化选项,使用前应该了解每种优化选项的含义,然后选择最合适的一种。通常,一旦选择了最高级别的优化,编译器就会近乎病态地追求代码优化,这可能会影响程序的正确性,导致程序错误。

因此,你应该熟悉你所使用的编译器,知道在优化过程中哪些参数会受到影响,哪些参数不会受到影响。

代码优化

1.选择正确的算法和数据结构

你应该熟悉算法语言。用更快的二分查找法或随机查找法代替速度较慢的顺序查找法,用快速排序、归并排序或根排序代替插入排序或冒泡排序法,这些都可以大大提高程序执行的效率。

选择合适的数据结构也很重要,比如在一堆随机存储的数据中使用大量的插入和删除指令,要比使用链表快得多。数组和指针关系密切,一般来说,指针更灵活简洁,而数组更直观易懂。对于大多数编译器来说,使用指针比使用数组生成的代码更短,执行效率更高。

但在 Keil 中,情况正好相反,使用数组比使用指针生成的代码更短。

2. 使用尽可能最小的数据类型

如果可以使用字符类型(char)定义变量,就不要使用整型(int)变量来定义它;如果可以使用整型变量,就不要使用长整型(long int);如果可以避免使用浮点型变量,就不要使用浮点型变量。

当然定义完变量之后不要超出它的作用域,如果赋值超出了变量的作用域,C编译器不会报错,但是程序运行会出错,而且这样的错误很难发现。

3.使用自增和自减指令

通常使用自增、自减指令和复合赋值表达式(如a-=1和a+=1等)可以生成高质量的程序代码。编译器通常可以生成inc和dec之类的指令,而当使用a=a+1或a=a-1之类的指令时,很多C编译器会生成2~3个字节的指令。

4.降低计算强度

你可以用计算量更少,但功能相同的表达式来替代原来复杂的表达式。如下:

(1)余数运算

a=a%8;

可以改为:

a=a&7;

注意:位操作只需一个指令周期即可完成,而大多数 C 编译器使用子程序来完成“%”操作,代码较长,执行速度慢。通常,如果只需要求 2n 的平方的余数,可以使用位操作代替。

(2)平方运算

a=pow(a,2.0);

可以改为:

a=a*a;

注意:在内置硬件乘法器的微控制器(如 51 系列)中,乘法比平方快得多,因为浮点数的平方是通过调用子程序来实现的。在内置硬件乘法器的 AVR 微控制器(如 ATMega163)中,乘法仅需 2 个时钟周期即可完成。

即使在没有内置硬件乘法器的 AVR 微控制器中,乘法子程序也比平方运算子程序更短、更快。如果要计算立方,例如:

a=pow(a,3.0);

改成:

a=a*a*a;

效率的提升更加明显。

(3)利用移位实现乘法、除法运算

a=a*4;

b=b/4;

可以改为:

a=a>2;

注意:通常,如果需要乘以或除以 2n,可以使用移位方法。在 ICCAVR 中,如果乘以 2n,则可以生成左移代码,如果乘以其他整数或除以任意数,则可以调用乘法和除法子程序。

通过 shift 方法生成的代码比调用乘法和除法子程序生成的代码效率更高。事实上,只要你乘或除一个整数,就可以使用 shift 方法得到结果,如:

a=a*9

可以改为:

一个=(一个

单片机

覆盆子和树莓的价格波动及市场定位:是同一种植物吗?

2024-5-29 6:03:52

单片机

STC89C51 单片机烧写程序的硬件工具与软件设置

2024-5-29 7:03:09

0 条回复 A文章作者 M管理员
    暂无讨论,说说你的看法吧
个人中心
购物车
优惠劵
今日签到
有新私信 私信列表
搜索