Simple (maybe) question, digitalWrite a pin LOW for time using millis

Okay I'm sure this is very simple but this is somehow escaping me.

I'm trying to use millis to hold a pin LOW for a minimum amount of time.

So, a sensor input reads low, and that triggers an output to digitalWrite low.

I need the output to stay low for a interval after the sensor goes back to high.

Is there an example of this? I've been looking at a lot of blink without delay and related things but can't seem to figure this simple problem out.

Thanks for any help

Check that tip again!
Set a time stamp, startOfTime, when the sensor reads low. Then in the code look for millis() to exceed startOfTime plus "interval".
No delays in the code....
Please post Your code.

1 Like

And check out the StateChangeDetection example too because you want to know when the sensor input GOES low not just when it IS low.

Steve

1 Like

What makes you say that :thinking: .


In the Arduino IDE, use Ctrl T or CMD T to format your code then copy the complete sketch.

Use the </> icon from the ‘reply menu’ to attach the copied sketch.

1 Like
const byte InputPin = 2;
const byte OutputPin = 3;

boolean InputWasLOW = false;
unsigned long InputLastChangeTime;
unsigned DEBOUNCE_INTERVAL = 10;

int OutputState;
unsigned long OutputStateStartTime;
unsigned OUTPUT_LOW_TIME = 10000;  // Up to 65000 milliseconds

void setup()
{
  pinMode(InputPin, INPUT);
  pinMode(OutputPin, OUTPUT);
  digitalWrite(OutputPin, HIGH);
  OutputState = HIGH;
}

void loop()
{
  unsigned long currentMillis = millis();

  boolean inputIsLOW = digitalRead(InputPin) == LOW;

  if (inputIsLOW != InputWasLOW
      && currentMillis - InputLastChangeTime >= DEBOUNCE_INTERVAL)
  {
    // State has changed
    InputLastChangeTime = currentMillis;
    InputWasLOW = inputIsLOW;

    if (inputIsLOW)
    {
      // Input has just gone LOW
      OutputState = LOW;
      OutputStateStartTime = currentMillis;
      digitalWrite(OutputPin, OutputState);
    }
  }

  if (OutputState == LOW
      && currentMillis - OutputStateStartTime >= OUTPUT_LOW_TIME)
  {
    // End of LOW time
    OutputState = HIGH;
    digitalWrite(OutputPin, OutputState);
  }
}
1 Like

"interval" being an unsigned long.

Note you do this by subtraction.

if (millis() - startOfTime => interval)
1 Like

Correct. Lesson number 2 for OP...

Trying to explain this:

So when input (sensorPin6) goes low I'm calling to a void INTER()

void INTER() needs to contain the function described before,

Run a task:

Pull OUTPUT_PIN to low for a minimum amount of time.... so output stays low while sensorpin6 is low, and after sensorpin6 goes high, the OUTPUT_PIN stays low for an interval.

I'm sure the answer is already in the responses here, but I'm to dumb to see it.

Here is the huge, sloppy sketch that SOMEHOW works. As it is now, the switch to OUTPUT_PIN low works immediately.... This is the sketch I've been messing with to try to get this all to work....

//tail lamp dev v3

#include <Adafruit_NeoPixel.h>
#include  "taillightarrays.h"

#define PIN 3

const int sensorPin1 = A0;    // select a input pin for control 1 RUN LAMP
const int sensorPin2 = A1;    // select a input pin for control 2 TURN SIGNAL
const int sensorPin3 = A2;    // select a input pin for control 3 BRAKE LIGHT
const int sensorPin4 = A3;    // select a input pin for control 4 REVERSE
const int sensorPin5 = A4;    // party light
const int sensorPin6 = A5;    // turn signal delay function
const int OUTPUT_PIN = A6;    // OUTPUT PIN

const int NUM_PIXELS = 256;
Adafruit_NeoPixel strip = Adafruit_NeoPixel(NUM_PIXELS, PIN, NEO_GRB);


void setup()
{
  strip.begin();
  strip.setBrightness(15);
  strip.show();   // Initialize all pixels to 'off'
  pinMode(A0, INPUT_PULLUP);
  pinMode(A1, INPUT_PULLUP);
  pinMode(A2, INPUT_PULLUP);
  pinMode(A3, INPUT_PULLUP);
  pinMode(A5, INPUT_PULLUP);
  pinMode(A6, OUTPUT);


}

