Go Down

Topic: pwm with delay (Read 752 times) previous topic - next topic

TeslaIaint

Nov 26, 2012, 01:12 am Last Edit: Nov 26, 2012, 01:28 am by TeslaIaint Reason: 1
Hello,

In order to try to get my head around the "blink without delay" concept, I have run into a wall. I am trying to use pwm to turn on the led and modify the blink without delay example to replace the "delay (50);" I think you can see what I'm trying to do through the code. Unfortunately the light never comes on and I always get 0 in the serial monitor. Can anybody shed some light for me? Thanks in advance.
I'm trying to replace this:
Code: [Select]
int led = 3;

void setup()
{
 Serial.begin (9600);
 pinMode (led, OUTPUT);
}
void loop()
{
 for (int i = 0; i <=255; i++){
   analogWrite (led, i);
   delay (50);  
   Serial.println (i);
 }
}


with this:
Code: [Select]
int led = 3;

long interval = 50;
long previousMillis = 0;

void setup()
{
 Serial.begin (9600);
 pinMode (led, OUTPUT);
}
void loop()
{
 unsigned long currentMillis = millis();

 for (int i = 0; i <=255; i++){
   if (currentMillis - previousMillis > interval) {
     previousMillis = currentMillis;
     analogWrite (led, i);

     Serial.println (i);
   }
 }
}


PaulS

How long do you think it takes to rip through that for loop?

You need to ditch that whole for loop, and completely rethink how you fade an LED. There are plenty of examples around of fading without delay.

You need a variable that defines the PWM value for the pin. Each pass through loop, you see if it is time to change that value. If it is, change and apply the value, and record when you did that.

TeslaIaint

It doesn't take long at all to "rip" through the loop. The point isn't fading the led. The point is trying to understand "blink without delay" in a concept other than blinking a light.

PaulS

Quote
It doesn't take long at all to "rip" through the loop.

That's exactly why nothing happens in the loop. The first pass through the loop, enough time has elapsed to see some output. On no other pass through loop has enough time passed for the if test to evaluate to true.

You don't want to loop when you aren't delaying.

billroy

You're close.  Paul is right, lose the for loop.  Don't worry, loop() will be called again real soon.  More like this:
Code: [Select]

void loop()
{
  unsigned long currentMillis = millis();

//  for (int i = 0; i <=255; i++){                     //<-- delete this line
    if (currentMillis - previousMillis > interval) {
      previousMillis = currentMillis;
      analogWrite (led, i++);     // <-- increment i here
      Serial.println (i);
    }
//  }          // <-- delete this line
}


-br

TeslaIaint

