Adjusting brightness of LEDs on all 28X1 outputs

Mikler

Member
Help for a Newbie, please.

I am using all possible pins of a 28X1 as output pins, directly driving LEDs.

Can anyone suggest a snippet of code that I can use to be able to selectively adjust the brightness of the various LEDs.

I assume that I can't use PWM as this is not available on all the output pins.

Help appreciated

Thanks

Mik
 

womai

Senior Member
PWM would be the most straightforward way but of course the 28X1 only has two independent PWM channels.

You could create your own PWM function by using interrupts. Have a look at this thread for timer interrupt sample code:

http://www.picaxeforum.co.uk/showthread.php?t=11708

You can use the same interrupt routine. Now set the number of events per second to e.g. 100 (for that fast interrupt it helps to overclock the 28X1 to 16 MHz). In the interrupt routine, increment a counter by 1 each time the routine gets called (100 times per second), and set it back to 0 whenever it reaches 10. For each LED you need to have a variable that holds the desired brightness, let's say in a range from 0 to 10, with 10 being the brightest (always on) and 0 being off. Initialize all LEDs to "on".

Now in the interrupt routine, after incrementing the counter, for each LED check if the current counter value is higher than its brightness value. If it is, turn the respective LED off. When the counter reaches 10 and gets set to zero, turn all LEDs back on.

So let's say a particular LED has brightness value 5. This means the first 5 times the interrupt gets called the LED will stay turned on. After that, it will get turned off and stay that way for the next 5 interrupts. I.e. the LED is at half brightness.

To avoid visible flicker, you want to make the number of events per second as high as the Picaxe can handle (I doubt you can go much higher than 300 even at 16 MHz).

Wolfgang
 

westaust55

Moderator
Help for a Newbie, please.

I am using all possible pins of a 28X1 as output pins, directly driving LEDs.

Help appreciated

Thanks

Mik
What current are you passing through each LED? :confused:


Assuming 16 LEDs (ie portB and PortC) with a 330 Ohm resistor and "standard RED LED, then if ALL LED's are on simultaneouly, then the total current draw is 16 x ~12mA = 192mA.

While each PICAXE I/O can handle 20mA, the 28X1 can only handle a total current of 95mA through the Vdd pin.

Working backwards, and allowing a few ma of the PIC chip internals etc, so say we have 90ma available.
Then 90 / 16 ==> 5.6mA per LED.
At this current, they will be visible (according to what forum members here have done in the past) but not particularly bright.
The resistor will need to be determined by:
R (Ohms) = (Vcc - Vfwd) / 0.0056

Vcc is your power supply voltage - typically 4.5V or 5V
Vfwd will have to come from the datasheet for your particular LED's.


So it does depend upon how many LED's will ever be on at once,
but my recommendation would be to have each PIACXE output drive a transistor to in turn control the LED's .

Have a look at the circuit for the Signal Lamp in PIACXE Manual 3 page 9.
 

womai

Senior Member
Westaust,

the voltage drop across the LED is typically around 1.5V (i.e. more than a "normal" diode). With VCC=5V, that means there is only 3.5V across the current limiting resistor. So with your formual, that works out to a required resistor of 625 Ohm. I often use 1 kOhm under same conditions (Picaxe driving LED directly) and the LED is reasonably bright, so with 625 Ohms it should be perfectly fine.

Wolfgang
 

Mikler

Member
Hi Westaust

For various reasons, I am driving everything with 2 x AA batteries (alkaline) - I was therefore driving the 16 LEDs directly (each LED using about 18mA without a resistor).

However I was not aware of the 95mA limit.

The project is a bargraph-type display pulsing from 1 led to 16 leds back to 1 led every ten seconds or so...

I was hoping to get away without resistors or driver transistors....

Oh....
 

eclectic

Moderator
I am using all possible pins of a 28X1 as output pins, directly driving LEDs.

Can anyone suggest a snippet of code that I can use to be able to selectively adjust the brightness of the various LEDs.


Mik
Just checking, re. your bargraph-display.

