心有多大,舞台就有多大,愿望有多大,你的国际就有多大。
这句浓浓的鸡汤真实是太“唯心主义”了。由于,假如MCU资源十分有限,软件工程师的心再大,也没有舞台发挥自己的斧钺钩叉。
在宽广的人生舞台上才干大有作为,面临广袤的国际,大开大合地书写自己的人生,这种挥洒、适意的疏阔没有人不喜欢。可是,假如你要在一个资源受限的MCU上编程,就像是在一个空间狭小的舞台演出话剧,你需求重复思量,才干应对空间的短促,半分挥洒就会让剧情漫出舞台之外。为了利用好每一寸空间,你需求重复酌量、再酌量,调整、再调整,哪里还有半分适意可得?!
说实话,这种感觉真实坏透了。在一次产品开发中,笔者就切身体会过这种地狱般的短促和绰绰有余,现在想来,还有几丝寒意漫上心头……
1
顺畅的开端等于成功的一半。笔者开端开发中控锁模块时,就有这种夸姣的感觉。由于,从功用上来看,中控锁相当于车身控制器的一个子模块,笔者有车身控制器的开发经历,把它刀劈斧砍,择菜式地弄出来个中控锁,还不是小菜一碟?
事实证明,这还真是小菜一碟。由于咱们这款用在某个国产车上的中控锁的功用真实太简略了,便是三大块:机械钥匙解锁、闭锁+遥控钥匙解锁、闭锁+车身防盗功用,所谓车身防盗,便是车门被撬开时用转向灯和喇叭报警。
在以往开发车身控制器的前史堆集中,开关检测模块、守时器办理模块、遥控接纳解析模块都是现成的,无非是从之前的MCU上搬过来,略微移植一下即可。开发难度,自然是没有的,所以深谙底细的领导把整个产品的开发周期定为三个月。
在这三个月的时间里,硬件开发和软件开发是同步进行的,首要的作业自然是MCU的选型。
一切成功决议的背面都是对若干关键要素的权衡,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能廉价一块多呐!
领导接着笑言:“项目合作方要求降本钱,我都容许人家了,正好不知道从哪里下手呢!”
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个字节了!
胜利在望,可是接下来的每一步都将无比困难。为了完结领导组织的使命,我做好了重写一切代码的预备,拼了。
然后,救星忽然降临了。领导过来询问了RAM精简的状况后,深思顷刻后,悠悠地说了一句:
算了,RAM空间有必要得有20-30%的余量,要不今后功用晋级怎么办?
喜从天降,竟是这么令人猝不及防,我张着空洞洞的嘴巴,把冲到嗓子眼想谩骂的话生生咽了下去,配合着领导,说了一句总结陈词:
MCU资源受限,编程成了巨大的应战啊!
领导却模棱两可,高雅地一个回身,留给我一个巨大的背影,慢慢踱开了去。他的背影竟而越变越大,压得我有些窘慌,好像要挤出我藏在棉衣下的那个‘小’来!