tag 标签: 软件技巧

相关博文
  • 热度 37
    2014-7-10 22:01
    1285 次阅读|
    0 个评论
    这些建议是在我从硬件工程师过渡至软件工程师期间,曾经希望得到的建议。 嵌入式系统设计不仅要求了解硬件,还要求了解软件的作用方式,以及如何与之交互。设计硬件需要的某种范式可能与设计软件完全相反。当从硬件设计转向包含软件的设计时,硬件工程师应牢记以下十个技巧。 技巧#1:流程图第一,实现第二 当工程师首次迈入软件开发领域时,会有种强烈的诱惑力促使他们立刻投入工作并开始写代码。这样的定式思维就等同于在电路逻辑图还未完成前就试图设计印刷电路板(PCB)。在着手开发软件时,抑制一上来就想写代码的冲动是至关重要的,应首先用流程图制定一个软件架构图。这样的方法会使开发人员对应用所需的不同部分与组件形成一个概念,就像电路逻辑图可以告诉工程师需要哪些硬件元件一样。这样可确保程序整体建立在良好的组织和深思熟虑之上,减少程序调试时间,从长期看,这样做还可以节省时间、省去麻烦。 技巧#2:使用状态机控制程序流程 状态机是20世纪最伟大的软件发明之一。某应用程序往往可被分为多个状态机,每个状态机都控制该应用程序的特定部件。这些状态机都拥有自己的内部状态和状态转换,从中可看出软件如何与各种激励相互作用。用状态机来设计软件,可简化软件的开发,使之模块化、可维护,并易于理解。目前拥有的广泛资源可演示状态机的理论和算法。 技巧#3:避免使用全局变量 在函数式编程的年代,函数要先于形式,程序员的唯一目标是尽可能地让程序按预期方式快速运行,而不用考虑程序结构或可重用性。这种编程范式会毫无顾虑地使用全局性变量,程序中的任何函数都可能修改它。其结果就造成了变量被破坏的几率增加或变量被误用。在新推荐的面向对象范式中,应在最小的范围内定义变量并封装它们,以防止其他函数的误用或破坏。因此,建议您限制全局范围使用的变量数量。可在C语言中用外部关键字标识这些变量。 技巧#4:利用模块性的好处 无论问哪一名工程师,项目的哪部分最有可能延迟交付并超出预算?答案都是软件。软件往往是复杂的,且难以开发和维护,尤其是当整个应用都存在于单一文件或松散关联的多个文件中时。为了缓解可维护性、可重用性及复杂性,强烈建议程序员充分利用现代编程语言的模块化特性,将常用功能分解成模块。以这样的方式分解编码,程序员就能着手建立函数与特性库,然后在一个接一个的应用中重用它们,从而通过连续测试而改善代码质量,同时也减少了时间,降低了开发成本。 技巧#5:保持中断服务例程的简单性 中断服务例程用来中断处理器对当前代码分支的执行,从而处理刚刚触发中断的外围设备。无论何时执行中断,都需要一定数量的开销,用于保存当前程序的状态、运行中断,然后将处理器回归原程序状态。现代处理器要比多年前的处理器快得多,但仍需要考虑此花销。一般情况下,程序员都想把中断运行时间降至最低,以避免干扰主代码分支。这意味着中断应该短而简单。中断中不应调用函数。此外,如果中断开始变得过于复杂或耗时,则仅应在必要时利用中断做最少量的工作,例如,将数据装入缓冲区并设置一个标志,然后让主分支处理输入的数据。这样做可保证大多数处理器周期被用于运行应用,而不是处理中断。 技巧#6:使用处理器示例代码做外设的实验 设计硬件时,做原型测试电路总是有益的,这样可确保工程师对电路有正确的理解,然后再做电路板布局。此点对设计软件也同样适用。硅片制造商通常都有示例代码,可用来测试微处理器的各个部分,这样工程师们就可判定该部分的工作情况。此方法使人们洞察到软件体系架构的应该组织方式,以及可能造成的任何潜在问题。在设计初期阶段认清潜在的障碍,比在产品交付前最后几小时才发现它们要好。这是预先测试代码片段的一个很好的方法,但需提醒的是,制造商代码往往不是模块化的,未经大的修改不方便用于实际应用。这一局限已随着时间的发展而改变,也许某一天芯片供应商会给出可用于生产的代码。 技巧#7:限制功能复杂度 工程学中有一个旧词叫“KISS”——保持简单和直接。无论在处理何种复杂工作时,最简单的方法就是把它分解为更小、更简单、更易处理的任务。随着工作或功能变得越来越复杂,人们要准确无误地记录所有的细节也变得更困难。在写一个函数时,其复杂度在当时看似适中,然而要考虑到,一名工程师如何在六个月的维护时间内查看代码。测量函数复杂度(如循环的复杂度)的方法很多。现在有工具可以自动计算某个函数的循环复杂度。经验法则建议,函数的循环复杂度保持在10以下是最理想的。 无论在处理何种复杂工作时,最简单的方法就是把它分解为更易处理的任务。 技巧#8:使用源代码存储库并频繁提交 人都是会犯错误的,写代码时也会犯错。这就是为什么开发人员使用源代码存储库是如此重要。源代码存储库可使开发人员“登记”一个好的代码版本,并描述对该代码基所做的修改。该步骤不仅使得开发人员可以复原或追溯到代码的旧版本,还可以比较旧版本之间的不同。如果开发人员做的一系列改变破坏了系统,只需点击一下即可恢复好的代码版本!请谨记,如果不频繁提交代码,存储库就不会达到预期目的。如果做了不可逆的修改,两周后才提交代码,然后再恢复,就会造成大量工作和时间的损失! 技巧#9:代码做详细说明 在软件开发的激烈战斗中,开发人员很容易把注意力集中在编写和代码上,因此会忽略详细解释的需求。在压力之下,说明工作往往是项目的收尾工作,因为开发人员认为它是最后的一项工作。然而,当代码仍在你脑中新鲜热火时就做出详细解释是至关重要的,这样做可使开发人员或你自己读懂注释,理解代码的工作方式。 如果开发人员做的一系列改变破坏了系统,只需点击一下即可恢复好的代码版本! 技巧#10:使用一种Agile开发流程 无论做何种类型的工程工作,都建议您先设定并遵守一项流程。这样的结果应有一致的质量和成本,并能按时交付。软件开发人员已成功使用Agile开发流程来开发高质量软件。这一流程可按需求的优先等级做开发。优先级别最高的工作在限定的时间段内首先开展,这被称为迭代。这种方法的好处是它可使软件开发流程保持顺畅,还可以根据结果和客户所需,在每次迭代中适应并修改需求和任务。 《电子设计技术》网站版权所有,谢绝转载 技巧#10A:站在开发技术之巅 要学习嵌入式软件开发所使用的最新工具和技术,最好的一个场合是嵌入式系统研讨会(Embedded Systems Conferences)。该会议每年召开两次,地点分别位于加利福尼亚州圣荷西(San Jose)(www.ubmdesign.com/sanjose)和波士顿(east.ubmdesign.com)。会议吸引了来自全世界的工程师,他们可以开展互动、参加研讨会,并进行实际操作,以促进对软件开发的理解。此外,EDN.com社区还提供了与软件和硬件相关的一系列网站(www.edn.com/blogs),工程师们可通过不断的参与和学习,为了将最尖端技术应用于他们未来的发展项目而做好准备。 10大技巧 读者心得 “我不支持关于中断程序的建议。使用像德州仪器(TI)MSP430的低功耗微控制器时,主代码经常只用于将处理器置于睡眠状态。当处理器处于激活状态时,所有工作都在中断程序中完成。”—DickB “从我的经验看,也许这篇文章的标题应为‘软件工程师的10大技巧’。 我曾经在面试一个新职位的软件工程师时问了这样一个问题:‘如何为一个新项目写软件?’ 回答是:‘着手写软件代码!’ 我以为他会说‘阅读规范’,然后‘将软件分解成小模块并为它们设计流程图’或类似的话。 他没能得到这份工作。”—The Real Dr Bob “所有的都很好。想增加10b:让组织剩余成员(管理层)学习‘Agile’(和与其他开发流程相关的一般折中方案)。 要懂得一个最大的‘实话’:在项目刚开始时就设定项目完成的实际目标(一个反复出现的主题)。 有关同一话题的另一个观点:在初期适当地分配人力和流程,而不要等来不及的时候,在后期增加这些。 一个‘人年’工作量是相当于720个员工在下班前解决了一个问题吗?(难以解决这个问题)—Thinking_J 参与谈论 欲与他人分享对本文章的评论,请登录www.edn.com/4405862。 《电子技术设计》网站版权所有,谢绝转载
  • 热度 26
    2014-3-10 16:36
    1122 次阅读|
    0 个评论
    硬件设计师最常见的工作内容是通过写代码来测试硬件。这10个C语言技巧(C语言仍然是常见的选择)可以帮助设计师避免因基础性错误而导致某些缺陷的产生并造成维护方面的困扰。 为了成功的推出一个产品,软件开发过程本身需要经历无数的实践风险和障碍。任何工程师最不希望的事情就是因所使用语言或工具而带来的挑战。因此,这就需要硬件设计师编写代码来测试硬件的工作状况,在资源受限的情况下,还需要开发硬件和嵌入式软件。尽管工具和结构化编程已经有了很大进展,但通常选择的仍然是C语言,基础性错误的不断发生,仍会导致某些缺陷的产生并造成维护方面的困扰。为竭力避免这些C编程陷阱,这里有10个C语言技巧供硬件工程师参考。 技巧#1:不要使用“GOTO”语句 二十几年前,当计算机编程尚处于起步阶段时,程序流程是由“GOTO”语句来控制。该类语句允许程序员对当前代码行断行,而直接进入另一个不同的代码段。列表1为简单的示例。 列表1 使用GOTO语句 编程语言终究开始引入了函数的概念,即允许程序对代码进行断行。如果已经完成,不再使用goto语句来表示代码的断行。函数调用后,函数将回到下一条指令。列表2为示例。这一做法改善了程序结构,提高了可读性。自此,这被视为编写程序的正确方法。只要看到或想到goto语句,就会让软件工程师退缩,产生本能的厌恶。其中一个主要的原因是,一个遍布goto语句的程序会让让人很难抓住重心,不便于对程序的理解和维护。 列表2 用函数控制流程 技巧#2:使用FOR(;;)或While(1) 如果goto语句已经过时,那么对程序创建无限循环应该如何去做呢,这是一些硬件工程师可能会疑惑的问题。毕竟,之前都是通过创建一个goto语句然后再返回到main语句。解决这一问题就要利用C语言中已经存在的循环语句for和while(列表3和4)。 列表3 使用一个无限的For循环 列表4 使用一个无限的While循环 列表中的循环条件相对比较简单。for循环无非是以无条件情况使用条件语句。而另一方面,while循环是语句为真即予执行,这等同对任何条件的非零值。 技巧#3:使用合适的条件语句 除代码的可读性之外,程序的执行时间还主要依赖于做决定时所选择的条件结构类型。许多硬件工程师都熟悉简单的if语句的使用。然而,有时工程师可能没有意识到,如果第一个条件不正确,还可以使用else或else if语句。这可以节省处理器时间,而不必评估另一个条件语句。在列表5所示的前半部分代码中,如果Var值为1,则代码仍会查看Var是否为0。而在用了else语句的后半部分代码中,只评估第一个语句,之后就继续走下面的代码,这样就节省了时钟周期,使代码更加清晰。 列表5 用If/Else替代只用If If/else if/else语句可能并不永远适用。如果需要检查若干个可能的条件,switch语句可能更合适。这样,处理器可以评估语句,然后从一个答案列表中选择下一步动作,而不用连续地评估一堆条件。列表6显示的例子与列表5示例的类型相同。 列表6 使用Switch语句 以上示例的寓意是,让条件语句的选择更开放,以选择出最适合的语句。这种做法使程序结构更简单,便于理解程序流程,缩短处理器的额外时钟周期。 《电子设计技术》网站版权所有,谢绝转载 技巧#4:避免使用汇编语言 微处理器的自然语言为汇编语言指令。为低级别机器语言编程可能会为处理器提供更高效的代码。然而,人类并不是天生就会这种语言,并且经验表明,编写汇编语言会造成误解。误解会导致维护不当,更甚者,可能会使系统到处是bug。一般建议避免使用汇编语言。实际上,现在大多数编译器都能编译出非常高效的代码。采用C语言或C++语言等高级语言的开发,能获得更有序的结构,便于理解和维护,使代码的整体效果更好。列表7给出了一个示例,比较了使一个32位变量递增所使用的汇编代码和C语言代码。 列表7 用汇编和C语言完成一个变量的递增 汇编 C代码 当然,现在仍有一些场合适于使用汇编语言,但这种场合仍比较少。首个推荐的场合是开发引导装载程序。这种情况下,可能需要优化对启动过程中某个决策(启动应用或引导加载器)的速度。此时,分支判定用汇编代码就可能有意义了。另一种场合是开发一种在DSP上运行有严格时序要求的控制循环。为了从设备中的得到每个时钟周期,用汇编语言做控制循环的编码是有意义的。如果目前任务适合用汇编,应确保将其妥善存档便于有据可查,这样,未来的开发者(或未来的版本)会明白该代码的用途。 技巧#5:充分利用模块化 笔者最常见的经历是着手由硬件工程师开启的一个新项目往往是杂乱无章的代码组织。通常我们会发现,代码由一个单一的主模块组成,其中有2.5万多行代码。在这些应用中,一切都是全局性的,函数寥寥无几,goto语句贯穿整个代码结构。15年前这算正常,但如今已不再适用了!C语言编程使工程师能够将代码分成独立的功能模块,这简化了代码导航,同时还能够使工程师使用封装等面向对象技术。代码可以被组织成逻辑模块,这很有意义。虽然可能要先花点时间(几分钟),但从长远来看,这将能省掉很多漫长之夜,和很多调试之苦! 技巧#6:写千层饼式代码而非面条式代码 Beningo是一个意大利名字,和许多意大利人一样,我对意大利面食也是毫无保留地热爱。当拿意大利面食与软件相比时,我就会想到两种面食,即意大利面条和千层饼。意大利面条比较混乱,面条相互交织,纵横交错,结果完全没有任何类型的结构。编写非结构化代码就非常像意大利面条:咬一口,完全不知道吃的是哪部分。 另一种就是意大利千层饼!这种面食是分层的,是有结构的。分层开发的代码不仅更容易理解,还可以移走一层并添加一个新层,基本上能够实现重复使用和维护的简易性。图1为用千层饼式代码模型的一个简单软件模块示例。 图1 千层饼软件模型 驱动程序配置 应用程序配置 应用程序 驱动程序库 硬件 《电子设计技术》网站版权所有,谢绝转载 技巧#7:使用描述式变量名称 编写易于理解和维护的较大软件有许多障碍,其中之一就是变量的命名习惯。为了尽力缩短变量名,开发者通常会自创一些较短的、令人费解的助记符,往往只有他们自己才能明白的符号。现代语言使一个变量名可以包含数百个字符。为了让事情清晰明确,“直截了当”地方法要好于其它方式。因此,变量名一目了然不仅有利于开发人员,也有利于未来的维护团队。列表8给出一个示例。 列表8 变量的命名 技巧#8:少用#pragma语句 C语言中有一种特殊的#pragma语句。这些语句通常处理非标准的句法和特性,应尽可能避免使用这种语句,因为它们是非标准的,不能从一个处理器移植到另一个处理器。有些编译器可能要求用这类语句完成某项任务,例如定义一个中断服务程序。在这种情况下,可能除了使用#pragma语句以外别无它法。如果可能,将所有的#pragma语句放在一个模块或几个模块里。这有助于确保在代码移植时,只需要更新几处代码,而非整个代码库;此外,这也将有助于防止移植代码的首次编译所带来的困扰。 技巧#9:错误往往并不是看上去那样简单 在调试一个C程序时,有一个让人当心的陷阱就是编译器错误。由于编译器的复杂性,当检测到一个错误时,通常错误位于程序中的其它地方,而非编译器所指示的位置。这主要与编译器生成程序的步骤有关。错误类型通常是一致的,工程师可以发现的一些错误中,90%都是根源: •当心漏掉#include文件。这可能会使程序开发人员看到完美的代码行,但由于未包含必要的头文件,编译器便会将其标志为一个错误,表示有些东西未定义。 •当心漏掉分号。编写C代码时最常见的错误是忘记在句末加分号。 •当心漏掉括号。漏写括号是代码编写过程中又一常犯的错误,或是粗心漏掉,或是由于键入错误而产生一个错误字符。 •当心漏掉逗号。在复杂的定义中很容易忘记逗号! 一般情况下,当弹出一个奇怪的编译错误对话框时,要查看该行前已被编译的内容。很有可能就是错误所在!它可能是出现在一行上面,或中间部分,或在完全不同的文件里。 不要放弃!只要具备一定的经验,解决这些疑难问题就会成为一种第二天性。 技巧#10:优秀的程序员编写的代码行数不一定少 人们常有这种误解,即认为较一般的程序员而言,一个优秀的程序员往往写较少的代码行就能解决问题。不要卷入这一错误的想法!一个优秀的程序员通常具备思维缜密、结构清晰的编码基础。变量命名和封装都恰如其分,系统中几乎不用全局变量。函数应保持简短有效。如果代码看起来很混乱,需要多写几行才能使其看上去更清晰,那就不妨多写几行!可以上网查看获得C代码编写最混乱殊荣奖项的代码用作前车之鉴。优秀程序员写的代码简洁、易于理解和维护,代码行数并非最少(图2)! 图2 简短程序 作者简介 Jacob Beningo获得了软件工程职业认证(CSDP),专业从事高质量、稳健的嵌入式系统的开发和设计。他著有许多关于嵌入式设计方法的科技论文,并教授有关可编程的设备、引导加载程序和软件方法等课程。Beningo获得了中密歇根大学(简称CMU)(密歇根州欢喜山校区)工程物理学学士学位,以及密歇根大学(密歇根州安娜堡分校)空间系统工程硕士学位。 《电子设计技术》网站版权所有,谢绝转载
  • 热度 25
    2014-1-7 00:40
    1018 次阅读|
    1 个评论
    硬件设计师最常见的工作内容是通过写代码来测试硬件。这10个C语言技巧(C语言仍然是常见的选择)可以帮助设计师避免因基础性错误而导致某些缺陷的产生并造成维护方面的困扰。 为了成功的推出一个产品,软件开发过程本身需要经历无数的实践风险和障碍。任何工程师最不希望的事情就是因所使用语言或工具而带来的挑战。因此,这就需要硬件设计师编写代码来测试硬件的工作状况,在资源受限的情况下,还需要开发硬件和嵌入式软件。尽管工具和结构化编程已经有了很大进展,但通常选择的仍然是C语言,基础性错误的不断发生,仍会导致某些缺陷的产生并造成维护方面的困扰。为竭力避免这些C编程陷阱,这里有10个C语言技巧供硬件工程师参考。 技巧#1:不要使用“GOTO”语句 二十几年前,当计算机编程尚处于起步阶段时,程序流程是由“GOTO”语句来控制。该类语句允许程序员对当前代码行断行,而直接进入另一个不同的代码段。列表1为简单的示例。 列表1 使用GOTO语句 编程语言终究开始引入了函数的概念,即允许程序对代码进行断行。如果已经完成,不再使用goto语句来表示代码的断行。函数调用后,函数将回到下一条指令。列表2为示例。这一做法改善了程序结构,提高了可读性。自此,这被视为编写程序的正确方法。只要看到或想到goto语句,就会让软件工程师退缩,产生本能的厌恶。其中一个主要的原因是,一个遍布goto语句的程序会让让人很难抓住重心,不便于对程序的理解和维护。 列表2 用函数控制流程 技巧#2:使用FOR(;;)或While(1) 如果goto语句已经过时,那么对程序创建无限循环应该如何去做呢,这是一些硬件工程师可能会疑惑的问题。毕竟,之前都是通过创建一个goto语句然后再返回到main语句。解决这一问题就要利用C语言中已经存在的循环语句for和while(列表3和4)。 列表3 使用一个无限的For循环 列表4 使用一个无限的While循环 列表中的循环条件相对比较简单。for循环无非是以无条件情况使用条件语句。而另一方面,while循环是语句为真即予执行,这等同对任何条件的非零值。 技巧#3:使用合适的条件语句 除代码的可读性之外,程序的执行时间还主要依赖于做决定时所选择的条件结构类型。许多硬件工程师都熟悉简单的if语句的使用。然而,有时工程师可能没有意识到,如果第一个条件不正确,还可以使用else或else if语句。这可以节省处理器时间,而不必评估另一个条件语句。在列表5所示的前半部分代码中,如果Var值为1,则代码仍会查看Var是否为0。而在用了else语句的后半部分代码中,只评估第一个语句,之后就继续走下面的代码,这样就节省了时钟周期,使代码更加清晰。 列表5 用If/Else替代只用If If/else if/else语句可能并不永远适用。如果需要检查若干个可能的条件,switch语句可能更合适。这样,处理器可以评估语句,然后从一个答案列表中选择下一步动作,而不用连续地评估一堆条件。列表6显示的例子与列表5示例的类型相同。 列表6 使用Switch语句 以上示例的寓意是,让条件语句的选择更开放,以选择出最适合的语句。这种做法使程序结构更简单,便于理解程序流程,缩短处理器的额外时钟周期。 《电子设计技术》网站版权所有,谢绝转载 技巧#4:避免使用汇编语言 微处理器的自然语言为汇编语言指令。为低级别机器语言编程可能会为处理器提供更高效的代码。然而,人类并不是天生就会这种语言,并且经验表明,编写汇编语言会造成误解。误解会导致维护不当,更甚者,可能会使系统到处是bug。一般建议避免使用汇编语言。实际上,现在大多数编译器都能编译出非常高效的代码。采用C语言或C++语言等高级语言的开发,能获得更有序的结构,便于理解和维护,使代码的整体效果更好。列表7给出了一个示例,比较了使一个32位变量递增所使用的汇编代码和C语言代码。 列表7 用汇编和C语言完成一个变量的递增 汇编 C代码 当然,现在仍有一些场合适于使用汇编语言,但这种场合仍比较少。首个推荐的场合是开发引导装载程序。这种情况下,可能需要优化对启动过程中某个决策(启动应用或引导加载器)的速度。此时,分支判定用汇编代码就可能有意义了。另一种场合是开发一种在DSP上运行有严格时序要求的控制循环。为了从设备中的得到每个时钟周期,用汇编语言做控制循环的编码是有意义的。如果目前任务适合用汇编,应确保将其妥善存档便于有据可查,这样,未来的开发者(或未来的版本)会明白该代码的用途。 技巧#5:充分利用模块化 笔者最常见的经历是着手由硬件工程师开启的一个新项目往往是杂乱无章的代码组织。通常我们会发现,代码由一个单一的主模块组成,其中有2.5万多行代码。在这些应用中,一切都是全局性的,函数寥寥无几,goto语句贯穿整个代码结构。15年前这算正常,但如今已不再适用了!C语言编程使工程师能够将代码分成独立的功能模块,这简化了代码导航,同时还能够使工程师使用封装等面向对象技术。代码可以被组织成逻辑模块,这很有意义。虽然可能要先花点时间(几分钟),但从长远来看,这将能省掉很多漫长之夜,和很多调试之苦! 技巧#6:写千层饼式代码而非面条式代码 Beningo是一个意大利名字,和许多意大利人一样,我对意大利面食也是毫无保留地热爱。当拿意大利面食与软件相比时,我就会想到两种面食,即意大利面条和千层饼。意大利面条比较混乱,面条相互交织,纵横交错,结果完全没有任何类型的结构。编写非结构化代码就非常像意大利面条:咬一口,完全不知道吃的是哪部分。 另一种就是意大利千层饼!这种面食是分层的,是有结构的。分层开发的代码不仅更容易理解,还可以移走一层并添加一个新层,基本上能够实现重复使用和维护的简易性。图1为用千层饼式代码模型的一个简单软件模块示例。 图1 千层饼软件模型 驱动程序配置 应用程序配置 应用程序 驱动程序库 硬件 《电子设计技术》网站版权所有,谢绝转载 技巧#7:使用描述式变量名称 编写易于理解和维护的较大软件有许多障碍,其中之一就是变量的命名习惯。为了尽力缩短变量名,开发者通常会自创一些较短的、令人费解的助记符,往往只有他们自己才能明白的符号。现代语言使一个变量名可以包含数百个字符。为了让事情清晰明确,“直截了当”地方法要好于其它方式。因此,变量名一目了然不仅有利于开发人员,也有利于未来的维护团队。列表8给出一个示例。 列表8 变量的命名 技巧#8:少用#pragma语句 C语言中有一种特殊的#pragma语句。这些语句通常处理非标准的句法和特性,应尽可能避免使用这种语句,因为它们是非标准的,不能从一个处理器移植到另一个处理器。有些编译器可能要求用这类语句完成某项任务,例如定义一个中断服务程序。在这种情况下,可能除了使用#pragma语句以外别无它法。如果可能,将所有的#pragma语句放在一个模块或几个模块里。这有助于确保在代码移植时,只需要更新几处代码,而非整个代码库;此外,这也将有助于防止移植代码的首次编译所带来的困扰。 技巧#9:错误往往并不是看上去那样简单 在调试一个C程序时,有一个让人当心的陷阱就是编译器错误。由于编译器的复杂性,当检测到一个错误时,通常错误位于程序中的其它地方,而非编译器所指示的位置。这主要与编译器生成程序的步骤有关。错误类型通常是一致的,工程师可以发现的一些错误中,90%都是根源: •当心漏掉#include文件。这可能会使程序开发人员看到完美的代码行,但由于未包含必要的头文件,编译器便会将其标志为一个错误,表示有些东西未定义。 •当心漏掉分号。编写C代码时最常见的错误是忘记在句末加分号。 •当心漏掉括号。漏写括号是代码编写过程中又一常犯的错误,或是粗心漏掉,或是由于键入错误而产生一个错误字符。 •当心漏掉逗号。在复杂的定义中很容易忘记逗号! 一般情况下,当弹出一个奇怪的编译错误对话框时,要查看该行前已被编译的内容。很有可能就是错误所在!它可能是出现在一行上面,或中间部分,或在完全不同的文件里。 不要放弃!只要具备一定的经验,解决这些疑难问题就会成为一种第二天性。 技巧#10:优秀的程序员编写的代码行数不一定少 人们常有这种误解,即认为较一般的程序员而言,一个优秀的程序员往往写较少的代码行就能解决问题。不要卷入这一错误的想法!一个优秀的程序员通常具备思维缜密、结构清晰的编码基础。变量命名和封装都恰如其分,系统中几乎不用全局变量。函数应保持简短有效。如果代码看起来很混乱,需要多写几行才能使其看上去更清晰,那就不妨多写几行!可以上网查看获得C代码编写最混乱殊荣奖项的代码用作前车之鉴。优秀程序员写的代码简洁、易于理解和维护,代码行数并非最少(图2)! 图2 简短程序 作者简介 Jacob Beningo获得了软件工程职业认证(CSDP),专业从事高质量、稳健的嵌入式系统的开发和设计。他著有许多关于嵌入式设计方法的科技论文,并教授有关可编程的设备、引导加载程序和软件方法等课程。Beningo获得了中密歇根大学(简称CMU)(密歇根州欢喜山校区)工程物理学学士学位,以及密歇根大学(密歇根州安娜堡分校)空间系统工程硕士学位。 《电子设计技术》网站版权所有,谢绝转载
  • 热度 19
    2013-12-30 18:54
    763 次阅读|
    0 个评论
    这些建议是在我从硬件工程师过渡至软件工程师期间,曾经希望得到的建议。 嵌入式系统设计不仅要求了解硬件,还要求了解软件的作用方式,以及如何与之交互。设计硬件需要的某种范式可能与设计软件完全相反。当从硬件设计转向包含软件的设计时,硬件工程师应牢记以下十个技巧。 技巧#1:流程图第一,实现第二 当工程师首次迈入软件开发领域时,会有种强烈的诱惑力促使他们立刻投入工作并开始写代码。这样的定式思维就等同于在电路逻辑图还未完成前就试图设计印刷电路板(PCB)。在着手开发软件时,抑制一上来就想写代码的冲动是至关重要的,应首先用流程图制定一个软件架构图。这样的方法会使开发人员对应用所需的不同部分与组件形成一个概念,就像电路逻辑图可以告诉工程师需要哪些硬件元件一样。这样可确保程序整体建立在良好的组织和深思熟虑之上,减少程序调试时间,从长期看,这样做还可以节省时间、省去麻烦。 技巧#2:使用状态机控制程序流程 状态机是20世纪最伟大的软件发明之一。某应用程序往往可被分为多个状态机,每个状态机都控制该应用程序的特定部件。这些状态机都拥有自己的内部状态和状态转换,从中可看出软件如何与各种激励相互作用。用状态机来设计软件,可简化软件的开发,使之模块化、可维护,并易于理解。目前拥有的广泛资源可演示状态机的理论和算法。 技巧#3:避免使用全局变量 在函数式编程的年代,函数要先于形式,程序员的唯一目标是尽可能地让程序按预期方式快速运行,而不用考虑程序结构或可重用性。这种编程范式会毫无顾虑地使用全局性变量,程序中的任何函数都可能修改它。其结果就造成了变量被破坏的几率增加或变量被误用。在新推荐的面向对象范式中,应在最小的范围内定义变量并封装它们,以防止其他函数的误用或破坏。因此,建议您限制全局范围使用的变量数量。可在C语言中用外部关键字标识这些变量。 技巧#4:利用模块性的好处 无论问哪一名工程师,项目的哪部分最有可能延迟交付并超出预算?答案都是软件。软件往往是复杂的,且难以开发和维护,尤其是当整个应用都存在于单一文件或松散关联的多个文件中时。为了缓解可维护性、可重用性及复杂性,强烈建议程序员充分利用现代编程语言的模块化特性,将常用功能分解成模块。以这样的方式分解编码,程序员就能着手建立函数与特性库,然后在一个接一个的应用中重用它们,从而通过连续测试而改善代码质量,同时也减少了时间,降低了开发成本。 技巧#5:保持中断服务例程的简单性 中断服务例程用来中断处理器对当前代码分支的执行,从而处理刚刚触发中断的外围设备。无论何时执行中断,都需要一定数量的开销,用于保存当前程序的状态、运行中断,然后将处理器回归原程序状态。现代处理器要比多年前的处理器快得多,但仍需要考虑此花销。一般情况下,程序员都想把中断运行时间降至最低,以避免干扰主代码分支。这意味着中断应该短而简单。中断中不应调用函数。此外,如果中断开始变得过于复杂或耗时,则仅应在必要时利用中断做最少量的工作,例如,将数据装入缓冲区并设置一个标志,然后让主分支处理输入的数据。这样做可保证大多数处理器周期被用于运行应用,而不是处理中断。 技巧#6:使用处理器示例代码做外设的实验 设计硬件时,做原型测试电路总是有益的,这样可确保工程师对电路有正确的理解,然后再做电路板布局。此点对设计软件也同样适用。硅片制造商通常都有示例代码,可用来测试微处理器的各个部分,这样工程师们就可判定该部分的工作情况。此方法使人们洞察到软件体系架构的应该组织方式,以及可能造成的任何潜在问题。在设计初期阶段认清潜在的障碍,比在产品交付前最后几小时才发现它们要好。这是预先测试代码片段的一个很好的方法,但需提醒的是,制造商代码往往不是模块化的,未经大的修改不方便用于实际应用。这一局限已随着时间的发展而改变,也许某一天芯片供应商会给出可用于生产的代码。 技巧#7:限制功能复杂度 工程学中有一个旧词叫“KISS”——保持简单和直接。无论在处理何种复杂工作时,最简单的方法就是把它分解为更小、更简单、更易处理的任务。随着工作或功能变得越来越复杂,人们要准确无误地记录所有的细节也变得更困难。在写一个函数时,其复杂度在当时看似适中,然而要考虑到,一名工程师如何在六个月的维护时间内查看代码。测量函数复杂度(如循环的复杂度)的方法很多。现在有工具可以自动计算某个函数的循环复杂度。经验法则建议,函数的循环复杂度保持在10以下是最理想的。 无论在处理何种复杂工作时,最简单的方法就是把它分解为更易处理的任务。 技巧#8:使用源代码存储库并频繁提交 人都是会犯错误的,写代码时也会犯错。这就是为什么开发人员使用源代码存储库是如此重要。源代码存储库可使开发人员“登记”一个好的代码版本,并描述对该代码基所做的修改。该步骤不仅使得开发人员可以复原或追溯到代码的旧版本,还可以比较旧版本之间的不同。如果开发人员做的一系列改变破坏了系统,只需点击一下即可恢复好的代码版本!请谨记,如果不频繁提交代码,存储库就不会达到预期目的。如果做了不可逆的修改,两周后才提交代码,然后再恢复,就会造成大量工作和时间的损失! 技巧#9:代码做详细说明 在软件开发的激烈战斗中,开发人员很容易把注意力集中在编写和代码上,因此会忽略详细解释的需求。在压力之下,说明工作往往是项目的收尾工作,因为开发人员认为它是最后的一项工作。然而,当代码仍在你脑中新鲜热火时就做出详细解释是至关重要的,这样做可使开发人员或你自己读懂注释,理解代码的工作方式。 如果开发人员做的一系列改变破坏了系统,只需点击一下即可恢复好的代码版本! 技巧#10:使用一种Agile开发流程 无论做何种类型的工程工作,都建议您先设定并遵守一项流程。这样的结果应有一致的质量和成本,并能按时交付。软件开发人员已成功使用Agile开发流程来开发高质量软件。这一流程可按需求的优先等级做开发。优先级别最高的工作在限定的时间段内首先开展,这被称为迭代。这种方法的好处是它可使软件开发流程保持顺畅,还可以根据结果和客户所需,在每次迭代中适应并修改需求和任务。 《电子设计技术》网站版权所有,谢绝转载 技巧#10A:站在开发技术之巅 要学习嵌入式软件开发所使用的最新工具和技术,最好的一个场合是嵌入式系统研讨会(Embedded Systems Conferences)。该会议每年召开两次,地点分别位于加利福尼亚州圣荷西(San Jose)(www.ubmdesign.com/sanjose)和波士顿(east.ubmdesign.com)。会议吸引了来自全世界的工程师,他们可以开展互动、参加研讨会,并进行实际操作,以促进对软件开发的理解。此外,EDN.com社区还提供了与软件和硬件相关的一系列网站(www.edn.com/blogs),工程师们可通过不断的参与和学习,为了将最尖端技术应用于他们未来的发展项目而做好准备。 10大技巧 读者心得 “我不支持关于中断程序的建议。使用像德州仪器(TI)MSP430的低功耗微控制器时,主代码经常只用于将处理器置于睡眠状态。当处理器处于激活状态时,所有工作都在中断程序中完成。”—DickB “从我的经验看,也许这篇文章的标题应为‘软件工程师的10大技巧’。 我曾经在面试一个新职位的软件工程师时问了这样一个问题:‘如何为一个新项目写软件?’ 回答是:‘着手写软件代码!’ 我以为他会说‘阅读规范’,然后‘将软件分解成小模块并为它们设计流程图’或类似的话。 他没能得到这份工作。”—The Real Dr Bob “所有的都很好。想增加10b:让组织剩余成员(管理层)学习‘Agile’(和与其他开发流程相关的一般折中方案)。 要懂得一个最大的‘实话’:在项目刚开始时就设定项目完成的实际目标(一个反复出现的主题)。 有关同一话题的另一个观点:在初期适当地分配人力和流程,而不要等来不及的时候,在后期增加这些。 一个‘人年’工作量是相当于720个员工在下班前解决了一个问题吗?(难以解决这个问题)—Thinking_J 参与谈论 欲与他人分享对本文章的评论,请登录www.edn.com/4405862。 《电子技术设计》网站版权所有,谢绝转载
  • 热度 21
    2013-12-27 21:50
    792 次阅读|
    0 个评论
    这些建议是在我从硬件工程师过渡至软件工程师期间,曾经希望得到的建议。 嵌入式系统设计不仅要求了解硬件,还要求了解软件的作用方式,以及如何与之交互。设计硬件需要的某种范式可能与设计软件完全相反。当从硬件设计转向包含软件的设计时,硬件工程师应牢记以下十个技巧。 技巧#1:流程图第一,实现第二 当工程师首次迈入软件开发领域时,会有种强烈的诱惑力促使他们立刻投入工作并开始写代码。这样的定式思维就等同于在电路逻辑图还未完成前就试图设计印刷电路板(PCB)。在着手开发软件时,抑制一上来就想写代码的冲动是至关重要的,应首先用流程图制定一个软件架构图。这样的方法会使开发人员对应用所需的不同部分与组件形成一个概念,就像电路逻辑图可以告诉工程师需要哪些硬件元件一样。这样可确保程序整体建立在良好的组织和深思熟虑之上,减少程序调试时间,从长期看,这样做还可以节省时间、省去麻烦。 技巧#2:使用状态机控制程序流程 状态机是20世纪最伟大的软件发明之一。某应用程序往往可被分为多个状态机,每个状态机都控制该应用程序的特定部件。这些状态机都拥有自己的内部状态和状态转换,从中可看出软件如何与各种激励相互作用。用状态机来设计软件,可简化软件的开发,使之模块化、可维护,并易于理解。目前拥有的广泛资源可演示状态机的理论和算法。 技巧#3:避免使用全局变量 在函数式编程的年代,函数要先于形式,程序员的唯一目标是尽可能地让程序按预期方式快速运行,而不用考虑程序结构或可重用性。这种编程范式会毫无顾虑地使用全局性变量,程序中的任何函数都可能修改它。其结果就造成了变量被破坏的几率增加或变量被误用。在新推荐的面向对象范式中,应在最小的范围内定义变量并封装它们,以防止其他函数的误用或破坏。因此,建议您限制全局范围使用的变量数量。可在C语言中用外部关键字标识这些变量。 技巧#4:利用模块性的好处 无论问哪一名工程师,项目的哪部分最有可能延迟交付并超出预算?答案都是软件。软件往往是复杂的,且难以开发和维护,尤其是当整个应用都存在于单一文件或松散关联的多个文件中时。为了缓解可维护性、可重用性及复杂性,强烈建议程序员充分利用现代编程语言的模块化特性,将常用功能分解成模块。以这样的方式分解编码,程序员就能着手建立函数与特性库,然后在一个接一个的应用中重用它们,从而通过连续测试而改善代码质量,同时也减少了时间,降低了开发成本。 技巧#5:保持中断服务例程的简单性 中断服务例程用来中断处理器对当前代码分支的执行,从而处理刚刚触发中断的外围设备。无论何时执行中断,都需要一定数量的开销,用于保存当前程序的状态、运行中断,然后将处理器回归原程序状态。现代处理器要比多年前的处理器快得多,但仍需要考虑此花销。一般情况下,程序员都想把中断运行时间降至最低,以避免干扰主代码分支。这意味着中断应该短而简单。中断中不应调用函数。此外,如果中断开始变得过于复杂或耗时,则仅应在必要时利用中断做最少量的工作,例如,将数据装入缓冲区并设置一个标志,然后让主分支处理输入的数据。这样做可保证大多数处理器周期被用于运行应用,而不是处理中断。 技巧#6:使用处理器示例代码做外设的实验 设计硬件时,做原型测试电路总是有益的,这样可确保工程师对电路有正确的理解,然后再做电路板布局。此点对设计软件也同样适用。硅片制造商通常都有示例代码,可用来测试微处理器的各个部分,这样工程师们就可判定该部分的工作情况。此方法使人们洞察到软件体系架构的应该组织方式,以及可能造成的任何潜在问题。在设计初期阶段认清潜在的障碍,比在产品交付前最后几小时才发现它们要好。这是预先测试代码片段的一个很好的方法,但需提醒的是,制造商代码往往不是模块化的,未经大的修改不方便用于实际应用。这一局限已随着时间的发展而改变,也许某一天芯片供应商会给出可用于生产的代码。 技巧#7:限制功能复杂度 工程学中有一个旧词叫“KISS”——保持简单和直接。无论在处理何种复杂工作时,最简单的方法就是把它分解为更小、更简单、更易处理的任务。随着工作或功能变得越来越复杂,人们要准确无误地记录所有的细节也变得更困难。在写一个函数时,其复杂度在当时看似适中,然而要考虑到,一名工程师如何在六个月的维护时间内查看代码。测量函数复杂度(如循环的复杂度)的方法很多。现在有工具可以自动计算某个函数的循环复杂度。经验法则建议,函数的循环复杂度保持在10以下是最理想的。 无论在处理何种复杂工作时,最简单的方法就是把它分解为更易处理的任务。 技巧#8:使用源代码存储库并频繁提交 人都是会犯错误的,写代码时也会犯错。这就是为什么开发人员使用源代码存储库是如此重要。源代码存储库可使开发人员“登记”一个好的代码版本,并描述对该代码基所做的修改。该步骤不仅使得开发人员可以复原或追溯到代码的旧版本,还可以比较旧版本之间的不同。如果开发人员做的一系列改变破坏了系统,只需点击一下即可恢复好的代码版本!请谨记,如果不频繁提交代码,存储库就不会达到预期目的。如果做了不可逆的修改,两周后才提交代码,然后再恢复,就会造成大量工作和时间的损失! 技巧#9:代码做详细说明 在软件开发的激烈战斗中,开发人员很容易把注意力集中在编写和代码上,因此会忽略详细解释的需求。在压力之下,说明工作往往是项目的收尾工作,因为开发人员认为它是最后的一项工作。然而,当代码仍在你脑中新鲜热火时就做出详细解释是至关重要的,这样做可使开发人员或你自己读懂注释,理解代码的工作方式。 如果开发人员做的一系列改变破坏了系统,只需点击一下即可恢复好的代码版本! 技巧#10:使用一种Agile开发流程 无论做何种类型的工程工作,都建议您先设定并遵守一项流程。这样的结果应有一致的质量和成本,并能按时交付。软件开发人员已成功使用Agile开发流程来开发高质量软件。这一流程可按需求的优先等级做开发。优先级别最高的工作在限定的时间段内首先开展,这被称为迭代。这种方法的好处是它可使软件开发流程保持顺畅,还可以根据结果和客户所需,在每次迭代中适应并修改需求和任务。 《电子设计技术》网站版权所有,谢绝转载 技巧#10A:站在开发技术之巅 要学习嵌入式软件开发所使用的最新工具和技术,最好的一个场合是嵌入式系统研讨会(Embedded Systems Conferences)。该会议每年召开两次,地点分别位于加利福尼亚州圣荷西(San Jose)(www.ubmdesign.com/sanjose)和波士顿(east.ubmdesign.com)。会议吸引了来自全世界的工程师,他们可以开展互动、参加研讨会,并进行实际操作,以促进对软件开发的理解。此外,EDN.com社区还提供了与软件和硬件相关的一系列网站(www.edn.com/blogs),工程师们可通过不断的参与和学习,为了将最尖端技术应用于他们未来的发展项目而做好准备。 10大技巧 读者心得 “我不支持关于中断程序的建议。使用像德州仪器(TI)MSP430的低功耗微控制器时,主代码经常只用于将处理器置于睡眠状态。当处理器处于激活状态时,所有工作都在中断程序中完成。”—DickB “从我的经验看,也许这篇文章的标题应为‘软件工程师的10大技巧’。 我曾经在面试一个新职位的软件工程师时问了这样一个问题:‘如何为一个新项目写软件?’ 回答是:‘着手写软件代码!’ 我以为他会说‘阅读规范’,然后‘将软件分解成小模块并为它们设计流程图’或类似的话。 他没能得到这份工作。”—The Real Dr Bob “所有的都很好。想增加10b:让组织剩余成员(管理层)学习‘Agile’(和与其他开发流程相关的一般折中方案)。 要懂得一个最大的‘实话’:在项目刚开始时就设定项目完成的实际目标(一个反复出现的主题)。 有关同一话题的另一个观点:在初期适当地分配人力和流程,而不要等来不及的时候,在后期增加这些。 一个‘人年’工作量是相当于720个员工在下班前解决了一个问题吗?(难以解决这个问题)—Thinking_J 参与谈论 欲与他人分享对本文章的评论,请登录www.edn.com/4405862。 《电子技术设计》网站版权所有,谢绝转载