Here is the example I'm using in the Counter Documentation, it runs an assembly cog and it's counter. Feeding a value 0-100 to the parameter·variable sets the percent on of the channel. The spin code demonstrates it with a upward slope sawtooth, but you can write your own spin code to do whatever you want it to do. Setting the value in the spin's waitcnt sets the speed at which the value is updated (and hence how quickly the fading occurs). To change the IO pin the output is on, change the 0 in diraval and the trailing 0 (after the + symbol) in ctraval to the pin number.
PS ignore the reference to "PLL" in the top comment, thats an artifact of rewriting code, the example shown does not use the counter's PLL.
Try this, manual PWM without counters, assumes the LED is connected to I/O port 0. Used it during testing to test each processor to make sure its working.
Andre'
Call like this from other spin code:
VAR
· ' glowing rate · long glow_rate
OBJ · glow· : "glow_led_001.spin"····· ' glowing led driver
' /////////////////////////////////////////////////////////////////////////////
' glow_led_001.spin
' Glow Led object - simple glows the led slowly, lets you know the processor
' is processing, and looks very cool --
'
' AUTHOR: Andre' LaMothe
' LAST MODIFIED: 2.09.06
' VERSION 0.1
' COMMENTS: Simply call start(@rate) where rate is $00000000 - $FFFFFFFF
' $00000800 creates a 1 second cycle approx., looks nice
' ///////////////////////////////////////////////////////////////////////////
CON
DEBUG_LED_PORT_MASK = $00000001 ' debug LED is on I/O P0
VAR · long· cogon, cog
PUB start(glow_led_parms_ptr) : okay
'' Start glowing LED- starts a cog
'' returns false if no cog available
'' · stop · okay := cogon := (cog := cognew(@entry,glow_led_parms_ptr)) > 0
PUB stop
'' Stops driver - frees a cog · if cogon~ ··· cogstop(cog)
DAT ······················· org $000
' Entry point
'
entry ······················· nop ······················· ······················· ' initialize debug LED ······················· or· DIRA, #DEBUG_LED_PORT_MASK· ' set pin to output ······················· and OUTA, #(!DEBUG_LED_PORT_MASK) & $1ff ' turn LED off to begin ······················· mov lptr, par·················· ' copy parameter pointer to global pointer for future ref ······················· rdlong debug_led_inc, lptr····· ' now access main memory and retrieve the value
:glow_loop ······················· ' add the current brightness to the counter ······················· add debug_led_ctr, debug_led_brightness················ wc·····················
······················· ' based on carry turn LED on/off ······· if_c··········· or· OUTA, #DEBUG_LED_PORT_MASK ······· if_nc·········· and OUTA, #(!DEBUG_LED_PORT_MASK) & $1FF
······················· ' update brightness and invert increment if we hit 0 ······················· add debug_led_brightness, debug_led_inc················ wz····················· ······· if_z··········· neg debug_led_inc, debug_led_inc ······················· ' loop and do forever························································································· ······················· jmp #:glow_loop········
Thank you all for your replies. I used Paul's examples because I actully needed the LED to turn on and then fade away. I able to do this very simply be reversing 0 to period to period to 0 in the repeat line. ALSO I would like to use this fading on eight LED in a castcading effect. Any tips on what would be the easiest way of doing this?
Assuming you want some overlap between the 8 leds dimming then you will have to use both timmers and once one is in the off state reconfigure it to dim the next led, the two will then leapfrog each other.
Instead consider doing it using waitcnt in spin, its only LEDs after all you don't need high speed or precision. What you can do is have a loop and use wait count to ensure it is a certain length (to remove uncertainty due to code branches), then deterimine the on and off times of your leds interms of numbers of loops, it just becomes a matter of counting then.
Here is some spin that dims two leds, copy and paste bits for more, its badly written but you will get the idea:
'' A badly written program to dim one led after another.
'' As written dims leds on demoboard
'' You could do the same in asm and it would be much better.
CON
_clkmode = xtal1 + pll16x
_xinfreq = 5_000_000
PUB main | on_time1,off_time1,i,j,state1,target1,T,state2,target2 ,on_time2,off_time2,d2, delay2
dira[noparse][[/noparse]16] := 1 ' make an output
dira[noparse][[/noparse]17] := 1
T := 100 ' Time period in loops (make larger for slower dim)
on_time1 := T ' On time
on_time2 := T
off_time1 := 0 ' Off time
off_time2 := 0
state1 := 1 ' one is led on, 0 is off
state2 := 1
target1 := T
target2 := T
delay2 := 5000 ' Delay between first and second
repeat
outa[noparse][[/noparse]16] := state1
outa[noparse][[/noparse]17] := state2
i := i+1
j := j+1
if i == target1 ' first LED, just makes on time smaller and off time larger
if state1 == 1
target1 := ++off_time1
else
target1 := --on_time1
if on_time1 <> 0 ' So it stops.
!state1
i := 0
if j == target2 AND d2 > delay2
if state2 == 1
target2 := ++off_time2
else
target2 := --on_time2
if on_time2 <> 0
!state2
j := 0
if d2 < delay2 ' This is the delay for led2
d2 := d2 + 1
if d2 == delay2
j := 0
d2 := d2 + 1
Very close. But I need the to some how turn on one LED and while in the act of fading turn on the next LED. Do you think I can make this program work or change to a different method?(Assy?) And BIG thanks for the program.
Yes you can modify it to do what you want, just look at it, understand how it works and change it. What have you got to loose. Once you prove and refine the idea you could go for asm but there is no advantage IF this is fast enough.
I suspect you want to make something that looks like a knightrider stripe, the fading in that case is done by your eye, you keep seeing the led for a while before it disappears (called persistance of vision). And if the fade isn't long enough you just add a tiny capacitor (kit probably had bulbs not LEDs and that would have helped too. That is probably the simplest solution, then all you do is shift bits to turn each LED on in order, thats a tiny program in Spin or asm.
Hey Graham,
Can you help me understand this bit of code?
I think the starting value of "i" is 1 and starting value of "target1" is 100. Am I correct in thinking that the first IF statement is not met until the first 100 cycles?
thanks,
i := i+1
j := j+1
if i == target1 ' first LED, just makes on time smaller and off time larger
if state1 == 1
target1 := ++off_time1
else
target1 := --on_time1
if on_time1 <> 0 ' So it stops.
!state1
i := 0
Hey Graham,
Do you think this is the right direction?
I'm having trouble with the delay timing.
'' A badly written program to dim one led after another.
'' As written dims leds on demoboard
'' You could do the same in asm and it would be much better.
CON
_clkmode = xtal1 + pll16x
_xinfreq = 5_000_000
PUB main | on_time1,on_time2,on_time3,on_time4,on_time5,on_time6,on_time7,on_time8,off_time1,off_time2,off_time3,off_time4,off_time5,off_time6,off_time7,off_time8,state1,state2,state3,state4,state5,state6,state7,state8,target1,target2,target3,target4,target5,target6,target7,target8,i,j,k,l,m,n,o,p,T,d2, delay2
T := 50 ' Time period in loops (make larger for slower dim)
on_time1 := T ' On time
on_time2 := T
on_time3 := T
on_time4 := T
on_time5 := T
on_time6 := T
on_time7 := T
on_time8 := T
off_time1 := 0 ' Off time
off_time2 := 0
off_time3 := 0
off_time4 := 0
off_time5 := 0
off_time6 := 0
off_time7 := 0
off_time8 := 0
state1 := 1 ' one is led on, 0 is off
state2 := 0
state3 := 0
state4 := 0
state5 := 0
state6 := 0
state7 := 0
state8 := 0
target1 := T
target2 := T
target3 := T
target4 := T
target5 := T
target6 := T
target7 := T
target8 := T
i := i+1
j := j+1
k := k+1
l := l+1
m := m+1
n := n+1
o := o+1
p := p+1
if i == target1 ' first LED, just makes on time smaller and off time larger
if state1 == 1
target1 := ++off_time1
else
target1 := --on_time1
if on_time1 <> 0 ' So it stops.
!state1
i := 0
if j == target2 AND d2 > delay2
if state2 == 1
target2 := ++off_time2
else
target2 := --on_time2
if on_time2 <> 0
!state2
j := 0
if k == target3 AND d2 > delay2
if state3 == 1
target3 := ++off_time3
else
target3 := --on_time3
if on_time3 <> 0
!state3
k := 0
if l == target4 AND d2 > delay2
if state4 == 1
target4 := ++off_time4
else
target4 := --on_time4
if on_time4 <> 0
!state4
l := 0
if m == target5 AND d2 > delay2
if state5 == 1
target5 := ++off_time5
else
target5 := --on_time5
if on_time5 <> 0
!state5
m := 0
if n == target6 AND d2 > delay2
if state6 == 1
target6 := ++off_time6
else
target6 := --on_time6
if on_time6 <> 0
!state6
n := 0
if o == target7 AND d2 > delay2
if state7 == 1
target7 := ++off_time7
else
target7 := --on_time7
if on_time7 <> 0
!state7
o := 0
if p == target8 AND d2 > delay2
if state8 == 1
target8 := ++off_time8
else
target8 := --on_time8
if on_time8 <> 0
!state8
p := 0
if d2 < delay2 ' This is the delay for led2
d2 := d2 + 1
if d2 == delay2
j := 0
k := 0
l := 0
m := 0
n := 0
o := 0
p := 0
d2 := d2 + 1
The way PWM works is to have a constant frequency and variable on-time to off-time ratio. So what the program does it turn the LED on for 100 loops and off for one, then on for 99 loops and off for two, then on for 98 loops and off for three.
From first glances you need to add a delay for each LED, delay1, delay2 .... Realize that the delay section of code doesn't stop the loop going around it just waits for a certain number of loops before allowing the other parts of the program to do anything.
Gramam and Paul,
I decided to go in a different direction. Attached is my bit banging method and it works pretty good. I'm sure I could find a way to loop the process, but thats for another day.
My next step is to add the ablity to adjust the cycle rate and cycle delay. When I use the basic stamp, I use the RCTime command and connect a RC network to a input pin.
I tried this. Anyone know of a simple way to adjust a variable using a pot?
Mark
Comments
PS ignore the reference to "PLL" in the top comment, thats an artifact of rewriting code, the example shown does not use the counter's PLL.
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Paul Baker
Propeller Applications Engineer
Parallax, Inc.
Post Edited (Paul Baker (Parallax)) : 10/20/2006 10:54:01 PM GMT
Andre'
Call like this from other spin code:
VAR
· ' glowing rate
· long glow_rate
OBJ
· glow· : "glow_led_001.spin"····· ' glowing led driver
PUB start
·· ' start the glow object
· glow_rate := $800
· glow.start(@glow_rate)
And here's the object itself...
' /////////////////////////////////////////////////////////////////////////////
' glow_led_001.spin
' Glow Led object - simple glows the led slowly, lets you know the processor
' is processing, and looks very cool --
'
' AUTHOR: Andre' LaMothe
' LAST MODIFIED: 2.09.06
' VERSION 0.1
' COMMENTS: Simply call start(@rate) where rate is $00000000 - $FFFFFFFF
' $00000800 creates a 1 second cycle approx., looks nice
' ///////////////////////////////////////////////////////////////////////////
CON
DEBUG_LED_PORT_MASK = $00000001 ' debug LED is on I/O P0
VAR
· long· cogon, cog
PUB start(glow_led_parms_ptr) : okay
'' Start glowing LED- starts a cog
'' returns false if no cog available
''
· stop
· okay := cogon := (cog := cognew(@entry,glow_led_parms_ptr)) > 0
PUB stop
'' Stops driver - frees a cog
· if cogon~
··· cogstop(cog)
DAT
······················· org $000
' Entry point
'
entry
······················· nop
·······················
······················· ' initialize debug LED
······················· or· DIRA, #DEBUG_LED_PORT_MASK· ' set pin to output
······················· and OUTA, #(!DEBUG_LED_PORT_MASK) & $1ff ' turn LED off to begin
······················· mov lptr, par·················· ' copy parameter pointer to global pointer for future ref
······················· rdlong debug_led_inc, lptr····· ' now access main memory and retrieve the value
:glow_loop
······················· ' add the current brightness to the counter
······················· add debug_led_ctr, debug_led_brightness················ wc·····················
······················· ' based on carry turn LED on/off
······· if_c··········· or· OUTA, #DEBUG_LED_PORT_MASK
······· if_nc·········· and OUTA, #(!DEBUG_LED_PORT_MASK) & $1FF
······················· ' update brightness and invert increment if we hit 0
······················· add debug_led_brightness, debug_led_inc················ wz·····················
······· if_z··········· neg debug_led_inc, debug_led_inc
······················· ' loop and do forever·························································································
······················· jmp #:glow_loop········
'// VARIABLES //////////////////////////////////////////////////////////////////
debug_led_ctr·········· long··················· $00000000·· ' PWM counter
debug_led_inc·········· long··················· $0000000··· ' increment to add to counter
debug_led_brightness··· long··················· $80000000·· ' current brightness level
lptr··················· long··················· $00000000·· ' general long pointer
··················
http://forums.parallax.com/showthread.php?p=606978
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Tracy Allen
www.emesystems.com
Instead consider doing it using waitcnt in spin, its only LEDs after all you don't need high speed or precision. What you can do is have a loop and use wait count to ensure it is a certain length (to remove uncertainty due to code branches), then deterimine the on and off times of your leds interms of numbers of loops, it just becomes a matter of counting then.
Graham
Mark
Here is some spin that dims two leds, copy and paste bits for more, its badly written but you will get the idea:
I suspect you want to make something that looks like a knightrider stripe, the fading in that case is done by your eye, you keep seeing the led for a while before it disappears (called persistance of vision). And if the fade isn't long enough you just add a tiny capacitor (kit probably had bulbs not LEDs and that would have helped too. That is probably the simplest solution, then all you do is shift bits to turn each LED on in order, thats a tiny program in Spin or asm.
Graham
Can you help me understand this bit of code?
I think the starting value of "i" is 1 and starting value of "target1" is 100. Am I correct in thinking that the first IF statement is not met until the first 100 cycles?
thanks,
i := i+1
j := j+1
if i == target1 ' first LED, just makes on time smaller and off time larger
if state1 == 1
target1 := ++off_time1
else
target1 := --on_time1
if on_time1 <> 0 ' So it stops.
!state1
i := 0
Do you think this is the right direction?
I'm having trouble with the delay timing.
'' A badly written program to dim one led after another.
'' As written dims leds on demoboard
'' You could do the same in asm and it would be much better.
CON
_clkmode = xtal1 + pll16x
_xinfreq = 5_000_000
PUB main | on_time1,on_time2,on_time3,on_time4,on_time5,on_time6,on_time7,on_time8,off_time1,off_time2,off_time3,off_time4,off_time5,off_time6,off_time7,off_time8,state1,state2,state3,state4,state5,state6,state7,state8,target1,target2,target3,target4,target5,target6,target7,target8,i,j,k,l,m,n,o,p,T,d2, delay2
dira[noparse][[/noparse]16] := 1 ' make an output
dira[noparse][[/noparse]17] := 1
dira[noparse][[/noparse]18] := 1
dira[noparse][[/noparse]19] := 1
dira[noparse][[/noparse]20] := 1
dira[noparse][[/noparse]21] := 1
dira[noparse][[/noparse]22] := 1
dira[noparse][[/noparse]23] := 1
T := 50 ' Time period in loops (make larger for slower dim)
on_time1 := T ' On time
on_time2 := T
on_time3 := T
on_time4 := T
on_time5 := T
on_time6 := T
on_time7 := T
on_time8 := T
off_time1 := 0 ' Off time
off_time2 := 0
off_time3 := 0
off_time4 := 0
off_time5 := 0
off_time6 := 0
off_time7 := 0
off_time8 := 0
state1 := 1 ' one is led on, 0 is off
state2 := 0
state3 := 0
state4 := 0
state5 := 0
state6 := 0
state7 := 0
state8 := 0
target1 := T
target2 := T
target3 := T
target4 := T
target5 := T
target6 := T
target7 := T
target8 := T
delay2 := 2000 ' Delay between first and second
repeat
outa[noparse][[/noparse]16] := state1
outa[noparse][[/noparse]17] := state2
outa[noparse][[/noparse]18] := state3
outa[noparse][[/noparse]19] := state4
outa[noparse][[/noparse]20] := state5
outa[noparse][[/noparse]21] := state6
outa[noparse][[/noparse]22] := state7
outa[noparse][[/noparse]23] := state8
i := i+1
j := j+1
k := k+1
l := l+1
m := m+1
n := n+1
o := o+1
p := p+1
if i == target1 ' first LED, just makes on time smaller and off time larger
if state1 == 1
target1 := ++off_time1
else
target1 := --on_time1
if on_time1 <> 0 ' So it stops.
!state1
i := 0
if j == target2 AND d2 > delay2
if state2 == 1
target2 := ++off_time2
else
target2 := --on_time2
if on_time2 <> 0
!state2
j := 0
if k == target3 AND d2 > delay2
if state3 == 1
target3 := ++off_time3
else
target3 := --on_time3
if on_time3 <> 0
!state3
k := 0
if l == target4 AND d2 > delay2
if state4 == 1
target4 := ++off_time4
else
target4 := --on_time4
if on_time4 <> 0
!state4
l := 0
if m == target5 AND d2 > delay2
if state5 == 1
target5 := ++off_time5
else
target5 := --on_time5
if on_time5 <> 0
!state5
m := 0
if n == target6 AND d2 > delay2
if state6 == 1
target6 := ++off_time6
else
target6 := --on_time6
if on_time6 <> 0
!state6
n := 0
if o == target7 AND d2 > delay2
if state7 == 1
target7 := ++off_time7
else
target7 := --on_time7
if on_time7 <> 0
!state7
o := 0
if p == target8 AND d2 > delay2
if state8 == 1
target8 := ++off_time8
else
target8 := --on_time8
if on_time8 <> 0
!state8
p := 0
if d2 < delay2 ' This is the delay for led2
d2 := d2 + 1
if d2 == delay2
j := 0
k := 0
l := 0
m := 0
n := 0
o := 0
p := 0
d2 := d2 + 1
It then keeps the indentation and makes it easier to read.
or just attach the file
Graham
The way PWM works is to have a constant frequency and variable on-time to off-time ratio. So what the program does it turn the LED on for 100 loops and off for one, then on for 99 loops and off for two, then on for 98 loops and off for three.
And so on and so forth.
Graham
This is called a timing diagram, this will give you an idea of the values of the delays you will need to generate to get your sequence.
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Paul Baker
Propeller Applications Engineer
Parallax, Inc.
I decided to go in a different direction. Attached is my bit banging method and it works pretty good. I'm sure I could find a way to loop the process, but thats for another day.
Thanks,
Mark Harrison
I tried this. Anyone know of a simple way to adjust a variable using a pot?
Mark