gpt4 book ai didi

c - 将对象创建移动到 arduino 的 setup() 函数

转载 作者:太空狗 更新时间:2023-10-29 17:16:47 25 4
gpt4 key购买 nike

我创建了一个类来处理将数据发送到 LED 矩阵 (max7219)。

这就是我创建 LedControl 类实例的方法。

LedControl lc=LedControl(11, 13, 12);// data, clock, latch;

void setup()
{
...
}

现在我正在尝试向我的类(class)添加定时器中断。但我发现我无法在初始化程序 (LedControl::LedControl()) 中设置适当的注册表。如果我将此代码移至 setup,一切都会完美无缺。我的猜测是,使用 timer1 进行 PWM 的 Arduino 引导加载程序会在调用 setup() 之前但在我的对象已初始化之后覆盖这些注册表。

所以我的想法是像这样将对象创建移动到设置函数

// FAIL
LedControl lc;

void setup()
{
lc=LedControl(11, 13, 12);// data, clock, latch;
...
}

但随后我得到错误没有匹配函数调用'LedControl::LedControl()'

我尝试使用指针 (LedControl *lc; lc=&LedControl(11, 13, 12);),但据我所知,这意味着我将不得不在所有地方编写 (*lc).someFunction() 而不是 lc.someFunction()。甚至不如将注册表设置代码移动到 setup() 优雅。

所以我的问题是。如何在 setup() 函数中创建一个对象,但仍然有一个全局变量指向它?

最佳答案

你的第一个错误“没有匹配..”是因为你没有默认构造函数。您可以使该方法发挥作用。

向类添加一个无参数,即默认构造函数,如下所示:

class LedControl {
LedControl();
LedControl(uint8_t pin1, uint8_t pin2, uint8_t pin3);

private:
uint8_t pin1;
uint8_t pin2;
uint8_t pin3;
};

LedControl::LedControl() : pin1(0), pin2(0), pin3(0) {
// this constructor leaves the class unusable
}

LedControl::Ledcontrol(uint8_t p1, uint8_t p2, uint8_t p3)
: pin1(p1), pin2(p2), pin3(p3)
{
// this object is ready to use
}

对于此类,您的方法会起作用,但不是最佳方法。这一行做了太多工作:

void setup() {
lc = LedControl(11, 13, 12);// data, clock, latch;
}

这行代码涉及编译器为您创建一些代码:

  • 首先使用参数 11、13、12 在堆栈上构造该类的另一个实例。
  • 然后它应用 = 运算符 将数据从堆栈对象复制到您的全局对象。
  • 当 setup() 退出时,堆栈对象被刷新。

因为临时对象在栈上,你的程序并没有使用太多的内存,但是你的代码量更大,因为它涉及额外的操作来构造临时对象然后从临时对象复制到永久对象。

请注意,编译器正在为您创建一个= 运算符,以填充该行的功能

  lc = LedControl(11, 13, 12);

这可能有效也可能无效,具体取决于构造函数中的内容。编译器只能假定您需要一个简单的 = 运算符。基本赋值运算符要做的就是将所有数据成员从 = 右侧的实例复制到左侧的实例。编译器构造的 = 将不包含任何代码。

如果您的构造函数做了任何重要的事情(除了保存参数),那么编译器构造(猜测)的赋值运算符可能不会像您预期的那样工作。对于您的情况,构造函数可能会设置引脚模式,如下所示:

LedControl::LedControl(uint8_t p1, uint8_t p2, uint8_t p3) 
: pin1(p1), pin2(p2), pin3(p3)
{
pinMode(pin1, INPUT);
pinMode(pin2, OUTPUT);
pinMode(pin3, OUTPUT);
return;
}

这恰好起作用,但只是偶然。 pinMode() 调用是在构建临时对象并从该对象调用时进行的,而不是从全局 lc 调用。因为 pinMode() 是全局的,所以这种情况将实现正确的目标,但可能不是预期的方式。对于注册中断处理程序等更复杂的操作,您需要创建自己的赋值运算符:

LedControl& operator= (const LedControl & other);

在该方法中,您可以确保全局 lc 的状态是您所需要的。一种更简单/更安全的方法是根本不处理它。

您可能在其他库中看到过一种简单而有效的方法,即向分配引脚的类添加一个方法:

class LedControl {
void attach(uint8_t pin1, uint8_t pin2, uint8_t pin3);
};

void LedControl::attach(uint8_t pin1, uint8_t pin2, uint8_t pin3) {
this.pin1 = pin1;
this.pin2 = pin2;
this.pin3 = pin3;
// do other setup type operations
return;
}

现在你的程序,构建空白对象,并在 setup() 期间分配引脚:

LedControl lc; // not ready to use until attach pins

void setup() {
lc.attach(11, 13, 12);// data, clock, latch;
...
}

这不涉及临时对象构造,也不涉及赋值运算符。关于设计,有些人可能会公正地评论说用户可能会忘记调用 attach() 并使全局 lc 对象不可用。对于桌面应用程序,您可以添加一些代码来防止这种失败情况。对于嵌入式应用程序,这是您接受的风险,可以通过代码大小或内存节省方面的 yield 来平衡。

关于c - 将对象创建移动到 arduino 的 setup() 函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18806141/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com