How to program thresholds? [duplicate]

Hello guys (and gals)!

I'm trying to figure out how to program thresholds using my arduino board.

Essentially, to make this as simple as possible, this is what I have going on.

I am sampling a value every one second, I am taking the value and trying to make certain actions occur based on when this value crosses certain thresholds.

The value read every second will be a value between 0-150.

The thresholds will work something like this:

If value crosses over 20 and becomes 20 or higher, do an action.

If value crosses over 20 and becomes 19.9 or less, do a different action.

And then do the same for a threshold at 30, 40, 50, and 65.

I would need to have it so that if it reads a value of 15, and then a second later, reads a value of 23, it does an action. But if it reads 23, and then reads 24 a next, it needs to not do anything because it hasn't crossed over from one threshold to another. I only want an action to perform if a threshold is crossed either by increasing or decreasing past it.

So again, to reiterate;

If first value read is 34, and second is 42, do an action.

If first value is read at 57, and second at 44, do an action.

If first value is 24, and second value is 26, do nothing. (no threshold was crossed)

The next part would be figured out if a threshold was crossed twice, or more, to do that action twice or more times.

Any advice on how to code this?

• Store the previous value. May 14, 2015 at 1:17

I've gone ahead and decided to go with the following code. Its purpose is to turn vol up or down based on current car MPH. I choose to define brackets that cover a range of values. When one bracket ends, another begins. I've also set the previous bracket to current bracket at the end of each loop so that the application knows where it was previously, so that if it hops above or goes under a defined bracket, it does the desired action.

I've used a random generator to supply the MPH for testing purposes for now and commented out a few things that disturbed the testing process. If you'd like to critique this code to make is better, please let me know.

Note: I've also borrowed some of this code from another individual (Matthew McMillan, http://matthewcmcmillan.blogspot.com) who wanted to figure out how to convert a vehicle speed sensor wire info into MPH. I needed this code in order to make use of the vehicle's speed.

``````#include <SPI.h>
#include <Wire.h>

const int lightPin = 0;
const int hardwareCounterPin = 5;
const int samplePeriod = 1000; //in milliseconds
const float pulsesPerMile = 4000; // this is pulses per mile for Toyota. Other cars are different.
const float convertMph = pulsesPerMile/3600;
unsigned int count;
float mph;
unsigned int imph;
int roundedMph;
int previousMph;
int prevCount;

// Declare brackets
const int BracketA = 1;
const int BracketB = 2;
const int BracketC = 3;
const int BracketD = 4;
const int BracketE = 5;
const int BracketF = 6;

// Initialize Previous and Current Brackets
int PreviousBracket = 1;
int CurrentBracket = 1;

void setup(void) {
Serial.begin(9600);

TCCR1A = 0; //Configure hardware counter
TCNT1 = 0;  // Reset hardware counter to zero
}

