网志

轻量级硬件抽象

吉恩·布雷尼曼2012年1月31日

有些课程比其他课程难掌握。 您会认为,艰苦的战斗会更容易记住,但有时它并不能那样工作。 最近,有人要求我去接一个由另一名员工管理的项目。 该项目是另一个降低成本的项目。 硬件小组的任务是更新当前发货的产品,以减少现有的故障率,同时消除产品的成本。 重新设计使工程师改变了微控制器上的引脚分配,以释放一些模拟输入。 还强烈希望对该设备的现有固件进行尽可能少的更改,以限制重新验证产品的范围。

我的第一个冲动是立即进入并掌握更改,然后继续进行一些更有趣的事情。 我隔离了更改的信号,然后开始在代码中搜索受影响的引脚名称的出现。 当我发现100多个引脚名称之一的引用时,我感到非常惊讶。 为了避免做出更好的判断,我跳入了实例,并使用#ifdef语句修改了代码,以将一个信号的所有引用更改为另一个信号。 在一天的时间里,我对代码进行了转换,很快它就可以在新的原型上愉快地运行了。 不是我最好的工作,也不是我最骄傲的时刻,但是工作已经完成,我可以自由地回到我真正有趣的工作上。

例如:

    if(ready)
    {
#ifdef OLD
        PORTB.4 = 1;            // Turn LED off
#其他
        PORTB.7 = 1;            // Turn LED off
#万一
    }

很快,就决定需要对硬件进行一些更改。 开发了新版本的硬件,并进一步更改了引脚。 我们已经将一些较早的原型运送到了一个远程工程地点,在这两个版本的原型上都进行了一些测试。 现在,我需要维护固件的多个版本以支持两个不同的原型。 这已经开始迅速变得丑陋。 现在,本已杂乱的代码变得更加杂乱。

有了新的更改后,代码现在看起来像这样:

    if(ready)
    {
#ifdef OLD
        PORTB.4 = 1;            // Turn LED off
#elif PROTO_ONE
        PORTB.7 = 1;            // Turn LED off
#其他
        PORTC.2 = 0;            // Turn LED off
#万一
    }

一个简单的变化就不会出现 so bad. 但是要进行多次更改,再乘以变化的次数,很快代码就会变得一团糟。 但是等等,我能做些什么呢? 简单的答案是抽象。从webopedia中,我找到了以下抽象定义:

挑选(抽象)...的共同特征的过程 对象 和程序。例如,程序员将使用抽象来指出两个功能执行几乎相同的任务,并且可以将其合并为一个功能。抽象是最重要的技术之一 软件工程 并且与其他两项重要技术密切相关- 封装信息隐藏。所有这三种技术均用于降低复杂性。

这里的想法是想出一种将所需功能表达为每种硬件版本的单个包含文件的方法。 以这种方式,可以更改单个include语句,以便为每个硬件版本构建唯一的固件版本。 以最简单的形式 可以在概念上定义示例中语句的每个部分,并可以从代码中提取操作。

修改后的代码将显示为:

    if(ready)
    {
        MODE_LED = LED_ON;
    }

为了使它起作用,我们需要创建包含文件,其中包含从代码中抽象出来的动作。 需要三个包含文件:old.h,proto1.h和proto2.h。 这些文件中的每一个都需要必要的定义,以表示更高级别的功能或MODE_LED和LED_ON的表示。

对于old.h:

#定义MODE_LED        (PORTB.4)
#定义TURN_ON         1

对于proto1.h:

#定义MODE_LED        (PORTB.7)
#定义TURN_ON         1

对于proto2.h:

#定义MODE_LED        (PORTC.2)
#定义TURN_ON         0

现在,通过包含正确的包含文件,可以隐藏所有必要的更改,从而使代码更整洁,更易读。 再说一次,我之前已经学过这一课,但是当我遇到类似的问题时,我的第一选择就是错误的选择。

愿您的第一选择更好地为您服务。


要发布对评论的回复,请单击每个评论所附的“回复”按钮。要发布新评论(而不是回复评论),请查看评论顶部的“写评论”标签。

注册后,您可以参加所有相关网站上的论坛,并获得所有pdf下载的访问权限。

注册

我同意 使用条款隐私政策.

试试我们偶尔但很受欢迎的时事通讯。非常容易退订。
或登录