0

When I trigger high it will count for as long as I ask it while I am high then shut off. I am able to start counting again whenever I want by triggering low and going back to high and it starts from the beginning as long as the time in low is not within the time I asked it to be high. The problem is I go low mid count then quickly back to high the count picks up where millis left off without starting from the beginning. Is there a way to make this better.

unsigned long induceTime = 0;
unsigned long elapseTime;
long setTime = 10000;
int openClose;
int openClosePin = 2;
int writeToPin = 3;
void setup() {
Serial.begin(9600);
}

void loop() {
  int openClose = digitalRead(openClosePin);
  elapseTime = millis(); 
  if (openClose == HIGH && elapseTime < induceTime + setTime){ 
    digitalWrite(writeToPin, HIGH); 
    Serial.println(' ');
    Serial.println(elapseTime);
    Serial.println(' ');
    Serial.println(induceTime);
    Serial.println(' ');   
}
  if (openClose == LOW && elapseTime > induceTime + setTime){
    induceTime = elapseTime;
    Serial.println(elapseTime);
    Serial.println(induceTime);
}

delay(500);
}
1

Thanks for the help, this code is closer to what I was looking for. This is for a water level pump, when the trigger is high it turns on, when the water rises the trigger goes low and stays on during the timer as a failsafe and then turns off with when the elapsed time is greater than the set time and also not in my code it turns off with a additional trigger. Here is my working code.


unsigned long induceTime = 0;
unsigned long elapseTime;
long setTime = 10000;
int openClose;
int openClosePin = 2;
int writeToPin = 3;
void setup() {
Serial.begin(9600);
}

void loop() {
  int openClose = digitalRead(openClosePin);
  elapseTime = millis(); 
  if (openClose == HIGH){                //reset count
    induceTime = millis();
    digitalWrite(writeToPin, HIGH); 
    Serial.println(induceTime);  
}
  if (openClose == LOW){
    elapseTime = millis() - induceTime;  //induceTime is set when leave high
    if (elapseTime < setTime){
      digitalWrite(writeToPin, HIGH);
      Serial.println(elapseTime);
      Serial.println("within setTime high"); 
}
    if (elapseTime > setTime){
      digitalWrite(writeToPin, LOW);
      Serial.println(elapseTime);
      Serial.println("within setTime for low");
}
    Serial.println(' '); 
    Serial.println(elapseTime);
    Serial.println(' '); 
    Serial.println(induceTime);
    Serial.println(' '); 
}
delay(1000);                              //so that I can see serial monitor
}
| improve this answer | |
  • It's OK to accept your own answer as the solution to the problem. – VE7JRO Apr 18 at 17:03
0

First make your code rollover safe and second add an other condition:
So as I understood LOW/HIGH changes should start a timer from zero irrelevant if a running timer is over or not - so timer is still running HIGH/LOW -> and LOW/HIGH should restart

// repalce / paste before setup
unsigned long startTime = 0;
bool timerIsOn = false;
//unsigned long elapseTime;


 // replace your loopwith this
void loop() {
  int openClose = digitalRead(openClosePin);
//  elapseTime = millis(); 
  if (openClose == HIGH && timerIsOn = false){
       timerIsOn = true;
       startTime = millis();
       digitalWrite(writeToPin, HIGH); 
       Serial.print(' ');
       Serial.print(millis());
       Serial.print(' ');
       Serial.print(startTime);
        Serial.println(' ');
   }
   // This condition is for time is up 
  if (timerIsOn = true && millis() - startTime > setTime){ 
     digitalWrite(writeToPin, LOW);
     timerIsOn = false;
     Serial.print(setTime);
     Serial.print(' ');
     Serial.println(millis()-startTime);
  }
   // This condition is for going low before time is up        
  if (openClose == LOW && timerIsOn = true){
    digitalWrite(writeToPin, LOW);
    timerIsOn = false;
    Serial.print('timerIsOn = ');
    Serial.println(timerIsOn);
    Serial.print(' ');
    Serial.println(millis()-startTime);
  }
 // If you go LOW after time is up it does nothing waits for the next HIGH
}
| improve this answer | |
0

For starters, millis should be used relatively to avoid rollover. Simple fix is to subtract the induceTime over to the same side of the comparison. Example: elapseTime - induceTime > setTime

This also brings up the issue that your 'counter' is always elapseTime aka millis instead of (elapseTime - induceTime) so it never truly stops counting.

You are also never calling digitalWrite(writeToPin, LOW); So it goes high and stays high. I suspect you meant to set it to low in an else statement somewhere.

Now for the issue regarding quickly changing signals:

Beyond that you could use an interrupt and timer so that your sample rate (determined by the delay(500)) doesn't come into play. This will give the best possible timing at the cost of restricting which pins you can use for openClosePin and you should also check that you sufficiently debounce the signal (in hardware).

Alternatively you can reduce the 500 to an acceptable #. But you would then want to have another counter to prevent spamming your serial output.

Below example only implements ISR and reduction of 500. Does not implement timer (which would be required for precise use of setTime to shut the writeToPin off to LOW).

volatile unsigned long induceTime = 0;
volatile unsigned long elapsedTime;
unsigned long setTime = 10000;
//volatile int openClose; //may want to toggle this in isr...
int openClosePin = 2;
int writeToPin = 3;

void pinChangedISR(){
  if(digitalRead(openClosePin)){ //rising
    digitalWrite(writeToPin, HIGH);
    induceTime = millis();
  }
  else{//falling
    digitalWrite(writeToPin, LOW);
    elapsedTime = millis() - induceTime;
  }
}

void setup() {
  pinMode(writeToPin, OUTPUT);
  pinMode(openClosePin, INPUT); //may want INPUT_PULLUP depending on hardware
  attachInterrupt(digitalPinToInterrupt(openClosePin), pinChangedISR, CHANGE);
  Serial.begin(9600);
}

void loop() {
  static int frameCount = 0;
  unsigned long delayTime = 100;
  openClose = digitalRead(openClosePin);
  if (openClose == HIGH){ 
    elapsedTime = millis() - induceTime;
    if(elapsedTime >= setTime) digitalWrite(writeToPin, LOW);
    else if(setTime - elapsedTime < 100) delayTime = setTime - elapsedTime;
  }
  if(framecount >= 5){ //time to print...
    framecount = 0;
    if(digitalRead(writeToPin) == HIGH){
      Serial.println(' ');
      Serial.println(elapsedTime);
      Serial.println(' ');
      Serial.println(induceTime);
      Serial.println(' ');
    }
    else{ //this part's a bit different 
      Serial.println(elapsedTime); //reporting duration of last pulse when pulse inactive
      Serial.println(millis()); //reporting current time for inducetime comparison
    }
  } else ++framecount;
  delay(delayTime);
}
| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.