adding a delay?

Hello,
I am new to the programming and arduino world…
i managed to get an LED to fade in and out. but once it is completely off (at 0?), it startsturning on again immediately. How do I tell it to wait 1 second before starting again? or better yet, how to I get it to fade in and out equally like a wave) The code I am using is below. Please explain as much as possible! thank you!

int ledPin = 9;

void setup() {
}

void loop() {
for (int fadeValue = 0 ; fadeValue <= 255; fadeValue += 5) {
analogWrite(ledPin, fadeValue);
delay(30);
}

for (int fadeValue = 255 ; fadeValue >= 0; fadeValue -= 5) {
analogWrite(ledPin, fadeValue);
delay(30);
}
}

If you must use delay()

delay(1000);   // 1000 milli seconds

.

LarryD:
If you must use delay()

delay(1000);   // 1000 milli seconds

im sorry.. I cant figure out where to pt that in the code... Where would I put that?

You've got loops inside a loop. You can do what you want with a single loop. Consider what you might do with fadeValue inside this loop. Then find a way to do it without using delay().

Put it right after your looped statements:

...
    delay(30);
  }

  delay(1000);

...

Oh, and quote my reply so you can see the better way of expressing your code in the forum.

You said you wanted the light to fade like a wave, in this case you probably want to approach this a bit differently.

Think of the sin function. For some x value, it outputs a y value. We can think of this in terms of your program. In the case of your program, time is the x value. So, we can say that

brightness = sin(time)

However, if we want to put this into code, we have to take some considerations about how your program treats numbers.

First, you have different types of numbers. I see that you already know how to use the int type. The type that we will need is called float. A float type is just a decimal. If you want to deal with precision, you'll need floats. There are even more precise version of floats called double. We will be using double in this program.

Next, we need to know how to use the sin() function in code. Arduino makes this really easy, it's just sin(). Some programming languages make you call Math.sin() or something of that nature. You can forget all of that on Arduino. It's just sin().

The next part is time. In Arduino, we figure out the time by using millis(). This will give the total number of milliseconds since the Arduino was turned on.

Now, I'm going to throw a piece of code at you, don't panic.

brightness = (sin( ((double)millis()/1000.0f ) * 2.0f * 3.14159265f )/2 + 0.5) * 255

Here is the same code color-coded for easier explanation:

brightness = (sin(((double)millis()/1000.0f ) * 2.0f * 3.14159265f )/2 + 0.5) * 255

Okay, starting with the blue part:

(double)millis()/1000.0f

millis() is good, however if we feed only millis() into the sin() function, we will have a very rapidly blinking light, and that's not what we want. So, we are scaling it back by dividing by 1000. The whole of this piece of code will be outputting the number of seconds since startup. Not only that, but we also cast the millis() value to double. That what the (double) part is for. On top of that, the 1000 isn't just 1000. It says 1000.0f. That's telling the arduino to treat it as a float. All of this together means we get the number of seconds since startup in decimal seconds. Which gives us a lot of smoothness.

Next, the orange part:

2.0f * 3.14159265f

This is making the sin function normalized. The period is now 1 second instead of 2pi seconds. 2 pi doesn't really mean much to us, so normalizing this value is nice. This is basically like saying:

y = sin(x * 2 * pi)

You can also put another value in here like:

2.0f * 3.14159265f / period

This will directly affect the period and the period will be whatever number is in the "period" variable.

Now, we're onto the green part:

/2 + 0.5

So, this bit of code is dividing the output of the sin function by 2, so it goes from -0.5 to 0.5 and adds 0.5 to it so it goes from 0.0 to 1.0. Why did we do this? Well, that feeds into the next colored area.

The teal colored code:

* 255

This takes the output of the value from 0 to 1 and multiplies it by 255. This ensures that the value is always somewhere between 0 to 255. We do this because AnalogWrite can only take a value from 0 to 255. So now your code looks like this:

int ledPin = 9;   

void setup() {
}

void loop() {
   double fadeValue;
   fadeValue = (sin( ((double)millis()/1000.0f ) * 2.0f * 3.14159265f )/2 + 0.5) * 255;
   analogWrite(ledPin, fadeValue);

 }

