我正在编写一个电动机控制器,该电机控制器具有几个接口(按钮,蓝牙,触觉旋钮),这是一项稳步增长的任务,比我想象的要大。我只是尝试从低级模块开始(例如编写代码以在I2C总线上进行交谈),然后在该模块上方(代码) 特定设备 在I2C巴士上...),但是我经常不得不回到下部模块以处理我不容纳的怪癖。这要么需要很长时间,要么我得到了真正的黑客代码。

我的目标是8位MCU,因此自下而上似乎可以更好地利用硬件。如果我自上而下,我将没有任何结构可以建立或测试/调试。

我已经尝试为特定级别/驱动程序绘制一些总体图和一个图表,但是我不确定如何构造它们,因此我可以非常系统地对其进行系统的构建,并避免缺少需要通过2-3上升的奇数信号层。

我想这是获得CS学位的原因?我是电气工程师:P

有帮助吗?

解决方案

听起来您在正确的轨道上。有时,没有计划会阻止您以后再重新设计或重构部分。尝试以下一些提示:

  • 将代码保留在模块中,以逻辑功能分开。
  • 请勿重复代码,而是为共享功能设计可重复使用的方法。
  • 尽量避免诱惑为特殊情况添加黑客攻击。最终,这将变得无法实现。相反,请尽快调整和重构小部分。尝试在最后进行大型重新设计将更加困难。
  • 不要从一开始就试图过度设计系统,因为您可能只是在浪费时间进行实际实施时浪费时间。
  • 保持较低的级别尽可能简单,然后在顶部构建更高级的功能。
  • 记录您的功能并编写一些单元测试,尤其是在添加了复杂的条件语句之后。
  • 尝试捕获尽可能高的错误。例如,执行输入验证并检查返回值。这将使调试变得更加容易。

其他提示

在使用多层代码工作时,当API不允许您完全做自己想做的事情时,它很容易潜入较低的层。同时编写Mulitple层时,这尤其困难。

这里有一些建议:

  • 将所有其他级别对待,而不是您正在工作的层面,就好像它们被密封一样。由另一家公司,开发人员等创建的。抵制修改另一层以解决您当前层的问题的冲动。
  • 为您正在工作的一个创建一个“兄弟姐妹”。这很难从抽象的意义上描述,但是可以说您的下层是一个业务层,较高的层是UI,为其他应用程序创建另一个UI层。现在,拥有同一API的两个消费者可以帮助指出每一层中应该有什么。
  • 尝试交替交替在层次上工作的顺序。例如,在某些应用程序中,我发现首先设计UI更有用,然后努力到业务层/数据库以使该UI按设计工作。在其他时候,使用数据模型统计并达到UI会更好。但是关键是,您在这两种情况下以不同的方式“思考” API。从两个角度看多分层代码后,会有所帮助。
  • 经验很重要。有时,仅仅犯了过度耦合代码的错误是真正学会避免它的唯一方法。与其计划您的应用程序是完美的,不如计划它是不完美的。我的意思是首先设置一个快速的开发/测试/重构周期,以便您可以快速适应您不会看到的错误,直到制作它们后。这也是“丢弃原型制作”的区域。做一个简单的粗糙草稿,从中学习并扔掉。扔掉的部分很重要。即使它令人惊奇,也开始从头开始建造另一个。您将不可避免地会根据您从原型中学到的知识来使其变得更好(并且在我的生气方面更有条理)。

实际上,这比您的学位更多。如果您仍在学习有关如何控制硬件的知识,那么您的代码当然会更改。我不会为此感到痛苦。但是,由于您真正正在做的是原型制作,因此您应该准备好一旦代码工作就可以重构。删除冗余,分隔数据和功能,并组织界面,使其有意义。

我的经验是,设备驱动程序代码需要自上而下和自下而上的设计/实现,我称之为外部。您知道用户将要做什么,并且可以编写这些接口,并且您知道低级驱动程序需要做什么,并且您写了这一点。如果它们在中间不舒服,请重新考虑您的模块布局。

要改进,请对您的设计和代码进行评论,以审查具有更多经验的人。将自我放在其中,只是解决问题。您可能还会阅读一本关于面向对象的分析和设计的书(我曾经喜欢彼得·科德(Peter Coad)的书。我不知道现在谁在写它们)。一个好的将展示如何将问题划分为具有明确角色和责任的对象的示例。

另一个作品一旦您完成了驱动程序的原型制作并知道如何控制硬件,就是要确保您有详细的要求。在您写作时发现要求,没有什么比发现要求更重要的了。您还可以在编写代码之前尝试学习UML并使用图表进行设计。这对每个人都不起作用。另请注意,您不需要用支持面向对象的构造的语言进行编码以使用OOD。

如果您的问题是如何构建适当的抽象(似乎是这种情况),我认为您可以学习最重要的事情(除了询问设计代码评论/阅读书籍/读取代码)是 在开始编写代码之前努力思考.

通常,您会从对自己想要的工作以及应该如何完成的大概开始,然后继续编写代码。稍后,您发现自己没有思考,并且有几个张开的漏洞,因为您已经花了时间编写代码,因此很难修补,这会导致浪费时间或骇人听闻的代码。

考虑如何创建可以轻松处理更改的设计。例如,封装了需要在层之间传播的数据,因此,如果您以后发现错过了关键参数,则可以轻松地将其添加到结构中,而无需在任何地方修改代码。

尝试几次“在脑海中运行设计”,直到您重新确定您已经考虑了最重要的细节,并且可以分辨(这是最重要的部分,因为您总是会错过的事情或要求会改变)如果您错过了一些东西,则可以相对轻松地调整模块。

可以帮助您构建思考设计的方式。当然不是灵丹妙药,但它显示了创建软件设计时要考虑的不同标准。

有点像经典的国际象棋老师建议:”坐在你的手上" :-)

驾驶员可以接受层方法。

您的司机可能有几个“课程”:

  • 仅输入
  • 仅输出
  • 我和O。

他们应该具有标准化的界面,例如:

GetKnobLevel()
GetNextKeyboardButton

或者,另一种方法是拥有类似的东西

syscall(DRIVERNUMBER, command)

将参数/结果放在指定的寄存器中。

这是一种简单,可用的方法。一个更复杂的变体可能是在您的硬件通信代码和软件通信代码(而不是寄存器)之间进行循环排队。

这是我正在使用的心理模型:

---
Application
---
OS
---
Driver communicators
---
drivers
---
hardware

每一层之间都有一个紧密定义的,无方差的界面(我一直想象一个层之间的蛋糕,层之间的糖霜较厚...)。当然,OS可能不存在。

如果您的MCU支持软件和硬件中断,例如X86 CPU,则可以使用它们将驱动程序与驱动程序通信器隔离。

老实说,这是一种“过度工程”解决方案。但是,在您的复杂性变得越来越重大的情况下,要进行紧密的工程比拥有松散的工程更容易。

如果您在层之间进行通信,则可以为每个通信“频道”使用全局变量,并以纪律处分的方式访问它,仅使用函数访问它。

通常,您将需要在某种程度上进行纸质设计,一些探索性工作,并在真正着手编码项目之前重新设计。流程图和公交运输图在这里运行良好。

这是我在嵌入式系统工作中喜欢的方法,对我来说很好。

另外 - 传统的计算机科学课程对此问题空间没有很好地探索。它比网络或现代操作系统要宽容得多。

我认为,建筑良好的代码最重要的方面是 低度耦合副作用与状态的分离.

另外 - 代码是一种工艺。不要以为从一开始就可以做出完美的解决方案。在学习新事物时,请准备更改代码。实际上 - 确保您拥抱 改变自我 作为您工作的一部分。

不要太沮丧,而是 神话般的人月 想到:“计划扔掉;无论如何,您都会。”

推论是“使它起作用。使其正确。使其快速。”

我想这使我成为了预先进行一些设计的倡导者,但不会被它瘫痪。它不必第一次完美。计划重构。希望您能以这样的方式写东西,以至于您不会真正抛出太多代码,而要以更令人愉悦的方式重新安排。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top