Blink W/O delay with a TWIST

Hello everyone, I am working on a project that I have to NOT USE DELAY I picked Blink W/O delay as a starting point. (Because millis is new to me) However, I will be using a PIR as a trigger. The PIR has (2) pots on it. One is to adjust the sensitivity (Distance), and the other is to adjust the length of time the PIR puts out a digital signal when someone walks by. That's anywhere from 2 seconds to give or take 3 minutes. Which makes this even more complex. The project is battery powered. So instead of the PIR signal outputting for 3 minutes, I would simply like to use it a a "Trigger", meaning a 2 second HIGH OUTPUT from the PIR would allow me to BLINK the LED for as long as I like. I am in hope that someone can walk me through the correct process to accomplish this task, Thanks in advance. It still blinks, but not on the basis of the PIR signal.

/*
  Blink without Delay

  Turns on and off a light emitting diode (LED) connected to a digital pin,
  without using the delay() function. This means that other code can run at the
  same time without being interrupted by the LED code.

  The circuit:
  - Use the onboard LED.
  - Note: Most Arduinos have an on-board LED you can control. On the UNO, MEGA
    and ZERO it is attached to digital pin 13, on MKR1000 on pin 6. LED_BUILTIN
    is set to the correct LED pin independent of which board is used.
    If you want to know what pin the on-board LED is connected to on your
    Arduino model, check the Technical Specs of your board at:
    https://www.arduino.cc/en/Main/Products

  created 2005
  by David A. Mellis
  modified 8 Feb 2010
  by Paul Stoffregen
  modified 11 Nov 2013
  by Scott Fitzgerald
  modified 9 Jan 2017
  by Arturo Guadalupi

  This example code is in the public domain.

  https://www.arduino.cc/en/Tutorial/BuiltInExamples/BlinkWithoutDelay
*/

// constants won't change. Used here to set a pin number:
const int ledPin =  LED_BUILTIN;// the number of the LED pin
const int PIR_PWR = 7;
const int PIR_READ = 12;

int val = 0;

// Variables will change:
int ledState = LOW;             // ledState used to set the LED

// Generally, you should use "unsigned long" for variables that hold time
// The value will quickly become too large for an int to store
unsigned long previousMillis = 0;        // will store last time LED was updated

// constants won't change:
const long interval = 1000;           // interval at which to blink (milliseconds)

void setup() {
  // set the digital pin as output:
  pinMode (ledPin, OUTPUT);
  pinMode (PIR_PWR, OUTPUT);
  pinMode (PIR_READ, INPUT);
}

void loop() {

  digitalWrite (PIR_PWR, HIGH);
  val = digitalRead (PIR_READ);   // read the input pin
  digitalWrite (ledState, val);





  // here is where you'd put code that needs to be running all the time.

  // check to see if it's time to blink the LED; that is, if the difference
  // between the current time and last time you blinked the LED is bigger than
  // the interval at which you want to blink the LED.
  unsigned long currentMillis = millis();

  
  //if (val = digitalRead (PIR_READ);   // read the input pin
  //    digitalWrite (ledState, val));

  if (currentMillis - previousMillis >= interval) {
    // save the last time you blinked the LED
    previousMillis = currentMillis;

    // if the LED is off turn it on and vice-versa:


    if (ledState == LOW) {
      ledState = HIGH;
    } else {
      ledState = LOW;
    }

    // set the LED with the ledState of the variable:
    digitalWrite(ledPin, ledState);
  }
}

Are we allowed to know how long that might be, and what conditions affect your whim?

You could prefix the "if (currentMillis" test with a simple Boolean "blinking" flag and a logical AND.

In that case you need to detect when the PIR output changes from LOW to HIGH and start your timer at that moment. Take a look at the "state change" example sketch.

But what does that mean? Make each individual blink as long as you want, or blink over and over during a total time?

In another thread that you started you described
You can take me out to the garage and "SHOW ME" how to do it, and in a day or 2, I'll be as good if not better than you. I have to "SEE IT" to understand it. It's how "I" process stuff.

OK how about SEEING examples as ready to run code
to learn from them?
There are a number of very basic things like using curly braces to put together multiple lines of code to be executed only in case of .....
etc.
etc.

You will start to understand the descriptions given in the above postings.

You will need only half of very specialised codes to learn it if you have worked through
this tutorial.

Arduino Programming Course

It is easy to understand and has a good mixture between explaining important concepts and example-codes to get you going. So give it a try and report your opinion about this tutorial.

best regards Stefan

Maybe. But be careful. I stopped looking at this after reading

