【问题标题】:Arduino - Enum variable value change by itselfArduino - 枚举变量值自行更改
【发布时间】:2017-10-15 13:49:21
【问题描述】:

我创建了一个 Arduino 大型草图来控制 LED 通道以模拟简单的日落和日出。在我的类 LEDChannel 声明中,我有一个公共枚举来表示 LED 通道的状态,并且我在类中有一个 State 枚举的私有实例 (CurrentState) 来跟踪这个 LEDChannel 实例。

一切都编译好并上传到我的 Arduino Mega。问题是当我调试代码并检查 CurrentState 变量的值时,我得到的值超出了枚举范围。有时我得到值 7579(我上次测试中的实际值)。另一天,我可以得到一个 612 的值。该值应该只有 0 到 4。我验证了我的代码,并且在我更改此变量的值的任何地方,我都使用枚举。举例:

CurrentState = ManualSunset;

CurrentState 变量在 LEDChannel 类的默认构造函数中接收值 NoAction。

LEDChannel 类是一个更大的项目的一部分,它与其他类一起制作 Aquarium 控制器来表示 RTC 时间模块、蓝牙模块、风扇和温度传感器。

我使用 Visual Studio Community 2015 使用 Arduino 的 vMicro 插件开发了我的项目。如果你需要完整的项目,我会想办法让它可用。

这是 LEDChannel 声明/定义和主要 Arduino 程序 .ino。这是我的代码的精简版。我删除了所有不必要的代码。要重现该问题,只需在主程序nNbLEDChannel = 1; 中注释第 13 行即可。然后,您应该获得变量 CurrentState 的值 ManualSunrise (3)。不要认为 nNbLEDChannel 仅在主 .ino 文件中使用。

#pragma once

#if defined(ARDUINO) && ARDUINO >= 100
    #include "Arduino.h"
#else
    #include "WProgram.h"
#endif

//#include "DataTypes.h"
typedef byte duration;
class AquariumSimulator;

class LEDChannel
{
public:
    typedef enum State
    {
        AutomaticSunset = 0,
        AutomaticSunrise = 1,
        ManualSunset = 2,
        ManualSunrise = 3,
        NoAction = 4
    };

private:
    byte MaxBrightness;
    unsigned long lastTick;
    byte CurrentBrightness;
    LEDChannel::State CurrentState;
    byte DigitalPin;
    duration ManualSunsetDuration;// In secondes
    duration ManualSunriseDuration;// In secondes
    AquariumSimulator* pAquariumSim;

public:
    void StartManualSunrise(duration SecDuration);
    void PerformSunrise();
    LEDChannel();
    LEDChannel(byte DigitalPIN, AquariumSimulator* pSim);
private:
    void PerformManualSunrise();        
    void SetCurrentBrightness(byte value);
    void IncreaseCurrentBrightness(byte value = 1);
};

这里是 LEDChannel.cpp

#include "LEDChannel.h"
/*
Constuctor
*/
LEDChannel::LEDChannel(byte DigitalPIN, AquariumSimulator* pSim)
{
    LEDChannel();
    // Initialize default values
    pAquariumSim = pSim;
    pinMode(DigitalPIN, OUTPUT);// Configure Digital pin that control LED Channel
}

LEDChannel::LEDChannel() 
{
    CurrentState = NoAction;

}

void LEDChannel::PerformSunrise()
{

    switch (CurrentState)
    {
    case AutomaticSunrise:
        //PerformAutomaticSunrise();
        break;

    case ManualSunrise:
        PerformManualSunrise();
        break;
    }
}

void LEDChannel::PerformManualSunrise()
{

    unsigned long currentTick = millis();
    if (currentTick >= (lastTick + ManualSunriseDuration / MaxBrightness))
    {

        // If current brightness is at max brigthness value, stop sunset
        if (CurrentBrightness == MaxBrightness)
        {
            CurrentState = NoAction;
            lastTick = 0;
        }
        else
        {
            IncreaseCurrentBrightness();
            lastTick = currentTick;
        }
    }
}

void LEDChannel::SetCurrentBrightness(byte value)
{
    if (value > 255)
        CurrentBrightness = 255;
    else
        CurrentBrightness = value;
    analogWrite(DigitalPin, CurrentBrightness);

}

void LEDChannel::IncreaseCurrentBrightness(byte value)
{
    if ((CurrentBrightness + value) <= 255)
        CurrentBrightness += value;
    else
        CurrentBrightness = 255;
    SetCurrentBrightness(CurrentBrightness);
}

// Manual Sunrise for a duration in secondes
void LEDChannel::StartManualSunrise(duration SecDuration)
{

    switch (CurrentState)
    {
    case NoAction:
        CurrentState = ManualSunrise;
        ManualSunriseDuration = SecDuration;
        SetCurrentBrightness(0);
        break;
    }

}

还有主程序.ino

#include "LEDChannel.h"

LEDChannel** pLED;
byte nNbLEDChannel;

void setup()
{
    pLED = new LEDChannel*[1];
    pLED[0] = new LEDChannel(44, NULL);

    /*  If i put the next line as comment CurrentState get a valid value. 
    If i assigne a value to nNbLEDChannel I get invalid value for CurrentState*/
    nNbLEDChannel = 1;  

    pLED[0]->StartManualSunrise(10);
}

void loop()
{
    pLED[0]->PerformSunrise();
}

【问题讨论】:

  • 请提供Minimal, Complete, and Verifiable examplethis-&gt; 指针也可以省略。这是隐含的,像this-&gt;Sunrise = Sunrise; 这样的声明会让人感到困惑。你在哪里初始化CurrentState
  • 您好,感谢您的回答。 this-> 仅用于确保使用想要的变量来帮助我诊断问题。这是我的完整项目的链接dropbox.com/s/2k0dh1zsf49bvy5/SunsetSunriseArduino2.zip?dl=0 CurrentState 变量在 LEDChannel() 构造函数中使用 this->CurrentState = NoAction 初始化我将使用最少的代码进行更多测试并为您提供可验证的示例。
  • 我刚刚更新了我的代码,以最低要求重现问题,并更新了我的描述以反映我的代码。

标签: c++ enums arduino


【解决方案1】:

我没有拿出我的 Arduino UNO 板,但我很确定您的主要问题是您试图从另一个构造函数中调用默认构造函数。编辑:您对 LEDChannel() 的调用实际上构建了一个新的类实例,然后永远不会被使用或分配。 Arduino 默认使用的 C++ 标准版本不支持该功能,请参阅以下answer 了解更多信息(如果您使用的是支持它的标准)。这意味着 CurrentState 变量未初始化,并且在您观察时将是一些随机值。取消注释:

nNbLEDChannel = 1;

确实与错误没有任何关系,只是重新排列显然恰好将 CurrentState 变量设置为有效值的内存。

类似的功能,在构造函数中具有通用代码,可以通过将通用初始化代码从默认构造函数移到另一个类似这样的函数中来实现,然后由两个构造函数调用(不要忘记初始化所有将此函数中类的成员变量设置为默认值,然后在其后进行任何其他“特殊”初始化):

LEDChannel::LEDChannel(byte DigitalPIN, AquariumSimulator* pSim)
{
    // Initialize default values
    commonInitFunction();

    //Do other "special" initialization
    pAquariumSim = pSim;
    //pinMode(DigitalPIN, OUTPUT);// Configure Digital pin that control LED Channel
}

LEDChannel::LEDChannel()
{
    // Initialize default values
    commonInitFunction();

    //Do other "special" initialization
}

void LEDChannel::commonInitFunction()
{
    CurrentState = NoAction;
    //make sure all other member variables have been initialized to something either in here or
    //in your constructors to keep from having unexpected behavior
}

虽然在初始化器列表中初始化变量是个好主意,如 here 所述,这会将您的构造函数更改为以下(注意:我只是选择了一些随机默认值):

LEDChannel::LEDChannel(byte DigitalPIN, AquariumSimulator* pSim):
  MaxBrightness(255),
  lastTick(0),
  CurrentBrightness(0),
  CurrentState(NoAction),
  DigitalPin(DigitalPIN),
  ManualSunsetDuration(60),
  ManualSunriseDuration(60),
  pAquariumSim(pSim)
{
    //pinMode(DigitalPIN, OUTPUT);// Configure Digital pin that control LED Channel
}

LEDChannel::LEDChannel():
  MaxBrightness(255),
  lastTick(0),
  CurrentBrightness(0),
  CurrentState(NoAction),
  DigitalPin(0),
  ManualSunsetDuration(60),
  ManualSunriseDuration(60),
  pAquariumSim(NULL)
{
    CurrentState = NoAction;
}

这确保所有值都被初始化(包括以正确的顺序)以用于类的实例化。

顺便说一句,我确实注意到您提供的代码中的其他一些项目可能会导致您出现一些意外行为。

由于 CurrentBrightness 是一个字节(即 uint8_t),在您的 void LEDChannel::IncreaseCurrentBrightness(byte value) 方法中,您检查 CurrentBrightness + 值是否

第二个是你的枚举的 typedef 关键字没有做任何事情,因为你没有指定类型。在 C++ 中,如果您只想用您给它的原始名称引用它,则不需要 typedef 用于枚举或结构,就像您在此处所做的那样。看到一些答案here,尽管没有一个被接受,前几个是

【讨论】:

  • 实际上,将初始化放在构造函数之外的其他函数中,以防止在另一个构造函数中使用构造函数解决了我最小代码示例中的问题。但是,即使在我更正了代码之后,我的主项目仍然存在同样的问题。我会验证其他班级,看看我是否做了同样的事情。
  • 我做了一些其他的测试,发现我课堂上的 pSim* 没有初始化蓝牙。由于此指针用于访问 LEDChannel 对象以在 arduino 从蓝牙设备接收到命令时调用 StartManualSunrise(),因此它显示 CurrentState 变量的值无效。
  • 很高兴我能提供帮助。我敢打赌,既然您已经看到了一些错误,那么从现在开始捕捉这些类型的错误会更容易
  • 是的,下次会更容易。我的 C++ 程序员技能还差得很远。它提醒我要始终仔细检查变量初始化,不要总是试图将问题缩小到最小的部分。
【解决方案2】:

你保证不能在 setup() 之前调用 loop() 吗?

在指针数组之后立即设置值是问题的“根源”,这很可疑。这使我怀疑 pLED 值正在发生变化,或者您有其他索引问题导致 nNbLEDChannel 所在的内存被解释为 LEDChannel 对象。

【讨论】:

  • 我确认在 setup() 之前无法调用 loop() 我验证了 arduino main.cpp 文件并使用 vMicro 调试器对其进行了测试。 loop() 仅在 setup() 之后调用。但是,我怀疑索引问题也存在问题。我将继续我的测试。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-05-05
  • 2011-10-14
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多