You need non-linear curve, and the amount of bits depends on how fast you wish the LEDs to dim, so that the eye may not notice the brightness changes. The link below leads to page from which you'll find my code for controlling 16 model railway light signal LED's with individual PWM (I needed to get the LEDs emulate low voltage filament bulbs used in railway signals, and also to have the property to first dim out the previous aspect (light) before brightening the next one. The system also has flashing lights, also slowly brighting and dimming with PWM. I calculated the brightness values as 0..FF as it was the easisest way to figure out if the brightness value was full on or fully off (is it zero or if adding one would cause overflow). There are 16 such varialbles and the interlocking logic managed these values by adding one or subtracting one from these varialbles. Another loop copied the values, cut lower nibble ("swap" and "and") and with lookup table converted these into x^3 form: ;--------------------------------------------------------------- ;Lookup-table (like x^3-path, 0..0x0F -> 0..0x20) ;--------------------------------------------------------------- Lookup addwf pcl,f retlw .0 retlw .0 retlw .0 retlw .0 retlw .1 retlw .1 retlw .2 retlw .3 retlw .5 retlw .7 retlw .9 retlw .13 retlw .16 retlw .21 retlw .26 retlw .32 another loop was then used to count from 32 to zero and decrement the newly calculated values until the value was zero and the led switched out. The output LEDs were in 2 x 6 matrix. after the complete LED operation phase (both brances of the 2x6 matrix), another calculus phase came and new values to 0..FF registers were calculated to be again lookup'ed and outout... The code is a bit clumsy, but this was my first PIC project that I did from start to finish! http://www.taprk.org/eng/project/semaphore/ The main loop has multiple entries of certain "subs" but that was at the time the easisest way to do final adjustment of the blink rate;) B.6 was driving the other ends of the leds (inverter amplifier and amplifier) and the B.0..B.5 pins the other ends of the LEDs thus driving 12 LED's independently w. 7 pins. Pekka Siiskonen [PS: 8 spaces for a tab in asm file, sorry!] > -----Original Message----- > From: Scott Dattalo [mailto:scott@DATTALO.COM] > Sent: 9. helmikuuta 2003 1:56 > To: PICLIST@MITVMA.MIT.EDU > Subject: Re: [PIC]: Non linear PWM of LEDs > > > On Sat, 8 Feb 2003, Josh Koffman wrote: > > > Hi all. I've been playing around with software PWM controlling some > > LEDs. Problem is, as the eye's response to brightness isn't > linear, when > > I simply control the LEDs brightness using an 8 bit value (with no > > compensation) they don't appear to dim smoothly. So my > thought was to > > take the 8 bit value, use it as an index into a lookup > table which would > > give me a higher bit value (ie a 12 or 14 bit). > > > > Here is the problem (as I see it anyways). If I increase the bit > > resolution of my PWM, the frequency will have to go down > (as the PIC is > > already running at full speed. yes, I could go to an SX > chip...I know). > > So, is there a resolution vs speed balance that anyone has > reached that > > gives optimal frequency and smoothness of the dimming? > Also, how do you > > choose the values for the lookup table? Most commercial theatrical > > dimmers use a "modified S curve" which is essentially the > integral of > > the area under a sine wave (I think). I'm sure if I had Maple or > > something (and knew how to use it) I could divide the area into 256 > > sections and come up with the proper values for the lookup > table. But > > since I don't have access to this high powered math > software, what are > > my options? Plotting out by hand seems only an invitation for > > frustration. > > > > Ideas welcome. > > Well, if you're using a software PWM then a really simple > solution may be > to just let the time base be logarithmic. For example, > suppose you had a > PWM with 8 levels. Normally, the time step is constant so > that a pulse of > 4 units, is on exactly twice as long as a pulse of 2 units. > In terms of a > time line: > > Start > V V > +---+---+---+---+---+---+---+---+---+---+---+ > 0 1 2 3 4 5 6 7 0 1 2 3 > > At the 0's the PWM turns on and at the 1-7 steps it turns off. Now, > suppose you made the time step like so: > > ++-+--+---+------+---------+--------------+---------------------++-+ > 01 2 3 4 5 6 7 01 2 > > So now, a pulse 4 units wide takes more than twice the time > of a pulse 2 > units wide. > > The difficult part here will be to perform the non-linear > time stepping. > There are several ways to go about doing this, but they depend on the > particulars of your system. > > Note that this really is the same thing that you're > suggesting; I've only > partioned the time differently. In your case, you're > suggesting that the > dynamic range of the PWM duty cycle be increased. In my case, I'm > suggesting that the dynamic range is kept the same, but the time base > adjusted. > > If you're using my software PWM (number of cycles = 7 + 2*Number PWM > outputs or 23 for 8 outputs), then the first few iterations > could be run > back to back while the latter ones interrupt driven. You're > still going to > want the roll over rate to be large enough so that there's no > perceivable > flicker. > > Another possibility is to consider a Pulse-Modulation scheme based on > phase accumulators. It gives you a non linear output that may be > suitable. For example: > > phase_step = some number --- controls the output level > phase_accumulator --- accumulates phase, i.e. an integrator > > The algorithm is simple: > > phase_accumulator = phase_accumulator + phase_step > if phase_accumulator rolls over, then set the output. > > In PIC assembly, it'd look something like this: > > DECFSZ MainCounter,F > goto update_pulses > > CLRF PWM_port > > update_pulses: > > MOVF phStep0,W > ADDWF phAccum0,F > RLF Rollovers,F > > MOVF phStep1,W > ADDWF phAccum1,F > RLF Rollovers,F > > ... > > MOVF phStep7,W > ADDWF phAccum7,F > RLF Rollovers,W ; the last shift goes into W > > IORWF PWM_port,W > > > That's 28 cycles instead of 23, but look closely how it works. The > rollover bit is simply the carry from the addition to the phase > accumulator. If you wrote the rollover bit to an I/O pin, it > would look > almost like a square wave DDS. In other words, if phStep = 1, then the > rollover rate would be 256 iterations and the frequency would be 512 > iterations. If phStep = 2, then the rollover is 128 and the > frequency is > 256. It's twice as fast. If phStep is 3, then the rollover is > in about 85 > iterations (256/3) and the frequency is about 512/3 iterations. In > general, the rollover rate is 256/N iterations and the > frequency is 512/N. > > However, notice that the above code *does not* toggle the > output at every > rollover. Instead, it latches the rollover. In effect, the > pulse outputs > are just the first cycle of the DDS frequency. > > pwStep pulse width out > ----------------------- > 1 256/1 = 256 > 2 256/2 = 128 > 3 256/3 = 85 > 4 256/4 = 64 > 5 256/5 = 51 > ... > > 128 256/128 = 2 > 129 256/129 = 1 > ... > 255 255/255 = 1 > > In other words, the output pulse is inversely proportional to > the pwStep. > Also note that there are way fewer than 256 steps. OTOH, it's > computationally simple. You can also do a few tricks to > sustain a constant > output, (either on or off). Also, the IORWF can be changed to ANDWF to > invert the polarity of the drive (and the outputs would all > have to be set > instead of cleared when the main counter rolls over). > > Scott > > -- > http://www.piclist.com hint: The PICList is archived three different > ways. See http://www.piclist.com/#archives for details. > -- http://www.piclist.com#nomail Going offline? Don't AutoReply us! email listserv@mitvma.mit.edu with SET PICList DIGEST in the body