November 23, 2024, 09:15:11 AM

News:

Got VSA?  Want to use your Prop-SX?  Now you can!  See the VSA section of the Library forum for Prop-SX code that works with VSA.


Dimmer-o-Rama -- can it be made better??

Started by TinkersALot, December 15, 2009, 01:25:12 PM

Previous topic - Next topic

TinkersALot

December 15, 2009, 01:25:12 PM Last Edit: December 15, 2009, 08:08:40 PM by TinkersALot
I am driving 3 each dimmers with a BS2. My first pass program is shown below. I am trying for a "psuedo random" display. This program is "functional" toward that end, but I don't think I am doing this the "best way". For example, this program nearly-completely-fills the BS2 program space. And the local variable memory is completely allocated. I'm posting the program here in the hops that someone may see ways for me to improve it (smaller and less variables).

Updated program is shown below.


JonnyMac

Do you really need all the DEBUG statements?  By removing them you can recover 32% of your program space.  You see, DEBUG is just a specialized form of SEROUT so, in the BS2, it consumes a lot of program space.

You obviously have programming experience.  What you may consider is using a conditional compilation directive so that you can turn levels of DEBUGging on and off.
Jon McPhalen
EFX-TEK Hollywood Office

JonnyMac

Here's another trick to consider -- you have some code like this:

 rnd_address = random_value // 256