What exactly do you mean by "selectively"?

If, for example,
ALL low numbers/levels LED's are equally "dull" at the same time,
and
ALL high numbers / levels LED's are "bright",

then you could use PAUSE to modify brightness.

e
 

westaust55

Moderator
PICAXE max current limitations

Hi Westaust
:
:
However I was not aware of the 95mA limit.
:
:
I was hoping to get away without resistors or driver transistors....

Oh....
PICAXE Manual 1 page 56 under the Digital Output head now makes reference to the current limitation (which in turn is taken from the PIC datasheets).
 

Mikler

Member
Hi Eclectic

Perhaps I should be clearer...

I have 16 LEDS

I am lighting the first, then also the second, then also the third etc etc until all are lit. I then reverse the process untill they are all off. This cycle repeats over a ten second period.

What I am trying to do (I know it sounds 'nuts' :) is make the illuminating of each LED more gradual so it looks smoother. So when LED No.1 is fully on, LED No.2 is slowly starting to get brighter....

Help appreciated.

Thanks

Mik
 

Mikler

Member
Hi Westaust

Firstly, THANKS VERY MUCH! - (I had looked up another PIC datasheet - in error, the wrong one, that referred to a max of 200mA) - I could have really got myself into trouble here....

Aaaaargh!!! - Back to the drawing board.... I may have to use ULN2003's or something similar but really didn't want to - the whole purpose of this project was a minimum of components <sigh>

Question - could I pulse the LEDS very fast so that the duty cycle ensures that the LEDs are at an acceptable illumination level, but that the average current is within spec....

Help/Comments greatly appreciated!

Thanks

Mik
 

BCJKiwi

Senior Member
The current limit is a Microchip issue.
The data sheets showed (in error) 200mA for many years but recent addenda datasheets have shown the 95mA.

The 95mA could actually be calculated from the info in the original data sheets so the the 200mA was always an erroneous number.
 
Last edited:

lbenson

