新闻中心

EEPW首页 > 嵌入式系统 > 牛人业话 > MCU资源受限 怎么面对编程的挑战

MCU资源受限 怎么面对编程的挑战

作者:光华居士时间:2019-05-10来源:电子产品世界收藏

心有多大,舞台就有多大,梦想有多大,你的世界就有多大。

本文引用地址:http://www.amcfsurvey.com/article/201905/400449.htm

这句浓浓的鸡汤实在是太“唯心主义”了。因为,如果资源非常有限,软件工程师的心再大,也没有舞台施展自己的斧钺钩叉。

在广阔的人生舞台上才能大有作为,面对广袤的世界,大开大合地书写自己的人生,这种挥洒、写意的疏阔没有人不喜欢。可是,如果你要在一个资源受限的上编程,就像是在一个空间狭小的舞台上演话剧,你需要反复思量,才能应对空间的局促,半分挥洒就会让剧情漫出舞台之外。为了利用好每一寸空间,你需要反复斟酌、再斟酌,调整、再调整,哪里还有半分写意可得?!

说实话,这种感觉实在坏透了。在一次产品开发中,笔者就切身体会过这种地狱般的局促和捉襟见肘,现在想来,还有几丝寒意漫上心头......

1

顺利的开始等于成功的一半。笔者开始开发中控锁模块时,就有这种美好的感觉。因为,从功能上来看,中控锁相当于车身控制器的一个子模块,笔者有车身控制器的开发经验,把它刀劈斧砍,择菜式地弄出来个中控锁,还不是小菜一碟?

事实证明,这还真是小菜一碟。因为我们这款用在某个国产车上的中控锁的功能实在太简单了,就是三大块:机械钥匙解锁、闭锁+遥控钥匙解锁、闭锁+车身防盗功能,所谓车身防盗,就是车门被撬开时用转向灯和喇叭报警。

在以往开发车身控制器的历史积累中,开关检测模块、定时器管理模块、遥控接收解析模块都是现成的,无非是从之前的上搬过来,稍微移植一下即可。开发难度,自然是没有的,所以深谙内情的领导把整个产品的开发周期定为三个月。

在这三个月的时间里,硬件开发和软件开发是同步进行的,首要的工作自然是MCU的选型。

timg (2).jpg

所有成功决定的背后都是对若干关键因素的权衡,MCU的选型也不例外,MCU的资源、成本、性能、生命周期、供货能力都是必须考虑的因素。其中,资源是最为软件工程师看重的指标。

最初,领导并没有插手MCU选型的工作,这项任务落在了我和硬件工程师张工的头上。我个人比较青睐于飞思卡尔的单片机,因为我之前从事的所有产品的开发都用飞思卡尔系列,代码移植起来比较方便,可是张工却倾向于微芯的一颗MCU。反复论战之后,报领导裁决,领导决定使用微芯方案,选用的MCU是微芯的PIC16F1509,原因无它,便宜!

这个芯片内置512字节RAM,8K字节程序Flash,和之前用过的MCU比起来确实袖珍得可以。最初打眼一看,RAM和Flash的数量好像有点少,资源到底够用不够用,说实话我心里是没谱的,带着这种忐忑的心情,我开始了代码的移植工作。

虽然之前没有用过微芯的产品,但是毕竟中控锁的功能太简单,而这颗MCU也太小巧玲珑了,所以移植工作进行地顺风顺水,在硬件电路板还没有拿到手之前,我就完成了初步编程工作。板子到手后,一顿操作猛如虎,调试、运行、修改三板斧下来,最终软件基本定型时,RAM用了300个字节左右,Flash更是用了不到4K。

当然,这并不能说明我水平有多高,只能说明这个产品实在太简单了。

2

我本以为,这将是我有史以来用过的资源最少的一款MCU,不曾想,这个记录很快就被我自己打破了。

项目启动两个月后,软硬件开发工作就结束了,提前了原计划整整一个月的时间。在随后召开的项目会议上,我带着忆苦思甜的幸福感,向领导汇报了代码移植、调试工作,并表达了最初对MCU资源的忐忑之情。

透过厚厚的镜片,领导滴溜溜地转了一下眼睛,询问了一下RAM和Flash的具体使用量,老实、不带任何戒心的我如实地告知了领导具体数字。那一刻我还不知道,正是这种诚实让我在接下来的一个月里度过了一段不堪回首、鸡飞狗跳的日子。

从我这里得知RAM、Flash的具体使用量之后,领导歪了歪憨态可掬的脖子,把头转向张工,问起PIC16F1508的资源来。看着张工沉思的样子,我心中火光电闪,瞬间‘领会了’领导的意图。领导做硬件出身,MCU选型也是他平时主抓的业务工作之一,他无非是想知道pin to pin兼容、成本更低的PIC16F1508能不能替换更贵的PIC16F1509罢了。