This line is functionally equivalent, faster (because it's not doing a division operation), and uses a little less space:

 rnd_address = random_value.LOWBYTE
Jon McPhalen
EFX-TEK Hollywood Office

TinkersALot

Thank you for the great feedback! I will adopt some of these suggestions tonight. It may even give me 'room' to put in one more sub-routine for the final fade command that I did not have room for. Is it useful to keep posting new versions of the program, or would that be a bad idea?

TinkersALot

In considering your feedback further, it seems like I could cut in half the number of calls to random, by taking random_value.HIGHBYTE as the value assigned to some of the program variables as well.

Thank you again for helping me make this program better/smaller/faster/tighter.


JonnyMac

You're using a 16-bit value for your random number and extracting eight bits at a time, so you could do this:

  RANDOM lottery
  value1 = lottery.LOWBYTE
  value2 = lottery.HIGHBYTE
  RANDOM lottery
  value3 = lottery.LOWBYTE
  value4 = lottery.HIGHBYTE
Jon McPhalen
EFX-TEK Hollywood Office

TinkersALot

December 15, 2009, 08:07:47 PM #6 Last Edit: December 19, 2009, 12:11:54 PM by TinkersALot
This is a revision to the code that:

1. Reduces the RAM used (by sharing some variables where that can be safely done)
2. Removed all debug statements
3. Make use of HIGHBYTE and LOWBYTE to cut in half the number of calls to RANDOM
4. Has "last fade command" implemented (since there is 'plenty' of room for new code now)
5. Has more limited use of randomization due to it not (yet) producing 'visually interesting shows'.
6. Most of the intricate if-then-else-if logic has been replaced with a single generic function. The sacrifice made for this improvement was slightly heavier use of RAM.
7. Has more "light pattern" functions that encapsulate different arrangements of calls to the 'driver routines' and which are called by the main loop.

I'm not sure this is done yet, and will continue to try to add back some of the 'dynamic behavior' of the psuedo-random-based actions but this version is still fun to use in this current form:


' =========================================================================
'
'   File....... Dimmer-O-Rama.BS2
'   Purpose.... FC-4 Features Driver
'   Author..... TinkersALot
'   E-mail.....
'   Started....
'   Updated.... December 2009
'
'   {$STAMP BS2}
'   {$PBASIC 2.5}
'
' =========================================================================

' -----[ Program Description ]---------------------------------------------
'
'
' -----[ Revision History ]------------------------------------------------


' -----[ I/O Definitions ]-------------------------------------------------

DimmerPin       PIN     0                       ' SETUP = out, no ULN


' -----[ Constants ]-------------------------------------------------------

#SELECT $STAMP
 #CASE BS2, BS2E, BS2PE
   T2400       CON     396
   T38K4       CON     6
 #CASE BS2SX, BS2P
   T2400       CON     1021
   T38K4       CON     45
 #CASE BS2PX
   T2400       CON     1646
   T38K4       CON     84
#ENDSELECT

SevenBit        CON     $2000
Inverted        CON     $4000
Open            CON     $8000
DimmerBitRate   CON     Open + T38K4
MinLightLevel   CON     95


' -----[ Variables ]-------------------------------------------------------

random_value       VAR     Word
Alias              VAR     Byte                    ' lamp levels
out_level01        VAR     Alias
out_level02        VAR     Byte
out_level03        VAR     Byte
out_level04        VAR     Byte
LoopCounterMain    VAR     Byte
LoopCounterAction  VAR     Byte
LoopCounterDriver  VAR     Byte
rnd_address        VAR     Byte
rnd_channel        VAR     Byte
Seed               VAR     Byte
out_address        VAR     Nib
last_address       VAR     Nib
out_channel01      VAR     Nib
last_channel01     VAR     Nib
out_channel02      VAR     Nib
last_channel02     VAR     Nib
LoopStart          VAR     Nib
LoopEnd            VAR     Nib
MaxValue           VAR     Nib
Result             VAR     Nib
PreviousValue      VAR     Nib


' -----[ Initialization ]--------------------------------------------------

Reset:

 '   "!FC4", address, "X"
 '   -- sets all channels to 0% (0)
 '
 FOR out_address = 0 TO 2
   GOSUB AllChannelsOff
   PAUSE 35
 NEXT

'  FOR LoopCounterMain = 0 TO 2
'    GOSUB GetVersionInfo
'  NEXT

 LoopCounterMain = 0

Main:
 GOSUB GetRandomAddressChannel
 GOSUB GetRandomOutput01
 GOSUB GetRandomOutput02

 '=============================================================
 ' set up constraints and then call the GetValueFromBits routine
 ' that returns the first bit field that is set
 '
 LoopStart      = 5
 LoopEnd        = 7
 Seed           = rnd_address
 MaxValue       = 2
 PreviousValue  = last_address
 GOSUB GetValueFromBits
 last_address   = last_address + 1
 out_address    = Result

 LoopStart      = 0
 LoopEnd        = 3
 Seed           = rnd_channel
 MaxValue       = 3
 PreviousValue  = last_channel01
 GOSUB GetValueFromBits
 last_channel01 = last_channel01 + 1
 out_channel01  = Result

 LoopStart      = 4
 LoopEnd        = 7
 Seed           = rnd_channel
 MaxValue       = 3
 PreviousValue  = last_channel02
 GOSUB GetValueFromBits
 last_channel02 = last_channel02 + 1
 out_channel02  = Result

 SELECT LoopCounterMain
   CASE 0
     GOSUB DoPattern00

   CASE 1
     GOSUB DoPattern00
     GOSUB DoPattern01

   CASE 2
     GOSUB DoPattern00
     GOSUB DoPattern02

   CASE 3
     GOSUB DoPattern00
     GOSUB DoPattern03

   CASE 4
     GOSUB DoPattern00
     GOSUB DoPattern04

   CASE 5
     GOSUB DoPattern00
     FOR out_address = 0 TO 2
       GOSUB SimpleCrossFade
     NEXT

   CASE 6
     GOSUB DoPattern00
     FOR out_address = 0 TO 2
       GOSUB LevelSetCrossFade
     NEXT

   CASE 7
     GOSUB DoPattern00
     FOR out_address = 0 TO 2
       GOSUB LevelSetSteppedCrossFade
     NEXT
 ENDSELECT

 LoopCounterMain = LoopCounterMain + 1
 IF ( LoopCounterMain > 7 ) THEN
   LoopCounterMain = 0
 ENDIF

 GOTO Main


' -----[ Status Routines ]-------------------------------------------------

'--------------------------------------------------------------------------
'
'   "!FC4", address, "V"
'     -- requests verDimmerPinn string from FC-4
'     -- should be followed by SERIN to receive three-byte string
'
GetVersionInfo:
 SEROUT DimmerPin, DimmerBitRate, [ "!FC4", out_address, "V" ]
 SERIN  DimmerPin, DimmerBitRate, [ STR Alias\3 ]
 DEBUG "FC-4 Version Info: ", DEC out_address, STR Alias\3, CR
 PAUSE 500
RETURN

'--------------------------------------------------------------------------
'
'   "!FC4", address, "G"
'     -- retrieves present dimmer levels (four bytes)
'     -- should be followed by SERIN to receive four-byte status
'
Show_Status:
 SEROUT DimmerPin, DimmerBitRate, [ "!FC4", %00, "G" ]
 SERIN  DimmerPin, DimmerBitRate, [ STR Alias\4 ]
 DEBUG  "Levels = ", DEC3 out_level01, " ", DEC3 out_level02, " ",
                     DEC3 out_level03, " ", DEC3 out_level04, CR
RETURN


' -----[ Randomizer Routines ]---------------------------------------------
'
GetRandomAddressChannel:
 RANDOM random_value
 rnd_address = random_value.HIGHBYTE
 rnd_channel = random_value.LOWBYTE
RETURN

GetRandomOutput01:
 RANDOM random_value
 out_level01 = random_value.HIGHBYTE
 out_level02 = random_value.LOWBYTE
RETURN

GetRandomOutput02:
 RANDOM random_value
 out_level03 = random_value.HIGHBYTE
 out_level04 = random_value.LOWBYTE
RETURN


'--------------------------------------------------------------------------
'
' Find the first bit in the Seed that is set and use
' that bit position as the value to assign to the
' result
'
GetValueFromBits:
 Result = 16
 FOR LoopCounterAction = LoopStart TO LoopEnd STEP 1
   IF ( 1 & ( Seed >> LoopCounterAction ) ) THEN
     Result = LoopCounterAction - LoopStart
     ' force loop exit
     GOTO HaveBitValue
   ENDIF
 NEXT
HaveBitValue:
 IF ( Result = 16 ) THEN
   Result = PreviousValue + 1
   IF ( Result > MaxValue ) THEN
     Result = 0
   ENDIF
 ENDIF
RETURN


' -----[ Action Routines ]-------------------------------------------------

DoPattern00:
 FOR out_address = 0 TO 2 STEP 1
   FOR LoopCounterAction = 0 TO LoopCounterMain + 1 STEP 1
     IF ( LoopCounterAction & 1 ) THEN
       GOSUB AllChannelsOn
     ELSE
       GOSUB AllChannelsOff
     ENDIF
     PAUSE 750
   NEXT
 NEXT
RETURN

DoPattern01:
 GOSUB ChaseCountUpByChannelMajor
 PAUSE 750
 GOSUB ChaseCountDownByChannelMajor
 PAUSE 750
 GOSUB ChaseCountUpByAddressMajor
 PAUSE 750
 GOSUB ChaseCountDownByAddressMajor
 PAUSE 750
 GOSUB ChaseCountUpAllChannels
 PAUSE 750
 GOSUB ChaseCountDownAllChannels
 PAUSE 750
 GOSUB AllAddressChannelsOff
 PAUSE 750
RETURN

DoPattern02:
 FOR out_address = 0 TO 2 STEP 1
   FOR LoopCounterAction = 0 TO 8 STEP 1
     IF ( LoopCounterAction & 1 ) THEN
       GOSUB SetAllChannelLevels
     ELSE
       GOSUB SlowDimAllChannelsToZero
     ENDIF
     PAUSE 750
   NEXT
 NEXT
RETURN

DoPattern03:
 FOR out_address = 0 TO 2 STEP 1
   FOR LoopCounterAction = 0 TO 8 STEP 1
     IF ( LoopCounterAction & 1 ) THEN
       GOSUB SlowBrightAllChannels
     ELSE
       GOSUB SlowDimAllChannelsToZero
     ENDIF
     PAUSE 750
   NEXT
 NEXT
RETURN

DoPattern04:
 FOR LoopCounterAction = 0 TO 8 STEP 1
   FOR out_address = 0 TO 2 STEP 1
     FOR out_channel01 = 0 TO 3 STEP 1
       GOSUB FadeDownOneChannel
       PAUSE 750
       GOSUB FadeUpOneChannel
       PAUSE 750
     NEXT
   NEXT
 NEXT
RETURN


' -----[ Driver Routines ]-------------------------------------------------


'--------------------------------------------------------------------------
'
'   "!FC4", address, "A"
'     -- sets all channels to 100% (255)
'
AllChannelsOn:
 SEROUT DimmerPin, DimmerBitRate, [ "!FC4", out_address, "A" ]
RETURN

AllChannelsOff:
 SEROUT DimmerPin, DimmerBitRate, [ "!!!!!!!FC4", out_address, "X" ]
RETURN

AllAddressChannelsOn:
 FOR out_address = 0 TO 2 STEP 1
   GOSUB AllChannelsOn
 NEXT
RETURN

AllAddressChannelsOff:
 FOR out_address = 0 TO 2 STEP 1
   GOSUB AllChannelsOff
 NEXT
RETURN


'--------------------------------------------------------------------------
'
'   "!FC4", address, "D", digCtrl
'     -- sets outputs to 0% or 100% based on "digCtrl"
'     -- digCtrl.0 --> channel 1; digCtrl.3 --> channel 4
'
ChaseCountUpAllChannels:
 FOR LoopCounterDriver = %0000 TO %1111
   SEROUT DimmerPin, DimmerBitRate, [ "!FC4", out_address, "D", LoopCounterDriver ]
   PAUSE 200
 NEXT
RETURN

ChaseCountDownAllChannels:
 FOR LoopCounterDriver = %1111 TO %0000 STEP -1
   SEROUT DimmerPin, DimmerBitRate, [ "!FC4", out_address, "D", LoopCounterDriver ]
   PAUSE 200
 NEXT
RETURN

ChaseCountUpByAddressMajor:
 FOR out_address = 0 TO 2
   FOR LoopCounterDriver = %0000 TO %1111
     SEROUT DimmerPin, DimmerBitRate, [ "!FC4", out_address, "D", LoopCounterDriver ]
     PAUSE 200
   NEXT
 NEXT
RETURN

ChaseCountDownByAddressMajor:
 FOR out_address = 0 TO 2
   FOR LoopCounterDriver = %1111 TO %0000 STEP -1
     SEROUT DimmerPin, DimmerBitRate, [ "!FC4", out_address, "D", LoopCounterDriver ]
     PAUSE 200
   NEXT
 NEXT
RETURN

ChaseCountUpByChannelMajor:
 FOR LoopCounterDriver = %0000 TO %1111
   FOR out_address = 0 TO 2
     SEROUT DimmerPin, DimmerBitRate, [ "!FC4", out_address, "D", LoopCounterDriver ]
     PAUSE 200
   NEXT
 NEXT
RETURN

ChaseCountDownByChannelMajor:
 FOR LoopCounterDriver = %1111 TO %0000 STEP -1
   FOR out_address = 0 TO 2
     SEROUT DimmerPin, DimmerBitRate, [ "!FC4", out_address, "D", LoopCounterDriver ]
     PAUSE 200
   NEXT
 NEXT
RETURN

'--------------------------------------------------------------------------
'
'   "!FC4", address, "L", channel, level
'     -- sets "channel" (1 to 4) to "level" (0 to 255)
'
SetChannelLevel:
 out_level01 = out_level01 MIN MinLightLevel
 SEROUT DimmerPin, DimmerBitRate, [ "!FC4", out_address, "L", out_channel01, out_level01 ]
RETURN


'--------------------------------------------------------------------------
'
'   "!FC4", address, "S", level1, level2, level3, level4
'     -- sets all channel levels
'     -- you must send four bytes after the "S" command
'
SetAllChannelLevels:
 out_level01 = out_level01 MIN MinLightLevel
 out_level02 = out_level02 MIN MinLightLevel
 out_level03 = out_level03 MIN MinLightLevel
 out_level04 = out_level04 MIN MinLightLevel
 SEROUT DimmerPin, DimmerBitRate, [ "!FC4", out_address, "S", out_level01, out_level02, out_level03, out_level04 ]
RETURN


'--------------------------------------------------------------------------
'
'   "!FC4", address, "P", level
'     -- presets all channels to "level"
'
SlowDimAllChannelsToZero:
 GOSUB AllChannelsOn
 FOR LoopCounterDriver = 255 TO 0 STEP -1
   SEROUT DimmerPin, DimmerBitRate, [ "!FC4", out_address, "P", LoopCounterDriver ]
   PAUSE 35
 NEXT
RETURN

SlowBrightAllChannels:
 GOSUB AllChannelsOff
 FOR LoopCounterDriver = 0 TO 255
   SEROUT DimmerPin, DimmerBitRate, [ "!FC4", out_address, "P", LoopCounterDriver ]
   PAUSE 35
 NEXT
RETURN

SetLevelAllChannels:
 GOSUB AllChannelsOff
 out_level01 = out_level01 MIN MinLightLevel
 FOR out_address = 0 TO 2
   FOR LoopCounterDriver = 0 TO 3
     SEROUT DimmerPin, DimmerBitRate, [ "!FC4", out_address, "P", out_level01 ]
     PAUSE 35
   NEXT
 NEXT
RETURN


'--------------------------------------------------------------------------
'
'   "!FC4", address, "F", channel, start, end, stpTime
'     -- fades "channel" from "start" to "end"
'     -- duration of fade is "stpTime" (in milliseconds) x steps
'
FadeUpOneChannel:
 SEROUT DimmerPin, DimmerBitRate, [ "!FC4", out_address, "F", out_channel01, 0, 255, 8 ]
 PAUSE 2100
RETURN

FadeDownOneChannel:
 SEROUT DimmerPin, DimmerBitRate, [ "!FC4", out_address, "F", out_channel01, 255, 0, 8 ]
 PAUSE 2100
RETURN


'--------------------------------------------------------------------------
'
'   "!FC4", address, "C", 0, chA, chB, stpTime
'     -- cross fades from "chA" and "chB"
'     -- "chA" starts at 100%
'     -- "chB" starts at 0%
'     -- duration of fade is "stpTime" (in milliseconds) x 256
'
SimpleCrossFade:
 SEROUT DimmerPin, DimmerBitRate, [ "!FC4", out_address, "C", 0, out_channel01, out_channel02, 8 ]
 PAUSE 3800
RETURN


'--------------------------------------------------------------------------
'
'   "!FC4", address, "C", 1, chA, lvlA, lvlB, chB, stpTime
'     -- partial cross fades from "chA" and "chB"
'     -- "chA" starts at "lvlA", ends at "lvlB"
'     -- "chB" starts at "lvlB", ends at "lvlA"
'     -- duration of fade is "stpTime" (in milliseconds) x steps
'
LevelSetCrossFade:
 SEROUT DimmerPin, DimmerBitRate, [ "!FC4", out_address, "C", 1, out_channel01, 255, 0, out_channel02, 8 ]
 PAUSE 3800
RETURN


'--------------------------------------------------------------------------
'
'   "!FC4", address, "C", 2, chA, lvlA, lvlB, chB, steps, stpTime
'     -- partial cross fades from "chA" and "chB"
'     -- "chA" starts at "lvlA", ends at "lvlA" + "steps" (255 max)
'     -- "chB" starts at "lvlB", ends at "lvlB" - "steps" (0 min)
'     -- duration of fade is "stpTime" (in milliseconds) x steps
'
LevelSetSteppedCrossFade:
 SEROUT DimmerPin, DimmerBitRate, [ "!FC4", out_address, "C", 2, out_channel01, 255, 0, out_channel02, 255, 8 ]
 PAUSE 3800
RETURN
[font]