Measuring time of my sensor level

Hello All!

I am trying to measure the time when the sensor level is above/below threshold, namely HT.

I have put the code together, but somehow I am stuck with using it within the main loop.

For example, if I use the if () to check the timings, I have a problem with the fact that timing of above HT is 0 when it starts running... Not sure how to go beyond this problem, except with the force, see the code below :slight_smile: I am printing out the values of the functions and it seems to be ok... Anyway, please have a look at the code, and let me know what do you think about it.

Here is my serial print out:

Sensor set!
TAHT: 0
TBHT: 909
TAHT: 73
TBHT: 1064
ledState: 1
TAHT: 57
TBHT: 1393
ledState: 0
TAHT: 91
TBHT: 851
ledState: 1
TAHT: 74
TBHT: 922
ledState: 0
TAHT: 98
TBHT: 631
ledState: 1

Best.

void loop()

  static unsigned long aboveHT;
  static unsigned long belowHT;

   aboveHT = timeAboveHT();
//forcing to start 
  if(aboveHT==0){
    aboveHT=50;
  }
  belowHT = timeBelowHT();

  Serial.print(" TAHT: "); Serial.println(aboveHT);
  Serial.print(" TBHT: "); Serial.println(belowHT);

  if (aboveHT > 20 && aboveHT < 100 && belowHT > 500) {
    ledState = !ledState;
    Serial.print("ledState: "); Serial.println(ledState);
  }

Function that gives me time in ms

// ok time above ht
unsigned long timeAboveHT() {
  
  //measure time while above HT
  if (Sensor.readProximity() > HT) {
    startTime = millis();
    elapsedTime = 0;
    //if (startTime > 150) {
    while (Sensor.readProximity() > HT) {
      currentTime = millis();
      elapsedTime = currentTime - startTime;
    }
    //return elapsedTime;
  }
  //Serial.print("t A HT: "); Serial.println(elapsedTime);
  return elapsedTime;
}

// ok time below ht
// you can define the lenght of the  time to close the window, namely room
unsigned long timeBelowHT() {

  //measure time while below HT
  if (Sensor.readProximity() < HT) {
    elapsedTime = 0;
    startTime = millis();
    while (Sensor.readProximity() < HT) {
      currentTime = millis();
      elapsedTime = currentTime - startTime;
    }
     
  }
  return elapsedTime;
}

I would like to see the whole code and i am a tad unclear on what is your exact question.

You need a better state machine. Record timing only When status changes

Say you start below HT, make a note of current millis() and note your current state is “below” and do other stuff until you go above HT. At that point take millis() and subtract from Frist value, add that to belowHT.

Now that millis() is the start time of above, so make a note that what you want to check now is going below. When it happens take millis() and subtract from start time, add that to aboveHT.

Now that millis() is the start time of below, so make a note that what you want to check now is going above again. When it happens take millis() and subtract from start time, add that to belowHT.

Rinse and repeat
Would look something like this (typed here, so fully untested)

// insert code to define Sensor
#include <XXXX.h>
XXXX Sensor;

enum : byte {WAITING_ABOVE, WAITING_BELOW} currentState;
unsigned long aboveHT =0;
unsigned long belowHT = 0;
unsigned long startTime;
const int HT = 22; // whatever type is appropriate 

void setup()
{
  // initialize Sensor
  ...

  if (Sensor.readProximity() > HT)
    currentState = WAITING_BELOW;
  else 
    currentState = WAITING_ABOVE;
  startTime = millis();
}

void loop()
{
  int p = Sensor.readProximity(); // or whatever is the right type for this
  unsigned long currentTime = millis();

  switch (currentState) {
    case WAITING_ABOVE:
      if (p > HT) {
        belowHT += currentTime - startTime;
        startTime = currentTime;
        currentState = WAITING_BELOW;
      }
    break;
    case WAITING_BELOW:
      if (p < HT) {
        aboveHT += currentTime - startTime;
        startTime = currentTime;
        currentState = WAITING_ABOVE;
      }
    break;
  }
   
  // do other stuff if not too long

}

Hello!

Thank you for your idea about a better state machine, indeed, it works much better now, the only think I had to do is to "reset to 0" the belowHT and aboveHT, like this:

main loop:

  OS = Sensor.readProximity();
  
  unsigned long currentTime = millis();

  switch (currentState) {
    case WAITING_ABOVE:
      if (OS > HT) {
        belowHT=0;
        belowHT += currentTime - startTime;
        Serial.println("");
        Serial.print("b HT :  "); 
        Serial.println(belowHT);
        startTime = currentTime;
        currentState = WAITING_BELOW;
      }
      break;
    case WAITING_BELOW:
      if (OS < HT) {
        aboveHT=0;
        aboveHT += currentTime - startTime;
        Serial.println("");
        Serial.print("a HT :  ");
        Serial.println(aboveHT);
        startTime = currentTime;
        currentState = WAITING_ABOVE;
      }
      break;
  }