void loop()
{


  int state1 = 0; // initialize state1 value to zero
  int state2 = 0; // initialize state2 value to zero
  int state3 = 0; // initialize state3 value to zero
  int state4 = 0; // initialize state4 value to zero
  int state5 = 0; // initialize state4 value to zero

  if (digitalRead(sensorPin1) == LOW) // read the value from the sensor1: //run
    state1 = 1;
  else state1 = 0;


  if (digitalRead(sensorPin2) == LOW) // read the value from the sensor2: //turn
    state2 = 2;
  else state2 = 0;


  if (digitalRead(sensorPin3) == LOW) // read the value from the sensor3: //brake
    state3 = 4;
  else state3 = 0;


  if (digitalRead(sensorPin4) == LOW) // read the value from the sensor4: //reverse
    state4 = 8;
  else state4 = 0;

  if (digitalRead(sensorPin5) == LOW) // read the value from the sensor4: //party lights
    state5 = 20;
  else state5 = 0;


  int totalState = state1 + state2 + state3 + state4 + state5; //total of states to a single int

  //totals of state for which frame to render


  if (totalState == 0) { //off
    RenderFrame (ledarrayoff);
  }


  if (totalState == 1) { //run
    strip.setBrightness(50);
    RenderFrame (ledarrayrun);
  }


  if (totalState == 2 or totalState == 3) { //turn anime turn run anime
    strip.setBrightness(255);
    turnAnimeStep();
  }

  if (totalState == 4) { //brake
    RenderFrame (ledarraybrake);
    strip.setBrightness(255);
  }


  if (totalState == 5) { //run brake
    strip.setBrightness(255);
    RenderFrame (ledarraybrake);
  }


  if (totalState == 6) { //turn brake
    strip.setBrightness(255);
    turnbrakeAnimeStep();
  }


  if (totalState == 8) { // reverse
    strip.setBrightness(255);
    RenderFrame (ledarrayreverse);
  }


  if (totalState == 9) { // run reverse
    RenderFrame (ledarrayrunreverse);
    strip.setBrightness(255);
  }


  if (totalState == 10 or totalState == 11) { // turn reverse and run turn reverse
    turnReverseAnimeStep();
    strip.setBrightness(255);
  }


  if (totalState == 12) { // brake reverse
    RenderFrame (ledarraybrakereverse);
    strip.setBrightness(255);
  }


  if (totalState == 13) { // run brake reverse
    RenderFrame (ledarraybrakereverse);
    strip.setBrightness(255);
  }


  if (totalState == 14 or totalState == 15) { // turn brake reverse
    turnbrakeReverseAnimeStep ();
    strip.setBrightness(255);
  }

  if (totalState == 20) { // party lights
    PARTYLIGHTS ();
  }

  if (digitalRead(sensorPin6) == LOW) {
    INTER ();
  }

  else {
    digitalWrite(OUTPUT_PIN, HIGH);
  }

}

//Anime state machines