Senior Member
If you have 8 steps of brightness for each of 16 leds, with each coming full on before the next one starts, then you have 128 steps to have them all full on. If the total sequence takes 8.192 seconds, then each step takes 8,192/128 or about 64 milliseconds. If you loop 128 times, 8 times for each pin, then for the single pin which is blinking, you can add 8 ms of on-time for each of 8 passes for that pin, and be off for the remainder of the 64ms, going from 8ms on to 64ms on. Then you turn that pin on full and move to the next. The following code does that in the simulator (you can't see the dimming, but can see the pin blinking on and off and then going on). Reversing it would be similar. This assumes that you have the proper resistors on each LED--minimum of, say, 680 Ohms. Not tested in reality. Perception of brightness is logarithmic, so the blinkOnTime steps might need to be adjusted. This could be fit to Wolfgang's interrupt code--you'ld only need about 16 interrupts per second. Adjust timing to suit. If you want more than 8 brightness steps, adjust accordingly.

Code:
' 28Blink ' blinks at increasing intensity through 16 LEDs
#picaxe 28X
symbol loopCount = b13
symbol countOf16 = b12
symbol pins_B = b11
symbol pins_c = b10
symbol blinkPin = b9
symbol blinkOnTime = b8
symbol blinkOffTime = b7
symbol blinkStep = b6

dirsc = %11111111 ' all outputs on Port C

main:
  pins_B = 0 ' bit signifies that led should be on (1-8)
  pins_C = 0 ' bit signifies that led should be on (9-16)
  blinkPin = 0
  blinkStep = 0

  for loopCount = 0 to 127
    pins = pins_B
    pinsc = pins_C
    blinkOnTime = loopCount // 8 + 1 * 8 ' 8ms * 1-8
    blinkOffTime = 64 - blinkOnTime
    if blinkPin < 8 then
      high blinkPin
      pause blinkOnTime
      if blinkOffTime > 0 then
        low blinkPin
        pause blinkOffTime
      endif
    else
      blinkPin = blinkPin - 8 ' adjust for portC pin#
      high portc blinkPin
      pause blinkOnTime
      if blinkOffTime > 0 then
        low portc blinkPin
        pause blinkOffTime
      endif
      blinkPin = blinkPin + 8 ' reverse adjustment
    endif
    blinkStep = loopCount // 8
    if blinkStep = 7 then
      inc blinkPin
      if blinkPin < 9 then
        pins_B = pins_B * 2 + 1 
      else
        pins_C = pins_C * 2 + 1 
      endif
    endif
  next loopCount 
  pause 5000
  goto main
 

eclectic

Moderator
@Mikler

I don't know if you've solved your
fading chaser problem, but this might help.

1. First, make sure that the resistors will limit the maximum current.

2. The program is only meant to be a basis for experiment.
It looks awful in simulation, but, not bad in real life.

3. It ain't pretty, but, alter the values as required, until the display "looks" right.

Code:
#picaxe 28x1

setfreq m8          ; **** also try m4 ?

let dirsc = %11111111
symbol LedON = b0
symbol Level = b1
symbol pulslen = 150 ;*** try 50 100 200 .....
symbol Valstep = 1   ;***try 2,3,4,5 ..... 

 main:
 pause 2000 

;normal outputs on
for LedON = 0 to 7
for Level = 1 to pulslen step Valstep
pulsout LedON,Level
pause 1
next
high LedON
next

;portc outputs on
for LedON = 0 to 7
for Level = 1 to pulslen step Valstep
high portc LedON : pulsout 0,Level
low portc LedON
next
high portc LedON
next

;portc outputs off
for LedON = 7 to 0 step - 1
for Level = pulslen to 1 step - Valstep
high portc LedON  : pulsout 0,Level
pause 1
next
low portc LedON
next

;normal outputs off
for LedON = 7 to 0 step -1
for Level = pulslen to 1 step -Valstep
pulsout LedON,Level
pause 1
next
low LedON
next

goto main
e
 

Mikler

Member
Hi Eclectic

Thaks for your help

Please can you explain part of your code....

with normal output pins, you used:
pulsout LedON,Level
This I understand

But with PortC output pins you did something different....
high portc LedON : pulsout 0,Level

Assuming that we are attempting to pulse an LED on portC 2 only,
why do use '0' i.e. pin 0 only - surely this will affect all LEDs that are 'on'?

M
 

SilentScreamer

Senior Member
I think the answer to your question is "for...next" increments the value each time next is reached. So the code fades one led, then once that "for...next" has completed the other next is triggered which makes LEDon one higher.

Try it in the simulator and look at the variables as it does it, it might help you understand (to see the variables click the ">>" buttonO).
 

eclectic

Moderator
@Mikler / SS

You can only use Pulsout on “ordinary” outputs 0 – 7.
The command cannot be used on PortC

In the program,
A PortC pin is switched on.
Output0 is pulsed, for a known time, then
PortC off

Code:
;portc outputs on
for LedON = 0 to 7
for Level = 1 to pulslen step Valstep
high portc LedON : pulsout 0,Level  ; the “timer”
low portc LedON
next
high portc LedON
next
The simulator is much too slow to show it working properly.

I've just rebuilt the circuit and tried it.
It's not perfect, but it works.

Breadboard it and try it. It'll cost nothing. :)


e
 

hippy

Ex-Staff (retired)
What eclectic describes is the fundamental basis of LED Multiplexing which also allows brightness control -
Code:
.--------.     ___     LED
|     AA |----|___|----|>|---.
|        |                   |
|     KK |-------------------'
`--------'
1) When AA=0, KK=1 no current will flow and LED is off ( reverse bias ).
2) When AA=0, KK=0 no current will flow and LED is off.
3) When AA=1, KK=1 no current will flow and LED is off.
4) When AA=1, KK=0 current will flow and LED is on.

Note that if KK is 1, AA can be changed 0 or 1 and the LED will not come on. So AA can be set off (low) or on (high), KK then pulsed low, then returned to high. The brightness will depend on how long the pulse lasts for. This is the usual mechanism for Common Cathode operation of multiple or dimming LED's.

The same can be done by setting KK low (on) or high (off) and pulsing AA high, then returning low. This is the usual mechanism for Common Anode operation of multiple or dimming LED's.

Both AA and KK can be put on any PICAXE output pins but it makes sense to put the pin being pulsed on a 'standard output pin' so PULSOUT can be used to create the pulse, otherwise a TOGGLE PORTC, PAUSE, TOGGLE PORTC ( or similar sequence ) needs to be used to achieve the pulsing. PULSOUT has much finer control of the pulse timing.

For a larger multiplexor, all pulsed pins can be on the 'standard output pins' and the others on PORTC, they can be individually set using HIGH PORTC or LOW PORTC, or, often very conveniently in this case, all set together using LET PINSC.

If the multiplex only requires 8 I/O lines ( 2x6, 3x5, 4x4 ), they can all be placed on the single 'standard output pins' ( assuming it has 8 I/O lines - 20M, 18X etc ).

Charlieplexing reduces the number of I/O pins needed for multiplexing at the expense of more complicated LED wiring and slightly more complicated code for PICAXE's which can have the I/O port pin directions changed. A single 8-bit I/O port allows the control of 8x7 (56) LED's.

The same AA and KK configuration is used as previous but operation is more complicated, I/O pins are both AA and KK - A pin which is output low is the KK ( only one is a KK / low at any time ), a pin which is output high is an AA with a LED on, a pin which is an input is an AA with a LED off.

This should work with a 28X or 28X1, will work very well with a 28X2, and should potentially work with an 18X and also 14M, though I haven't calculated what maximum size multiplex the 14M could handle.
 
Last edited:

Mikler

Member
Hi Eclectic

Thanks again but I am looking to understand these lines of code.
(Thanks Hippy - I will print out your text and try and understand it...)

>> high portc LedON : pulsout 0,Level ; the &#8220;timer&#8221;
>> low portc LedON

high portc LedON = Turn on the current Port C LED
- this I understand
pulsout 0,Level = send pulses to standard output 0

Surely this is going to pulse whatever LED I have connected to output 0

Forgive a newbie question - i am obviously missing something here <sigh>

Mik
 

eclectic

Moderator
Edited

>> high portc LedON : pulsout 0,Level ; the “timer”
>> low portc LedON

high portc LedON = Turn on the current Port C LED
- this I understand
pulsout 0,Level = send pulses to standard output 0

Surely this is going to pulse whatever LED I have connected to output 0

Forgive a newbie question - i am obviously missing something here <sigh>

Mik
No, you're not missing anything. You're correct.
There is a "fluttering" on pin 1.

Again, please try and breadboard it,
to see the result.

e
 

Mikler

Member
Thanks Hippy and Eclectic

'The penny has just dropped' about multiplexing.... Aaaargh... my brain hurts :)

Can I ask another question? Do 'get me out of trouble', if I don't use multiplexing, can I control the dimming of an LED connected to a PortC using the 'pauseus' command instead of 'pulseout' and use that to give me 'finer' control?

Mik
 

eclectic

Moderator
Thanks Hippy and Eclectic

'The penny has just dropped' about multiplexing.... Aaaargh... my brain hurts :)

Can I ask another question? Do 'get me out of trouble', if I don't use multiplexing, can I control the dimming of an LED connected to a PortC using the 'pauseus' command instead of 'pulseout' and use that to give me 'finer' control?

Mik
Yes.
Code:
;portc outputs on
for LedON = 0 to 7
for Level = 1 to pulslen step Valstep
high portc LedON : pauseus Level ;pulsout 0,Level
low portc LedON
next
high portc LedON
next

;portc outputs off
for LedON = 7 to 0 step - 1
for Level = pulslen to 1 step - Valstep
high portc LedON  : pauseus Level ;pulsout 0,Level
pause 1
next
low portc LedON
next
does work on a 28X1
(I've just tried it)

You'll probably need to play with the "Level" values.

e
 
Last edited:
Top