Pages: [1]   Go Down
Author Topic: Best approach for changing PWM in certain time?  (Read 912 times)
0 Members and 1 Guest are viewing this topic.
0
Offline Offline
Newbie
*
Karma: 0
Posts: 41
Arduino DUE rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi, I'm creating a sort of timer for turn/DIM leds.
On this timer I can specify the duration I want that the leds take from 0 to 255 (PWM value), so to speak from off (0%) to full bright (100%).

So whats the best approach to do this and have always a smooth incresed brightness, taking in consideration that the user can setup a diferent duration time from 1 minute to 120 minutes to do the 0 to 100% DIM variation?

Thanks.
Logged

Check all my projects based on Atmel/Arduino -> www.aqualed-light.com

Seattle, WA USA
Online Online
Brattain Member
*****
Karma: 654
Posts: 50945
Seattle, WA USA
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
Hi, I'm creating a sort of timer for turn/DIM leds.
No, you are using existing timers to make things happen.

Quote
On this timer I can specify the duration I want that the leds take from 0 to 255
Can the time be changed during a cycle? What does that do to the cycle? What is to happen when the LED gets to full brightness?

Are you aware that the human eye can not distinguish 255 different brightness levels?

Quote
So whats the best approach to do this and have always a smooth incresed brightness
What you have is basically a state machine. The state, at any time, defines what the current brightness level is. You need to invoke certain actions (change the PWM level) at each state change, and you need to change states at appropriate times. Since the desire is to have the state change occur at specific intervals, you need to record when the last state change occurred, and compare that to "now" on each pass through loop, to see if it is time to change state.

Recording when the last state change occurred is done using millis(), as is determining the current time.

Look at the blink with delay example.

Under these circumstances is it not appropriate for you to use delay().
Logged

0
Offline Offline
Newbie
*
Karma: 0
Posts: 41
Arduino DUE rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi, thanks for your reply PaulS, when I said timer I meant to say that my machine is as sort of a clock to turn ON/OFF leds, so the user specifies X time and Y duration for the on, the machine at that time starts increasing PWM values from 0 to 255 divided by the Y duration specified, them the leds stay on until reach the time specifyd for OFF and do the oposit, witch is decreasing the PWM from 255 to 0 in another duration specifyed for OFF cycle.

Hope you understand now what I'm doing?

My main problem for now is trying to avoid float vars, since I have this already running with floats.

I take the duration value, convert it to seconds, them divide 255 for those seconds and I get the increment.
Using mils() everytime reach my next changing second I increase the PWM, I think is mor or less like you are saying... but how to take the float vars out so I can save as much memory space as possible?
« Last Edit: July 02, 2011, 05:28:43 am by Baltasar » Logged

Check all my projects based on Atmel/Arduino -> www.aqualed-light.com

Seattle, WA USA
Online Online
Brattain Member
*****
Karma: 654
Posts: 50945
Seattle, WA USA
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
I take the duration value, convert it to seconds, them divide 255 for those seconds and I get the increment.
Watch your clock for a minute. Tick, tick, tick...

How much time elapses during each tick? Is it 1.0 seconds, or 2.3? or 5.1? The millis() function returns the number of milliseconds that have elapsed since the Arduino was reset, as an unsigned long (i.e. integer) value.

Determining a fractional number of milliseconds to wait is useless, since "now" and "then" are always integer values.

Even if you were able to change the PWM level at other than integral times, the length of time between changes only needs to be calculated when the total interval changes.

Avoiding float calculations that happen many times every pass through loop is a good idea. Avoiding all float calculations is an unnecessary objective.

Though, in this case, float calculations won't be useful anyway.
Logged

0
Offline Offline
Newbie
*
Karma: 0
Posts: 41
Arduino DUE rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Ok I see, let me show the code I have now, so you can comment on that or send me to a better direction...

This are excerpts from the total code as I have lots of other functions than the ON/OFF/DIM for the leds.

Code:
on_led_increment =  255.0 / (((float)dur_on * 60) );


