在本节中,SiliconLabs将共享在软件开发方面的经验教训。要害词extern,staTIc和volaTIle都是什么?你应该在你的代码中运用递归仍是malloc()?
1)查找硬件设备的现有软件示例
开发任何嵌入式解决方案的第一步是找到能够使您的使命更简略的示例。您在自界说解决方案中找到的特定部分的软件示例将协助您以另一种办法“检查”设备,并协助您从头解说设备标准,即便这些示例是针对其他计算机架构或软件言语的。
2)编译器的代码
没有完美的计算机软件言语。一切言语都有自己的优势和缺点。用于EFM32宗族的Simplicity Studio中运用的软件言语是C。C言语有着很长的前史,它被广泛信赖,而且在嵌入式规划上体现杰出,可是其语法及特性很难把握。当你在C中编码时,你实际上是为编译器和其他构建东西编写指令。记住这一点。C言语是“挨近金属”的言语,由于您的代码在人类可读格局下编写的代码,汇编代码和二进制映像的构建进程的成果之间仅有几个过程。
C代码具有严厉的类型,要求某些变量匹配得足够好以履行安全赋值。这是为了维护你不要做愚笨的工作,比方变量(即指针)的地址和变量的内容。可是经常在嵌入式开发中,您需求能够将纯数字转化为地址,以便指定寄存器地址。这需求你了解类型转化,以告知编译器你真的知道你在做什么。
3)运用描绘性变量和函数称号
你能够做的最好的工作是保证你的代码规划得很好,运用描绘性的变量和函数名。在C代码中没有与长称号相关的运转功用丢失。当构建东西将C代码转化为二进制机器码时,将删去一切标识符。请考虑在FAT文件体系(FF)库中找到的以下代码段:
上面的代码有一些注释,这当然有协助,是一件非常好的工作,可是很难经过检查变量,函数,枚举和预处理符号知道这个代码的切当原因。考虑运用以下代码作为代替:
是的,代码有点宽,难以键入,但Simplicity Studio供给代码完结与CTRL +空格键的快捷键,你能够随时剪切和张贴。代码可读性会增强,需求更少的寻觅变量名。咱们能够经过检查第二个例子来阐明,这段代码旨在检查方针目录,并在找到方针目录中的已删去(从前已填充但现在可用)或零(从未填充)短文件名条目时中止。描绘性称号答应您像读一段故事似得阅览代码,在你阅览时告知你目的。
4)严厉的对待注释
一个好的软件开发人员在几个要害的当地给代码添加了许多注释。注释,如长变量名,不影响到运转时可履行二进制文件的文件巨细,仅仅在那里,以协助阅览文档的代码。解决方案中每个文件的顶部应阐明该文件的目的,而且在每个函数的顶部应有较长的注释,阐明函数的用处以及描绘输入和输出。除了这些要害的当地,应该在逐行的基础上运用注释,不管代码的目的清不清楚。运用描绘性变量称号能够协助解说代码的目的,并削减必要的注释,使得那里的注释更杰出。信任我,一年后你不会记住开始写代码的目的,所以要注重注释了!
5)运用emlib库
关于EFM32程序员,emlib库是你的朋友。接入EFM32外设时,尽可能的调用这些库。这些库经过杰出测验,并有额定的代码来协助寻觅问题,而不仅仅是直接调整寄存器。
例如,以下代码运用emlib库:
TIMER_TopSet(TIMER3, 1000);
相同的工作能够经过预处理器界说寻址内存映射外设的寄存器来完结,界说TIMER3为0x40010C00。咱们不运用这个地址,由于它很难被记住,但这是TIMER3映射在主内存中的当地。
TIMER3-》TOP = 1000;
一切外设以彻底相同的办法映射到内存地址,因而有时您会看到运用此指针表明法的示例,而不是emlib库函数。假如您将看到em_timer.h中的TIMER_TopSet函数界说,您将看到该函数与此示例彻底相同,因而在这种情况下,库函数没有供给任何附加值。可是,运用emlib库,有时会得到比简略操作映射寄存器更多的功用。例如,CMU_ClockEnable函数在终究运用“bit band”指令保证寄存器位自动地设置之前,小心肠代表您做出许多决议。尽可能频频地运用这些库函数,以取得一切EFM32库规划师规划的便利性。
6)界说变量以避免仓库和堆的问题
C的许多方面关于非专业的程序员来说并不显着,但在嵌入式规划中运转代码时变得很重要。关于初学者,一切本地声明的变量都在栈上。这些是您在函数或任何代码块中界说的变量。
仓库是从“内存顶部”或物理RAM中最高可用地址开端的内存区域,然后向下计数,直到到达仓库约束。假如您界说了太多的部分变量,或许您的代码经过运用递归或其他嵌套函数动态创立这些变量,那么您的仓库空间会被占满。
大局变量是在模块等级的一切函数和其他代码块之外界说的变量。编译器自动为heap上的大局声明的变量分配内存,这是仓库外的主内存池的一部分,假如您测验分配太多的RAM,将会发生编译器过错。可是,在代码中运用malloc()指令能够动态地在运转时在堆中分配RAM。
在具有有限RAM的嵌入式处理器上运用recursion或malloc()指令是一个冒险的使命!你有必要了解你的代码将需求多少递归测验(或malloc()调用)以便解决问题,然后规划一个永久不会竭尽仓库空间的解决方案。
假如您在代码中界说一切变量并让编译器确认怎么自动办理内存,您将遇到较少的超出仓库或堆的问题。即便有这样的预防措施,假如你的代码几乎是可用的RAM巨细,当你编译和构建你的代码,你将需求学习怎么监督仓库和堆的巨细,这部分内容超出本节的领域。
7)大局静态变量和部分静态变量的差异
运用要害字“static”界说的变量表明不同规模的不同内容。在内部函数中,static要害字用在变量的前面,以记住它在函数调用之间的值。它具有一种“粘性”,你能够在函数的第一次调用时初始化它,然后让它坚持其值,而不是每次函数履行时从头初始化非静态变量。在大局规模,一切变量都是“粘性”的,由于它们只在运转时开端时初始化一次,然后记住它们的值。可是,放置在大局变量前面的static要害字指示编译器该变量关于该模块是本地的,而且不被外部模块运用。关于同一个“static”要害字,这是一个彻底不同的意义。
8)volatile和extern的意义及怎么相互影响
只需变量和函数在模块中未声明为static,它们就能够在该模块外部运用,并在其他模块中运用。为了告知编译器你打算在模块中运用相同的变量,你在一个模块中界说一个惯例办法的变量,并在规划中一切其他模块的界说之前添加要害字“extern”。现在,您规划中的一切模块都能够拜访同一个变量。可是,假如规划中的其他模块中的一个模块目的修正开始界说的方位之外的变量的值,则有必要在该变量前面添加要害字“volatile”。这个volatile要害字告知编译器该变量能够在模块之外更改,并阻挠优化器删去好像没有作用的句子。
此外,当运用Release版别和Debug版别时,运用volatile非常重要。当优化设置添加时,编译器将自动测验紧缩不必要的代码。这意味着您需求避免编译器这样做,经过运用volatile要害字能够改动当时规模之外的任何变量。