LED Progress Bar

I am making an LED progress where the user holds a button down and every second they hold it an additional bar lights up. If they let go anywhere in that sequence before getting to the end, they all turn off. I immediately went to stacking if statements. Turns out there's a limit of 8 nested items! How do I do this more efficiently?
if ina[RedButton] == 1
outa[7..13] := %1000000
waitcnt(clkfreq + cnt)
if ina[RedButton] == 1
outa[7..13] := %1100000
waitcnt(clkfreq + cnt)
if ina[RedButton] == 1
outa[7..13] := %1110000
waitcnt(clkfreq + cnt)
if ina[RedButton] == 1
outa[7..13] := %1111000
waitcnt(clkfreq + cnt)
if ina[RedButton] == 1
outa[7..13] := %1111100
waitcnt(clkfreq + cnt)
if ina[RedButton] == 1
outa[7..13] := %1111110
waitcnt(clkfreq + cnt)
if ina[RedButton] == 1
outa[7..13] := %1111111
RedFlag := 1
else
outa[7..13] := %0000000
else
outa[7..13] := %0000000
else
outa[7..13] := %0000000
else
outa[7..13] := %0000000
else
outa[7..13] := %0000000
else
outa[7..13] := %0000000
Comments
Reference: Propeller Manual v1.2 · Page 59
https://www.parallax.com/sites/default/files/downloads/P8X32A-Web-PropellerManual-v1.2.pdf#page59
eg:
while ina[RedButton] == 1
https://www.parallax.com/sites/default/files/downloads/P8X32A-Web-PropellerManual-v1.2.pdf#page188
VAR long pressTimer, pressPhase, outPattern, RedFlag PUB Main dira[7..13] := %1111111 repeat CheckButton 'do other stuff PUB CheckButton if ina[RedButton] if pressPhase if cnt - pressTimer > clkfreq pressTimer += clkfreq pressPhase++ if pressPhase > 6 RedFlag := 1 outPattern >>= 1 outPattern |= %100000 outa[7..13] := outPattern else outPattern := %100000 pressPhase := 1 pressTimer := cnt outa[7..13] := outPattern elseif pressPhase pressPhase := 0 outa[7..13] := 0 'RedFlag := 0 'Set to zero if applicable.
You have to define "RedButton".
I haven't tested this.
Edit: Set LED pins as outputs. More RedFlag code.
{Test for LED Meter while pressing button} CON _clkmode = xtal1 + pll16x 'Standard clock mode * crystal frequency = 80 MHz _xinfreq = 5_000_000 RED_BUTTON = 0 VAR OBJ debug : "Parallax Serial Terminal" PUB MAIN debug.start(115200) waitcnt(CLKFREQ/2+CNT) '' Wait for start up debug.str(string($d,"Hello.", $d)) waitcnt(CLKFREQ+CNT) repeat debug.Clear repeat while ina[RED_BUTTON] == 1 debug.str(string($d,"Button Pressed.")) waitcnt(CLKFREQ+CNT)
SHL and SHR are assembly commands. DOH I'm off track now.
CON _CLKMODE = XTAL1 + PLL16X _XINFREQ = 5_000_000 OBJ pst : "Parallax Serial Terminal" PUB M | idx, RedButton, seven_bits pst.Start(115_200) waitcnt(clkfreq * 2 + cnt) RedButton := 6 'RedButton has to be assigned a pin. Change it to your pin dira[7..13]~~ 'Same as := 1 repeat idx := 7 repeat 7 if ina[RedButton] 'Same as ina[RedButton] == 1 waitcnt(clkfreq / 1000 * 3 + cnt) 'Debounce, let the button settle. if ina[RedButton] outa[7..13] := seven_bits := seven_bits + (1 << idx--) '<< means shift left, -- means 'post decrement' waitcnt(clkfreq + cnt) else outa[7..13]~ 'Same as := 0 pst.Str(String(pst#NL, "seven_bits = ")) pst.Bin(seven_bits, 7) pst.Str(String(pst#NL, "idx = ")) pst.Dec(idx)
pub main | btnstate, t0, t1, level setup repeat ' wait for button release btnstate := ((btnstate << 1) | ina[RED_BTN]) & %11 if (btnstate == %00) quit repeat btnstate := ((btnstate << 1) | ina[RED_BTN]) & %11 ' re-scan if (btnstate == %11) ' held down? t1 := cnt ' update button timing level := ((t1-t0) / clkfreq) <# 8 ' get # of seconds pressed outa[MSB..LSB] := %11111111 >> (8-level) ' update graph else t0 := t1 := cnt ' reset timing outa[MSB..LSB] := %00000000 ' clear display
Hint: Don't hard-code pin numbers into your listing except into a CONstant definition that you can easily change later.
Update: Working code attached.
repeat idx := 7 seven_bits := 0 repeat 7 if ina[RedButton] 'Same as ina[RedButton] == 1 waitcnt(clkfreq / 1000 * 3 + cnt)
{Test for LED Meter while pressing button} CON _clkmode = xtal1 + pll16x 'Standard clock mode * crystal frequency = 80 MHz _xinfreq = 5_000_000 RED_BUTTON = 0 VAR long pattern OBJ debug : "Parallax Serial Terminal" PUB MAIN debug.start(115200) waitcnt(CLKFREQ/2+CNT) '' Wait for start up debug.str(string($d,"Hello.", $d)) dira[7..13] ~~ waitcnt(CLKFREQ+CNT) repeat debug.Clear pattern := %11111110000000 outa[7..13] := pattern repeat while ina[RED_BUTTON] == 1 debug.str(string($d,"Button Pressed.")) waitcnt(CLKFREQ+CNT) pattern >>= %01 outa [7..13] := pattern
CON _clkmode = xtal1 + pll16x _clkfreq = 80_000_000 BUTTON_PIN = 0 FIRST_LED = 7 LEDS_IN_BAR = 7 LAST_LED = FIRST_LED + LEDS_IN_BAR - 1 BAUD_115200 = 115200 VAR long pressTimer, pressPhase, outPattern long redFlag OBJ Pst : "Parallax Serial Terminal" PUB Main dira[LAST_LED..FIRST_LED] := |< LEDS_IN_BAR - 1 Pst.Start(BAUD_115200) repeat if redFlag DisplayRedFlag else DisplayNormal CheckButton 'do other stuff PUB CheckButton if ina[BUTTON_PIN] if pressPhase if cnt - pressTimer > clkfreq pressTimer += clkfreq pressPhase++ if pressPhase => LEDS_IN_BAR redFlag := true outPattern <<= 1 outPattern |= 1 outa[LAST_LED..FIRST_LED] := outPattern else outPattern := 1 pressPhase := 1 pressTimer := cnt outa[LAST_LED..FIRST_LED] := outPattern elseif pressPhase pressPhase := 0 redFlag := false outa[LAST_LED..FIRST_LED] := 0 PUB DisplayRedFlag Pst.ClearEnd Pst.NewLine Pst.ClearBelow Pst.Home Pst.Str(string(11, 13, "Red Flag Active!")) PUB DisplayNormal Pst.ClearEnd Pst.NewLine Pst.ClearBelow Pst.Home Pst.Str(string(11, 13, " LED Bar Program", 11, 13)) Pst.Str(string(11, 13, "pressPhase = ")) Pst.Dec(pressPhase) if pressPhase Pst.Str(string(11, 13, "outPattern = %")) Pst.Bin(outPattern, LEDS_IN_BAR)
Make sure you set "BUTTON_PIN" to the pin you are using.
I switched the value of "FIRST_LED" temporarily to 16 and tested the code on a QuickStart board. It seemed to work as expected.
Cleaned out the debug code:
{Test for LED Meter while pressing button} CON _clkmode = xtal1 + pll16x 'Standard clock mode * crystal frequency = 80 MHz _xinfreq = 5_000_000 RED_BUTTON = 0 VAR long pattern PUB MAIN dira[7..13] ~~ waitcnt(CLKFREQ+CNT) repeat pattern := %11111110000000 outa[7..13] := pattern repeat while ina[RED_BUTTON] == 1 waitcnt(CLKFREQ+CNT) pattern >>= 1 if pattern == %00000000111111 pattern := %00000001111111 outa [7..13] := pattern
Assume button on P0 active low, leds on P7..P13 active high
...........init no button? reset cnt and leds else clamp,turn on led, next cnt, wait
: DEMO 0 BEGIN 0 PIN@ IF DROP 0 %11111110000000 OUTCLR ELSE 6 MIN DUP 7 + HIGH 1+ THEN 1 s AGAIN ;
This version inits the count to the same as the first led and clamps at the last led.
: DEMO 7 BEGIN 0 PIN@ IF DROP 7 $3F80 OUTCLR ELSE 13 MIN DUP HIGH 1+ THEN 1 s AGAIN ;
pub demo | i i := 7 dira[7..13]~~ repeat if ina[0] ' assume button is on P0 i := 7 outa[7..13]~ else outa |= i<#13 i++ waitcnt(clkfreq+cnt)
Couldn't resist.....some propbasic
DEVICE P8X32A, XTAL1, PLL16X FREQ 80_000_000 swpin PIN 25 input 'switch input pulled hi 5k active lo ledpins pin 8..14 output '7 x led strip dlay con 80_000_000 '1 second of clocks @ 80MHz pval VAR long temp var long ' ====================================================================== PROGRAM START ' ====================================================================== START: do pval=%1111111 ledpins=pval 'all off waitpeq 0,swpin 'wait for switch operation temp=cnt+dlay do waitcnt temp,dlay if swpin=0 then 'switch operated pval=pval<<1 else exit endif ledpins=pval loop loop end
Dave
" : DEMO 7 BEGIN 0 PIN@ IF DROP 7 $3F80 OUTCLR ELSE 13 MIN DUP HIGH 1+ THEN 1 s AGAIN ;"
It even looks so ....light on the keyboard. Efficient.
Or maybe my brain is just playing tricks on me, hard to tell
Yes doggiedoc, that video is exactly what I'm looking to do.
main : idx repeat idx := (((idx + ina[redbutton]) <# 8 ) * ina[redbutton]) outa[hilight..lolight] := |< idx - 1 waitcnt(clkfreq+cnt)
The idx variable increments each time around the loop, only up to 8, due to the <#, and always returns to zero if the button is up, due to the muliplication.
The outputs are set to the decoded value of idx, minus 1. Read |< idx as "idx to the power of 2".
idx. |< idx - 1 0. 0. %00000000 1. 1. %00000001 2. 3. %00000011 3. 7. %00000111 4. 15 5. 31 6. 63 7. 127. 8. 255. %11111111 ...
You can flip the order by outa[lolight..hilight] instead of outa[hilight..lolight].
Excellent. The first thing I ever learned from Tracy Allen, I think it was in 2008, was scaling values. I learned to move the decimal point to the right to eliminate the decimal point, do integer calculations and then move the point back to the left.