LED chaser/scanner

Jakob2803

Senior Member
While you are pondering my tachometer thread, I want to ask how to make an LED chaser/scanner. :) They seem to be inspired by that Knight Rider car. I would like to make one that chases back and forth with an adjustable speed. There is one made in Picaxe here: http://picprojects.org.uk/projects/ledchaserpwm/ but I am not sure I understand it correctly. How does the PWM aspect work?
I have written some code that creates a basic chase sequence but I am wondering how to adjust it. I would like to use an adjustable resistor/potmeter/trimpot and then let the Pic read the voltage level (readadc) and then use that to adjust the delay.
 

nick12ab

Senior Member
PWM control of LEDs is simply turning them on and off quickly with varying duty cycle to give the illusion of different brightnesses.

If you want assistance with your own code, could you please post it? A good starter, however, would be to use the readadc reading in a pause command. The PICAXE software PWM supports hardly any pins so you will have to implement software PWM yourself using pause commands.
 

westaust55

Moderator
The link that you gave is to a PIC ( not PicAxe) based project but could be done using an 18 pin PICAXE.

Have you done a search of this forum for past LED chasers/sequencers?
There have been such projects in the past inspired by knight rider type lighting.
Here is one past thread:
http://www.picaxeforum.co.uk/showthread.php?8956-Light-chaser

Are you looking to only have 8 LEDs or is the ultimate goal a greater number if LEDs.
For greater numbers, shift registers, IO expanders and multiplexing are some options. There are also some LED driver chips others have mentioned on this forum that can driver/control a large number of LEDs with 1 chip.

In the project you gave a link to the PWM is being used for 4 levels of LED brightness.
Such a feature may also be implemented directly with a PICAXE and also is a feature of some of the LED driver chips either as PWM or current control. With a PICAXE directly driving LEDs using the PWM to control the common side of the LEDs (via a transistor) is likely the best option.
 
Last edited:

Jakob2803

Senior Member
I am not sure what number of LEDs would be sufficient. The plan it to place them behind a strip of plexi that would be 5-6 inches long at most, to diffuse the light. I could do it with a 555 timer and a decade counter, but I also want to scan "backwards" after having done the first cycle.
 

Haku

Senior Member
In an RC Knight Rider car I have I replaced the rubbish 5 LED setup with a 'correct' 8 LED setup which is driven by an 18X running this code:
Code:
#picaxe 18x

'KITT scanning light

symbol pawz=24
symbol z1=255
symbol z2=100
symbol z3=33
symbol z4=7
symbol z5=1
setfreq m8


do
 for b0=0 to pawz:pulsout 0,z1:pulsout 1,z2:pulsout 2,z3:pulsout 3,z4:pulsout 4,z5:next b0
 for b0=0 to pawz:pulsout 1,z1:pulsout 0,z2:pulsout 1,z3:pulsout 2,z4:pulsout 3,z5:next b0
 for b0=0 to pawz:pulsout 2,z1:pulsout 1,z2:pulsout 0,z3:pulsout 1,z4:pulsout 2,z5:next b0
 for b0=0 to pawz:pulsout 3,z1:pulsout 2,z2:pulsout 1,z3:pulsout 0,z4:pulsout 1,z5:next b0
 for b0=0 to pawz:pulsout 4,z1:pulsout 3,z2:pulsout 2,z3:pulsout 1,z4:pulsout 0,z5:next b0
 for b0=0 to pawz:pulsout 5,z1:pulsout 4,z2:pulsout 3,z3:pulsout 2,z4:pulsout 1,z5:next b0
 for b0=0 to pawz:pulsout 6,z1:pulsout 5,z2:pulsout 4,z3:pulsout 3,z4:pulsout 2,z5:next b0
 for b0=0 to pawz:pulsout 7,z1:pulsout 6,z2:pulsout 5,z3:pulsout 4,z4:pulsout 3,z5:next b0
 for b0=0 to pawz:pulsout 6,z1:pulsout 7,z2:pulsout 6,z3:pulsout 5,z4:pulsout 4,z5:next b0
 for b0=0 to pawz:pulsout 5,z1:pulsout 6,z2:pulsout 7,z3:pulsout 6,z4:pulsout 5,z5:next b0
 for b0=0 to pawz:pulsout 4,z1:pulsout 5,z2:pulsout 6,z3:pulsout 7,z4:pulsout 6,z5:next b0
 for b0=0 to pawz:pulsout 3,z1:pulsout 4,z2:pulsout 5,z3:pulsout 6,z4:pulsout 7,z5:next b0
 for b0=0 to pawz:pulsout 2,z1:pulsout 3,z2:pulsout 4,z3:pulsout 5,z4:pulsout 6,z5:next b0
 for b0=0 to pawz:pulsout 1,z1:pulsout 2,z2:pulsout 3,z3:pulsout 4,z4:pulsout 5,z5:next b0
