专栏首页编程C语言嵌入式系统编程修炼之性能优化

C语言嵌入式系统编程修炼之性能优化

这是我13年前创作和发表在互联网上的文章,这么多年过去了,这篇文章仍然在到处传播。现在贴回Linuxer公众号。

全文目录:

C语言嵌入式系统编程修炼之道——背景篇

C语言嵌入式系统编程修炼之道——软件架构篇

1.模块划分

2.多任务还是单任务

3.单任务程序典型架构

4.中断服务程序

5.硬件驱动模块

6.C的面向对象化

总结

C语言嵌入式系统编程修炼之道——内存操作篇

1.数据指针

2.函数指针

3.数组vs.动态申请

4.关键字const

5.关键字volatile

6.CPU字长与存储器位宽不一致处理

总结

C语言嵌入式系统编程修炼之道——屏幕操作篇

1.汉字处理

2.系统时间显示

3.动画显示

4.菜单操作

5.模拟MessageBox函数

总结

C语言嵌入式系统编程修炼之道——键盘操作篇

1.处理功能键

2.处理数字键

3.整理用户输入

总结

C语言嵌入式系统编程修炼之道——性能优化篇

1.使用宏定义

2.使用寄存器变量

3.内嵌汇编

4.利用硬件特性

5.活用位操作

总结

C语言嵌入式系统编程修炼之性能优化

使用宏定义

在C语言中,宏是产生内嵌代码的唯一方法。对于嵌入式系统而言,为了能达到性能要求,宏是一种很好的代替函数的方法。

写一个"标准"宏MIN ,这个宏输入两个参数并返回较小的一个:

错误做法:

正确做法:

对于宏,我们需要知道三点:

(1)宏定义"像"函数;

(2)宏定义不是函数,因而需要括上所有"参数";

(3)宏定义可能产生副作用。

下面的代码:

将被替换为:

发生的事情无法预料。

因而不要给宏定义传入有副作用的"参数"。

使用寄存器变量

当对一个变量频繁被读写时,需要反复访问内存,从而花费大量的存取时间。为此,C语言提供了一种变量,即寄存器变量。这种变量存放在CPU的寄存器中,使用时,不需要访问内存,而直接从寄存器中读写,从而提高效率。寄存器变量的说明符是register。对于循环次数较多的循环控制变量及循环体内反复使用的变量均可定义为寄存器变量,而循环计数是应用寄存器变量的最好候选者。

(1) 只有局部自动变量和形参才可以定义为寄存器变量。因为寄存器变量属于动态存储方式,凡需要采用静态存储方式的量都不能定义为寄存器变量,包括:模块间全局变量、模块内全局变量、局部static变量;

(2) register是一个"建议"型关键字,意指程序建议该变量放在寄存器中,但最终该变量可能因为条件不满足并未成为寄存器变量,而是被放在了存储器中,但编译器中并不报错(在C++语言中有另一个"建议"型关键字:inline)。

下面是一个采用寄存器变量的例子:

本程序循环n次,i和s都被频繁使用,因此可定义为寄存器变量。

内嵌汇编

程序中对时间要求苛刻的部分可以用内嵌汇编来重写,以带来速度上的显著提高。但是,开发和测试汇编代码是一件辛苦的工作,它将花费更长的时间,因而要慎重选择要用汇编的部分。

在程序中,存在一个80-20原则,即20%的程序消耗了80%的运行时间,因而我们要改进效率,最主要是考虑改进那20%的代码。

嵌入式C程序中主要使用在线汇编,即在C程序中直接插入_asm{ }内嵌汇编语句:

利用硬件特性

首先要明白CPU对各种存储器的访问速度,基本上是:

CPU内部RAM > 外部同步RAM > 外部异步RAM > FLASH/ROM

对于程序代码,已经被烧录在FLASH或ROM中,我们可以让CPU直接从其中读取代码执行,但通常这不是一个好办法,我们最好在系统启动后将FLASH或ROM中的目标代码拷贝入RAM中后再执行以提高取指令速度;

对于UART等设备,其内部有一定容量的接收BUFFER,我们应尽量在BUFFER被占满后再向CPU提出中断。例如计算机终端在向目标机通过RS-232传递数据时,不宜设置UART只接收到一个BYTE就向CPU提中断,从而无谓浪费中断处理时间;

如果对某设备能采取DMA方式读取,就采用DMA读取,DMA读取方式在读取目标中包含的存储信息较大时效率较高,其数据传输的基本单位是块,而所传输的数据是从设备直接送入内存的(或者相反)。DMA方式较之中断驱动方式,减少了CPU 对外设的干预,进一步提高了CPU与外设的并行操作程度。