I am now adding the decision part, which will be based on if(), btw I guess the switch is good as ifs in terms of memory and speed... anyway, will get back, if I will run into problems, btw, when dealing with two bools the ifs are not that complicated, but when dealing with three of them, I am wondering... have never tried that yet, so is there a different way to handle three bools?

Best.

Boolean logic with if will do just fine. Just make sure to write the tests correctly and don’t leave out possibilities of interests (with 3 boolean you have 8 possible cases)

Cheers again J-M-L for your input,

this is my "interface" for following the sensor threshold dynamics :

  if ( (aboveHT > 5 && aboveHT < 150) && (belowHT > 5 && belowHT > 500) ) {

    aboveHT = 0;
    belowHT = 0;

    ledState = !ledState;
    return;
  }
  //brightness 100%
  else if ( (aboveHT > 5 && aboveHT < 150) && (belowHT > 5 && belowHT < 500) ) {

    aboveHT = 0;
    belowHT = 0;

    ledState1 = true;
    return;
  }

With the following "decision" code works ...

  // 1) Led ON 50% (1-0-0)
  if (ledState && !ledState1 && !fading) {
    brightness = 50;
    fadeIn();
    return;
  }
  // 2) Led OFF    (0-0-0)
  else if (!ledState && !ledState1 && !fading) {
    brightness = 0;
    fadeOut();
    ledState = false;
    return;
  }
  // 3) led ON 100% (1-1-0)
  else if (ledState && ledState1 && !fading) {
    brightness = 255;
    fadeIn();
    return;
  }
  // 4) Led OFF    (0-1-0)
  else if (!ledState && ledState1 && !fading) {
    brightness = 0;
    fadeOut();
    ledState1 = false;
    return;
  }

However, as can be seen from the above threshold dynamics code, after 500ms I cannot change the ledState1, which is exactly what I want, but I am not really sure how can I signal that with a e.g. led on pin x? For example that would help me to know when the time has elapsed... because, if I interrupt the below HT before that time, I have to wait again?

Anyway, what do you think? Is this the right way to approach this? What if() may I be missing for basic operation of on and off? BTW the fading coms in mins.

Any ideas?

Best.

On your first comment, indeed if you don’t want to sum times below and above, no need to go to zero just change the += into =

aboveHT=0;
        aboveHT += currentTime - startTime;

becomes just        aboveHT = currentTime - startTime;for example

Instead of posting buts of code which I don’t know where they fit, explain the logic in plain English and explain when this needs to happen

Note that(belowHT > 5 && belowHT > 500)is a bit overkill, if you are greater than 500 then you are greater than 5, so the first test is not needed

This is definitely over kill :slight_smile:

(belowHT > 5 && belowHT > 500)

In this case, the main idea is to catch the proximity values that are above HT between 5 and 500ms, but I am not sure, if I need the 5. This was meant as a safety. I am doing the same with the aboveHT, for example. The point is in the "window time", e.g. above and below.

// brightness 50 / off
  if ( (aboveHT > 5 && aboveHT < 100) && belowHT > 500 ) {
    ledState = !ledState;
    aboveHT = 0;
    belowHT = 0;
    return;
  }
//brightness 100
  if ( (aboveHT > 5 && aboveHT < 100) && (belowHT > 5 && belowHT < 350) ) { 
    ledState1 = true;
    aboveHT = 0;
    belowHT = 0;
    return;
  }

Due to the fact that this is rather fast in the main loop, I am considering the debounce, something like ...

            //debouncer
            if (ledState != lastButtonState) {
              //reset the debouncing timer
              lastDebounceTime = millis();
            }
            if ((millis() - lastDebounceTime) > debounceDelay) {
              if (ledState != buttonState) {
                buttonState = ledState;
    
                if (buttonState == HIGH) {
                  ledState = !ledState;
                }
              }
            }
            lastButtonState = ledState;

However, I am not sure whether I need one in this case...

I also want to add the fading... So far I am using the fading after checking for aboveHT and belowHT. The structure is as follows:

  1. start
  2. check the Above and Below
  3. fade(while above longer than 1sec)
  4. make a decision with ifs
  5. go (back) to start

here is the code of fading!

//    myFading function with time!
//    check if we are above HT
    if (Sensor.readProximity() > HT ) {
  
      // depending on brightness level decide, if you want to fadeUp or not
      // if you are above 126 ...
      if (brightness > 126) {
        fadeUp = true;
      }
      // if you are below 126...
      else if (brightness < 126) {
        fadeUp = false;
      }
      //anyway, invert the decision...
      else {
        fadeUp = !fadeUp;
      }
      fadeUp = !fadeUp;
  
      //start measuring time
      elapsedTime = 0;
      startTime = millis();
      //measure the time while we are above HT
      while (Sensor.readProximity() > HT) {
        currentTime = millis();
        elapsedTime = currentTime - startTime;
        //if above 750, start fading
        if (elapsedTime > 750) {
          myFading();
          //due to the decision ifs...
          fading = true;
          ledState = true;
        }
      }
    }

But, something is not ok! For example, if I run the code, just the above two ifs()

// brightness 50% / off
if ( (aboveHT > 5 && aboveHT < 100) && belowHT > 500 ) {
ledState = !ledState;
aboveHT = 0;
belowHT = 0;
return;
}
//brightness 100%
if ( (aboveHT > 5 && aboveHT < 100) && (belowHT > 5 && belowHT < 350) ) {
ledState1 = true;
aboveHT = 0;
belowHT = 0;
return;
}

without the fade function, works ok for basic stuff :confused: interestingly, it also works with the fading function, but not all the time, not stable and slow, sometimes it evens drops the right timing :confused:

Hello guys!

After some time, I had to go back to the beginning... in general, the code I have posted is ok, however, I am wondering, if and how can I put the code, which is in setup:

if (Sensor.readProximity() > HT) {
    currentState = WAITING_BELOW;
  }
  else {
    currentState = WAITING_ABOVE;
  }

into the main loop?

Actually, why is this piece of code in setup?

Best.

Actually, why is this piece of code in setup?

this is because when you start your arduino you don't know in which state you are. This lets you starts with the right state and track transitions (state change) in the loop

Thank you! Is there a way to have this code to run within the main loop? Actually, it is sure that the level will be below the HT once the program is started... so I have changed to " currentState = WAITING_ABOVE; ", is that ok?

best.

I'm not sure I understand why you want this in the main loop... it serves no purpose. I gave you the code that needs to be in the main loop in post #2. that's the one dealing with state changes.

This is all good and thank you for that, but when I put Arduino to sleep then it wakes up back in the main loop, which means that whatever happened in the setup is not really useful, right? Anyway, now I am using the currentState = WAITING_ABOVE; I will tell you another reason, when I read data from the sensor, so fast, as in setup, for example, then I can tell you the sensor needs some time (eg. ms) to stabilise its reading, but that is another story... anyway, so far it works with "hard encoded beginning" which is going to be always below HT, at least till the main loops starts :), right?

Best.

you never mentioned sleeping...

So when you wake up indeed you need to do the same thing as in the setup to ensure you start from the right state.... --> code to be added after the wake up

yeah sorry for the sleeping :slight_smile: I have only woke up, thanks anyway, will keep you updated, best.

According to your suggestion in #13, would you say, this is the right way to use the interrupt then?

//interrupt
ISR (PCINT0_vect)
{
// we are using interrupt to wake up the uC

sleep_disable();

power_all_enable(); // power everything back on

//////////////////////////////// WHAT DO YOU WANT WHEN THE DEVICE IS WOKE UP ?!

// turn LED on 50% ?
ledState = true;
ledState1 = false;
fading = false;
currentState = WAITING_BELOW;

}

best.

yes if this is the right state when you wake up then  currentState = WAITING_BELOW;is OK. otherwise do as in the setup() - double check where you really are

So far so good!

I am moving toward WDT, but I have already spotted the problem, actually, how can I make a fading function without "stoping" or rather delaying the main loop for the time of fading?

For example, while I am fading then the main loop "stops", and if I am delaying for more than few seconds, which is normal, then my WDT will not be reseted and this will reset the program during fading. This is what I do not want.

Anyway, I want to reset the WDT at the end of the main loop, which signals that the code got to there OK! Otherwise the WDT should after some time (2 sec) reset the whole program and reboot.

Below I am attaching the fading function that I am running within the main loop, I have also bolded where I am also planing to put the WDT reset.

What do you think? Any thoughts?

Best.

  //    myFading function with time!

  if (OS > HT) {
    //    //define fade and make rotation
    fadeUp = fadeRotation();
    //start measuring time
    elapsedTime = 0;
    startTime = millis();
    //measure time while we are above HT
    while (Sensor.readProximity() > HT) {
      currentTime = millis();
      elapsedTime = currentTime - startTime;

    
      // --->  WDT reset here. ??? <--- ///

      if (elapsedTime > 1000) {
        //fading
        myFading();
        fading = true;
        ledState = true;

      }
    }
  }

Otherwise the WDT should after some time (2 sec) reset the whole program and reboot

Why would you have to do this... Just write good code...

Your fader should be handled as a state and not block the loop, just have steps performed as the loop() loops.

Indeed, that would be wonderful, to write perfect code, but my code is not perfect. In addition, peripheral hardware may have the same problem, anyway, how would you tackle my fading fuction, namely fader to not block the main loop? Can you give me an example?

Ihave nust realized that myFading fuction is not blocking the main loop, actually it "waits" for the elapsedTime to be over 1000ms, anyway, I guess I need to bring the brightness++ and --idea into the main loop...

Best.