Arduino - Enum variable value change by itself - c++

I created an Arduino mega sketch to control LEDs channel to simulate simple sunset and sunrize. In my class LEDChannel declaration, i have an public enum to represent the state of the LED Channel and i have a private instance (CurrentState) of State enum in the class to keep track of this LEDChannel instance.
Everything compile well and is uploaded to my Arduino Mega. The problem is when i debug my code and check the value of CurrentState variable i get a value outside of enum range. Sometime i get value 7579 (actual value in my last test). Another day i can get a value of 612. The value should only be 0 to 4. I verified my code and any place i change the value of this variable, i use the enum. By example :
CurrentState = ManualSunset;
CurrentState variable receive the value NoAction in the default constructor of LEDChannel Class.
The class LEDChannel is part of a bigger project to make an Aquarium controller with other class to represent RTC time module, Bluetooth module, Fan and temperature sensor.
I developed my project with Visual Studio Community 2015 with vMicro plugin for Arduino. If you need the complete project, i will find a way to make it available.
Here is the LEDChannel Declaration/definition and main Arduino program .ino. This is a light version of my code. I removed all unnecessary code. To reproduce the problem, just comment line 13 in main program nNbLEDChannel = 1;. You should then get value ManualSunrise (3) for variable CurrentState. Take not that nNbLEDChannel is only used in main .ino file.
#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);
};
Here is the 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;
}
}
And main program .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();
}

I didn't get out my Arduino UNO board, but I am pretty sure your main problem is the fact that you are trying to call the default constructor from within another constructor. Edit: The call to LEDChannel() you did actually constructed a new instance of the class which then never gets used or assigned. The version of the C++ standard being used by default by Arduino doesn't support that feature, see the following answer for more information (It also demonstraits the correct syntax for calling a constructor from another constructor if you are using a version of the standard which supports it). This means that the CurrentState variable is uninitialized and will be some random value as you are observing. Uncommenting out the line:
nNbLEDChannel = 1;
really doesn't have anything to do with the error and just rearranges the memory which apparently happens to put the CurrentState variable to a valid value.
Similar functionality, having common code within a constructor, can be achieved by moving your common initialization code out of the default constructor and into another function like this, which is then called by both constructors (don't forget to initialize all of the member variables of the class in this function to a default value and then do any other "special" initialization after it):
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
}
Although it is a good idea to initialize variables in an initializer list, as stated here, which would then change your constructors to be the following (Note: I just picked some random default values):
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;
}
This ensures all values are initialized (including in the proper order) for the instantiation of the class.
On a side note, I did notice a few other items in the code you provided which might cause you some unexpected behavior.
Since CurrentBrightness is a byte (i.e. uint8_t), in your void LEDChannel::IncreaseCurrentBrightness(byte value) method, your check to see if the CurrentBrightness + value is <= 255. This will only ever be false if the sum is equal to 255 because of overflow. Basically, if the CurrentBrightness is 250 and I add the value of 10 to it then I will get a value of 4 if I am not mistaken. This is probably not the desired behavior of this check.
The second is that the typedef keyword for your enum is not doing anything since you didn't specify a type. In C++, you don't need the typedef for an enumeration or struct if you only want to refer to it by the original name you gave it, like you did here. See some of the answers here, even though none of them were accepted the first few are

Have you guaranteed that loop() cannot be called before setup() ?
It is suspicious that setting a value immediately after your pointer array is the "source" of the problem. This leads me to suspect that either the pLED value is getting changed or you have some other indexing problem that is causing the memory where nNbLEDChannel resides to be interpreted as a LEDChannel object.

Related

Storing value in 2d array variable during runtime in c++

