turn 3 LED in sequence waiting 1 sec. between each while checking conditions

Hi everyone, thanks for reading. (my english may not be the best, I'm sorry about that).

The project I'm working on consist in turning on 3 LED, one after every second a person is blowing through a flexible pipe.
I'm using a IR emitter and receiver for checking the movement of an helix that spins with the air blown through the tube. Everytime I get a difference in the IR signal (from continuous to interrupted and viceversa) I count a 'revolution'. Once one revolution is detected, I check if one second passed, once it has, I check if there are a minimum of revolutions (so I can assure there's been a constant blowing through the pipe) and if there are, I turn on the first LED.

I want to count three seconds continuously and turn one LED every second of constant blowing.

My problem is that after the first LED is lit, I want to check the next second and if I still get the minimum of revolutions within that second, turn the second LED on. The same with the third led in the third second.

I get the first LED turned on after 1000millis and at least 10 revolutions, but the other 2 turn on really quick and there is no 1 second waiting time.

I'm not very good at programming so I feel I may be using silly code in some parts, if you have any suggestions on how I could optimize some parts of the code It would be great.

Thank you in advance,
Natalia.

My code, i deleted the commented lines for debugging so its quickier to read.

const int sensorPin=A0;
const int ledApin=4;    // if I put it in 1, it would be turned on all the time even if i set the LED to LOW.
const int ledBpin=2;
const int ledCpin=3;

int irCommStatus; // 0 for continuous IR beam (sensor values under 100). 1 for interrupted IRbeam (100+).
int prevIrCommStatus; // stores the previous value
int revolutions = 0; // counts how many changes in irCommStatus have been.
int currentLED = 0;  //id for showing which led is turned on

long previousMillis =0; // store the last time this was used
long interval = 1000;  // is 1 second, but this sketch has a delay of 2millis. so idk if I should change it.

void setup()
{
  pinMode(sensorPin,INPUT);
  pinMode(ledApin,OUTPUT);
  pinMode(ledBpin,OUTPUT);
  pinMode(ledCpin,OUTPUT);
  Serial.begin(9600);
}

void loop(){

  int sensorVal=analogRead(sensorPin);
  prevIrCommStatus = irCommStatus;          // before refreshing the var val, store the previous value. 

  if (sensorVal< 70){  
    irCommStatus = 0;
  } else if(sensorVal > 100){
    irCommStatus = 1;
  }

  if (prevIrCommStatus != irCommStatus){
    revolutions++;                                      // we asumme the helix spinned and we add 1 revolution. 
  }                                                            // everything works perfect until here.

 
if (revolutions > 1){                                  //if there is at least one revolution, I start to count the time.
 
  unsigned long currentMillis = millis();       //taken from blink without delay example

  if (currentMillis - previousMillis > interval) { //check if the last time was longer ago than the interval
     
   if (revolutions > 10){                                // if there is at least 10 revolutions 
     
      switch(currentLED){                              // I turn the LED on according to the currentLED var
        case 0:
        digitalWrite(ledApin, HIGH);      
        revolutions =1;                                   // I do not set it to 0 because I have to check the three seconds continously
        break;                                                // and It would have to wait to another revolution to start counting again
        case 1:
        digitalWrite(ledBpin,HIGH);
        revolutions =1;
        break;
        case 2:
        digitalWrite(ledCpin,HIGH);
        revolutions =1;
        break;
        case 3:
        currentLED =0;                                   // this turns off my 3 leds, not sure why. I just wanted to reset the counter
                                                                 // because It'd go to infinite.
      }
     

       previousMillis = currentMillis;               //set last time as the current time

  //     currentLED++;                                 // this was what I was trying to set the LEDcounter one forward
       
       } else if (revolutions < 10) {                //if there are less than 10 revolutions per second in any of the seconds
       digitalWrite(ledApin, LOW);                  // turn off all the LEDs
       digitalWrite(ledBpin, LOW);
       digitalWrite(ledCpin, LOW);
              revolutions=0;                             
       previousMillis = currentMillis;
       }
  }
  
}


  delay(2);          // this delay works better than 1 or higher for reading my sensors.
}

THANKS!!!!!

using CTRL-T in your IDE reformats the code

Try this variation, I have not tested it if it behaves like you want

const int sensorPin = A0;
const int ledApin = 4; 
const int ledBpin = 2;
const int ledCpin = 3;

int irCommStatus = 0;       // 0 for continuous IR beam (sensor values under 70). 1 for interrupted IRbeam (100+).
int prevIrCommStatus = 0;   // stores the previous value
int revolutions = 0;    // counts how many changes in irCommStatus in last second
int currentLED = 0;     // id for showing which led is turned on

unsigned long previousMillis = 0;         // store the last time this was used
const unsigned long interval = 1000;      // is 1 second, but this sketch has a delay of 2millis. so idk if I should change it.
const int MinimumRevolutions = 10;

void setup()
{
  pinMode(sensorPin, INPUT);
  pinMode(ledApin, OUTPUT);
  pinMode(ledBpin, OUTPUT);
  pinMode(ledCpin, OUTPUT);

  Serial.begin(9600);

}


void loop()
{
  // CHECK FOR PULSE
  int sensorVal = analogRead(sensorPin);
  prevIrCommStatus = irCommStatus;          // before refreshing the var val, store the previous value.

  if (sensorVal < 70) {
    irCommStatus = 0;
  } else if (sensorVal > 100) {
    irCommStatus = 1;
  }


  // PULSE DETECTED => COUNT
  if (prevIrCommStatus != irCommStatus)
  {
    if (revolutions == 0) previousMillis = millis();   // start measure time with first revolution.
    revolutions++;
  }

  // IF A SECOND AFTER FIRST PULSE HAS PASSED
  // WE CHECK IF WE HAVE TEN OR MORE IN LAST SECOND
  if (millis() - previousMillis >= interval)
  {
    // if not enough revolutions reset the system
    if (revolutions < MinimumRevolutions)
    {
      currentLED = 0;                               //  if (currentLED > 0) currentLED--; 
    }
    else  // increase number of LEDS
    {
      if (currentLED < 3) currentLED++;      // 3 == MaxLEDs 
    }
    revolutions = 0;  // reset counter for next second
  }
  

  // DISPLAY NUMBER OF LEDS
  digitalWrite(ledApin, currentLED >= 1);   // true == HIGH  false == LOW
  digitalWrite(ledBpin, currentLED >= 2);
  digitalWrite(ledCpin, currentLED >= 3);

  delay(2);  // needed?
}

Thank you, I tried your code and it does not work. Now after 1 second the 1st led turns on and in way less than a second it turns off. afterwards no other led is turned on nor even the 1st one.

I'm still trying to make it work, so if anybody else has an opinion or at least an idea how to structure the code correctly it would be amazingly appreciated.

thanks!!

I don't think this line should be in a previous "if" try moving it to its own line after before the
if (prevIrCommStatus != irCommStatus) closed brakets and see if that works (after would be a 50/50 as the line before it could make counter=1 before it executes)

if (revolutions == 0) previousMillis = millis();

my thinking is that when revolution==0 for a split second the prevIrCommStatus != irCommStatus was in a failed state so previousMillis never got updated thus it automatically passed the next timer test.

I DID IT!. i wrote the program all over again using a slightly different structure and it worked perfectly. (in the code pasted below I shortened the time interval because i was tired of blowing all the time).

Now I'm working on 2 things:

  • turn off the LEDs and restart all conditions if you stop blowing at 1st or 2nd second. (at third when you complete it is solved). because of the structure of this new code is not that simple as checking if there are not enough revolutions.

  • SPLIT each second in chunks and check if there is at least one revolution in each. this is because if i stop blowing before a second finishes, but i already made 10 revolutions, the LED will turn on anyway. I need the people to keep blowing during all the process. Now that I realize this i think it would be better to use a kind of piezo or something to check the blowing itself instead of the helix, but whatever... i need to make it work at least for testing in few time, aftrwards i will change the system to something that actually measures the blowing.

now, the code which i solved for this post issue.

const int sensorPin = A0;
const int ledApin = 4; 
const int ledBpin = 2;
const int ledCpin = 3;

int irCommStatus = 0;       // 0 for continuous IR beam (sensor values under 70). 1 for interrupted IRbeam (100+).
int prevIrCommStatus = 0;   // stores the previous value
int revolutions = 0;    // counts how many changes in irCommStatus in last second
int prevRevolutions;
int currentLED = 0;     // id for showing which led is turned on

int sensorVal;

unsigned long previousMillis = 0;         // store the last time this was used
const unsigned long interval = 500;      // is 1 second, but this sketch has a delay of 2millis. so idk if I should change it.
const int MinimumRevolutions = 10;

void setup()
{
  pinMode(sensorPin, INPUT);
  pinMode(ledApin, OUTPUT);
  pinMode(ledBpin, OUTPUT);
  pinMode(ledCpin, OUTPUT);

  Serial.begin(9600);

}

void loop(){

  sensorVal = analogRead(sensorPin);
  prevIrCommStatus = irCommStatus;

  //CHECK FOR PULSE 
  if (sensorVal < 70) {
    irCommStatus = 0; 
  }
  else if (sensorVal > 100) {
    irCommStatus = 1; 
  }
  //IF A PULSE IS DETECTED, INCREASE REVOLUTIONS
  if (prevIrCommStatus != irCommStatus){
    revolutions+= 1;
  }
  ///// done with detection phase.


  //IF THERE IS AT LEAST ONE REVOLUTION 
  if (revolutions >= 1){
    // START COUNTING TIME
    unsigned long currentMillis = millis();          
    //IF A SECOND HAS PASSED  
    if (currentMillis - previousMillis >= interval){ 
      //AND THERE IS AT LEAST TEN REVOLUTIONS, INCREASE LED ID.
      if (revolutions > 10){
        currentLED += 1;
      } 

      // turn on LEDs according to the LED ID set.
      switch(currentLED){
      case 1:
        digitalWrite(ledApin, HIGH);
        revolutions =1;
        previousMillis=currentMillis;
        break;
      case 2:
        digitalWrite(ledApin, HIGH);
        digitalWrite(ledBpin, HIGH);
        revolutions =1;
        previousMillis=currentMillis;
        break;
      case 3:
        digitalWrite(ledApin, HIGH);
        digitalWrite(ledBpin, HIGH);
        digitalWrite(ledCpin, HIGH);
        delay(1500);
        digitalWrite(ledApin, LOW);
        digitalWrite(ledBpin, LOW);
        digitalWrite(ledCpin, LOW);      
        revolutions =0;
        previousMillis=currentMillis;
        currentLED=0;
        break;
      }
    }
  } 

  Serial.println(sensorVal);

  delay(2); 
}