void loop()
{

  if (on_finished == 0 && sec_on_count == 0){
    sec_on_count = sec_count;
    sec_on_count = sec_count + ldur_on;
  }


if (on_finished == 0 && sec_count == sec_on_count && led_dim < 255) {

    sec_on_count += 1;

    if (led_dim < 255) {
      led_dim += (float)on_led_increment;
      for (led = led_dim - on_led_increment; led <= led_dim; led += 0.10){
        analogWrite(10, led);
      }
    }

    if (led_dim >= 255) {
      on_finished = 1;
      getCloudsSec();
    }
}

void SyncClock() {
  // create a military-time integer from RTC values
  mil_time = (hours * 100) + minutes;
  sec_count = hours * 60;
  sec_count *= 60;
  sec_count += (minutes * 60);
  sec_count += seconds;
}
« Last Edit: July 02, 2011, 08:08:52 pm by Baltasar » Logged

Check all my projects based on Atmel/Arduino -> www.aqualed-light.com

Global Moderator
UK
Offline Offline
Brattain Member
*****
Karma: 310
Posts: 26638
I don't think you connected the grounds, Dave.
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

For this sort of thing, I often use an 8.24 fixed-point format (32 bit overall), using the top eight bits as the PWM value, and simply accumulate pre-calculated fractions.
Logged

"Pete, it's a fool looks for logic in the chambers of the human heart." Ulysses Everett McGill.
Do not send technical questions via personal messaging - they will be ignored.

0
Offline Offline
Newbie
*
Karma: 0
Posts: 41
Arduino DUE rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hummm, sorry... AWOL can you detail that or give a code example, I'm too new on this to understand most of what you are saying.
Logged

Check all my projects based on Atmel/Arduino -> www.aqualed-light.com

Global Moderator
UK
Offline Offline
Brattain Member
*****
Karma: 310
Posts: 26638
I don't think you connected the grounds, Dave.
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Imagine a "long" variable "x" as an array of four "byte"s "xb[4]" (define a union).
Because the Arduino is little-endian, the most significant eight bits of "x" are held in xb[3].
xb[3] will the value written to our PWM device.

Now, if we set "x" to 0x01000000, xb[3] will contain 0x01.
Assume we want to fade x from 1 to 5 in 300 steps, so we take the difference of 5 and 1 (4) and divide by 300, yielding  0.0133.
Now, multiply 0.013333 by 224 (= 16 777 216) to give 223 696 (0x000369D0)
Store this value in a "long" called "inc".
Now, repeatedly add "inc" to "x", but only write xb [3] to your PWM device each time through the loop.

This technique is most useful when you've got a number of LEDs to fade to and from different values, but in a fixed number of steps.

(it comes out a lot easier than I described it!)
Logged

"Pete, it's a fool looks for logic in the chambers of the human heart." Ulysses Everett McGill.
Do not send technical questions via personal messaging - they will be ignored.

0
Offline Offline
Shannon Member
****
Karma: 223
Posts: 12745
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

You don't need floats for ratiometric things like this.

Say you want to step 255 steps in 317 seconds.  You initialize a variable accum to 0, and every second you do this:

Code:
 accum += 255 ;
  while (accum >= 317)
  {
     brightness += 1 ;
     analogWrite (pin, brightness) ;
     accum -= 317 ;
  }

After 317 seconds you have incremented the variable by 255 a total of 317 times.  But you have also decremented it by 317 a total of 255 times (and also stepped the brightness 255 steps).

This integer ratio based technique is the mainstay of all graphics promitives (drawing sloped lines) and is variously known as DDA (digital differential analyzer), or Bressenham's algorithm.  And it avoids floats and is ultra-fast.

If you process every millisecond, just use 317000 instead of 317
« Last Edit: July 02, 2011, 07:01:45 pm by MarkT » Logged

[ I won't respond to messages, use the forum please ]

0
Offline Offline
Newbie
*
Karma: 0
Posts: 41
Arduino DUE rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

MarkT,thanks for the help you solution is almost perfect for me.

Going now to do more tests and see if I reach the perfect result that I need, since apart the need of diming from 0 to 255 I need to show on the LCD the dimming percentage (0% to 100%), converting is easy, but I get again the float values that I can't compare with the integer pwm values. For example 48% represents 122,4 pwm value, if I want to stop during the DIM on a specific value like this 48% there is no way sinve only going to pass on 122 integer.

 smiley-roll
Logged

Check all my projects based on Atmel/Arduino -> www.aqualed-light.com

Pages: [1]   Go Up
Jump to: