传递外围对象以用作嵌入式系统中的类成员

时间:2018-08-17 02:56:18

标签: c++ embedded mbed

在用C ++进行嵌入式编程(例如,使用MBED)时,我经常为设备外围设备(如I2C或串行设备)全局声明对象,这些对象通常为用于特定应用程序的设备引脚使用参数:

I2C i2c(SDA_1, SCL_1);
Serial my_serial(D7, D8);

如何正确将这些对象传递给其他类?我想将所有特定于应用程序的信息保留在平台级代码中,理想情况下,应用程序中的每个类都应使用这些对象的相同实例,但是我似乎无法正确设置构造函数语法,因此外围设备对象可以在声明时传递到类中,然后用作该类中的成员对象。

示例: 我在main.cpp文件中全局声明了一个设备外围设备:

I2C i2c(SDA_1, SCL_1);

我需要在我的应用程序中使用的几个对象(例如ThingController)中使用此i2c外设。这是我尝试通过指针传递这些对象的方法:

ThingController.h

class ThingController {
public:
    ThingController(I2C *i2c);
    void init();
    void run();
private:
    I2C my_i2c;

ThingController.cpp

Editor::Editor(I2C *i2c)
{
    my_i2c = *i2c;

为此,对于头文件,我得到“对于I2C类不存在默认构造函数”,这意味着它只是在尝试创建该类的新实例。如果我尝试按值传递,则得到相同的结果。

执行此操作的语法是什么?或者,就我对此的想法而言,我是否还有路?我无法在网上找到其他与我遇到的问题类似的东西,这让我感到很奇怪,因为如果我想在应用程序中使用类,那么我需要执行此确切任务的频率有多高。每个人都只是遍历大量特定于应用程序的引脚,然后为每个类创建这些硬件外设的新实例吗?还是另一种方法?

2 个答案:

答案 0 :(得分:2)

您已将成员my_i2c声明为I2C instance ,这意味着如果不声明,其默认构造函数将在ThingController的构造函数中调用自己不称呼它。由于它没有default constructor,因此您会收到此错误。

您需要做的就是使实例成员成为 reference (或指针)而不是值,如下所示:

class ThingController {
public:
    ThingController(I2C& i2c);
    void init();
    void run();
private:
    I2C& my_i2c;
}

Editor::Editor(I2C& i2c) :
    my_i2c(i2c)
{
}

您可以使用指针而不是引用,但是在这种情况下,引用的语义更适合您的情况-您只想初始化一次而不更改它。

最好阅读constructors and member initialiser syntax(涵盖所有内容)。

  

每个人都只是遍历大量特定于应用程序的引脚,然后为每个类创建这些硬件外设的新实例吗?还是另一种方法?

不,那将是一个非常糟糕的主意。 :)诸如I2C和SPI之类的外围设备应具有单件包装器类,该类允许您序列化访问。例如,如果您传递了引脚定义并创建了I2C类的多个实例,则最终可能会导致代码的两个不同部分试图同时访问外设,从而导致各种奇怪和难以调试的问题。上面的方法很好,并且您还需要查看在I2C类上添加互斥锁并具有锁定/解锁方法。

答案 1 :(得分:1)

首先,您不应全局声明任何内容-至少应声明所有C ++类。这将为您提供各种形式的初始化命令错误。在大多数嵌入式系统中,初始化的顺序非常重要。

您应该做的是在主循环/应用程序代码本地声明所有此类对象。如果您的代码中有几个部分需要访问I2C,则将对象传递给他们。

但是,如果程序的某些部分需要访问原始I2C,则您的设计已经错误。 OO设计很糟糕,要让程序的某些随机部分了解硬件特定的内容,例如“ SDA_1”,“ SCL_1”。

仅I2C驱动程序应直接与外围设备对话并“了解” I2C硬件。您需要在那之上实现一个HAL。 (可选地,HAL可以是抽象基类,驱动程序可以继承它。)并且,您应该只允许与可用的硬件外围设备一样多的I2C对象实例。