How do I sequence LEDs? Plus other ?'s
Hello friends,
I have downloaded some very interesting LED .spin files from the OBEX, but I do not understand how they generate patterns or sequences. I would like to start off small and do this for example, blink all odd pinned LEDs, and while the odd LEDs are on, the evens are off, and vice verse. I was thinking a not statement would suffice paired with an if statement. However, I do not know how to conveniently assign a variable/constant for even numbered pins, or for that matter, how to assign multiple pins in general. Forgive me for my lack of knowledge I've only had this Propeller chip for a few days! Anyways, any help is appreciated!
I have downloaded some very interesting LED .spin files from the OBEX, but I do not understand how they generate patterns or sequences. I would like to start off small and do this for example, blink all odd pinned LEDs, and while the odd LEDs are on, the evens are off, and vice verse. I was thinking a not statement would suffice paired with an if statement. However, I do not know how to conveniently assign a variable/constant for even numbered pins, or for that matter, how to assign multiple pins in general. Forgive me for my lack of knowledge I've only had this Propeller chip for a few days! Anyways, any help is appreciated!

Comments
PUB even dira[23..16] := %01010101 repeat outa[23..16] ^= %01010101 ' even pins waitcnt(clkfreq/2 + cnt) PUB odd dira[23..16] := %10101010 repeat outa[23..16] ^= %10101010 ' odd pins waitcnt(clkfreq/2 + cnt) PUB even_odd dira[23..16]~~ outa[23..16] := %01010101 ' preset repeat outa[23..16] ^= %11111111 ' toggle even/odd waitcnt(clkfreq/2 + cnt)Given that each cog has its own direction register you can also run one cog only dealing with the odd pins and another handling the even pins. If both signal groups are related timing wise it would be more sensible to keep processing in one cog though which basically means your patterns have to be combined before being displayed.another way could be to start with &01010101 shift the bits one to the left and then shift back one to the right etc. etc.
best regards Stefan
This is very helpful. Although when I uploaded you supplied code only the odd numbered pins lit up; and it never switched back and forth between even/odd. I do not know how to debug it but I tried, and got no results. I understand now that [xx..yy] is how you list multiple pins. This will be very helpful in the future! One thing I am still confused about is how to shift the bits left/right. I know you use a << operator and specify how many bits to shift but how do you tell the dira to now turn on those pins? So if I had 001111 and shifted left 1111, how does it know that dira[xx..yy] := 001111 is now dira[xx..yy] := 110000 ?
As for your code only lighting odd LEDs, I don't know. Can you attach your program so I/we can have a look? re: shifting, ususally you setup dira once and do the rest with outa, e.g.
dira[23..16]~~ ' all 8 LEDs are output outa := $01010101 ' preset repeat outa <-= 1 waitcnt(clkfreq/10 + cnt)In general a cog should only ever touch pins (dira) it is going to drive (outa).What's the final goal here?
So do I use the % symbol for binary or the $ symbol for binary? I thought the manual suggested % for indicating binary? Also I do not know what "WYSIWYG" means, sorry. The end goal of all of this is being able to com up with sequences for LEDs. Essentially patterns for lights that I can incorporate into projects for my kids. I thought the propeller would be ideally suited for this task.
WYSIWYG, What You See Is What You Get. This is one of three editor types you can chose to edit your postings. Unfortunately this particular one is broken (I use the standard version). This can be changed in your profile settings.
Oh well that clears some things up! I have tried to bit shift, which I got to work a couple times, but overall not so much. So what I did was use binary for every outa call. Please examine my code and tell me what you think. Please don't be too harsh!
{{ ######################################################################################################## ######################################################################################################## ******************************** LED SEQUENCE: BIT by BIT ******************************** ******************************** By Justin A. McGillivary ******************************** ******************************** Date: September 30th, 2013 ******************************** ######################################################################################################## ######################################################################################################## - OVERVIEW - - This program demonstrates, bit by bit, an LED sequence for the Propeller P8X32A QuickStart Board (Rev.A 40000). - Here is a demonstration of how to control an LED sequence by turning off/on bits in some given order for effect. - This code, while some might consider 'sloppy' is easy to understand and grasp. By looking at each line of code with a "%" prefix, which indicates the LED(s) to be lit in Binary (ex. %10101010), it is easy to visualise what is taking place. - There is also a display of how to incorporate a system of repeats to generate a sequence of events. The infinite loop cycles the entire program while each "portion" is repeated a set number of times. Within these sets are the patterns to execute. The sequence of LEDs being lit can be changed by adjusting the repeat counts for each repeating loop. So what is taking place/actually happening? - We'll start by looking at the intial REPEAT loop. Since this has no whole number associated with it, it cycles forever. Each additional repeat is a PORTION or a PATTERN. The patterns make up the portions, and they repeat individually, while the portions repeat the patterns and make up the guts of the program. In the first pattern the LEDs will cycle with ODD/EVEN pins by turning every other bit on, or off, and vice verse. The second pattern turns on the LEDs from the outside bits to the inside bits, e.g pins 23/16 to 22/17 to 21/18 to 20/19. The next pattern turns 4 bits on, shifts them left, and repeats. So while 4 bits are on, 4 are off, and it alternates. The fourth pattern turns individual bits on or off in a left to right then right to left order. If you notice the binary symbol, "%" you can clearly see how the pattern unfolds. - Try changing any of the code to see how it affects the patterns! $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ $$$$$$$$$$$$$$$$$$$$$$ This program is uploaded in accordance with $$$$$$$$$$$$$$$$$$$$$$ $$$$$$$$$$$$$$$$$$$$$$ Parallax's Terms & Conditions on the Object Exchange. $$$$$$$$$$$$$$$$$$$$$$ $$$$$$$$$$$$$$$$$$$$$$ Please refer to http://obex.parallax.com/ for more details. $$$$$$$$$$$$$$$$$$$$$$ $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ }} PUB main dira[23..16] := %11111111 repeat ' Set up infinite loop repeat 3 ' Repeat this PORTION 3 times repeat 5 ' Repeat this pattern 5 times outa[23..16] := %10101010 ' ALTERNATING waitcnt(clkfreq/4 + cnt) !outa[23..16] waitcnt(clkfreq/4 + cnt) repeat 3 ' Repeat this pattern 5 times outa[23..16] := %00000000 ' OUTSIDE to INSIDE waitcnt(clkfreq/4 + cnt) outa[23..16] := %10000001 waitcnt(clkfreq/4 + cnt) outa[23..16] := %11000011 waitcnt(clkfreq/4 + cnt) outa[23..16] := %11100111 waitcnt(clkfreq/4 + cnt) outa[23..16] := %11111111 waitcnt(clkfreq/4 + cnt) repeat 5 ' Repeat this pattern 5 times outa[23..16] := %00001111 ' 4 ON/OFF waitcnt(clkfreq/4 + cnt) outa[23..16] <<= 4 waitcnt(clkfreq/4 + cnt) repeat 3 ' Repeat this pattern 5 times outa[23..16] := %10000000 ' LEFT to RIGHT waitcnt(clkfreq/4 + cnt) outa[23..16] := %11000000 waitcnt(clkfreq/4 + cnt) outa[23..16] := %11100000 waitcnt(clkfreq/4 + cnt) outa[23..16] := %11110000 waitcnt(clkfreq/4 + cnt) outa[23..16] := %11111000 waitcnt(clkfreq/4 + cnt) outa[23..16] := %11111100 waitcnt(clkfreq/4 + cnt) outa[23..16] := %11111110 waitcnt(clkfreq/4 + cnt) outa[23..16] := %11111111 waitcnt(clkfreq/4 + cnt) outa[23..16] := %00000001 ' RIGHT TO LEFT waitcnt(clkfreq/4 + cnt) outa[23..16] := %00000011 waitcnt(clkfreq/4 + cnt) outa[23..16] := %00000111 waitcnt(clkfreq/4 + cnt) outa[23..16] := %00001111 waitcnt(clkfreq/4 + cnt) outa[23..16] := %00011111 waitcnt(clkfreq/4 + cnt) outa[23..16] := %00111111 waitcnt(clkfreq/4 + cnt) outa[23..16] := %01111111 waitcnt(clkfreq/4 + cnt) outa[23..16] := %11111111 ' END OF LINEEDIT:
I also uploaded it to the OBEX, it can be found at...
http://obex.parallax.com/object/714
repeat 5 ' Repeat this pattern 5 times outa[31..16] := %11111111_00000000 ' LEFT to RIGHT repeat 8 outa[31..16] >>= 1 waitcnt(clkfreq/4 + cnt) outa[23..8] := %00000000_11111111 ' RIGHT TO LEFT repeat 8 outa[23..8] <<= 1 waitcnt(clkfreq/4 + cnt)Your next step could be to e.g. replay patterns from DAT memory (rather than hardcode the sequence in you method).How do I use the DAT object to do this? Any tutorials you could possibly point me to?
The thing I am after is learning how to generate these patterns more accurately and using less code (more efficient).
CON #0, PLAY, REWIND PUB null | indx dira[16..23]~~ indx := 0 ' first position repeat case sequence[indx++] ' read command and advance index PLAY: indx := display(indx) ' play pattern sequence REWIND: indx := 0 ' restart PRI display(indx) repeat sequence[indx++] ' number of patterns outa[16..23] := sequence[indx++] ' display waitcnt(clkfreq/4 + cnt) ' hardwired delay (could be part of sequence) return indx DAT sequence byte PLAY, 2, %11000011, %00111100 ' PLAY, pattern count, P0, P1, ... PN byte PLAY, 2, %11110000, %00001111 byte PLAY, 4, %10101010, %01010101, %11001100, %00110011 byte REWIND DATThis command interface can be easily expanded to include repeat counts, delays and data manipulations (e.g. rotate the following pattern n times) ...I've also written a lot of LED sequencer code for places like Disneyland.
If I could put you into a time machine and take you forward a year, I think you'd write a program more like the one that's attached.
Keys:
-- make your code flexible
-- make your code easy to read
-- make your code easy to modify
All keys involve not embedding "magic numbers" into your code. Changing the timing of your program would be a lot of work because of the style. Please trust me that when you're writing code for others they will want changes -- sometimes before you've finished implementing the last request.
What Marko suggested is something I do with LED sequencers: put the patterns and sequences into tables (in DAT sections). Here's how I translated your patterns (not all shown).
dat { patterns } ' patterns are simple; all elements use same timing Alternate byte 2 ' # elements in pattern byte %01010101 ' element #1 byte %10101010 OutsideIn byte 5 byte %00000000 byte %10000001 byte %11000011 byte %11100111 byte %11111111 FlipFlop byte 2 byte %00001111 byte %11110000Honestly, the hardest part is coming up with meaningful names for the patterns! Note that my table includes the number of elements in the pattern -- this lets me use any value in the table. We can play a the pattern with this bit of code Updated: 04 OCT):
pub play_pattern(p_pat, msb, lsb, ms, cycles, p_flag) | elements, p_leds '' Play pattern '' -- p_pat is pointer to pattern '' -- msb and lsb define output range (limit to eight bits) '' -- ms is timing (milliseconds) for each step '' -- cycles is # of times to play pattern '' -- p_flag is pointer to flag variable (set to false when done) '' * use -1 for no flag if (p_flag > 0) ' using flag? long[p_flag] := true ' mark busy repeat cycles elements := byte[p_pat] ' get elements in pattern p_leds := p_pat + 1 ' set working pointer to 1st element repeat elements ' loop through elements set_leds(msb, lsb, byte[p_leds++]) ' display, point to next pause(ms) ' hold if (p_flag > 0) ' using flag? long[p_flag] := false ' mark doneIt's a little involved, but gives you a lot of flexibility. You pass the address of the pattern, the pins to use, the timing for each element, and the number of cycles to play. By passing the pins as parameters you can use the same table on different sets of outputs. You could even play them in different cogs (I did this on a Disney project).
LED output is easy:
This sets your outputs -- wherever they are and makes sure that the IO pins are in output mode.
Here's my translation of your program (Updated: 04 OCT.
pub main | scale set_leds(LED7, LED0, %0000_0000) ' start off repeat 3 play_pattern(@Alternate, LED7, LED0, 250, 5, -1) ' play in main cog play_pattern(@OutsideIn, LED7, LED0, 250, 3, -1) play_pattern(@FlipFlop, LED7, LED0, 250, 5, -1) play_pattern(@RightLeft, LED7, LED0, 250, 3, -1)Easy, right? Need to speed up a pattern? No problem, change the timing parameter in the call. Done!
There's an additional feature in my program that let's you define sequences that include the timing for each step. I'll leave you to explore that.
Have fun!
WHOOPS! When I updated the program to allow pins as parameters I neglected to fully edit the set play_pattern() and play_sequence() methods. Those are fixed now and the demo updated to show you how to launch them into their own cogs so you can have patterns running in the background while your foreground code is doing other things. To facilitate this feature, I added a flag to each method that gets set to true when the pattern or sequence is playing, and then to false when done. By using a flag we don't have to calculate the duration of a pattern or sequence (steps * ms * cycles).
I realize that some of this code looks a little funky, but that's only because you're new. There will be an "Aha!" moment where it all comes together and you're free to be as creative as you like.
At some point you may want to add a little more pizazz while keeping the simplicity of storing patterns in DAT tables. This is what we did for the Disneyland Buzz Lightyear hand stamper. That device plays audio and a little light show at the same time. When the trigger is activated one of the audio clips is selected along with the pattern that goes with it. The main loop launches the WAV player cog, then the light show cog. The main loop waits monitors the audio and when finished, kills the light show cog if it has not already stopped.
We achieved a small level of brightness control by using quarternary numbers instead of binary patterns. For eight outputs this gives us four levels of brightness, though one assumes 0 will always be one of those levels. Have a look at the attached program.
BTW... did you see this post:
-- http://forums.parallax.com/showthread.php/150675-For-League-of-Legend-and-Wes-Borland-(Limp-Bizkit)-Fans?p=1211781#post1211781
I'm still worn out from several late nights (after my day job) programming that costume.