[Solved] Time elapsed since event triggered

I am having some trouble with measuring the amount of time that has passed since a certain event has occurred. I thought I understood how to use the millis() function to measure elapsed time, but clearly I do not.

I am trying to measure the amount of time that has passed since the voltage value from a strain gauge is greater than the “ActivationVoltage” (which is determined using a potentiometer). If this elapsed time is greater than the specified interval value, then I want another event to occur.

Please look at my code below and let me know what I am doing wrong. Thank you.

// TRANSMITTER CODE

#include <VirtualWire.h>

int ElapsedTime;  
int interval = 1000;
unsigned long previousMillis;

void setup()
{
    Serial.begin(9600);	  // Debugging only
    Serial.println("setup");

    // Initialise the IO and ISR
    vw_set_ptt_inverted(true); // Required for DR3100
    vw_setup(2000);	 // Bits per sec
    vw_set_tx_pin(3); 
        
    pinMode(8, INPUT);
   }

void loop()
{
  char *msg;
  int straingauge = analogRead(A1); //Read input from strain gauge
  int PotValue = analogRead(A0); //Read input from Potentiometer
    
  //Convert the analog reading (which goes from 0 - 1023) to a voltage (0 - 5V):
  float ActivationVoltage = PotValue * (5.0 / 1023.0);
  float Activationweight = (1.8745*ActivationVoltage)-0.0744;
  
  //Print out the activation weight value:
  //Serial.print("Activation Weight: ");
  //Serial.print(Activationweight);
  //Serial.println("lbs");
  
  //Convert the analog reading (which goes from 0 - 1023) to a voltage (0 - 5V):
  float voltage = straingauge * (5.0 / 1023.0);
    
  //Convert the voltage to weight
  float weight = (1.8745*voltage)-0.0744;
  
  //Print out the actual weight value:
  //Serial.print("Actual Weight: ");
  //Serial.print(weight);
  //Serial.println(" lbs");
  //Serial.println();
 
  unsigned long currentMillis = millis();
 
  if(voltage >= ActivationVoltage){
     
    previousMillis = currentMillis; 
    char *msg = "1";
    vw_send((uint8_t *)msg, strlen(msg));
    vw_wait_tx(); // Wait until the whole message is gone
    
    Serial.println(currentMillis);
    Serial.println(previousMillis);
    Serial.println(currentMillis-previousMillis);
    Serial.println();
  
    if ((unsigned long)(currentMillis - previousMillis) >= (interval))
        {
            char *msg = "3";
            vw_send((uint8_t *)msg, strlen(msg));
            vw_wait_tx(); // Wait until the whole message is gone
            //previousMillis = currentMillis;            
        }
    }  
    
  if(voltage < ActivationVoltage)
    {
    char *msg = "2";
    vw_send((uint8_t *)msg, strlen(msg));
    vw_wait_tx(); // Wait until the whole message is gone
    }
   
}

Do you have a DR3100? If not, take this line out:

vw_set_ptt_inverted(true); // Required for DR3100

declare all the time related variables as unsigned long in the pre-setup area, don't redeclare them in loop code:
currentMillis, previousMillis, interval

I made the changes your suggested, but I still need help with measuring the amount of time that has passed since the voltage from the strain gauge is greater than the activation voltage using the millis() function.

As it stands your code sets previousMillis to currentMillis each time through loop() whilst voltage >= ActivationVoltage so the interval will never be exceeded.

What you need to do is to set a variable with a better name, say startMillis to millis() when voltage becomes greater or equal to ActivationVoltage and then do not do it again, thus starting the timing at the state change. To do this set a boolean variable to true when you have saved the start time and check the boolean next time through loop(). If it is true then do not save the start time again. If the voltage difference is no longer present or the message has been sent then set the boolean variable to false ready for next time.

Thank you for your help UKHeliBob! I am at work right now so I cannot test my code, but I think it might work (but I have been wrong before).

  1. I set the Boolean variable “timer” equal to false in the beginning of my program.
  2. If the “voltage” is greater than “activationvoltage” and “timer” equals to false then the start time (“startMillis”) is recorded and the Boolean variable is changed to true.
  3. While in this “if” function, if “millis()” minus “startMillis” is greater than “interval” than another event occurs.
  4. As soon as the “voltage” goes below “activationvoltage” than the “timer” variable changes back to false and is ready to start the countdown once “voltage” is greater than “activationvoltage” again.

I am new to arduino and coding in general so please let me know if my code or logic is wrong. I appreciate your help. Thank you.

// TRANSMITTER CODE

#include <VirtualWire.h>

int ElapsedTime;  
int interval = 1000;
unsigned long startMillis;
unsigned long elapsedtime;
boolean timer = false;

void setup()
{
    Serial.begin(9600); // Debugging only
    Serial.println("setup");

    // Initialise the IO and ISR
    vw_setup(2000); // Bits per sec
    vw_set_tx_pin(3); 
        
    pinMode(8, INPUT);
}