loop
As the 18X only has 1 PWM output I used pulsout instead as it works on all the output pins, the on/off frequency of the LEDs is nowhere near a proper PWM output but it's quick enough to look ok in the toy car, and as only 1 LED is ever on it uses little power. A Picaxe running at 16mhz or higher will make the LEDs blink on/off faster with that code and look a little less crude, but it will never match a properly coded PIC doing the same job, or a dedicated multiple-LED driving IC.

To alter the speed of the above chaser code on-the-fly you simply need to read a potentiometer and change the pawz variable accordingly.
 

Jakob2803

Senior Member
In an RC Knight Rider car I have I replaced the rubbish 5 LED setup with a 'correct' 8 LED setup which is driven by an 18X running this code:
Code:
#picaxe 18x

'KITT scanning light

symbol pawz=24
symbol z1=255
symbol z2=100
symbol z3=33
symbol z4=7
symbol z5=1
setfreq m8


do
 for b0=0 to pawz:pulsout 0,z1:pulsout 1,z2:pulsout 2,z3:pulsout 3,z4:pulsout 4,z5:next b0
 for b0=0 to pawz:pulsout 1,z1:pulsout 0,z2:pulsout 1,z3:pulsout 2,z4:pulsout 3,z5:next b0
 for b0=0 to pawz:pulsout 2,z1:pulsout 1,z2:pulsout 0,z3:pulsout 1,z4:pulsout 2,z5:next b0
 for b0=0 to pawz:pulsout 3,z1:pulsout 2,z2:pulsout 1,z3:pulsout 0,z4:pulsout 1,z5:next b0
 for b0=0 to pawz:pulsout 4,z1:pulsout 3,z2:pulsout 2,z3:pulsout 1,z4:pulsout 0,z5:next b0
 for b0=0 to pawz:pulsout 5,z1:pulsout 4,z2:pulsout 3,z3:pulsout 2,z4:pulsout 1,z5:next b0
 for b0=0 to pawz:pulsout 6,z1:pulsout 5,z2:pulsout 4,z3:pulsout 3,z4:pulsout 2,z5:next b0
 for b0=0 to pawz:pulsout 7,z1:pulsout 6,z2:pulsout 5,z3:pulsout 4,z4:pulsout 3,z5:next b0
 for b0=0 to pawz:pulsout 6,z1:pulsout 7,z2:pulsout 6,z3:pulsout 5,z4:pulsout 4,z5:next b0
 for b0=0 to pawz:pulsout 5,z1:pulsout 6,z2:pulsout 7,z3:pulsout 6,z4:pulsout 5,z5:next b0
 for b0=0 to pawz:pulsout 4,z1:pulsout 5,z2:pulsout 6,z3:pulsout 7,z4:pulsout 6,z5:next b0
 for b0=0 to pawz:pulsout 3,z1:pulsout 4,z2:pulsout 5,z3:pulsout 6,z4:pulsout 7,z5:next b0
 for b0=0 to pawz:pulsout 2,z1:pulsout 3,z2:pulsout 4,z3:pulsout 5,z4:pulsout 6,z5:next b0
 for b0=0 to pawz:pulsout 1,z1:pulsout 2,z2:pulsout 3,z3:pulsout 4,z4:pulsout 5,z5:next b0