My main code is .ino file for STM32F103C8T6 with STM32 official core. I have also included my library files of .h file and .cpp file.
I want store a values in 2d array called uint32_t Page[15][14]; in .h file of my library
How to store a value in 2d array variable during runtime. I have posted my code below. For me the code below is perfect, but still did not print the value stored in the array by calling the function HatriX_Signal with correct parameters. Kindly let me know what is wrong in my code below.
// .ino file
#include "HATRIX.h"
HATRIX Hatrix;
void setup()
{
Hatrix.HATRIX_INIT(115200);
}
void loop()
{
Hatrix.HatriX_Signal(Temperature_Signal, 0x66, Page[2][0]);
Serial.println(Page[2][0]);
Serial.println((float)Page[2][0] / 100);
}
// .h file
#ifndef HATRIX_H
#define HATRIX_H
#include "Arduino.h"
#include "Thermo_Couple_Input.h"
#define Number_of_Pages 15
#define Number_of_Bytes_Per_Page 64
static Thermo_Couple_Input TC_IN;
static uint32_t Page[Number_of_Pages][(Number_of_Bytes_Per_Page / 4) - 2];
enum Signal { Temperature_Signal,
Pressure_Signal,
Co2_Signal,
Analog_Industrial_Input_Signal,
General_Purpose_Output_Signal,
PWM_Power_Signal,
PWM_Voltage_Signal
};
class HATRIX
{
public:
void HATRIX_INIT(uint32_t bauderate);
void HatriX_Signal(uint8_t Signal, uint8_t I2C_Address, uint32_t Page);
};
#endif
// .cpp file
#include "HATRIX.h"
void HATRIX::HATRIX_INIT(uint32_t bauderate)
{
Serial.begin(bauderate);
}
// \brief Note: The value we get from Thermocouple is float value. So, we multiply the value with 100 and store it in specified static uint32_t Page by user.
// \param enum_Signal choose accordingly from enum signal: { Temperature_Signal ,
// Pressure_Signal ,
// Hatrix.Co2_Signal ,
// Analog_Industrial_Input_Signal ,
// General_Purpose_Output_Signal ,
// PWM_Power_Signal ,
// PWM_Voltage_Signal };
// \param I2C_Address Address of I2C to get the temperature from desired Thermocouple.
// \param Page Give the Page details to store your value. example: Hatrix.Page[4][3]
void HATRIX::HatriX_Signal(uint8_t signal, uint8_t I2C_Address, uint32_t Page)
{
if(signal == Temperature_Signal);
{
TC_IN.Thermo_Couple_Input_Channel(I2C_Address);
Serial.println("Page");
Page = fThermocoupleTemperature * 100;
Serial.println(Page);
}
}
When calling HATRIX::HatriX_Signal(...), you pass a copy of a uint32_t of the multidimensional array Hatrix.Page to the function.
Inside the HATRIX::HatriX_Signal(...) function, you assign a new value to this variable called Page. But since it's just a copy of the value from the array, the array itself won't be effected by this.
In order to get the value of the function you can either use a pointer to the value in the array or a reference to the value in the array, preferably, return the value directly.
Your function could either look like this using a pointer:
void HATRIX::HatriX_Signal(uint8_t signal, uint8_t I2C_Address, uint32_t* Page)
{
if(signal == Temperature_Signal);
{
TC_IN.Thermo_Couple_Input_Channel(I2C_Address);
TC_IN.fThermocoupleTemperature = TC_IN.fThermocoupleTemperature * 100;
Serial.println("Page");
*Page = TC_IN.fThermocoupleTemperature;
Serial.println(*Page);
}
}
and called like:
Hatrix.HatriX_Signal(Hatrix.Temperature_Signal, 0x66, &Hatrix.Page[2][0]);
or look like this using a reference:
void HATRIX::HatriX_Signal(uint8_t signal, uint8_t I2C_Address, uint32_t& Page)
{
if(signal == Temperature_Signal);
{
TC_IN.Thermo_Couple_Input_Channel(I2C_Address);
TC_IN.fThermocoupleTemperature = TC_IN.fThermocoupleTemperature * 100;
Serial.println("Page");
Page = TC_IN.fThermocoupleTemperature;
Serial.println(Page);
}
}
and called like:
Hatrix.HatriX_Signal(Hatrix.Temperature_Signal, 0x66, Hatrix.Page[2][0]);
or alternatively, as I would advice, look like this:
uint32_t HATRIX::HatriX_Signal(uint8_t signal, uint8_t I2C_Address)
{
if(signal == Temperature_Signal);
{
TC_IN.Thermo_Couple_Input_Channel(I2C_Address);
TC_IN.fThermocoupleTemperature = TC_IN.fThermocoupleTemperature * 100;
Serial.println("Page");
uint32_t page = TC_IN.fThermocoupleTemperature;
Serial.println(page);
return page;
}
}
and called like:
Hatrix.Page[2][0] = Hatrix.HatriX_Signal(Hatrix.Temperature_Signal, 0x66);
How to fix this program:
Raw data such as this 2D array should be made private, as per the fundamental OO principle of private encapsulation.
Should you wish the user to access this array it should be done through a "setter" function taking (x,y) coordinates.
Provide a similar "getter" function for read/print access.
HatriX_Signal and similar should not pass along a pointer to data in a class member, because that's nonsense. You already have access to that data through the this pointer.
Generally, I'd advise to read a beginner-level book about C++ and OO, or alternatively ditch C++ completely if you have no intention of using OO program design anyhow.

Pointer gives abnormal values after deferencing

I am trying to replicate a big C++ library. It has the following structure of code
RobotRunner.h
class RobotRunner
{
public:
VectorNavData* vectorNavData;
};
RobotRunner.cpp
void RobotRunner::run()
{
printf("Quaternion[0]: %f \n", vectorNavData->quat[0]); //Output: 243235653487854 - Abnormal values
}
SimulationBridge.h
class SimulationBridge
{
private:
VectorNavData _vectorNavData; // Actual value of vectornavdata from the robot is stored here
RobotRunner* _robotRunner = nullptr; //Pointer to the RobotRunner Object
}
SimulationBridge.cpp
void SimulationBridge::init()
{
_robotRunner = new RobotRunner();
printf("Quaternion[0]: %f \n", _vectorNavData.quat[0]); // Output: 0.43 - Normal and expected
_robotRunner->vectorNavData = &_vectorNavData;
}
void SimulationBridge::run()
{
_robotRunner->run();
}
//This function runs continuously and updates the _vectorNavData in a separate thread
void SimulationBridge::readIMU()
{
while(true)
{
//_lowState stores the values of different robot parameters at a given time
_vectorNavData.accelerometer[0] = _lowState.imu.accelerometer[0];
_vectorNavData.accelerometer[1] = _lowState.imu.accelerometer[1];
_vectorNavData.accelerometer[2] = _lowState.imu.accelerometer[2];
_vectorNavData.quat[0] = _lowState.imu.quaternion[1];
_vectorNavData.quat[1] = _lowState.imu.quaternion[2];
_vectorNavData.quat[2] = _lowState.imu.quaternion[3];
_vectorNavData.quat[3] = _lowState.imu.quaternion[0];
_vectorNavData.gyro[0] = _lowState.imu.gyroscope[0];
_vectorNavData.gyro[1] = _lowState.imu.gyroscope[1];
_vectorNavData.gyro[2] = _lowState.imu.gyroscope[2];
}
}
VectorNavData is a struct which stores the details about the orientation of the robot. It has the following definition
struct VectorNavData {
Vec3<float> accelerometer;
Vec3<float> gyro;
Quat<float> quat;
};
I have included only the necessary part of the code here for brevity.
Code Explanation:
SimulationBridge class communicates with the robot in the simulation. It takes in vectorNavData and stores it in the member variable _vectorNavData. SimulationBridge also contains the pointer to the RobotRunner class as one of it's member. I am allocating the address of _vectorNavData object to the pointer _robotRunner->vectorNavData (check SimulationBridge.cpp). Inside the RobotRunner class I deference this pointer and use the values in other parts of the code.
Problem:
If I print the vectorNavData inside the SimulationBridge.cpp the values seems to be normal. But after assigning the pointer of the same object to the robot runner, if I print the values there the values seems to be abnormally high. My question is, is this way of using pointers for dynamic allocation recommended? If not what is the best alternative way I can use?
Another important point to note is, I am compiling the code with CMake and "-O3" optimization flag is set to the CMAKE_CXX_FLAGS. If I remove this flag, the code sorta works fine for the above object pointer but I am still getting similar error for another object pointer in another part of the code. I have not included that here because it's pretty complex to describe the code structure and the problem essentially is the same.

