基于模块化的嵌入式软件设计研究

来源:网络

点击:1456

A+ A-

所属频道:新闻中心

关键词: 嵌入式软件,C语言

      嵌入式软件多采用C语言编写。文章提出了一种C语言模块化编程的实现方法,并详细描述该技术实现的细节。使用这种模块化编程的方法,可以用C语言编写出带有C++语言部分面向对象特征的软件模块。采用这种方法编写的代码具有很高的重复利用率,而且更利于修改和维护。

      一、嵌入式软件编程语言

      嵌入式软件通常采用汇编、C语言、C++语言进行编写。从三种语言执行效率上进行比较则汇编最高、C语言次之、C++语言最慢,从三种语言模块化编程的难易程度上进行比较则C++语言最好、C语言次之、汇编最差,在大多数情况下,嵌入式软件多采用C语言进行编写,原因如下:

      1.C语言是面向过程的高级语言,代码移植性和可读性远高于汇编;2.大多数嵌入式软件开发环境都提供汇编和C语言编译器,而C++语言编译器有可能不提供;3.三种语言相比C语言学习起来较容易。

      由于嵌入式软件多采用C语言编写,因此本文着重讲述如何用C语言进行模块化编程。

      二、软件模块化设计概述

      面对越来越复杂的软件开发任务,人们提出了各种软件设计的模型。从用户需求和系统要实现的任务功能出发,把大型的软件划分为相对较小的模块。模块化设计的核心是模块的独立性(即高内聚,低偶合),主要包括功能独立性和结构独立性,这使得软件开发的分工易于实现。

      模块化设计有如下优点:

      1.提高代码重复利用率;

      2.方便修改和维护;

      3.便于调试排错;

      4.易于扩展。

      软件设计的模块化降低了设计开发的复杂度并使设计步骤清晰,也有利于提高软件健壮性、灵活性、可复用性等。进行模块化软件设计时应综合考虑模块的可分解性、可结合性、可理解性、连续性及模块保护几方面的要求。

      模块的可分解性要求把一个大的、复杂的问题分解为一些小的、简单的问题,通过解决各个小问题来解决大问题;模块的可结合性要求不同时期、不同项目、不同环境下设计的模块应能自由地结合在一起构成新的系统;模块的可理解性要求通过某种方法设计的每个模块不需要参考相邻的模块就能被人看懂;模块的连续性要求通过某种方法设计出的模块,在需求发生变化时只影响一个或少数几个模块;模块保护则要求通过某种方法设计出的模块,在运行期间发生的错误被限制在这个模块内部或仅仅传播到少数几个摸块。

      模块化设计时应将上述要求有机地结合起来。在保证正确性和健壮性的基础上,应尽可能提高软件的可扩充性和可复用性。

      三、使用C语言进行模块化代码编写

      通过模块化所实现的软件是由被加工的对象及其在该对象上所实现的有关功能构成。在开发软件的过程中,一般采用两种方法:其一是把重点放在功能的实现上,其二是把重点放在对象上。基于功能的软件开发方法中,其功能实现中考虑的“过程”和“操作”是多变和不稳定的,程序结构围绕事先确定好的功能,使得功能的扩充、删除及修改变得相当困难。这样的软件结构脆弱、功能集中、耦合度大,很难满足可扩充性、可维护性的要求,软件的重用性也差。

      面向对象的程序设计中考虑的“对象”和“数据结构”是相对稳定的。尽管功能是千变万化的,但一个问题空间中的对象一般总能保持其相对稳定不变性,这样围绕对象构造的软件系统也自然会有好的稳定性。面向对象方法把属性和服务封装在对象中,当外部功能发生变化时,这种封装可以保持对象结构的相对稳定,使得改动仅局限在一个对象内部,减小了因改动引起的系统波动效应,因此,面向对象方法开发的软件具有易于扩充、修改和维护的特性。另外,面向对象方法具有的继承性和封装性也支持软件重用,并且易于扩充,能较好地适应复杂大系统不断发展和变化的要求。

      C++拥有面向对象的特性,因此使用C++语言可以方便、轻松的完成软件模块化设计。

      C语言是面向过程的语言,不具备C++语言面向对象的优势,模块化编程不像C++实现起来那么容易,但是通过C语言的高级应用还是可以实现的。使用C语言来实现C++语言面向对象特征,通过举例对比的方式描述具体实现过程,详细如下:

      C++定义一个对象是通过“类”,类封装了一个对象所用到的数据和方法,C语言中没有类但是有“结构体”,C语言中可以使用一个“结构体”来定义一个对象。例如实现一个一阶数字低通滤波器模块:

      传递函数一阶低通数字滤波器,下面分别使用C++语言和C语言分别编写该软件模块,通过对比,可以看到C++语言和C语言实现模块的一些共性,从而更容易理解C语言实现模块化编程的原理。

      使用C++语言可以如下编写代码(C++语言实现该模块有很多中写法,如下的代码虽然不是C++语言最佳的实现方式,但是更类C,更容易理解):

      CLpf这个类定义了一个低通滤波器对象,CLpf类中包含了模块数据:模块输入m_Input、模块输出m_Output、模块参数m_Tc、模块参数m_Fc、模块变量m_K、模块变量m_OldOutput,CLpf类中还包含了对象的方法:模块初始化Init()、模块复位Reset()、模块主要功能实现Calc(),上述类的定义部分是C++语言模块化编程的第一步。

      使用C语言建议如下编写:

    基于模块化的嵌入式软件设计研究

      C语言通过结构体定义了一个新的数据类型LPF,因为这种带有数据和方法的数据类型已经拥有了一些面向对象的特征也可以理解为一个简单对象,LPF包含了模块输入Input、模块输出Output、模块参数Tc、模块参数Fc、模块变量K、模块变量OldOutput,LPF中也同样包含了对象的方法:模块初始化Init()、模块复位Reset()、模块主要功能实现Calc()。上述结构体定义是C语言模块化编程的第一步,只是声明了数据和方法的接口。

      C++语言实现对象的方法,可以如下编写:

    基于模块化的嵌入式软件设计研究

      C++语言只要再定义了方法实现部分就完成了完整的类,CLpf类已经可以方便使用,因为可以如下定义CLpf m_Lpf,并且可以方便如下调用这个对象的几个方法m_Lpf.Init()、m_Lpf.Reset()、m_Lpf.Calc()。

      C语言实现对象的方法,可以如下编写:

    基于模块化的嵌入式软件设计研究

      C语言定义的LPF数据类型,虽然可以如下定义LPF Lpf,但是不能像C++一样按照如下方法调用对象的如下几个方法Lpf.

      Init()、Lpf.Reset()、Lpf.Calc(),虽然编译器通常不会报错,但是执行是错误的,因为有如下2点错误:

      C语言中的方法调用是需要传递对象的指针;Lpf对象实例中的几个方法的函数指针没有初始化,这种方法不能正常执行。

      因此需要在声明对象时将LPF结构的数据和函数指针进行初始化,可以按照如下方法定义LPF默认值,这是C语言模块化编程不同于C++的重要一点,即C语言模块化编程的第三步。

      模块默认值宏定义如下:

    基于模块化的嵌入式软件设计研究

      C语言中使用LPF数据类型,则应该在声明对象实例的同时进行初始化,这点不同于C++,例如:LPF Lpf = LPF_DEFAULTS,这样声明的Lpf对象实例,其方法指针指向了正确的方法实现函数,并且数据有初值(C++语言可以通过构造函数来给数据赋初值),Lpf对象调用其方法可以按照如下形式:Lpf.Init(&Lpf)、Lpf.Reset(&Lpf)、Lpf.Calc(&Lpf),通过这种方法在C语言中实现了代码的模块化设计。

      四、结束语

      基于上述方法,可以实现C语言模块化设计要求,是一种值得推广的编码方式。
     

    (审核编辑: 智汇李)