我创建了一个处理向led矩阵发送数据的类(max7219).
这就是我在创建LedControl类的实例时所做的.
LedControl lc=LedControl(11, 13, 12);// data, clock, latch;
void setup()
{
...
}
Run Code Online (Sandbox Code Playgroud)
现在我正在尝试向我的班级添加计时器中断.但我发现我无法在初始化器(LedControl::LedControl())中设置适当的注册表.如果我将此代码移动到setup,那么一切都很完美.我的猜测是,timer1用于PWM 的Arduino引导程序会在调用之前覆盖这些注册表,setup()但是在我的对象初始化之后.
所以我的想法是将对象创建移动到设置功能,就像这样
// FAIL
LedControl lc;
void setup()
{
lc=LedControl(11, 13, 12);// data, clock, latch;
...
}
Run Code Online (Sandbox Code Playgroud)
但后来我得到了错误 no matching function for call to 'LedControl::LedControl()'
我尝试使用指针(LedControl *lc; lc=&LedControl(11, 13, 12);),但据我所知,这意味着我必须在(*lc).someFunction()任何地方写,而不是lc.someFunction().甚至不如将注册表设置代码移动到setup()更优雅.
所以我的问题是.如何在setup()函数中创建一个对象,但仍然有一个指向它的全局变量?
jdr*_*5ca 12
您的第一个错误"没有匹配.."是因为您没有默认构造函数.你可以使用这种方法.
在类中添加一个无参数AKA默认构造函数,如下所示:
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
}
Run Code Online (Sandbox Code Playgroud)
使用此类,您的方法将起作用,但不是最佳方法.这条线做得太多了:
void setup() {
lc = LedControl(11, 13, 12);// data, clock, latch;
}
Run Code Online (Sandbox Code Playgroud)
这行代码涉及编译器为您创建一些代码:
因为临时对象在堆栈上,所以您的程序没有使用太多内存,但是您的代码大小更大,因为它涉及额外的操作来构造从临时对象到临时对象的临时对象.
请注意,编译器正在为您创建一个=运算符,以填充该行的功能
lc = LedControl(11, 13, 12);
Run Code Online (Sandbox Code Playgroud)
这取决于构造函数中的内容,可能会也可能不起作用.编译器只能假定您需要一个simple =运算符.所有基本赋值运算符都会将所有数据成员从=右侧的实例复制到左侧的实例.编译器构造=将不包含任何代码.
如果您的构造函数执行任何重要操作(除了保存参数),那么编译器构造(猜测)赋值运算符可能无法按预期工作.对于您的情况,构造函数可能设置引脚模式,如下所示:
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;
}
Run Code Online (Sandbox Code Playgroud)
这恰好发挥作用,但只是偶然.在构造临时对象并从该对象调用而不是从全局lc调用时,将调用pinMode().因为pinMode()是全局的,所以这种情况将达到正确的目标,但可能不是预期的方式.对于更复杂的操作,例如注册中断处理程序,您需要创建自己的赋值运算符:
LedControl& operator= (const LedControl & other);
Run Code Online (Sandbox Code Playgroud)
在该方法中,您可以确保全局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;
}
Run Code Online (Sandbox Code Playgroud)
现在你的程序,构造空白对象,并在setup()期间分配引脚:
LedControl lc; // not ready to use until attach pins
void setup() {
lc.attach(11, 13, 12);// data, clock, latch;
...
}
Run Code Online (Sandbox Code Playgroud)
这不涉及临时对象构造,也不涉及赋值运算符.在设计方面,有些人可能会公平地评论用户可能忘记调用attach()并使全局lc对象无法使用.对于桌面应用程序,您可以添加一些代码以防止出现此类故障.对于嵌入式应用程序,这是您接受的风险,它可以通过代码大小或内存节省的增益来平衡.
我刚刚偶然发现了同样的问题。我想创建一个全局调试端口对象,但无法将其创建为全局实例,因为调用 setup() 后该端口将无法工作。我有同样的假设,即 arduino 代码在我的构造函数(全局对象)之后和 setup() 之前做了一些设置。
我发现这是最简单的解决方案,将我的对象声明为指针并在设置中初始化它。在你的情况下,它将是:
LedControl* lc;
void setup()
{
lc = new LedControl(11, 13, 12);// data, clock, latch;
}
void loop()
{
lc->doSomething();
}
Run Code Online (Sandbox Code Playgroud)
因此不需要额外的构造函数或运算符。由于该对象一直使用到断电为止,因此在这种情况下不需要删除。