我目前正在开发一些软件来驱动四轴飞行器的ESC。在我的ESC类中,我需要初始化PWM引脚并等待大约5秒以使ESC进行验证,然后再向其发送任何其他节流值。
目前,我的班级如下。
在ESC.h中
class ESC
{
private:
int ESCPin;
bool ESCInitialised;
//Timer Objects
SimpleTimer startupTimer;
void endInit();
public:
void initESC(int pin);
bool isInitialised() const { return ESCInitialised; };
void setPWM(uint16_t dut);
};
在ESC.cpp中
#include "ESC.h"
void ESC::initESC(int pin){
ESCInitialised = false;
ESCPin = pin;
InitTimersSafe();
SetPinFrequency(ESCPin, 500);
pwmWriteHR(ESCPin,32768);
startupTimer.setTimeout(5000, endInit);
}
void ESC::setPWM(uint16_t dut){
pwmWriteHR(ESCPin, dut);
}
void ESC::endInit(){
ESCInitialised = true;
}
我希望ESCInitialised布尔值保持私有,因为它不应该被任何其他类修改,所以我使用公共getter方法isInitialised()来返回它。一次性计时器结束后,它应该调用endInit()函数将ESCinitialised bool设置为true,这样主代码就可以确定何时通过新的节流值。
在当前状态下,我收到错误
In static member function 'static void ESC::endInit()':
ESC.h:14: error: invalid use of member 'ESC::ESCInitialised' in static
member function
bool ESCInitialised;
非常感谢任何建议。
答案 0 :(得分:4)
此时您的问题就开始了:
startupTimer.setTimeout(5000, endInit);
看起来,您的方法需要获得一个可以在没有任何对象的情况下调用的函数,因此您必须使用静态函数。
但是,在类中定义的静态函数无法访问对象中的数据成员!简单地说,从类中调用静态函数时不涉及任何对象。
如果你不想使你的变量也是静态的,最终会使一切变为静态,并且你不能再使用类的多个实例,你需要一种方法来绑定一个对象和一个方法你的回调。
我不知道你的startupTimer.setTimeout
是如何定义的。但是如果它只是一个指向可调用对象的指针,它就可以这样做:
startupTimer.setTimeout(5000, [this](){ endInit(); } );
endInit
方法必须不再是静态的。
如果您的计时器界面没有提供向回调添加一些用户数据,则您没有机会将对象数据设置为回调。用于计时器对象的这种接口几乎是无用的。这使得无法使用任何类型的OOP。因此,只有一个机会可以列出静态/全局范围辅助函数。 这是非常糟糕的设计
这是一个非常糟糕的工作:
template <typename T, int n>
class UglyObjectCallbackHandler
{
static T* obj;
static void(T::*callback)();
public:
static void SetObj( T* _obj ) { obj = _obj; }
static void SetCallback( void(T::* _callback)() ) { callback = _callback; }
static void ForwardCallback() { (obj->*callback)(); }
};
template <typename T, int n> T* UglyObjectCallbackHandler<T,n>::obj;
template <typename T, int n> void(T::* UglyObjectCallbackHandler<T,n>::callback)();
class A
{
private:
int i;
void(*callback)();
std::function<void()> callback_func= [this](){ f(); };
public:
A( int _i ): i{_i} { }
void f() { std::cout << "Callback fired" << i << std::endl; }
};
class TimerFake
{
private:
void (*ptr)();
public:
void SetCallback( void (*_ptr)() ) { ptr = _ptr; }
void Fire() { (*ptr)(); }
};
int main()
{
// multiple client instances possible
A a(9);
UglyObjectCallbackHandler<A,0>::SetObj( &a );
UglyObjectCallbackHandler<A,0>::SetCallback( &A::f );
A b(77);
UglyObjectCallbackHandler<A,1>::SetObj( &b );
UglyObjectCallbackHandler<A,1>::SetCallback( &A::f );
TimerFake timer0;
timer0.SetCallback( &UglyObjectCallbackHandler<A,0>::ForwardCallback );
TimerFake timer1;
timer1.SetCallback( &UglyObjectCallbackHandler<A,1>::ForwardCallback );
timer0.Fire();
timer1.Fire();
}
我们的想法是将多个运行时对象(如ESC对象)保存到编译时生成的列表中。所以这里的模板提供了第二个参数,它是要调用的实例的索引。 因为模板提供了静态回调方法(转发器),所以它可以用来回调设计不良的接口。如上所述:这是一个非常糟糕的主意。更好地使用功能齐全的Timer lib!