不等张工发言,我已经在内心里盘算了一下:‘1508的Flash是4K字节,程序空间是够用的,但是它的RAM是256字节,明显不够用。’一念至此,我舒了一口气,给张工眨了眨眼睛,于是,张工如实地告知了领导1508的资源。

我本以为事情到此就结束了,却不曾想,领导又把他那扎煞在硬硬的衣领里面的脖子朝我转过来,向我交待了一个匪夷所思的任务:

把代码改改,把RAM使用量降到256字节以下,用PIC16F1508能便宜一块多呐!

timg (5).jpg

领导接着笑言:“项目合作方要求降成本,我都答应人家了,正好不知道从哪里下手呢!”

3

代码基本定型,这时要精简掉将近20%左右的RAM使用量,肿么办?

笔者首先想到的是那些取值范围有限的全局变量,这些变量之前都是用uint8_t类型定义的,在这种定义下,MCU会用一个8位的字节来存储它。这对于一个实际上当成布尔量使用的变量来说绝对是一种浪费,显然,用一个‘位’来存储它更节约空间。还有那些取值范围不超过7的,都可以用3位存储,不超过15的,可以用4位存储,以此类推。

具体实现方式也很简单,像MCU的硬件寄存器定义一样,定义一个位域形式的结构体,把这些变量以结构体中位域形式的成员变量的形式来表示。通过这番操作,笔者居然省掉了整整20来个字节的RAM空间。

当然这也不是没有代价的,那些“干脆利落”的变量名称不见了,结构体.成员变量形式的“麻烦啰嗦”的名称倒是随处可见,散布在源代码各个角落,甚是扎眼。

革命尚未成功,同志仍需努力,要把RAM使用量降到256字节以下,还需要继续精简。我的目光在各个源文件之间流连不断,内心不断地做着权衡和取舍。我深深地知道:要省RAM,必须修改某些模块的实现方式,而这必然要付出牺牲代码阅读性的代价。

主动绞杀阅读上的美感,这种感觉实在是难受极了。

目光所及之处,正是定时器管理模块的“软件定时器结构体”,这里有个成员变量是“定时回调函数”,这是一个16位指针变量,指向回调函数首地址。定时器启动时,把回调函数首地址赋给该变量,等计时满时,定时器管理模块会“自动”调用该回调函数,这是一种多么优美的设计!当然,优美的代价是每一个软件定时器节点都需要安排两个字节存储该回调函数首地址,10个定时器节点就对应整整20个字节。

当断不断反受其乱,我怀着无比悲壮的心情修改了定时器管理模块的设计,把这个成员变量删掉,代之以一个表示定时超时的标志flag,这个flag用一个位变量表示即可,通过和软件定时器结构体中临近成员变量(正好也是一个位变量)的结合,这个flag实际上不会引入任何额外的存储需求。在定时器管理模块设计中,通过查询超时标志flag,“手动”调用相应的回调函数,一样可以满足程序功能要求。

通过这种方式,我又节省了20个字节。目标越来越近了,我也越来越欲减乏术了。

4

这一天,距离256个字节的目标只剩下10个字节了,我默默地躺在床上,盯着头顶的天花板,久久无法入眠。

这是最孤寂的时刻,在静静的午夜,宇宙向它的聆听者展示着广漠的荒凉。

我不禁想起了大刘在《三体》中写过的智子工程-将一个9维空间的质子展开为2维,然后在这个展开后变得无比巨大的2维质子上蚀刻微观集成电路。。。我要是能把RAM展开就好了!

RAM展开?还能展开到Flash里面去吗?这时,‘RAM不够,Flash来凑’的八字真言奇迹般地出现在我眼前,我隐约觉得哪里有些变量实际上只取一些固定值了,那么,把这些变量直接定义成常量,它就不消耗RAM空间了,转而去消耗Flash空间了!对,明天就这么干。

果不其然,第二天,我就在遥控钥匙的解析接收程序里找到了一个四字节的数组变量,它在实际运行中只取常量值。改掉它之后,距离目标只剩下6个字节了!

胜利在望,但是接下来的每一步都将无比艰难。为了完成领导安排的任务,我做好了重写所有代码的准备,拼了。

1557473596613040.jpg

然后,救星突然降临了。领导过来询问了RAM精简的情况后,沉思片刻后,悠悠地说了一句:

算了,RAM空间必须得有20-30%的余量,要不以后功能升级怎么办?

喜从天降,竟是这么令人猝不及防,我张着空洞洞的嘴巴,把冲到嗓子眼想骂人的话生生咽了下去,配合着领导,说了一句总结陈词:

MCU资源受限,编程成了巨大的挑战啊!

领导却不置可否,优雅地一个转身,留给我一个高大的背影,慢慢踱开了去。他的背影竟而越变越大,压得我有些窘慌,似乎要挤出我藏在棉衣下的那个‘小’来!



关键词: MCU 嵌入式

评论


相关推荐

技术专区

关闭