活用位操作

使用C语言的位操作可以减少除法和取模的运算。在计算机程序中数据的位是可以操作的最小数据单位,理论上可以用"位运算"来完成所有的运算和操作,因而,灵活的位操作可以有效地提高程序运行的效率。举例如下:

对于以2的指数次方为"*"、"/"或"%"因子的数学运算,转化为移位运算">"通常可以提高算法效率。因为乘除运算指令周期通常比移位运算大。

C语言位运算除了可以提高运算效率外,在嵌入式系统的编程中,它的另一个最典型的应用,而且十分广泛地正在被使用着的是位间的与(&)、或(|)、非(~)操作,这跟嵌入式系统的编程特点有很大关系。我们通常要对硬件寄存器进行位设置,譬如,我们通过将AM186ER型80186处理器的中断屏蔽控制寄存器的第低6位设置为0(开中断2),最通用的做法是:

而将该位设置为1的做法是:

判断该位是否为1的做法是:

上述方法在嵌入式系统的编程中是非常常见的,我们需要牢固掌握。

总结

在性能优化方面永远注意80-20准备,不要优化程序中开销不大的那80%,这是劳而无功的。

宏定义是C语言中实现类似函数功能而又不具函数调用和返回开销的较好方法,但宏在本质上不是函数,因而要防止宏展开后出现不可预料的结果,对宏的定义和使用要慎而处之。很遗憾,标准C至今没有包括C++中inline函数的功能,inline函数兼具无调用开销和安全的优点。

使用寄存器变量、内嵌汇编和活用位操作也是提高程序效率的有效方法。

除了编程上的技巧外,为提高系统的运行效率,我们通常也需要最大可能地利用各种硬件设备自身的特点来减小其运转开销,例如减小中断次数、利用DMA传输方式等。

本系列文章全文完

本文来自企鹅号 - Linuxer媒体

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 从趣味游戏到编程思维——Scratch编程课程设计思想

    邓博士和很多在学习编程孩子的家长交流后,发现一个共同的特点:家长其实对于孩子为什么要学编程并不是很理解,就觉得反正买个课程又不贵,孩子喜欢而已,就试试呗!另外,...

    企鹅号小编
  • UG数控编程-加工思路总结

    大家好,我是度心,今天给大家介绍一下UG编程多年来的一些加工思路总结,希望对正在学习UG编程的同学们有帮助!!!! 现在很多人都想学门技术,希望即能赚钱又有发展...

    企鹅号小编
  • 2018年,程序员的计划清单!

    1. 学习一门新的不同风格的编程语言 这是很有必要的一件事,因为如果你只了解一种语言,它就会局限你解决问题的能力和你的职业发展。所以在新的一年,你应该花些时间学...

    企鹅号小编
  • 出货量8亿颗!阿里系芯片公司中天微发布中国自研CPU架构RISC-V处理器

    据中天微官网9月3日消息,杭州中天微系统有限公司宣布,正式推出支持RISC-V第三代指令系统架构处理器CK902,可灵活配置TEE引擎,支持物联网安全功能。中天...

    新智元
  • 高性能网关设备及服务实践

    针对海量的网络流量,转发性能是我们最关键的一个方面,那构建高性能的后台服务器有哪些关键的技术和需要注意的地方。

    鹅厂网事
  • 施耐德PLC漏洞历险记

    工控安全是维护国家基础设施的安全,可工控设备并不像web那么常见,因此工控安全的研究较之web安全也相对迟缓。最近,瑞不可当工控团队入手了一台施耐德PLC,就让...

    FB客服
  • 编写程序到底是什么玩意?

    所以你会发现,在学编程的人中,逻辑思维能力强的人,编程一般都学得不错,而做事丢三落四的人一般都学得不好。

    良月柒
  • 梯度检验与高级优化

    梯度检验与高级优化 导读 神经网络 反向传播算法 目录 关键词 梯度检验与高级优化 1 关键词 缺位错误 off-by-one error 偏置项 bias ...

    昱良
  • 手游加固-腾讯云手游安全MTP

    腾讯云手游安全MTP针对市面通用手游外挂进行打击,同时提供腾讯游戏专用加固壳,全方位保护手游安全

    用户3570397
  • AAAI 2019 | 自动机器学习计算量大!这种多保真度优化技术是走向应用的关键

    作者:Yi-Qi Hu, Yang Yu, Wei-Wei Tu, Qiang Yang, Yuqiang Chen , Wenyuan Dai

    机器之心

扫码关注云+社区

领取腾讯云代金券