Great! Now we have a wave. But, if we ever use a delay in here, it will just stop. How do we make it stop every time it goes to 0? Well, 2 ways. The first way, we could just check if fade value is equal to 0 and delay. However, using delay() is generally frowned upon because it causes something called "busy waiting". Instead, we're going to find a way to continue running without changing the fade.

So, without getting way too complex with the math, we can do something like the following:

int ledPin = 9;   
int startFade = 0;
double period = 1.0; //period in seconds
void setup() {
}

void loop() {
   
   int fadeValue;
   
   if(millis() >= startFade)
   {
      double fadeValue;
      fadeValue = (cos( ((double)(millis() - startFade + (period/2.0f) * 1000)/1000.0f ) * 2.0f * 3.14159265f / period)/2 + 0.5) * 255;
      analogWrite(ledPin, fadeValue);
    
      if(millis() - startFade == period * 1000)
      {
         startFade = millis() + 1000;
         analogWrite(ledPin, 0);
      }
   }



 }

A couple things I did:
Changed the sin function to a cos function. It's just easier to work with because it peaks at 0. Then, I shifted the wave over by half of a period so it starts at 0, climbs to 1 by t = 0.5, and comes back to 0 at t = 1. I also added the code that can deal with adjusting the period length. However, the really important part is:

      if(millis() - startFade == period * 1000)
         startFade = millis() + 1000;

This part is saying that once the time is right about the time that the led should be off, turn it off and set a new time where the fade should start again. Before it becomes that time, the fading code just won't run at all. Then, once it does we make sure to start the cos() at 0 again with:

millis() - startFade + (period/2.0f) * 1000

This is saying, take the millis and subtract off the time we start at, so we start at 0. Then, make sure to shift over by half of a period so the cos() value starts at 0.

So, that was a huge mouthful. However, I hope it helps you a ton. Honestly, using delay() at all is probably a bad idea and it will make you use it as a crutch. Think creatively and try to avoid delay whenever possible.

Also, if my code doesn't work, please tell me. I simulated it, so it should work. No guarantees though.

Just aside...
This is a great example of why some beginners should have paid attention in maths class at school. AND why schools should start teaching STEM subjects again!

No offence suggested to the OP, he may well be across xniinja's explanation, but I fear for many others that might still have trouble opening the cardboard package. They should start trying harder, or take up knitting (!)... that takes practice too!

I was lucky, and caught just enough back then, but many newbies expect the logic and maths to fall out of the Arduino experimenters box along with the AC adapter.

lastchancename:

AND why schools should start teaching STEM subjects again!

IMO, too much “STEM” is where the problem lies. On the other hand, if science and math were taught outside of the ‘touchy-feeley’ STEM umbrella, perhaps students would learn this stuff. But it all needs to be made palpable to the various ‘boards’, who decide based on their ‘gut’, what subjects get taught, and which are not funded. Thus STEM was born. Crunch everything hard into a single category, to what purpose? To save money.

Remember “tracking”? Back in the 1960s it was believed that some students could grasp science and math, while others should go into retail or food service. So they gave us a test. Pass and you got science education. Fail, and the highest math you ever saw (until you got to the university) was arithmetic. And maybe something called “Earth Science”.

STEM is the same thing, repackaged. STEM considers robotics, rudimentary biology (cutting planaria in half kind of thing, or measuring the amount of plastic in waste), are presented as Science subjects. Without any understanding of the scientific method (thanks post-modernism) students are left with the impression that STEM is actually a game of Trivial Pursuit.

But of course, it is far harder to control the outcome of real scientific study. So we now have STEM. Watered down, but controllable.

Chris, maybe you're being a bit harsh.

Kids need some exposure - even at the battery, switch and bulb level - to see if those type of things 'float their boat' in grade 6, then as they stream into higher years, they can identify which direction they 'might' be interested. Physics, chemistry, geology, biology, maths etc were all study options when i was in year 8... a long time ago!

But many/most schools at the moment would rather teach gender equality, anti-bullying and job-seeking methods than the actual skills needed to get and hold a job.

