1引言
随着市场竞争的日趋激烈,要求电子工程师能够在短时间内编写出执行效率高而又可靠的嵌入式系统的执行代码。同时,由于实际系统的日趋复杂,要求所写的代码规范、模块化并便于多个工程师以软件工程的形式进行协同开发。汇编语言作为传统的嵌入式系统的编程语言,已经不能满足这样的实际需要了。而C语言以其结构化和能产生高效代码满足了这样的需要,成为电子工程师在进行嵌入式系统编程时的首选开发工具而得到了广泛支持:早在1985年就推出了针对8051的C51编译器,而其它流行嵌入式处理器系统如196系列,PIC系列,MOTORAL系列,MSP430系列,AD公司和TI公司的DSP系列都有功能强大的C语言编译系统以及丰富的C语言库函数。
2高级C语言编程与汇编语言编程相比的优势
在国内,大量的程序员仍采用汇编语言作为开发工具进行编程,汇编语言有执行效率高的优点,但其可移植性和可读性差,以及它本身就是一种编程效率低下的低级语言,这些都使它的编程和维护极不方便,从而导致整个系统的可靠性也较差。而使用C语言进行嵌入式系统的开发,有着汇编语言编程不可比拟的优势。
(1)编程调试灵活方便
C语言作为高级语言的特点决定了它灵活的编程方式,同时,当前几乎所有系列的嵌入式系统都有相应的C语言级别的仿真调试系统,使得它的调试环境十分方便。
(2)生成的代码编译效率高
当前较好的C语言编译系统的编译效率已基本达到中等程序开发人员的水平。
(3)完全模块化
一种功能由一个函数模块完成,数据交换可方便地约定实现,这样十分有利于多人协同进行大系统项目的合作开发;同时,由于C语言的模块化开发方式,使得用它开发的程序模块可不经修改的被其它项目所用。可以很好地利用现成的大量C程序资源与丰富的库函数,从而最大程度地实现资源共享。
(4)可移植性好
由于不同系列的嵌入式系统C语言编译工具都是以1983年的ANSI-C作为基础进行开发的,因此,一种C语言环境下所编写的C语言程序,只需将部分与硬件相关的地方进行适度修改,就可方便地移值到另外一种系列上,例如,C51下编写的程序通过改写头文件,同时做少量的程序修改,可方便地移值到196或PIC系列上。也就是说,基于C语言环境下的嵌入式系统能基本达到平台的无关性。
(5)便于项目维护管理
用C语言开发的代码便于开发小组计划项目、灵活管理、分工合作,以及后期维护,基本上可以杜绝因开发人员变化而给项目进度或后期维护或升级所带来的影响,从而保证整个系统的高品质、可靠性以及可升级性。
3嵌入式C语言编译器与PC机上的标准ANSI-C编译器的主要区别
不同系列的嵌入式系统的C编译器,根据它所对应的不同芯片系列有其各自的特点,在这里,以KEIL公司的针对51系列的KEILC51编译器为例,简要说明它与ANSI-C的主要区别,其它的编译系统与ANSI-C的差别,可具体参照指定编译系统手册,找出它们的不同之处。清楚嵌入式系统的C编译器与标准ANSI-C的区别是用C编译器系统进行嵌入式系统开发的前提条件。
不同的嵌入式C编译系统之所以与ANSI-C有所不同,主要是由于它们所针对的硬件系统有其各自不同的硬件特点,对国内开发人员熟悉的51系列单片机,有着最为丰富的编译系统,其中最为出色的当属KEIL(也就是大家熟知的FRANKLING,但FRANKLING只相当于KEIL的早期产品,它是KEIL公司在美国销售时曾使用的一个品牌)。
从头文件来说,51系列有不同的厂家,不同的系列产品,如仅ATMEL公司就有大家熟悉的89c2051、89c51、89c52以及大家不熟悉的89s8252等系列产品。它们都是基于51系列的芯片,唯一不同之处在于内部资源如定时器、中断、I/O等数量以及功能的不同,为了实现这些功能,只需将相应的功能寄存器的头文件加载在程序中就可实现它们所指定的不同功能。因此,KEILC51系列头文件集中体现了各系列芯片的不同功能。
从数据类型来说,由于8051系列器件包含位操作空间和丰富的位操作指令,直接嵌入式C与ANSI-C相比,比ANSI-C多一种位类型,使得它能如同汇编一样,灵活的进行位指令操作。
从数据存储类型来说,8051系列有片内、片外程序存储器,片内、片外数据存储器,片内程序存储器还分直接寻址区和间接寻址类型,分别对应code、data、xdata、idata以及根据51系列特点而设定的pdata类型,使用不同的存储器,将使程序执行效率不同,在编写C51程序时,最好指定变量的存储类型,这样将有利于提高程序执行效率(此问题将在后面专门讲述)。与ANSI-C稍有不同,它只分SAMLL、COMPACT、LARGE模式,各种不同的模式对应不同的实际硬件系统,也将有不同的编译结果。
从数据运算操作和程序控制语句以及函数的使用上来讲,它们几乎没有什么明显的不同,只是在函数的使用上,由于嵌入式系统的资源有限,它的编译系统不允许太多的程序嵌套,C语言的丰富的库函数对程序开发提供了很大的帮助,但它的库函数和ANSI-C也有一些不同之处,从编译相关的不同来说,由于51系列是8位机,扩展16位字符不被C51所支持,其次,ANSI-C所具备的递归特性不被C51所支持,在C51中,要使用递归特性,必须用REENTRANT进行申明才能使用。
KEILC51与标准ANSI-C在库函数,由于部分库函数不适合嵌入式处理系统,因此被排除在外,如字符屏幕和图形函数,也有一些库函数继续使用,但这些库函数是厂家针对硬件特点相应开发的,它们与ANSI-C的构成及用法都有很大不同,如printf和scanf。在ANSI-C中这两个函数通常用于屏幕打和,接收字符,而在KEILC51中,它们则主要用于串行数据的收发。
4如何充分利用C语言的特点和优势快速编出高效的C语言程序和对程序的优化
尽管嵌入式C语言是一种强大而方便的开发工具,但开发人员如果要达到用C语言快速编出高效而易于维护的嵌入式系统程序,首先必须对C语言编程有较透彻的掌握,其次,还应该对实际电子硬件系统有深入的理解,当然在学习嵌入式C之前,较为熟练地掌握用汇编语言编程是十分必要的。下面,结合我们的实际开发经验和实例,对一些需要特别注意和用心揣摩的地方进行讲解:
图1工作流程图 (1)以软件工程的方式进行总体程序设计安排,养成良好的、规范化的编程风格,对能高效编出易于维护的嵌入式系统程序具有至关重要的作用,图1给出较为合理的工作流程框图。
使用正规、一致的编程风格十分重要,建议使用"TheCProgrammingLanguage"一书中使用的书写风格,对变量命名采用大部分Windows程序员所采纳的Hungarian命名法则,再加上模块化的编程方式,详尽的程序说明文档,久而久之,能够实现高效编程,适应多人分工协作,也适合项目开发的规范化,以及后期维护,同时,也便于程序的重新利用,这样使人感到逻辑清楚,代码简单,注释明白。
(2)灵活选择变量的存储类型是提高程序运行效率的重要途径。
由于嵌入式系统的资源有限,它有不同的有限存储器资源,对需进行位操作的变量,其存储类型为bdata,对直接寻址存储器类型为data,对间接寻址存储器类型为idata(间接寻址存储器也可访问直接寻址存储器区),对外部寻址存储器类型为xdata,当对不同的存储器类型进行操作时,,编译后的代码执行效率各不相同,内部存储器中直接寻址空间和间接寻址空间也不相同。
为了提高执行效率,对存储器类型的设定,应该根据以下原则:只要条件满足,尽量先使用内部直接寻址存储器(data),其次设定变量为间接寻址存储器(idata),在内部存储器数量不够的情况下,才使用外部存储器,而且在外部存储器中,优先选择(pdata),最后才是(xdata),而且,在内部和外部存储器共同使用的情况下,要合理分配存储器,对经常使用和计算频繁的数据,应该使用内部存储器,其它的则使用外部存储器。要根据它们的数量进行分配,在例程中,因为内部数据存储器的数量足够,我们在例程中将所有变量都申明为直接数据存储器,这样能使程序访问数据存储器的时间最少,从而提高程序运行效率。
(3)合理设置变量类型以及设置运算模式可以大大减小代码量,提高程序执行效率。
由于51系列是8位机,它只能直接处理8位无符号数的运算,而对其它类型的数据则需通过额外的算法来实现,因此,在对变量进行类型设置时,要尽可能选用无符号的字符类型,尽量少使用有符号以及多字节类型,因此,在程序设计中,都尽量采用无符号数以提高运算速度,以此避免进行多余运算。
在运算时,可以进行定点运算的尽量进行定点运算,避免进行浮点运算。如*2或/2,就可以使用移位操作来代替除法运算。这样不仅可以减少代码量,同时,还能大大提高程序执行效率,例如,对直流信号通常采用一滞后滤波法。它的表达式为:Y0=(1-K)X0+K*Y0,在这个运算式中,如果将K值取为0.75,则可以通过移位运算代替浮点运算或多字节的算术运算,从而简小编译后的程序模块,提高程序执行效率。而将K值取为0.75并不会影响数据滤波的效果。
(4)灵活设置变量,高效利用存储器,提高程序执行效率。
在C嵌入式编程中,由于嵌入式系统资源有限,而C语言中通常是采用模块化编程方法,如何实现高效的数据传输对提高程序执行效率十分关键。
通常,在C程序中,子程序模块中与其它变量无关的变量尽可能使用局部变量;对整个程序都要使用的变量将其设置为全局变量更合适;这样,子程序模块可以直接申明要使用的变量为外部变量即可。其次要结合C语言的特点进行灵活的数据传输,C语言中所特有的指针、结构、联合如果能够灵活使用,可以大大提高编程效率,也可以方便我们进行数据传输,主程序和子程序传递数据量不能过多,否则影响执行效率;子程序模块和主程序模块都定义了相同的数据类型,在进行数据传输时,主程序模块和子程序模块定义相同的数据类型,在进行数据传输时,只需将指针传送到子程序模块,这样,既可以使不同的程序有很好的独立性和良好的封装性,又能实现不同程序数据的灵活高效传输,这样,可使不同的开发人员开发出独立性很强的通用子程序模块。
(5)将汇编程序嵌入嵌入式C程序中,完成实时响应或精确控制任务。
在一些实时性要求很高,如中断程序处理、数据采集程序、实时控制程序以及一些实时的带符号或多位运算中,建议将汇编语言嵌入C程序中进行处理。
在KEILC51的C编译系统中,C程序能够与汇编程序实现方便灵活的接口,在C程序中调用汇编十分方便灵活,对二者调用的主要难度在于:实现数据的准确传输,汇编与C中实现数据传输可通过两种方式,一是利用工作寄存器进行数据传送,这种方式安全,但根据传送数据类型的不同,只能传送1个~3个参数,另外一种方案是指定特定的数据区,二者在特定的工作区内进行数据传输,这种方式,其传递数据量可自行控制,但不安全,需要开发人员仔细控制。
(6)利用丰富的库函数,可以大大提高编程效率。在KEILC51中,开发厂家提供了许多常用的库函数,以供编程人员使用。开发人员可灵活地使用这些函数,以提高编程效率。
在实际进行项目开发时,如果能遵守科学的工程开发规则,灵活地运用C语言的强大功能,熟悉硬件特点,就能够在较短时间内编写出高效率、高可靠、易维护的嵌入式系统的执行代码。 |