loop
As the 18X only has 1 PWM output I used pulsout instead as it works on all the output pins, the on/off frequency of the LEDs is nowhere near a proper PWM output but it's quick enough to look ok in the toy car, and as only 1 LED is ever on it uses little power. A Picaxe running at 16mhz or higher will make the LEDs blink on/off faster with that code and look a little less crude, but it will never match a properly coded PIC doing the same job, or a dedicated multiple-LED driving IC.

To alter the speed of the above chaser code on-the-fly you simply need to read a potentiometer and change the pawz variable accordingly.
Damn that is some advanced code. :) Yes regarding the potentiometer, how would I do that? The command to use would probably be readadc but how do I keep the picaxe from exploding from all the current the pot would generate? A voltage divider?

Edit: Nick, here is my code, I think it could be done with fewer lines but I do not know how. :)
Code:
symbol LED0 = B.0 'Naming output pins
symbol LED1 = B.1
symbol LED2 = B.2
symbol LED3 = B.3
symbol LED4 = B.4
symbol LED5 = B.5
symbol LED6 = B.6
symbol LED7 = B.7
symbol tid = b0

main:

chase:
let tid = 20 'Set delay
'This would be where readadc could be used I think

high LED0 'Start chase sequence
pause tid

high LED1
pause tid
low LED0

high LED2
pause tid
low LED1

high LED3
pause tid
low LED2

high LED4
pause tid
low LED3

high LED5
pause tid
low LED4

high LED6
pause tid
high LED7

low LED5
pause tid
low LED6
pause tid

high LED6 'Chase back
pause tid
low LED7

high LED5
pause tid
low LED6

high LED4
pause tid
low LED5

high LED3
pause tid
low LED4

high LED2
pause tid
low LED3

high LED1
pause tid
low LED2

high LED0
pause tid
low LED1

goto main
 

nick12ab

Senior Member
Damn that is some advanced code. :) Yes regarding the potentiometer, how would I do that? The command to use would probably be readadc but how do I keep the picaxe from exploding from all the current the pot would generate? A voltage divider?

Edit: Nick, here is my code, I think it could be done with fewer lines but I do not know how. :)
Code:
symbol LED0 = B.0 'Naming output pins
symbol LED1 = B.1
symbol LED2 = B.2
symbol LED3 = B.3
symbol LED4 = B.4
symbol LED5 = B.5
symbol LED6 = B.6
symbol LED7 = B.7
symbol tid = b0

main:

chase:
let tid = 20 'Set delay
'This would be where readadc could be used I think

high LED0 'Start chase sequence
pause tid

high LED1
pause tid
low LED0

high LED2
pause tid
low LED1

high LED3
pause tid
low LED2

high LED4
pause tid
low LED3

high LED5
pause tid
low LED4

high LED6
pause tid
high LED7

low LED5
pause tid
low LED6
pause tid

high LED6 'Chase back
pause tid
low LED7

high LED5
pause tid
low LED6

high LED4
pause tid
low LED5

high LED3
pause tid
low LED4

high LED2
pause tid
low LED3

high LED1
pause tid
low LED2

high LED0
pause tid
low LED1

goto main
Why would the pot generate lots of current? It wouldn't and even if it did, as long as the output isn't greater than the PICAXE supply voltage at any point, there will be no damage.

Here's my version of your code, taking advantage of the fact that 'B.0' etc. are just pin constants.
Code:
symbol tid = b0
symbol loopcounter = b1
symbol temp = b2
    dirsB = %11111111
    tid = 20
    do
        for loopcounter = 0 to 7
            high loopcounter
            temp = loopcounter - 1
            low temp
            temp = loopcounter + 1 max 7
            if temp < 8 then : high temp : end if
            pause tid
        next loopcounter
        for loopcounter = 7 to 0 step -1
            high loopcounter
            temp = loopcounter - 1
            high temp
            temp = loopcounter + 1 max 7
            low temp
            pause tid
        next loopcounter
    loop