//turn anime machine
void turnAnimeStep()
{
  static byte frame = 0;    // reset to replay
  static unsigned long lastTime = 0;
  static unsigned long tween = 0;
  if (millis() - lastTime < tween)
    return;

  lastTime = millis();
  switch (frame) {
    case 0 :
      RenderFrame (ledarrayt1);
      tween = 200;
      frame++;
      break;

    case 1 :
      RenderFrame (ledarrayt2);
      tween = 15;
      frame++;
      break;

    case 2 :
      RenderFrame (ledarrayt3);
      tween = 15;
      frame++;
      break;

    case 3 :
      RenderFrame (ledarrayt4);
      tween = 15;
      frame++;
      break;

    case 4 :
      RenderFrame (ledarrayt5);
      tween = 15;
      frame++;
      break;

    case 5 :
      RenderFrame (ledarrayt6);
      tween = 15;
      frame++;
      break;

    case 6 :
      RenderFrame (ledarrayt7);
      tween = 15;
      frame++;
      break;

    case 7 :
      RenderFrame (ledarrayt8);
      tween = 15;
      frame++;
      break;

    case 8 :
      RenderFrame (ledarrayt9);
      tween = 15;
      frame++;
      break;

    case 9 :
      RenderFrame (ledarrayt10);
      tween = 15;
      frame++;
      break;

    case 10 :
      RenderFrame (ledarrayt11);
      tween = 15;
      frame++;
      break;

    case 11 :
      RenderFrame (ledarrayt12);
      tween = 15;
      frame++;
      break;

    case 12 :
      RenderFrame (ledarrayt13);
      tween = 15;
      frame++;
      break;

    case 13 :
      RenderFrame (ledarrayt14);
      tween = 15;
      frame++;
      break;

    case 14 :
      RenderFrame (ledarrayt15);
      tween = 15;
      frame++;
      break;

    case 15 :
      RenderFrame (ledarrayt16);
      tween = 15;
      frame++;
      break;

    case 16 :
      RenderFrame (ledarrayt17);
      tween = 15;
      frame++;
      break;

    case 17 :
      RenderFrame (ledarrayt18);
      tween = 15;
      frame++;
      break;

    case 18 :
      RenderFrame (ledarrayt19);
      tween = 15;
      frame++;
      break;

    case 19 :
      RenderFrame (ledarrayt20);
      tween = 15;
      frame++;
      break;

    case 20 :
      RenderFrame (ledarrayt21);
      tween = 15;
      frame++;
      break;

    case 21 :
      RenderFrame (ledarrayt22);
      tween = 15;
      frame++;
      break;

    case 22 :
      RenderFrame (ledarrayt23);
      tween = 15;
      frame++;
      break;

    case 23 :
      RenderFrame (ledarrayt24);
      tween = 15;
      frame = 0;
      break;
  }
}

//turn brake anime machine
void turnbrakeAnimeStep()
{
  static byte frame = 0;    // reset to replay
  static unsigned long lastTime = 0;
  static unsigned long tween = 0;

  if (millis() - lastTime < tween)
    return;

  lastTime = millis();
  switch (frame) {
    case 0 :
      RenderFrame (ledarraytb1);
      tween = 200;
      frame++;
      break;

    case 1 :
      RenderFrame (ledarraytb2);
      tween = 15;
      frame++;
      break;

    case 2 :
      RenderFrame (ledarraytb3);
      tween = 15;
      frame++;
      break;

    case 3 :
      RenderFrame (ledarraytb4);
      tween = 15;
      frame++;
      break;

    case 4 :
      RenderFrame (ledarraytb5);
      tween = 15;
      frame++;
      break;

    case 5 :
      RenderFrame (ledarraytb6);
      tween = 15;
      frame++;
      break;

    case 6 :
      RenderFrame (ledarraytb7);
      tween = 15;
      frame++;
      break;

    case 7 :
      RenderFrame (ledarraytb8);
      tween = 15;
      frame++;
      break;

    case 8 :
      RenderFrame (ledarraytb9);
      tween = 15;
      frame++;
      break;

    case 9 :
      RenderFrame (ledarraytb10);
      tween = 15;
      frame++;
      break;

    case 10 :
      RenderFrame (ledarraytb11);
      tween = 15;
      frame++;
      break;

    case 11 :
      RenderFrame (ledarraytb12);
      tween = 15;
      frame++;
      break;

    case 12 :
      RenderFrame (ledarraytb13);
      tween = 15;
      frame++;
      break;

    case 13 :
      RenderFrame (ledarraytb14);
      tween = 15;
      frame++;
      break;

    case 14 :
      RenderFrame (ledarraytb15);
      tween = 15;
      frame++;
      break;

    case 15 :
      RenderFrame (ledarraytb16);
      tween = 15;
      frame++;
      break;

    case 16 :
      RenderFrame (ledarraytb17);
      tween = 15;
      frame++;
      break;

    case 17 :
      RenderFrame (ledarraytb18);
      tween = 15;
      frame++;
      break;

    case 18 :
      RenderFrame (ledarraytb19);
      tween = 15;
      frame++;
      break;

    case 19 :
      RenderFrame (ledarraytb20);
      tween = 15;
      frame++;
      break;

    case 20 :
      RenderFrame (ledarraytb21);
      tween = 15;
      frame++;
      break;

    case 21 :
      RenderFrame (ledarraytb22);
      tween = 15;
      frame++;
      break;

    case 22 :
      RenderFrame (ledarraytb23);
      tween = 15;
      frame = 0;
      break;
  }
}

