How do you make an LED Blink once (HIGH for one second) when triggered?

Hi,

I'm pretty sure this is quite simple but don't know the best way to go about it.

Basically I want to tell a digital output pin to be HIGH when triggered by the IF command, but only for a second.
Then I want it to be LOW, until triggered again.

The problem I'm having is that when triggered I can only figure out how to have it HIGH as a constant, unless I use a delay. The problem with using a delay for say 10 seconds, then if it is triggered again within that time, it will not respond due to the delay.

How do I do this?

Here's my code:

int analogPin1 = 1; // read photo resitor analog pin 1
int analogPin2 = 2; // read photo resitor analog pin 2
int LEDpin6 = 6; // LED controlled by pin6
int LEDpin5 = 5; // LED controlled by pin5
int val1 = 0; // variable to store the value read
int val2 = 0;
boolean running = false;

void setup()

{
Serial.begin(9600);
pinMode (LEDpin6, OUTPUT);
pinMode (LEDpin5, OUTPUT);
pinMode (analogPin1, INPUT);
pinMode (analogPin2, INPUT);
}

void loop()
{
val1 = analogRead(analogPin1);
val2 = analogRead(analogPin2);

Serial.println(val1);
Serial.println(val2);
delay (100);
{
if (analogRead(analogPin1) < 600)
{
digitalWrite(LEDpin6, HIGH);
}
else
digitalWrite(LEDpin6, LOW);
}

{

if (analogRead(analogPin2) < 600)

{
digitalWrite(LEDpin5, HIGH);

}
else
{
digitalWrite(LEDpin5,LOW);
}
}
}

I've been looking at this but don't know how to implement it correctly using the analog input.

Could you explain further please?

(I'm new to this in case you can't tell)

As PaulS often says when this question comes up - how would you yourself solve this problem with a watch, paper and pencil. Millis is your watch, variables are your paper & pencil.

I'm not clear on the requirements though. If the triggering condition is true and remains true, what does the output do? Does it go high for a second, then go low and immediately return high after the next analog read? Or does it stay high for as long as the triggering condition is true and go low a second after the trigger is false?

Currently it stays HIGH for as long as the triggering condition is true and then goes LOW for as long as the triggering condition is false.

What I would like is for the output to be HIGH for a a second upon reading the analog input as True, then to return to being LOW (whilst still True) until the input trigger returns false then true again.

Does that make sense? To put it into context, I have a photo resistor and an LED (to test it). The ideal situation would be:

  • The photo resistor is uncovered (can detect light) and the LED is off.
  • Then when I cover the photo resistor with my finger (detects it's dark), the led will flash for a second then go off.
  • I remove my finger, the photo resistor is uncovered (can detect light) and the LED remains off.
  • I cover the photo resistor with my finger again (detects it's dark), the led will flash for a second then go off.
  • And so on and so on....

KE7GKP:
Do you understand how blink without delay works? Instead of just sitting on your hands until the clock runs out, you simply note what time it is now, and what time it will be when you want to change the output. Then each time through the loop you check the current time against your "wake-up call" time to see if you should take the pin low again.

Does that mean it won't work for what I want it to do then?

I don't want it to be a specific time to wake up, I want it to be a specific state.

I'm confused....

I don't want it to be a specific time to wake up, I want it to be a specific state.

Same thing, you have a state that you send the output into, a logic one, when it is triggered. Then set a time when you are going to clear that output back to zero. Check each time round the loop if millis() exceeds that time, when it does set the output to zero.

Grumpy_Mike:
Same thing, you have a state that you send the output into, a logic one, when it is triggered. Then set a time when you are going to clear that output back to zero. Check each time round the loop if millis() exceeds that time, when it does set the output to zero.

I'm probably just not understanding correctly but does, "Then set a time when you are going to clear that output back to zero", still apply if I don't want a time to clear the output? I want the state change back to false to clear the output.

Then set a time when you are going to clear that output back to zero", still apply if I don't want a time to clear the output

Yes, instead of clearing the output then set your Boolean variable to false instead. It doesn't matter what you are doing, just set the time when you want to do it.

Sorry, I'm really new to all of this and these terms, what would that look like as a line of code?

Sorry, I'm really new to all of this and these terms, what would that look like as a line of code?

bool setPinHigh = false;
unsigned long startTime = 0;
unsigned long onTime = 1000;

void loop()
{
   // See if the condition is true to trigger the action is true
   if(digitalRead(triggerPin) == HIGH)
   {
     setPinHigh = true;
     startTime = millis();
   }
   else
      setPinHigh = false;

   // If the action is to be triggered, and has not been triggered recently, trigger it
   if(setPinHigh && millis() - startTime < onTime)
   {
     digitalWrite(actionPin, HIGH);
     pinIsHigh = true;
   }
   else
   {
      digitalWrite(actionPin, LOW);
      setPinHigh = false;
   }
}

Well, OK, that is not a line of code.

It checks to see if the trigger pin is HIGH (you may need to change this to LOW, depending on your resistors). If it is, it sets a flag saying that the action pin needs to be set HIGH.

Then it checks the need to set the action pin HIGH. If the trigger switch was pressed, the need is there, but the time that the pin is to be HIGH may have expired, or may not. If the need is there, and the elapsed time is less than the threshold, the pin is (re)set HIGH. Otherwise it is set LOW.

This is the basis for the blink without delay example. Separate the need to do something (based on the trigger) from the decision to do something (based on need AND time).

PaulS:
Well, OK, that is not a line of code.

It checks to see if the trigger pin is HIGH (you may need to change this to LOW, depending on your resistors). If it is, it sets a flag saying that the action pin needs to be set HIGH.

Then it checks the need to set the action pin HIGH. If the trigger switch was pressed, the need is there, but the time that the pin is to be HIGH may have expired, or may not. If the need is there, and the elapsed time is less than the threshold, the pin is (re)set HIGH. Otherwise it is set LOW.

This is the basis for the blink without delay example. Separate the need to do something (based on the trigger) from the decision to do something (based on need AND time).

Thank you very much for that. I've had a play around and I've got it kinda working, and I kinda understand it. It looks like this at present:

int analogPin1 = 1;     // read photo resitor analog pin 1
int LEDpin6 = 6;          // LED controlled by pin6
int val1 = 0;           // variable to store the value read

unsigned long startTime = 0;
unsigned long onTime = 1000;

void setup(){
  Serial.begin(9600);          
  pinMode (LEDpin6, OUTPUT);
  pinMode (analogPin1, INPUT);
}

void loop(){
  val1 = analogRead(analogPin1);

  Serial.println(val1);             
  delay (100);
  
  if (analogRead(analogPin1) < 300){
    digitalWrite(LEDpin6, HIGH);
  }
  
  if (digitalRead(LEDpin6) == LOW){
    startTime = millis();
  }
  else{
  }
  
  if(millis() - startTime < onTime){
    digitalWrite(LEDpin6, HIGH);
  }
  else{
    digitalWrite(LEDpin6, LOW);

  }
}

Thing is, it still blinks continuously. How do I stop it doing that? I just want it to blink once when triggered!

This is driving me crazy! :S

and I kinda understand it.

Obviously not well enough. The setPinHigh variable managed the do-it-once part that your code is not now doing.

PaulS:
Obviously not well enough. The setPinHigh variable managed the do-it-once part that your code is not now doing.

I did have the variable in there but it still blinked repeatedly and when I removed it, it made no difference.

Any ideas?

int analogPin1 = 1;     // read photo resitor analog pin 1
int LEDpin6 = 6;          // LED controlled by pin6
int val1 = 0;           // variable to store the value read

bool setPinHigh = false;
unsigned long startTime = 0;
unsigned long onTime = 1000;

void setup(){
  Serial.begin(9600);          
  pinMode (LEDpin6, OUTPUT);
  pinMode (analogPin1, INPUT);
}

void loop(){
  val1 = analogRead(analogPin1);

  Serial.println(val1);             
  delay (100);
  
  if (analogRead(analogPin1) < 300){
    digitalWrite(LEDpin6, HIGH);
  }
  
  if (digitalRead(LEDpin6) == LOW){
    setPinHigh = true;
    startTime = millis();
  }
  else{
    setPinHigh = false;
  }
  
  if(setPinHigh && millis() - startTime < onTime){
    digitalWrite(LEDpin6, HIGH);
    setPinHigh = true;
  }
  else{
    digitalWrite(LEDpin6, LOW);
    setPinHigh = false;

  }
}
  if (digitalRead(LEDpin6) == LOW){

You are reading from the LED pin? The one you set as an OUTPUT?

PaulS:

  if (digitalRead(LEDpin6) == LOW){

You are reading from the LED pin? The one you set as an OUTPUT?

ah good point. i moved it round so it looks like this but now it doesn't blink, it just stays on or off constantly

int analogPin1 = 1;     // read photo resitor analog pin 1
int LEDpin6 = 6;          // LED controlled by pin6
int val1 = 0;           // variable to store the value read

bool setPinHigh = false;
unsigned long startTime = 0;
unsigned long onTime = 1000;

void setup(){
  Serial.begin(9600);          
  pinMode (LEDpin6, OUTPUT);
  pinMode (analogPin1, INPUT);
}

void loop(){
  val1 = analogRead(analogPin1);

  Serial.println(val1);             
  delay (100);
  
  if (analogRead(analogPin1) > 300){
    digitalWrite(LEDpin6, HIGH);
    setPinHigh = true;
    startTime = millis();
    }
    else{
    setPinHigh = false;
  }
  
  if(setPinHigh && millis() - startTime < onTime){
    digitalWrite(LEDpin6, HIGH);
    setPinHigh = true;
  }
  else{
    digitalWrite(LEDpin6, LOW);
    setPinHigh = false;

  }
}
  val1 = analogRead(analogPin1);

  Serial.println(val1);             
  delay (100);
  
  if (analogRead(analogPin1) > 300){

Was there something wrong with the first, known, reading?

As a new programmer, you should be putting the { on a new line, and using Tools + Autoformat to line your code up properly. It's much easier to see program flow when the { and } line up, and everything is properly indented.

Look at your code. What happens if the reading is over 300? setPinHigh is set to true and "now" is recorded.

Then, what happens? The state of setPinHigh is checked (true) and the time that the LED should have been on is tested. The LED has not been on for that long, so it is turned on.

Then, what happens? Loop ends, and the process starts over. The reading is still over 300, so the on time is reset.

You need to keep track of the previous value, and reset startTime only if the current reading is above the threshold and the previous reading was not.

You need something more like this:

int analogPin1 = 1;     // read photo resitor analog pin 1
int LEDpin6 = 6;          // LED controlled by pin6

int currVal = 0;
int prevVal = 0;
bool setPinHigh = false;
unsigned long startTime = 0;
unsigned long onTime = 1000;

void setup()
{
  Serial.begin(9600);          
  pinMode (LEDpin6, OUTPUT);
  pinMode (analogPin1, INPUT);
}

void loop()
{
  currVal = analogRead(analogPin1);
  if(currVal > 300 && prevVal <= 300)
  {
    digitalWrite(LEDpin6, HIGH);
    setPinHigh = true;
    startTime = millis();
  }
  else
  {
    setPinHigh = false;
  }

  if(setPinHigh && millis() - startTime < onTime)
  {
    digitalWrite(LEDpin6, HIGH);
  }
  else
  {
    digitalWrite(LEDpin6, LOW);
    setPinHigh = false;
  }

  prevVal = currVal;
}

Wow, thank you so much. That's brilliant.

Few quick questions if you have the time about what you did in order to build on it.

Quite a simple thing would be what if I wanted to adjust the blink so it was for say 3 seconds, not just 1?
I would presume that it would be a case of editing this value "unsigned long onTime = 1000;" but having tried that it did not work. I have looked elsewhere in the code and cannot think what else would need changing to make this relevant?

Also, building on that further, what if I say wanted to make the LED blink once when <300 and once also when >300?
Is that complicated?

Thanks again PaulS.

Quite a simple thing would be what if I wanted to adjust the blink so it was for say 3 seconds, not just 1?
I would presume that it would be a case of editing this value "unsigned long onTime = 1000;" but having tried that it did not work.

That is the only change required. What happened when you changed the value of onTime? How did you change it? "That did not work" leaves about a bazillion possibilities. Perhaps you could narrow it down a little. Otherwise, we'll blame it on the solar flares.

Also, building on that further, what if I say wanted to make the LED blink once when <300 and once also when >300?
Is that complicated?

You mean once when the transition to 300+ occurs and once when the transition to 300- occurs?
This code:

  if(currVal > 300 && prevVal <= 300)
  {
    digitalWrite(LEDpin6, HIGH);
    setPinHigh = true;
    startTime = millis();
  }
  else
  {
    setPinHigh = false;
  }

handles the first transition. Change

if(currVal > 300 && prevVal <= 300)

to

if((currVal > 300 && prevVal <= 300) || (currVal <= 300 && prevVal > 300))