I cannot get an MBED ticker within a class to call a member method

I wrote the following MBED-based C++ program as an experiment for a more detailed project I am working on for my Nucleoboard Microcontroller:
#include "mbed.h"
DigitalOut greenLed(PA_5);
#include "mbed.h"
class TimedLED
{
public:
TimedLED()
{
Ticker t;
t.attach_us(this, &TimedLED::flip, 1000000);
}
void flip(void)
{
static int count = 0;
greenLed.write(count%2); //-- toggle greenLed
count++;
}
};
int main()
{
TimedLED flash;
while (1);
}
All the references I looked at seemed to indicate that t.attach_us(this, &TimedLED::flip, 1000000) should call the method, 'flip' every second and so cause the LED to toggle on and off. This is not happening, however. I cannot see what the problem is. I hope someone can help me clear this up.
I am getting the following warning message indicating that this format is deprecated, but the link to the documentation was broken, so I couldn't get more details:
Function "mbed::Ticker::attach_us(T *, M, us_timestamp_t) [with T=TimedLED, M=void(TimedLED::*)()]" (declared at /extras/mbed_fd96258d940d/drivers/Ticker.h:122) was declared "deprecated" "t.attach_us(this, &TimedLED::flip, 1000000);"
Even if it is deprecated, it still should work, shouldn't it? Also, presumably if the deprecation message is correct, there is a newer way to do the same thing. I can't find reference to an alternative method though anywhere.
You declare Ticker t; in your constructor on the stack, when the constructor exits it will clear the object, and thus the code will not run.
Declare the variable in your class, and it'll run as expected:
class TimedLED
{
public:
TimedLED()
{
t.attach(callback(this, &TimedLED::flip), 1.0f);
}
void flip(void)
{
static int count = 0;
greenLed.write(count%2); //-- toggle greenLed
count++;
}
private:
Ticker t;
};
Also note the change in the constructor, this is the prefered (non-deprecated) way to attach callbacks in mbed OS 5.

Arduino variable usage

I'm a newbie when it comes to Arduino and C++.
I'm trying to write a program that reads the input data from analog pin zero (a POT).
after the value is read I want it to print to the serial monitor, but only once. if the value of from analog pin zero changes I want it to print the new value to the serial monitor. I'm trying to use global variables, but to no avail. any help would be greatly appreciated!
int entered=0;
int flag;
void setup()
{
Serial.begin(9600);
}
void loop() {
int potValue=analogRead(A0);
if (!entered){
entered=1;
Serial.println(potValue);
}
int flag=potValue;
if (flag!=flag){
entered=0;
}
}
That is really close. This line is your mistake
int flag=potValue;
As written, that creates a new local variable flag. The local variable hides the global variable. So the comparison is always to itself and never fails. Change the line to :
flag=potValue;
and your program will function as desired.
You can save some memory and code space like this:
int g_lastValue = 0;
void loop() {
int nowValue = analogRead(A0);
if (nowValue != g_lastValue) {
Serial.println(nowValue);
g_lastValue = nowValue;
}
...
}
The use of g_ as name prefix is a cue that a variable is global. I use this naming convention as it helps when reading a function to know variables that are not local. Without a name cue, you need to scan the entire function body to see if there is a variable declaration present, and only by looking through the function and not finding a declaration can you know the variable must be global. On small functions, not really an issue, but as your code grows, you may want some self documentation a naming convention provides.
You're on your way but you are getting tangled a bit in variables.
It can be simpler: just one global variable and one conditional check.
int lastRead = -1; // init to value outside of possible range
void setup()
{
Serial.begin(9600);
}
void loop() {
// get current value
int currentRead = analogRead(0);
//compare and only print if !=
if (currentRead != lastRead){
lastRead = currentRead; // store
Serial.println(lastRead);
}
}

Visual Studio Compiler is highlighting Static variables differently?

I'm programming in C++ and have a method which uses a static variable. The method isn't working as I think it should; upon investigation, I found that my static variable is being highlighted in red in two places and blue in other places. Below is the code:
int GameModeState::changeJob(int number)
{
static int job = 1; //red
if (number == 1)
{
job = (job+1); //First one is red, second one is blue
return job; //blue
} else {
return job; //blue
}
}
I'm calling this method with other methods, one shown for example:
int GameModeState::getJob()
{
int currentJob = (changeJob(2));
return currentJob;
}
I want a method like getJob() to simply return the current value of job, while another method, when calling changeJob(number) is changeJob(1), to increment job's value by one. (Hence the if/else statement in changeJob(number)).
Since the job variables are highlighted differently, I'm thinking the compiler is saying that it views the two separately somehow? I'm getting stuck with job being some even value.
EDIT I also have Awesomium... I believe that is the only addition to the compiler, but I'm not completely sure.
MOAR EDIT In another class, I have a method which should determine the current job's number and do something based on if the number is even or odd (since right now there are only two jobs)
void ZoneMovementState::_changeZone(const String& message, const Awesomium::JSValue& input, Awesomium::JSValue& output)
{
//Awesomium::JSValue::Object object = input.getObject();
//String zoneFilename = Convert::toString(object[L"zoneFilename"].toString());
// If the number from getJob is even, the player is currently a geologist
if (GameModeState::getJob()%2 == 0)
{
ZoneParser::getSingleton().load("../media/zones/geology_zone.xml", false);
} else {
ZoneParser::getSingleton().load("../media/zones/farm_zone.xml", false);
}
transitionHandler->go();
}
Ignore the two commented out lines; they deal with JS, which I'm not working on for now.
In the program, I can access the farm_zone until I increment job's value using the below method in GameModeState:
void GameModeState::_openNotebook(const String& message, const Awesomium::JSValue& input, Awesomium::JSValue& output)
{
mNotebookTransition->go();
static int currentJob = changeJob(1);
}
.... So I figured out my problem. While going through the code to show you guys, I realized that the static for currentJob was probably unneeded... once I removed it, my code works as it should now.
Thanks for the help guys!
Part of the problem here is you're using a static local for what very likely should just be a member variable. A static local maintains it's value across all calls to a function in all threads in a process. It's much more likely that you want it to persist for all calls to changeJob in a particular GameModeState instance (else why make it a member functon to begin with?).
To do this you'll need to define a member variable on GameModeState initialize it in the constructor and then access it in the method. For example
class GameModeState {
int job;
GameModeState() : job(1) {}
int changeJob(int number);
};
int GameModeState::changeJob(int number) {
if (number == 1) {
job = (job+1);
return job;
} else {
return job;
}
}
Note: I'm not entirely sure why you're seeing the color's your are seeing. Visual Studio by default won't color member variables a particular color in C++ so it's very likely another add-in you are using.
Nah, highlighting doesn't mean anything. That is, the editor doesn't call the compiler before deciding how/what/when to highlight. So that is not your problem. Sorry 'bout that :-)
You can prove this to yourself by going to Tools->Options->TextEditor and noticing that you can change the highlighting by choosing a different text-editing model.