void loop() {

/////////////////////////////////////////////////////////////
// This uses the hardware pulse counter on the Arduino.
// Currently it collects samples for one second.
//
bitSet(TCCR1B, CS12); // start counting pulses
bitSet(TCCR1B, CS11); // Clock on rising edge
delay(samplePeriod); // Allow pulse counter to collect for samplePeriod
TCCR1B = 0; // stop counting
count = TCNT1; // Store the hardware counter in a variable
TCNT1 = 0;     // Reset hardware counter to zero
mph = (count/convertMph)*10; // Convert pulse count into mph.
imph = (unsigned int) mph; // Cast to integer. 10x allows retaining 10th of mph resolution.

int x = imph / 10;
int y = imph % 10;

// Round to whole mile per hour
//if(y >= 5){
//  roundedMph = x + 1;
//}else{
//  roundedMph = x;
// }

//Code to write your own MPH for testing purposes.
//if (Serial.available() > 0) {
//}

//If mph is less than 1mph just show 0mph.
//Readings of 0.9mph or lower are some what erratic and can
//occasionally be triggered by electrical noise.
//if(x == 0){
//  roundedMph = 0;
// }

roundedMph = random(1,80);

// Don't display mph readings that are more than 50 mph higher than the
// Accelerating 50mph in one second is rocketship fast so it is probably
// not real.
if((roundedMph - previousMph) > 50){
roundedMph = previousMph;
}

//Place the gatherered MPH value into a bracket
//---------------------------------------------
if(roundedMph >= 0 && roundedMph < 20) {
CurrentBracket = BracketA;  //Value1
Serial.println("I Choose Bracket A");
}

if(roundedMph >= 20 && roundedMph < 30) {
CurrentBracket = BracketB;  //Value2
Serial.println("I Choose Bracket B");
}

if(roundedMph >= 30 && roundedMph < 40) {
CurrentBracket = BracketC;  //Value3
Serial.println("I Choose Bracket C");
}

if(roundedMph >= 40 && roundedMph < 50) {
CurrentBracket = BracketD;  //Value4
Serial.println("I Choose Bracket D");
}

if(roundedMph >= 50 && roundedMph < 65) {
CurrentBracket = BracketE;  //Value5
Serial.println("I Choose Bracket E");
}

if(roundedMph >= 65) {
CurrentBracket = BracketF;  //Value6
Serial.println("I Choose Bracket F");
}

//Decide if bracket stayed the same, went up, or down.
//---------------------------------------------------
if(CurrentBracket == PreviousBracket) {
//Do Nothing
Serial.println("Nothing Changed");
}

if(CurrentBracket > PreviousBracket) {
//Command for Vol Up
int VolUp;
VolUp = CurrentBracket - PreviousBracket;
Serial.println("Volume Went Up One by ");
Serial.println(VolUp);
delay(2000); // Delay to not change Vol to fast if near threshold
}

if(CurrentBracket < PreviousBracket) {
//Command for Vol Down
int VolDown;
VolDown = PreviousBracket - CurrentBracket;
Serial.println("Volume Went Down One by ");
Serial.println(VolDown);
delay(2000); // Delay to not change Vol to fast if near threshold
}
previousMph = roundedMph; // Set previousMph for use in next loop.
PreviousBracket = CurrentBracket; //Set PreviousBracket for use in next loop.
}
``````

The way you described it, the first and good solution I can approach it is state machine.

You have a lot of thresholds to check and very specific details such as going up at some level and doing something or nothing depending on the level.

What I advise you is creating the state machine for you code setting up all the thresholds and saving the actual state of your system into a variable. After you have this set up, coding is just a matter of switch/cases or if statements.

For example. The first part is to check if it goes until 20 and then keep with at least 20.

``````switch (state) {
case 1:
if (value >= 20 && value < 30)
state = 2;
break;
case 2:
if (value < 20)
state = 1;  // initial state
else if (value >= 20 && value < 30)
state = 3; // or call a function
break;
case 3:
doSomething();
break;
}
``````

And you could have some delay or timer interrupt to check the value each 1s and repeat the state machine again and again. If you change or read the value inside an interrupt function call, make sure you declare the variable as volatile otherwise the compiler will optimize it and your machine won't work properly.

This way you can expand the idea and have all the thresholds set up.

• That code is faulty – as it stands, once the state changes to 3, it stays at 3 no matter what value occurs. Also, when state is 1, a value of 30 or more doesn't get processed. So for example the sequence 15, 35, 15 results in no actions occurring. May 14, 2015 at 4:45
• Good point, @jwpat. Well, inside the function doSomething, there could be a verification and then decide which state to go in sequence. This code is just a start point where someone could develop their own code. The user has to make sure it checks every single situation to make sure it'll work properly. May 14, 2015 at 4:51
• It's always a good idea to add a Serial.print() and else/default to be notified via serial if any values go over/under your radar, especially as a beginner. Feb 21, 2016 at 9:05