//turn brake reverse anime machine
void turnbrakeReverseAnimeStep()
{
  static byte frame = 0;    // reset to replay
  static unsigned long lastTime = 0;
  static unsigned long tween = 0;

  if (millis() - lastTime < tween)
    return;

  lastTime = millis();
  switch (frame) {
    case 0 :
      RenderFrame (ledarraytbr1);
      tween = 200;
      frame++;
      break;

    case 1 :
      RenderFrame (ledarraytbr2);
      tween = 15;
      frame++;
      break;

    case 2 :
      RenderFrame (ledarraytbr3);
      tween = 15;
      frame++;
      break;

    case 3 :
      RenderFrame (ledarraytbr4);
      tween = 15;
      frame++;
      break;

    case 4 :
      RenderFrame (ledarraytbr5);
      tween = 15;
      frame++;
      break;

    case 5 :
      RenderFrame (ledarraytbr6);
      tween = 15;
      frame++;
      break;

    case 6 :
      RenderFrame (ledarraytbr7);
      tween = 15;
      frame++;
      break;

    case 7 :
      RenderFrame (ledarraytbr8);
      tween = 15;
      frame++;
      break;

    case 8 :
      RenderFrame (ledarraytbr9);
      tween = 15;
      frame++;
      break;

    case 9 :
      RenderFrame (ledarraytbr10);
      tween = 15;
      frame++;
      break;

    case 10 :
      RenderFrame (ledarraytbr11);
      tween = 15;
      frame++;
      break;

    case 11 :
      RenderFrame (ledarraytbr12);
      tween = 15;
      frame++;
      break;

    case 12 :
      RenderFrame (ledarraytbr13);
      tween = 15;
      frame++;
      break;

    case 13 :
      RenderFrame (ledarraytbr14);
      tween = 15;
      frame++;
      break;

    case 14 :
      RenderFrame (ledarraytbr15);
      tween = 15;
      frame++;
      break;

    case 15 :
      RenderFrame (ledarraytbr16);
      tween = 15;
      frame++;
      break;

    case 16 :
      RenderFrame (ledarraytbr17);
      tween = 15;
      frame++;
      break;

    case 17 :
      RenderFrame (ledarraytbr18);
      tween = 15;
      frame++;
      break;

    case 18 :
      RenderFrame (ledarraytbr19);
      tween = 15;
      frame++;
      break;

    case 19 :
      RenderFrame (ledarraytbr20);
      tween = 15;
      frame++;
      break;

    case 20 :
      RenderFrame (ledarraytbr21);
      tween = 15;
      frame++;
      break;

    case 21 :
      RenderFrame (ledarraytbr22);
      tween = 15;
      frame++;
      break;

    case 22 :
      RenderFrame (ledarraytbr23);
      tween = 15;
      frame = 0;
      break;
  }
}



//turn reverse anime machine
void turnReverseAnimeStep()
{
  static byte frame = 0;    // reset to replay
  static unsigned long lastTime = 0;
  static unsigned long tween = 0;

  if (millis() - lastTime < tween)
    return;

  lastTime = millis();
  switch (frame) {
    case 0 :
      RenderFrame (ledarraytr1);
      tween = 200;
      frame++;
      break;

    case 1 :
      RenderFrame (ledarraytr2);
      tween = 15;
      frame++;
      break;

    case 2 :
      RenderFrame (ledarraytr3);
      tween = 15;
      frame++;
      break;

    case 3 :
      RenderFrame (ledarraytr4);
      tween = 15;
      frame++;
      break;

    case 4 :
      RenderFrame (ledarraytr5);
      tween = 15;
      frame++;
      break;

    case 5 :
      RenderFrame (ledarraytr6);
      tween = 15;
      frame++;
      break;

    case 6 :
      RenderFrame (ledarraytr7);
      tween = 15;
      frame++;
      break;

    case 7 :
      RenderFrame (ledarraytr8);
      tween = 15;
      frame++;
      break;

    case 8 :
      RenderFrame (ledarraytr9);
      tween = 15;
      frame++;
      break;

    case 9 :
      RenderFrame (ledarraytr10);
      tween = 15;
      frame++;
      break;

    case 10 :
      RenderFrame (ledarraytr11);
      tween = 15;
      frame++;
      break;

    case 11 :
      RenderFrame (ledarraytr12);
      tween = 15;
      frame++;
      break;

    case 12 :
      RenderFrame (ledarraytr13);
      tween = 15;
      frame++;
      break;

    case 13 :
      RenderFrame (ledarraytr14);
      tween = 15;
      frame++;
      break;

    case 14 :
      RenderFrame (ledarraytr15);
      tween = 15;
      frame++;
      break;

    case 15 :
      RenderFrame (ledarraytr16);
      tween = 15;
      frame++;
      break;

    case 16 :
      RenderFrame (ledarraytr17);
      tween = 15;
      frame++;
      break;

    case 17 :
      RenderFrame (ledarraytr18);
      tween = 15;
      frame++;
      break;

    case 18 :
      RenderFrame (ledarraytr19);
      tween = 15;
      frame++;
      break;

    case 19 :
      RenderFrame (ledarraytr20);
      tween = 15;
      frame++;
      break;

    case 20 :
      RenderFrame (ledarraytr21);
      tween = 15;
      frame++;
      break;

    case 21 :
      RenderFrame (ledarraytr22);
      tween = 15;
      frame++;
      break;

    case 22 :
      RenderFrame (ledarraytr23);
      tween = 15;
      frame = 0;
      break;
  }
}


void INTER()
{
  digitalWrite(OUTPUT_PIN, LOW);
}


//PARTYLIGHTS
void PARTYLIGHTS()
{
  static byte frame = 0;    // reset to replay
  static unsigned long lastTime = 0;
  static unsigned long tween = 0;

  if (millis() - lastTime < tween)
    return;

  lastTime = millis();
  switch (frame) {
    case 0 :
      RenderFrame (PARTYLIGHT1);
      tween = 200;
      frame++;
      break;


    case 1 :
      RenderFrame (PARTYLIGHT2);
      tween = 200;
      frame = 0;
      break;
  }
}


void RenderFrame(const uint32_t *arr)
{
  for (uint16_t t = 0; t < 256; t++)
  {
    strip.setPixelColor(t, arr[t]);
  }
  strip.show();

}

In what way would you like the responses to be augmented so you can see it? Did you spend any time with reply #5?

How is your proposed function INTER() used? Do you intend to call it every time through loop?

Just to illustrate the basic principle:

1 Like

My take on a minimal sketch for this:


#define sensor 2      // for testing, replace with actual pins
#define outputpin 13

void setup()
{
  pinMode (sensor, INPUT_PULLUP) ;  // in case its open-collector
  pinMode (outputpin, OUTPUT) ;
  digitalWrite (outputpin, HIGH) ;  // resting state for this pin
}

// state names
#define IDLE 0
#define ACTIVE 1
#define RELEASED 2

// current state
byte state = IDLE ;

// timer stuff
#define INTERVAL 1000
unsigned long timer ;

void loop() 
{
  switch (state)
  {
    case IDLE: // IDLE waits for sensor trigger
    if (digitalRead (sensor) == LOW)
    {
      state = ACTIVE ;
      digitalWrite (outputpin, LOW) ; // activate output
    }
    break ;

    case ACTIVE: // ACTIVE waits for sensor to release
    if (digitalRead (sensor) == HIGH)
    {
      state = RELEASED ;
      timer = millis() ;  // on release start timer
    }
    break ;

    case RELEASED:  // waits for timeout (or retrigger)
    if (millis() - timer >= INTERVAL)
    {
      state = IDLE ;
      digitalWrite (outputpin, HIGH) ; // deactivate output
    }
    else if (digitalRead (sensor) == LOW) // retriggered before timeout
    {  
      state = ACTIVE ;
    }
    break ;
  }
}

Note that once you identify that there are 3 states needed then the coding is the simple part.

Drawing out a suitable state-transition diagram on a piece of paper is usually the place to start for this kind of code. Think about what to do in each state for each input change.

1 Like

MarkT

I was able to integrate you suggestion into my script. Thank you so much.

Thanks to everyone else who helped here as well. I'm (slowly) learning :slight_smile: