How do I loop within this loop?

I’m trying to detect motion and make LEDs light up as a heartbeat with a “startup” tone only at the beginning of the initial detection loop. If there is continual movement detected, the heartbeat should continue but the startup tone should only sound at the beginning of that “session” if you will, not every cycle. I chopped a couple of sketches together to get to my current point. I have commented the area that needs to be looped to.

The only programming experience I have is Basic on a Trash80 and recently openSCAD. I keep wanting to use if/then go/to for this problem. :confused:

edit: this is with an arduino UNO

sorry. here’s the sketch:

/* 
 * //////////////////////////////////////////////////
 * //making sense of the Parallax PIR sensor's output
 * //////////////////////////////////////////////////
 *
 * Switches a LED according to the state of the sensors output pin.
 * Determines the beginning and end of continuous motion sequences.
 *
 * @author: Kristian Gohlke / krigoo (_) gmail (_) com / http://krx.at
 * @date:   3. September 2006 
 *
 * kr1 (cleft) 2006 
 * released under a creative commons "Attribution-NonCommercial-ShareAlike 2.0" license
 * http://creativecommons.org/licenses/by-nc-sa/2.0/de/
 *
 *
 * The Parallax PIR Sensor is an easy to use digital infrared motion sensor module. 
 * (http://www.parallax.com/detail.asp?product_id=555-28027)
 *
 * The sensor's output pin goes to HIGH if motion is present.
 * However, even if motion is present it goes to LOW from time to time, 
 * which might give the impression no motion is present. 
 * This program deals with this issue by ignoring LOW-phases shorter than a given time, 
 * assuming continuous motion is present during these phases.
 *  
 */

 #include <toneAC.h>

/////////////////////////////
//VARS
//the time we give the sensor to calibrate (10-60 secs according to the datasheet)
int calibrationTime = 30;        

//the time when the sensor outputs a low impulse
long unsigned int lowIn;         

//the amount of milliseconds the sensor has to be low 
//before we assume all motion has stopped
long unsigned int pause = 5000;  

boolean lockLow = true;
boolean takeLowTime;  


int pirPin = 3;    //the digital pin connected to the PIR sensor's output
int LEDpin1 = 13;
int LEDpin2 = 12;


int i = 0;
int pmw = 255;  //set PWM max - this can differ for other board pins
int rate = 35;  //this is the beats per minute (60000 ms)
               //because there are two beats to simulate the 'lub-dub' of the heart,
               // a 60 beat heart rate is only a value of 30 in the rate variable
               //the delay is the key to this programs realism - divide the rate into a minute, then weight it and divide by the pmw
               //you can modify the weight by changing the fractions (i.e. .1, .2, .6) but to keep the timing correct, they should total 1
               //.1+.2+.1+.6 = 1


/////////////////////////////
//SETUP
void setup(){
  Serial.begin(9600);
  pinMode(pirPin, INPUT);
  pinMode(LEDpin1, OUTPUT);
  pinMode(LEDpin2, OUTPUT);
  digitalWrite(pirPin, LOW);

  //give the sensor some time to calibrate
  Serial.print("calibrating sensor ");
    for(int i = 0; i < calibrationTime; i++){
      Serial.print(".");
      delay(1000);
      }
    Serial.println(" done");
    Serial.println("SENSOR ACTIVE");
    delay(50);
  }

////////////////////////////
//LOOP
void loop(){

     if(digitalRead(pirPin) == HIGH){
       
       
for (long unsigned freq = 125; freq <= 15000; freq += 10) {  
    toneAC(freq); // Play the frequency (125 Hz to 15 kHz sweep in 10 Hz steps).
    delay(1);     // Wait 1 ms so you can hear it.
  }
  toneAC(); // Turn off toneAC, can also use noToneAC().

  delay(500); // Wait a second.

// need something here for loop within loop?

  digitalWrite(LEDpin1, HIGH);   //the led visualizes the sensors output pin state

    
 for(i = 0; i < pmw; i++) {
   analogWrite(LEDpin1,i);
   delay(((60000/rate)*.1)/pmw);
 }
 
 for (i = pmw; i > 0; i--){
   analogWrite(LEDpin1,i);
   delay(((60000/rate)*.2)/pmw);
 }
 
   for(i = 0; i < pmw; i++) {
   analogWrite(LEDpin2,i);
   delay(((60000/rate)*.1)/pmw);
 }
 
 for (i = pmw; i > 0; i--){
   analogWrite(LEDpin2,i);
   delay(((60000/rate)*.6)/pmw);
 }
 
       
       
       if(lockLow){  
         //makes sure we wait for a transition to LOW before any further output is made:
         lockLow = false;            
         Serial.println("---");
         Serial.print("motion detected at ");
         Serial.print(millis()/1000);
         Serial.println(" sec"); 
         delay(50);
         }         
         takeLowTime = true;
       

     if(digitalRead(pirPin) == LOW){       
       digitalWrite(LEDpin1, LOW);  //the led visualizes the sensors output pin state

       if(takeLowTime){
        lowIn = millis();          //save the time of the transition from high to LOW
        takeLowTime = false;       //make sure this is only done at the start of a LOW phase
        }
       //if the sensor is low for more than the given pause, 
       //we assume that no more motion is going to happen
       if(!lockLow && millis() - lowIn > pause){  
           //makes sure this block of code is only executed again after 
           //a new motion sequence has been detected
           lockLow = true;                        
           Serial.print("motion ended at ");      //output
           Serial.print((millis() - pause)/1000);
           Serial.println(" sec");
           delay(50);
         
           }
       }}}

Sounds like a state machine. You have an "idle/waiting" state, followed by a "startup" state, followed by "wait a second" (which only takes 500ms), followed by a "normal heartbeat" state. Depending on the values you read from the PIR and elapsed time, you will move from one state to the other.

Here's a useful tutorial from one of the other forum members: State Machine

I'm just getting ready for work so I haven't had / can't have a deep look at your sketch, but I think the problem is you're basing things on the pir pin being high, not having just gone high: MorgansS's idea of a state machine is good for taking care of that.

Specifically though, I wonder if you've seen this example sketch at adafruit?

As you'll see from the lines it prints to the monitor, it knows that the pir has just triggered: "Motion detected", where it sees the pin is high and the state has just changed. But, the led is on as long as the pin is high.

So strikes me (caveat: as I said, not had/having a deep look) that your siren should sound where they have the "Motion detected" message (new motion) but the heartbeat should be going wherever the led is on (pir still triggered).

(You should look at BlinkWithoutDelay for your heartbeat as well. I would go for a simple on/off heartbeat to start with, adding the lub-dub later.)

Thanks for the suggestions thus far. I'll attack it some more tomorrow and may have further questions.

PS, I often have a (simple) heartbeat going, just to show the skecth is running when there might be no other visible sign of life. It uses the blink without delay approach, so doesn't get in the way of anything else.

I do this:

byte heartBeatPin = 13;
unsigned long currentMillis;
unsigned long previousMillisHeartBeat = 0;
int heartBeatInterval = 500;
bool heartBeatStatus = false;

void setup()
{
  pinMode(heartBeatPin, OUTPUT);
}

void loop() {
  currentMillis = millis();
  heartBeat();
}

void heartBeat()
{

  if (currentMillis - previousMillisHeartBeat >= heartBeatInterval)
  {
    heartBeatStatus = !heartBeatStatus;
    digitalWrite(heartBeatPin, heartBeatStatus);
    previousMillisHeartBeat = currentMillis;
  }

}