It is important to have the loop() function in the sketch, even if it is empty, because without it the microcontroller on the Arduino board will try to execute whatever it finds next in memory after the statements in the setup() function have been executed. The microcontroller will try to execute whatever it finds in memory as an instruction, but the loop() function prevents it from doing this by keeping program execution in the loop.


I understand the need to simplify and even lie sometimes, but if this level of nonsense finds much voice in that material, be prepared to be wrong if you assert stuff you "learned" there.

a7

As written, this is complete nonsense:

It is important to have the loop() function in the sketch, even if it is empty, because without it the microcontroller on the Arduino board will try to execute whatever it finds next in memory after the statements in the setup() function have been executed. The microcontroller will try to execute whatever it finds in memory as an instruction, but the loop() function prevents it from doing this by keeping program execution in the loop.

Without a loop() function Arduino code will not even compile. Therefore, there's no way the "microcontroller on the Arduino board will try to execute whatever it finds next in memory after the statements in the setup() function have been executed ..." because you will not have loaded the non-compiled code on to it.

Hello Fredric58

I come back to the technique.

There are two ways to realise the project:

  1. controlling the timer with a variable, which has already been mentioned.

  2. controlling the blinking event with a variable:

digitalWrite(ledPin, ledState and pirEvent);

Have a nice day and enjoy coding in C++.

Thank you, I'll study up on state change. Actually I didn't think the question through all the way. My interest is in using millis was correct. I am not actually going to BLINK an LED. What I need to do is a servo.write 10 (degrees) delay for say (10). The catch is there a 15 different positions the servo will move to and between each, call it a sweep there are different delays. It actually works but I was told it was a wasteful way to do it. small sample attached. So in other words, I need to trigger the servo.write from the PIR (which will work with delay as it blocks the fact that the servo signal went low) and then I need to get rid of the delays and use millis. Hope that makes more sense.

This part works for a LED as long as the PIR signal is set for (2 sec - 3 mins)

  digitalWrite (POWER_PIR, HIGH);
  delay(30);  //to stabilize
  val = digitalRead (PIR_SIGNAL);   // read the input pin
  digitalWrite (LED, val);

This part I am having problems with