I am trying to slow the loop down by trying to use the "blink without delay." Are you saying that there is no way to slow the for loop down without using delay()?
It does work without any delay() like this:
Code: [Select]
for (int i = 0; i <=255; i++){
    analogWrite (led, i);
    Serial.println (i);


Arrch


I am trying to slow the loop down by trying to use the "blink without delay." Are you saying that there is no way to slow the for loop down without using delay()?
It does work without any delay() like this:
Code: [Select]
for (int i = 0; i <=255; i++){
    analogWrite (led, i);
    Serial.println (i);



Get rid of your for loop, that's what everyone is trying to say. You already have built in iteration by the mere nature of loop(), so an additional one is not needed. At every interval, you need to be thinking what you should be doing. Last interval you wrote 2 as the PWM value, perhaps the next interval should be 3, then 4, etc.

TeslaIaint

#7
Nov 26, 2012, 02:30 am Last Edit: Nov 26, 2012, 02:35 am by TeslaIaint Reason: 1
Thanks Billroy. That works. I had to add a line to constrain i to a maximum of 255.
Code: [Select]
int led = 3;
int i = 0;
long interval = 10;
long previousMillis = 0;

void setup()
{
 Serial.begin (9600);
 pinMode (led, OUTPUT);
}
void loop()
{
 unsigned long currentMillis = millis();

 if (currentMillis - previousMillis > interval) {
   previousMillis = currentMillis;
   i = min (i, 254);            sets pwm to 255 maximum
   analogWrite (led, i++);
   Serial.println (i);
 }
}



Although this works to turn the light on, I am still curious how to fix my origional code. Fading the light is just something I picked to try to get to understand the "blink without delay." That really was the origional question. I suppose the question is: how do I use the "blink without delay" with a for loop? Any ideas would be greatly appreciated

Nick Gammon


I suppose the question is: how do I use the "blink without delay" with a for loop? Any ideas would be greatly appreciated


I discuss that concept here:

http://www.gammon.com.au/blink
http://www.gammon.com.au/electronics

Arrch


Although this works to turn the light on, I am still curious how to fix my origional code. Fading the light is just something I picked to try to get to understand the "blink without delay." That really was the origional question. I suppose the question is: how do I use the "blink without delay" with a for loop? Any ideas would be greatly appreciated


I'm not sure why "don't use a for loop" isn't sticking. I can't think of a single situation where this code shell would be usefull:

Code: [Select]
for (int i=0;i<sum_num;i++)
{
  if (millis() - last_check > interval)
  {
    last_check = millis();
    // do stuff
  }
}

TeslaIaint

Code: [Select]
int led = 3;
int i = 0;
long interval = 10;
long previousMillis = 0;
int lastcheck = 0;

void setup()
{
 Serial.begin (9600);
 pinMode (led, OUTPUT);
}
void loop()
{
 unsigned long currentMillis = millis();
for (int i=0;i<=255;i++)
{
 if (millis() - lastcheck > interval)
 {
   lastcheck = millis();
   analogWrite (led, i);
 }
 Serial.println (i);
}
}


The above code works as intended. It resets the led to 0 every time through the loop. The following code works in a different way. Once the led reaches 255, it stays there constantly lit. As I said a few times, I'm trying to learn different ways of implementing a delay without "delay()." That's why it "wasn't sticking."
Code: [Select]

int led = 3;
int i = 0;
long interval = 10;
long previousMillis = 0;

void setup()
{
 Serial.begin (9600);
 pinMode (led, OUTPUT);
}
void loop()
{
 unsigned long currentMillis = millis();
 if (currentMillis - previousMillis > interval) {
   previousMillis = currentMillis;
   analogWrite (led, i++);
   i = constrain (i,0,255);
   Serial.println (i);
 }
// analogWrite (led, 0);
 //Serial.println (i);
}









Nick Gammon

Your first example in the previous post looks OK to me. Every 10 mS you are increasing the brightness by 1.
http://www.gammon.com.au/electronics

TeslaIaint

Thanks, Nick. That's what I'm trying to do. In my previous post I said that the first bit example of code that I modified from arrch was working correctly. It isn't. I doesn't increment every 10ms; It increments as fast as it can. The "delay" functions aren't working.  I'll play with it a bit and see if I can get it to work. I know I shouldn't worry about it as the second posted code in my previous post works, but I just like to try to understand things. Maybe there will be a situation where I could modify the code into something useful.

Nick Gammon

You had duplicate declarations if "i" there. This is a cut-down version:

Code: [Select]

int LED = 3;
unsigned long interval = 100;
unsigned long lastcheck = 0;

void setup()
 {
 }  // end of setup

void loop()
 {
 for (int i = 0; i <= 255; i++)
   {
   if (millis() - lastcheck > interval)
     {
     lastcheck = millis();
     analogWrite (LED, i);
     }  // end if time up
   }  // end of for
 }  // end of loop


Although I must confess that on my test board at least it isn't quite doing what I expect. The duty cycle seems to be jumping in a strange way.
http://www.gammon.com.au/electronics

Nick Gammon

Ach! I have it! The loops are the wrong way around. In your code you are adding to i, even if you don't send that value to the LED. In other words, you only send the updated "i" at intervals of "interval". Hence it jumps in brightness in large gaps.

This fades up nicely, relying on the byte value in "brightness" to wrap around at 255:

Code: [Select]

const int LED = 3;
const unsigned long interval = 10;
unsigned long lastcheck = 0;
byte brightness;

void setup()
 {
 }  // end of setup

void loop()
 {
 if (millis() - lastcheck > interval)
   {
   lastcheck = millis();
   analogWrite (LED, brightness++);
   }  // end if time up
 }  // end of loop
 
http://www.gammon.com.au/electronics

Go Up