void loop()
{
  char *msg;
  int straingauge = analogRead(A1); //Read input from strain gauge
  int PotValue = analogRead(A0); //Read input from Potentiometer
    
  //Convert the analog reading (which goes from 0 - 1023) to a voltage (0 - 5V):
  float ActivationVoltage = PotValue * (5.0 / 1023.0);
  float Activationweight = (1.8745*ActivationVoltage)-0.0744;
  
  //Print out the activation weight value:
  //Serial.print("Activation Weight: ");
  //Serial.print(Activationweight);
  //Serial.println("lbs");
  
  //Convert the analog reading (which goes from 0 - 1023) to a voltage (0 - 5V):
  float voltage = straingauge * (5.0 / 1023.0);
    
  //Convert the voltage to weight
  float weight = (1.8745*voltage)-0.0744;
 
  if(voltage >= ActivationVoltage)
  {
    char *msg = "1";
    vw_send((uint8_t *)msg, strlen(msg));
    vw_wait_tx(); // Wait until the whole message is gone

    if(timer=false)
    {
      startMillis = millis();
      timer = true;
    }
  
    elapsedtime = millis()-startMillis;
  
    if (elapsedtime >= interval)
    {
      char *msg = "3";
      vw_send((uint8_t *)msg, strlen(msg));
      vw_wait_tx(); // Wait until the whole message is gone
    }
  }  
    
  if(voltage < ActivationVoltage)
  {
    timer = false;     
    
    char *msg = "2";
    vw_send((uint8_t *)msg, strlen(msg));
    vw_wait_tx(); // Wait until the whole message is gone
  }
   
}

I did not look far into your code but this is wrong    if (timer = false)

I have confused the COMPARISON operator ‘==’ with the ASSIGNMENT operator ‘=’

I have changed the line to:

if(timer==false)
    {
      startMillis = millis();
      timer = true;
    }

Hopefully it’s all good now:

// TRANSMITTER CODE

#include <VirtualWire.h>

int ElapsedTime;  
int interval = 1000;
unsigned long startMillis;
unsigned long elapsedtime;
boolean timer = false;

void setup()
{
    Serial.begin(9600); // Debugging only
    Serial.println("setup");

    // Initialise the IO and ISR
    vw_setup(2000); // Bits per sec
    vw_set_tx_pin(3); 
        
    pinMode(8, INPUT);
}

void loop()
{
  char *msg;
  int straingauge = analogRead(A1); //Read input from strain gauge
  int PotValue = analogRead(A0); //Read input from Potentiometer
    
  //Convert the analog reading (which goes from 0 - 1023) to a voltage (0 - 5V):
  float ActivationVoltage = PotValue * (5.0 / 1023.0);
  float Activationweight = (1.8745*ActivationVoltage)-0.0744;
  
  //Print out the activation weight value:
  //Serial.print("Activation Weight: ");
  //Serial.print(Activationweight);
  //Serial.println("lbs");
  
  //Convert the analog reading (which goes from 0 - 1023) to a voltage (0 - 5V):
  float voltage = straingauge * (5.0 / 1023.0);
    
  //Convert the voltage to weight
  float weight = (1.8745*voltage)-0.0744;
 
  if(voltage >= ActivationVoltage)
  {
    char *msg = "1";
    vw_send((uint8_t *)msg, strlen(msg));
    vw_wait_tx(); // Wait until the whole message is gone

    if(timer==false)
    {
      startMillis = millis();
      timer = true;
    }
  
    elapsedtime = millis()-startMillis;
  
    if (elapsedtime >= interval)
    {
      char *msg = "3";
      vw_send((uint8_t *)msg, strlen(msg));
      vw_wait_tx(); // Wait until the whole message is gone
    }
  }  
    
  if(voltage < ActivationVoltage)
  {
    timer = false;     
    
    char *msg = "2";
    vw_send((uint8_t *)msg, strlen(msg));
    vw_wait_tx(); // Wait until the whole message is gone
  }
   
}

A couple of improvements:

  if(voltage >= ActivationVoltage)
  {
    ...
  }  
    
  if(voltage < ActivationVoltage)
  {
    ...
  }
   
}

Second if should be an else.

The arithmetic here is completely unnecessary.

float ActivationVoltage = PotValue * (5.0 / 1023.0);
float voltage = straingauge * (5.0 / 1023.0);
if(voltage >= ActivationVoltage)

With simple algebra, we can prove that. Simply replacing the voltage with their equivalencies:

if (straingauge * (5.0 / 1023.0) >= PotValue * (5.0 / 1023.0))

Multiply each side by 1023.0 / 5.0 gives us a simpler equation:

if (straingauge >= PotValue)
if(voltage >= ActivationVoltage)
  {
    ...
    if (timer==false)
    {
      startMillis = millis();
      timer = true;
    }

Thinking of startMillis as the last time that voltage was less than Activation voltage eliminates the need for the timer variable:

if(voltage >= ActivationVoltage)
{
  ...
  elapsedtime = millis()-lastTimeVoltageWasBelowActivation;
  
  if (elapsedtime >= interval)
  {
    // do something
  }
}
else
{
  lastTimeVoltageWasBelowActivation = millis();
}

Thanks a lot for all you help! It works exactly as I wanted it to now.

If the voltage is greater than the activation voltage and stays greater than the activation voltage for longer than the specified interval then another action occurs and the timer resets and starts counting again. On the other hand, if the voltage is greater than the activation voltage and but doesn't stay greater than the activation voltage for longer than the specified interval then the timer resets and starts counting again.

    if(voltage >= ActivationVoltage)
  {
    char *msg = "1";
    vw_send((uint8_t *)msg, strlen(msg));
    vw_wait_tx(); // Wait until the whole message is gone
  
    elapsedtime = millis()-startMillis;
  
    if(elapsedtime >= interval)
    {
      char *msg = "3";
      vw_send((uint8_t *)msg, strlen(msg));
      vw_wait_tx(); // Wait until the whole message is gone
      
      startMillis = millis();
    }
   }  
    
  else
  {
    startMillis = millis();
    char *msg = "2";
    vw_send((uint8_t *)msg, strlen(msg));
    vw_wait_tx(); // Wait until the whole message is gone
  }