It doesn't use much less memory, but it does use less memory and it does take up a lot less lines. The big savings would probably come when you add in the PWM routines.
 

Bill.b

Senior Member
Try this code for 8 LEDS if more are required, you can use a word variable (w0) and output over to words (port B and C 28x2)
and pot input on a.0
This code worked ok on symulation using an 18m2

Code:
symbol counter =b0
symbol delay = w2
symbol delayIn = c.0

delay = 200  'preset delay range 0 - 1023
dirsb= %11111111
counter=1
pinsb = counter
pause delay

main:
readadc10 delayIn,delay
'calculate requied delay range here if greater then 1023
do
	if counter=1 then
		counter=counter+2
	else 
		counter=counter*2
	endif
	pinsb = counter
	pause delay
	if counter > 192 then
		counter = 128
		pinsb = counter
	endif
	pause delay
loop until counter = 128
pause 100
do
	if counter=128 then
		counter=192
		pinsb = counter
	else
		counter=counter/2
		pinsb = counter
	Endif
	if counter= 3 then
		pause delay
		counter=1
		pinsb = counter
	endif
loop until counter=1
pause delay
goto main
Bill
 

IronJungle

Senior Member
Interesting... I was just playing with this last night.

It also depends on how sophisticated you want to be. Last night I was doing some simple experiments to learn the "let dirs", "let pins", and "lookup" commands. I decided to do a NightRider display. Here are the results and my simple code. No PWM, but it still looks "NightRider" to me; I guess due to eye and LED persistance.

30 sec vid at:

Code is:
Code:
#picaxe18m2
let dirsB = %11111111 ; 1 is output. 0 is input

main:

readadc C.1, b0 ' Read POT into var b0

for b1 = 0 to 7 step 1  ' turn ON or OFF the LEDs by using 'lookup' to set var b2
	lookup b1, ( %00000001, %00000010, %00000100 ,%00001000, %00010000, %00100000, %01000000, %10000000), b2
	let pinsb = b2
	pause b0
next b1


for b1 = 7 to 0 step -1 ' turn ON or OFF the LEDs by using 'lookup' to set var b2
	lookup b1, ( %00000001, %00000010, %00000100 ,%00001000, %00010000, %00100000, %01000000, %10000000), b2
	let pinsb = b2
	pause b0
next b1

goto main
 

Jakob2803

Senior Member
Ironjungle: I pasted your code into the programming editor and it simulates perfectly. :) Also your website is pretty cool with the GPI board and your other stuff. :D Unless I figure out something better (unlikely) I will probably use your code if that is okay ;)
Someone elsewhere showed me circuit using just a 555 and a decade counter, I will build it in Yenka and see if it works.
 

IronJungle

Senior Member
No problem using my code and thanks for the comments.

I think the PICAXE will be a whole lot easier than the 555 and way way way more flexible.

Good luck and be sure to post up your results.
 

Jakob2803

Senior Member
I have kinda built it on the breadboard, the speed fluctuates a lot because I have not connected anything to C.1 :) Will a high resistor make it slower or faster?
 

westaust55

Moderator
A pull-up resistor will increase the pause time and make the LED sequence changes slower.
A pull-down resistor will make the LED sequence run faster.
 
Last edited:

Jakob2803

Senior Member
A pull-up resistor will increase the pasue time and make the LED sequence changes slower.
A pull-down resistor will make the LED sequence run faster.
Thanks. Using the either the smallest or biggest resistor I have on the negative side, it makes it very fast. On the positive side it makes it very slow. It does not matter what resistor I use, what gives? Is it not adjustable then?
 

Haku

Senior Member
Damn that is some advanced code. :) Yes regarding the potentiometer, how would I do that? The command to use would probably be readadc but how do I keep the picaxe from exploding from all the current the pot would generate? A voltage divider?
Yes a voltage divider between the power lines going to the Picaxe, with the 'middle' pin of the pot going into a Picaxe pin, there you would simply use readadc into the pawz variable.
Probably putting the readadc code every other line of the main loop so you don't have to wait for the 'scan' to get back to the start before it reads and changes the speed.

This is what my code looks like when running:

Difficult to capture on camera, the fading trail effect looks better with your own eyes.
 

eclectic

Moderator
As a possibility,

One ADC pin for the "delay" value.

One PWMout pin, linked to
eight Inputs.
"Switch on" each input in a
0 - 7 - 0 - 7... pattern.

A PWMout subroutine

Pseudocode
Code:
For b0 = 0 to 255
PWMout 1, 63, b0
pause delay
next
For b0 =  255 to 0 step -1
PWMout 1, 63, b0
pause delay
next

return
e
 

Attachments

IronJungle

Senior Member
I think you are using my code for this. Here are some details on how the potentiometer I am adjusting is connected to the PICAXE (from the AXE091 documentation):

"The pot is a 10K device connected directly between the V+ and 0V power rails.
The wiper of the 10K pot is connected to the PICAXE input"

What is happening is the PICAXE is reading the voltage drop between the 10K pot wiper and ground. This value is read by the PICAXE as a value between 0-255 and used for the delay value in my code.
 

Jakob2803

Senior Member
I think you are using my code for this. Here are some details on how the potentiometer I am adjusting is connected to the PICAXE (from the AXE091 documentation):

"The pot is a 10K device connected directly between the V+ and 0V power rails.
The wiper of the 10K pot is connected to the PICAXE input"

What is happening is the PICAXE is reading the voltage drop between the 10K pot wiper and ground. This value is read by the PICAXE as a value between 0-255 and used for the delay value in my code.
Yes I am indeed using your lovely code for this. :) Okay thanks, I will try to get hold of a 10k pot. So it should be linear right?
 

IronJungle

Senior Member
Yes. Linear pot, but it does not have to be 10K. Any ol' pot will work. If the max value is too small the delay may be a bit 'notchy'.
 

IronJungle

Senior Member
You have to admit that was easier than using a 555 chip.
And... Now that you know how to control 8 LEDs with a PICAXE the sky is the limit!

Maybe work on the PWM version now?

Oh, and your breadboard is not that messy...
 

Jakob2803

Senior Member
You have to admit that was easier than using a 555 chip.
And... Now that you know how to control 8 LEDs with a PICAXE the sky is the limit!

Oh, and your breadboard is not that messy...
Thanks ;) So is there a way to use some of C-pins also to expand the number of LEDs? In your code you wrote "let pinsb" so you can't just lump more 0s and 1s on the back of that. The only way would be the clumsy one I started out with right? By writing high and low for each pin individually.
 

Bill.b

Senior Member
this code will scan 16 LEDs using port b and c of a 28x2

the 18 m2 will not work using direct outputs as c.4 and c.5 are inputs only.
you could use multiplexing to control 16 LEDs with the 18m2.

Code:
symbol counter =w3
symbol delay = w2
symbol delayIn = a.0

delay = 200  'preset delay range 0 - 1023
dirsb= %11111111
dirsc= %11111111
counter=1
pinsb = b6
pinsc = b7
pause delay
main:
readadc10 delayIn,delay
'calculate requied delay range here if greater then 1023
do
	counter=counter*2
	pinsb = b6
	pinsc = b7
	pause delay
loop until counter = 32768
pause 100
do
	counter=counter/2
	pinsb = b6
	pinsc = b7
               pause delay

loop until counter=1
pause delay
goto main
Bill
 

boriz

Senior Member
@Jakob2803. I'll try to explain.

Just like the word variable W0 is made up of B0 and B1, B0 is made up of Bit0-Bit7. So for example, changing Bit2 from 0 to 1 will also change the value of B0 and W0. They are all part of the same variable memory space. Hippy is suggesting using this feature to make setting output pins easier in your code. You make a sub like this:

Code:
setpins:
   pinC.3 = bit0
   pinC.1 = bit1
   pinC.2 = bit2
   pinC.0 = bit3
   pinB.7 = bit4
   pinB.6 = bit5
   pinB.5 = bit6
   pinB.1 = bit7
return
Then anyplace in your program where you need to update the output pins to a new pattern, you execute this code:

Code:
B0=new_pattern
gosub setpins
The reason why this can be better than the simple 'pins=new_pattern', is because the output pins can be spread over different output ports and be arranged in any order that's most convenient for your program or your hardware. Look at the example (taken from Hippys post) above. The Setpins subroutine is setting the pins of two different output ports (B and C) and they are in a non linear order. Probably chosen at random by Hippy just for sake of example, but real applications may require similar 'not ordered numerically' output patterns.

Make more sense now?
 

IronJungle

Senior Member
Thanks. It was Cheap, too. The end program has some extra features that I snipped out to keep the example simple. Pushing a button causes the LED bar to cycle from "NightRider", to "DriftUP", to "Drift Down", to "RandomDisplay, to "ect, etc, etc.". I actually think I will move the demo to a PCB because, well, it looks cool sitting on my desk. :cool:
 

Jeff Haas

Senior Member
IronJungle,

Can you post the whole project, including your original source, to your blog? I'm thinking of a friend who has a project coming up that should be able to adapt your work.

Jeff
 

IronJungle

Senior Member
Jeff:

No problem.
The 'simple' source code is on the YouTube vid description. What else is needed? Schematic?
Thanks for watching.
 

lemaxnut

Member
Newbie here so I could understand maybe 50% of this thread - I was looking to use all 14 outputs for an 18M2 CHI030 project board.
I am already using dirsB instruction to make outputs, do I do the same for pins C ? and how do I turn C pins on and off? does %00000111 still work ? What would the code look like, or is it sequential?
I will be boosting the output currents with ULN 2003 chip taking the signal from the C pins. Thanks!
 

lemaxnut

Member
this code will scan 16 LEDs using port b and c of a 28x2

the 18 m2 will not work using direct outputs as c.4 and c.5 are inputs only.
you could use multiplexing to control 16 LEDs with the 18m2.

Since C.4 and C.5 are inputs, would the code work if you indicated they were to just indicate outputs with 1 and the rest of the C pins with 0 ?
 

IronJungle

Senior Member
Can you post the whole project, including your original source, to your blog?
The project build page is up at: http://ijprojects.blogspot.com/2012/05/progression-of-picaxe-led-chaser-knight.html

The code is at the bottom of the blog page. I would be interested in any (kind) comments about my 'button press' detection loop. The goal was to not count holding down the button as multiple button presses. My code certainly works, but seems 'clunky' and I would like some educated suggestions on better ways.

Thanks all.
 

IronJungle

Senior Member
Okay, I'll post my button press routine here; maybe get a comment or two....
Basically, the program hits this routine over and over (and over) waiting for a button press. Is there a better way to guarantee one and only one button press will be detected at a time. Like I said above, the routine works, but seems like there is a better way.

Also, the LED Chaser has been running on 3 fully charged NiCad AA since May 26th. Predictions on how long it will run? (I guess 45 days.)
Winning guess gets, well; nothing. Bragging rights, I guess....

Code:
if ButtonPush = 1 then 'jump to a different Case Select routine
        pause 25
    Do While ButtonPush = 1
       pause 25
    loop
    pause 25
  
    if WhatCase = MaxCases then
       let WhatCase = 0 ' reset WhatCase if it is equal the # of possible display cases programmed
    endif

    WhatCase = WhatCase + 1
endif
 

vttom

Senior Member
I think the following snippet more-or-less does the same thing with no need for any pauses...

Code:
Do

  ' Park here while button is not pressed
  Do While ButtonPush = 0
  Loop

  ' Park here while button is pressed
  Do While ButtonPush = 1
  Loop

  If WhatCase = MaxCases then
    WhatCase = 1
  Else
    inc WhatCase
  EndIf

Loop
 
Top