val = digitalRead (PIR_SIGNAL);   // read the input pin
  if ( val )
  
  {servo1.write(0);
  delay(100);
  servo1.write(180);

This example is what I was told was the WRONG way to do it even though it will work. Still have a problem with the "trigger" part.

  servo1.write(0);
  delay(1000);
  servo1.write(10);
  delay(2000);
  servo1.write(20);
  delay(1000);
  servo1.write(30);
  delay(250);
  servo1.write(40);
  delay(250);
  servo1.write(30);
  delay(100);
  servo1.write(40);

Why did you start a second topic for this when a solution had already been posted in your other topic ?

The section quoted by @alto777 is complete nonsense, see my Post #8. So, given that the tutorial contains such an obvious and glaring section of nonsense, it's not unreasonable to assume that it contains others.

To come back on the TO's questions:

I describe in my own words with the request to confirm or correct my understanding of what the code shall do:
If PIR-sensor detects a movement start a sequence of servo-moves.

  1. PIR detects a movement servo-horn turns from position 0 degrees to position 10 degrees
  2. servo stays at position 10 degrees for 10 seconds
  3. servo moves from position 10 degrees to position 20 degrees
  4. servo stays at position 20 degress for 10 seconds
  5. servo moves from position 20 degrees to position 30 degrees
  6. servo stays at position 30 degress for 10 seconds
    etc. etc.
    until
    n. servo moves from position 140 degrees to position 150 degrees
    n + 1. servo stays at position 150 degress for 10 seconds

then turns back to position 0 degrees?

@Fredric58 you should confirm or correct this description.
If you correct it do it in a very similar way. Describing the whole thing in such small steps
takes 10 minutes but will speed up finishing the project minimum 10 hours earlier

best regards Stefan

From the other topic

So..... If you have a moment please expand upon this WITHOUT DELAY, per say possibly an example, And lets use the following because it's only 8 of my 60 lines long. If you say it can be done, I believe you. However, finding a tutorial that addresses this specific situation is damn near impossible, well....... it actually is impossible. different degrees with different delays.

  servo1.write(10);  //degrees
  delay(250);
  servo1.write(0);
  delay(50);
  servo1.write(30);
  delay(1000);
  servo1.write(45);
  delay(2000);

Note, however, that the requirement seems to change in different posts in that topic

See also my example code to meet the requirement, also in the other topic

struct phaseDataLayout
{
    byte angle;
    int period;
};

phaseDataLayout phaseData[4] = {
    { 10, 250 },
    { 0, 50 },
    { 30, 1000 },
    { 45, 2000 }
};

const byte phaseCount = sizeof(phaseData) / sizeof(phaseData[0]);

void setup()
{
    Serial.begin(115200);
}

void loop()
{
    unsigned long currentTime = millis();
    static unsigned long phaseStart = currentTime;
    static byte phase = 0;
    Serial.print("phase number ");
    Serial.print(phase);
    Serial.print("  angle = ");
    Serial.println(phaseData[phase].angle);
    if (currentTime - phaseStart >= phaseData[phase].period)
    {
        phase += 1;
        phase = phase % phaseCount;
        phaseStart = currentTime;
    }
}

I am reluctant to merge the two topics as the other one is already very confusing so I have closed it and posted a link to this one

So user @Fredric58
post a functional description as clear as you can and as detailed as you can.

This assuming might be wrong. If it is wrong I apologise for having suspected it
user @Fredric58 if you hoped for by writing unclear descriptions to get ready to use code I will never post ready to use code.

again
user @Fredric58
post a functional description as clear as you can and as detailed as you can.

best regards Stefan

That's a Sisyphean task, and one I'm not up for.

I'll stick with ignoring them/ calling them out if I see a single stupid statement.

Well thank you and sorry to piss anybody off. or be redundant, to have multiple posts on the same topic.

DESCRIPTION:

Bare bones Atmega 328P w/ 16Mhz crystal and caps, 5v supply

It "sleeps" all day, it "wakes" up at night by monitoring a LDR & 56K divider with a threshold of 200. Uses POWER_DOWN_MODE, I can do it with or without using a library.

WHEN it wakes up the first thing it does is power a PIR directly from the 328P, the PIR remains ON till it goes back to sleep.

When the PIR is activated (senses a person walking by) a digitalRead is used to send 5v from another pin of the 328P. to (2 MOSFETS) a N channel and a P channel LL MOSFETs used as an inverted High Side switch. Which turns on (2) separate devices. It sends power to a servo and a sound board. Separate 6v power supply. As long as the PIR output signal is HIGH both devices remain ON. The sound board is triggered by setting 1 of 10 pins to GND. The channel/pin on the sound board I use is hard wired to GND. so when the sound board is turn on, It starts talking immediately. It could probably be done differently but it works. It is an Adafruit FX stereo Sound Board

Then things go down hill.......

The SERVO (SG90 Micro servo) is also ON but won't do anything until the servo.write is implemented/called. Which should start about the same time the sound board starts talking. The servo makes 15 sweeps (+ - ) with different angles and delays between each sweep. And YES BOB, I'M WORKING ON IT, it's COMPLICATED. (there is still 15, call them presets, but the loop is much more simplified) Both servo and sound board run for about 18 seconds, those 18 seconds are controlled right now by the timer on the PIR (The HIGH going to the digitalRead). It has a range (approx) of anywhere between 2 seconds and 3 minutes. Right now it is set to 18 seconds. I would prefer to use only 2 seconds as a trigger, vs it outputting for 18 seconds each time it is triggered because I think that would be less power usage?

In a nut shell, if it is dark, and you walk by, sound goes on and servo wags for 18 seconds then it stops till the next person walks by only when it is dark.

I can complete all of these tasks on an individual basis, even though the way I go about some of them has been labeled a joke. I can make it all happen. It is combining them in their entirety and in the correct manner which is the challenge.

If for any reason this description isn't concise, please ask another question and I will edit the post with a clarification before going any further.

Thank you, and again my apologies.

OK. Things become clearer now.
From your description

I would conclude that you have a medium knowledge about programming.

If I add these sentences:

This is wrong.
A digitalRead() does not send out.
A digitalRead() does read in

So this means your description is either too short because you use a digitalRead() to initiate a digitalWrite ()

Or your are lazy in the description or you did not yet understand what digitalRead() / digitalWrite() are

I conclude that you made all your former projects by copy & paste and maybe adjusting some numbers but never changed the basic functionality of a given code.
And more important that your knowledge about programming is rather rudementary than medium advanced.

Now IMHO there are two ways to proceed

  1. a slow proceeding way
  2. a fast proceedig way

the slow proceeding way is to go on to refuse taking 6 hours of your preciuos time to really learn the basics about programming but instead
going on tinkering around trying this, trying that based on guessings and doing this each day 6 hours for weeks and months.

the fast proceeding way is
to take 6 hours of your precious time and to really learn the basics of programming by working through a tutorial

You may think uh 6 hours not working on my project and spending time on different code
YES! After having learned the basics and then going back to your code things will proceed much faster because you know how to code it.
At least most of it and the details that do not work yet you can ask by very specific questions in the forum getting directly answers instead of thhree rounds asking back.

So as a first step.
Stop describing

start describing in the most detailed way you can think of and concentrate on the functionality.

I write the beginning:
If it is dark enough so your LDR-voltage-divider goes above the theshold-value of 200
your barebone Atmega 328P wakes up from POWER_DOWN_MODE and starts running the code

Your code switches Power on of the PIR-sensor. Your PIR-sensor is directly powered from an IO-pin.

If your PIR is detecing a person the PIR's output switches from LOW to HIGH.
This PIR-output is connected to an IO-pin.

The code "waits" for the "PIR-motion-detected-signal"

If motion is detected the code shall do two things:

  1. switch on power of a RC-servo type MG90
  2. switch on power of the Adafruit FX stereo Sound Board

The questions start here

What changes that shall initiate the 15 servo-sweeps????
post for each and every of the 15 servo-sweeps the numbers how the servo-sweeps shall look like

  • what angle?
  • what waiting time?
  • what sweeping speed?

Soundboard and servo shall be active for 18 seconds and both shall be switched off = power off after 18 seconds.

So answer the questions above and start
working through this tutorial:

Arduino Programming Course

It is easy to understand and has a good mixture between explaining important concepts and example-codes to get you going. So give it a try and report your opinion about this tutorial.

best regards Stefan

A piece of code that works is one thing, UNDERSTANDING WHY IT WORKS is what I am looking for.
Ready to use code? Yes, it spins on the serial monitor, NO PROBLEM. Lets dive deeper into the existing code you already presented. And take a HUGE step backwards to when YOU didn't understand it. By a search I came to this. Does any of this apply to your code? If it does it would be helpful to know where to draw the lines between the parts.

Data Base Development Lifecycle

  1. Requirements analysis
  2. Logical design
    3.Physical design
    4 Implementation
  3. Monitoring, Modification and Maintenance

I've deleted some replies that were getting a bit rude. Keep it polite please and stick to answering the OP's question.

Note I have not considered whether the Arduino course linked to is or is not appropriate or accurate, I have only considered the rudeness of some of the comments.

No sanctions in case you are wondering.

The list that you posted specifically applies to database design. My process was as follows

  1. Requirements analysis - you provided the requirements
  2. Logical design - the use of an array of structs had already been suggested and it fits the bill to meet the requirements
  3. Implementation - I wrote the code in stages testing as I added functionality
  4. Testing the full solution - as some of the required time periods were short I tested with much longer periods as they are easier to monitor
  5. Final testing - periods were changed to meet the requirement
  6. User testing - I posted the code for you to test and give feedback

Here is a copy of my example with comments added for your delectation and delight

struct phaseDataLayout      //a struct layout to hold required data
{
    byte angle;         //the angle that the servo will turn to
    int period;         //the period in milliseconds to remain at that angle
};

phaseDataLayout phaseData[4] = {    //an array of 4 copies of the data layout
    { 10, 250 },                    //4 lines of pairs of data, one for each phase of operation
    { 0, 50 },
    { 30, 1000 },
    { 45, 2000 }
};

const byte phaseCount = sizeof(phaseData) / sizeof(phaseData[0]);   //calculate the number of phases in the array
                                                                    //allows extra phases to be added without code changes

void setup()
{
    Serial.begin(115200);
}

void loop()
{
    unsigned long currentTime = millis();                       //the current millis() value
    static unsigned long phaseStart = currentTime;              //the time that the current phase started.  
                                                                //the static declaration allows the variable to be reused
    static byte phase = 0;                                      //the current phase number
    Serial.print("phase number ");                              //print helpful information about what is going on
    Serial.print(phase);
    Serial.print("  angle = ");
    Serial.println(phaseData[phase].angle);                     //print the angle for the current phase
    if (currentTime - phaseStart >= phaseData[phase].period)    //if the period for the current phase has ended
    {
        phase += 1;                                             //move to next phase
        phase = phase % phaseCount;                             //reset phase number back to zero if all phases have been executed
                                                                //uses the modulo operator to do this
        phaseStart = currentTime;                               //save the time that the current phase started
    }

//any other non blocking code goes here

}

You will need to research structs, arrays, const declaration, static declarations and the modulo operator if you are not familiar with them

Of course, you also need to replace the print statements with Servo commands

Perry, I haven't any idea what you are talking about. I haven't been rude, but I am persistent. I wanna learn

I guess what I meant to ask was could you divide it into the list. However, now that it is commented out, I "think" I can come to a reasonable conclusion about which part belongs to what. Man, I feel terrible. I got a moderator on here telling me things are getting rude........? Yes, I have an issue. It's called Stage 4 Pancreatic CANCER. There isn't a Stage 5. I'm a bit loopy because of the drugs they put in me (poison). If you have been on my thread and thought I was stupid. I'm not. I hope none of you have to go through what I'm going through. (being POLITE) it isn't very much FUN!