For kids, yeah, but I work at a college. Granted, it's a two year college, but we are still using the same techniques as you would for fifth graders. Even at the university level, teaching has been dumbed down to appeal to short attention spans, and unexercised memories.

In physics class (that I help to produce) for example, they DO the battery, wire, bulb experiment! Why? Because the kids have never been exposed to that. I thought that was grade school stuff. So for one, we have a bit of catch-up to achieve.

Perhaps I am harsh. I strongly believe in gender, ethnic, and racial equality. But in a science class, we should go into it with equality already established. And the basic tennents of science should not need to be re-established over and over. But the concept that all opinions are equal has been interwoven with the ideals of general equality. And so sciencetific observations have become "just your opinion, man."

The teacher presents an opinion, and the student is then free to compare that opinion to other opinions. Ideally the student comes to a conclusion that is consistant with their observations and uses science to understand the world. Not necessarily though. The ideas are filtered through social, political and entertainment values. When it's called guided discovery (a STEM based method) the teacher is there to gently nudge the student toward understanding. We dare not tell them they are wrong though.

Chris,
That's an interesting and valid observation.
Many of the posters on here are from non-English speaking, and other regions of the world.
In many cases (I lived over there for 10+ years), the interesting thing that pushes their competitive learning streak - is they aren't told 'what you can't do'!

Yes, they blow things up and occasionally kill someone, but if you put those students into a richly resourced STEM/tech education system, the good ones will flourish - possibly better than the home-grown students'. Look at the best Chinese and Indian graduates... they're hungry and willing to take risks.

lastchancename:
Chris,
That's an interesting and valid observation.
Many of the posters on here are from non-English speaking, and other regions of the world.
In many cases (I lived over there for 10+ years), the interesting thing that pushes their competitive learning streak - is they aren't told 'what you can't do'!

Yes, they blow things up and occasionally kill someone, but if you put those students into a richly resourced STEM/tech education system, the good ones will flourish - possibly better than the home-grown students'. Look at the best Chinese and Indian graduates... they're hungry and willing to take risks.

I'm not interested in helping anyone who is going to use their knowledge to kill people. That goes equally for "terrorists" and the military. But what you say is true, good students who are willing to put in the work and enjoy learning are a joy to work with. If that weren't the case, I would not have lasted in this business for 29 years (and counting.)

xniinja:
Also, if my code doesn't work, please tell me. I simulated it, so it should work. No guarantees though.

Fantastic! Thanks so much for the help and your great explanation! I ran the code through the arduino and it runs perfectly for while then stays on (sometimes after the 3rd pulse, 7th pulse or 11th pulse), after that it stays on. so my guess is that there is a looping issue? How would I go about fixing that?

I found the issue. For some reason I put the following code to reset the wait time.

if(millis() - startFade == period * 1000)

In a perfect world, this would be fine. However, the Arduino isn’t an idealized machine. So, if we change that line of code to:

if(millis() - startFade >= period * 1000)

it should work perfectly. Even if it misses exactly when the two values are equal, it will still stop the loop. I added the code to compensate for this, I also made the wait period a variable so it’s more obvious what’s going on. Also, one last point. I changed startFade to an unsigned long variable. This is just an integer that can count really high. With this, the code will be able to run for a long time without rolling over. It will also be able to keep up with the millis() value. I don’t think this is what was happening to you, but eventually it would have been a problem.

Here is the updated code:

int ledPin = 9;   
unsigned long startFade = 0;
double period = 1.0; //period in seconds
double waitTime = 1.0; //Number of seconds to wait between pulses
void setup() {
Serial.begin(9600);
}

void loop() {
   
   int fadeValue;
   
   if(millis() >= startFade)
   {
      double fadeValue;
      fadeValue = (cos( ((double)(millis() - startFade + (period/2.0f) * 1000)/1000.0f ) * 2.0f * 3.14159265f / period)/2 + 0.5) * 255;
      Serial.println(fadeValue);
      analogWrite(ledPin, fadeValue);
    
      if(millis() - startFade >= period * 1000)
      {
         startFade = millis() + waitTime * 1000;
         analogWrite(ledPin, 0);
      }

   }

 }