Hey there guys. First post in a long time.
I find myself developing once again on an MSP430G2553 chip on a Rev 1.4 Launchpad and I am trying to take samples from the on-chip ADCs using Energia.
It's not secret that the on-chip ADCs are quite unstable (very accurate perhaps?), I don't get anywhere near the kind of jitter I see when using the MCP3008 (10-bit, 8-channel ADC converter IC). Regardless, I am very frustrated with the section of my code that deals with smoothing the signal from analog controls.
I am sampling 4 ADC values and averaging it, no problem.
What really frustrates me is that when I try to check if the new value is within a certain sensitivity (range) of the last recorded value, I have to do a strange work-around or else I get constant resends as if I'm not even checking if the value is in the certain range.
In other words, I cannot use the compare operators greater than, less than, greater than/equal to, and less than/equal to, in order to check if the new ADC value is within a certain range of the old recorded value.
To illustrate this, I will include the code I use to do this and show you what I would like to do (which doesn't work) and what I do currently (which still results in some glitches)
Just for reference, this is what the Control class looks like:
class Control
{
public:
//Identification information
int pin; //Sets the pin to be used by the control
int ID; //Identification number (0-31)
//Data processing variables
int value; //Stores the current value
int oldValue; //Stores the old value (for preventing constant resends)
int counter; //Counter used for averaging
int average; //Value use for calculating average
int sensitivity; //Value used for setting sensitivity (a variable in smoothing algorithm) @todo
//Constructor
Control(int nID, int nPin, int nSensitivity);
//Methods
int Read(void); //Reads the value of the control
boolean isNew(void); //Returns true if the value has updated (within a reasonable range, the sensitivity)
void Send(void); //Transmits the control change to the computer for processing
};
And this is what the Control.Read() function does (it includes the average code)
int Control::Read(void)
{
int pinVal = analogRead(pin);
if(pinVal == 1023 || pinVal == 0) //it is max/min
{
return pinVal; //I do this so that mins/maxs can be sent anyway. It's important that absolute mins/maxs are sent.
}
if(counter != 3) //Averaging counter that's stored on the class
{
average += analogRead(pin);
counter++; //Increment Counter
return 1025; //Not ready value (outside ADC range)
}
else
{
average /= 4; //Divide by 4 to average
counter = 0; //Reset counter
return average;
}
}
}
Code that I would like to use:
boolean Control::isNew(void)
{
value = Read(); //Set value of control
if(value == 1025) //Not ready
return false;
//First check for maxs/mins (to prevent resending)
if(value == 1023 || value == 0) //it is max/min
{
if(value != oldValue) //max/min was not sent already
{
oldValue = value;
return true;
}
}
//Check if its within sensitivity setting
if(value >= (oldValue-sensitivity) || value <= (oldValue+sensitivity)) //This does nothing to smooth input (constantly returns true, even when it shouldn't)
return false; //Still within sensitivity, report false
else
{
oldValue = value; //It's changed more than the sensitivity, update values and report true
return true;
}
}
return false; //If it hasn't returned true by now, return false
}
Code that I use right now...
boolean Control::isNew(void)
{
value = Read(); //Set value of control
if(value == 1025) //Not ready
return false;
//First check for maxs/mins (to prevent resending)
if(value == 1023 || value == 0) //it is max/min
{
if(value != oldValue) //max/min was not sent already
{
oldValue = value;
return true;
}
}
boolean within5 = false; //Please ignore the irrelevant name of this variable
int checkVal = 0;
//Then check if it's within 15 of previous value
for(int i=0;i<15;i++)
{
checkVal = value + i;
if(checkVal == oldValue)
{
within5 = true;
break;
}
checkVal = value - i;
if(checkVal == oldValue)
{
within5 = true;
break;
}
}
if(!within5) //Not within 15
{
oldValue = value;
return true;
}
return false; //If it hasn't returned true by now, return false
}
The main loop does something like this:
if(control_1.isNew())
{
control_1.Send(); //Simply prints the value to the serial line
}
Similarly, I have tried to see if the new ADC value is above a certain threshhold as to count it as a maximum value. Above a certain value (like 1015) the sensitivity check becomes erratic, it sends new values even if they're within (for example) 2 of the last value.
The code I used was:
if(value > 1015) //If it's above a certain threshhold value = 1023; //Count it as a maximum
The kind of output I would get is still like:
1020 1022 1018 1023 1023 1020
The sensitivity is normally set to within 10-20 for the on-board ADC. For controls connected to the MCP3008, the sensitivity is about 5, it is as stable as a rock.
What is going on? Why can't I compare these values? Is it related to the type of variable I store the value in? I have tried changing the related variables to unsigned integers and it has no effect.
It has had me pulling my hair out. I hate inefficient code on MCUs and using for loops simply to check if a value lies within some range seems pretty inefficient to me.
I'll post the finished project when I'm done.
Thanks guys!