November 25, 2024, 08:02:36 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.


Fluid Transfer Program

Started by Laytonk, April 23, 2013, 08:24:42 PM

Previous topic - Next topic

Laytonk

Hello, I need some assistance with a simple fluid transfer program using the HC-8+. Some background on the project I have a Prop1 Controller and a HC-8+ and if needed will purchase the microSD Adapter.  Just not sure what path to take so as to accomplish the project, Prop1 controlling the HC-8+, or using Vixien or Propeller to program the HC-8+. The system consists of one main fluid tank and three aux fluid tanks, the definitions below describe the planned controller connections and naming convention. I have also provided the planned program operation.
Definitions :
Switched Inputs
Aux Switch 1 = AS1 planned as IN0 on the HC-8+ (momentary)
Aux Switch 2 = AS2 planned as IN1 on the HC-8+ (momentary)
Aux Switch 3 = AS3 planned as IN2 on the HC-8+ (momentary)

Switched Outputs ON / OFF
Aux Pump 1 = AUX1 planned as OUT0 on the HC-8+
Aux Pump 2 = AUX2 planned as OUT1 on the HC-8+
Aux Pump 3 = AUX3 planned as OUT2 on the HC-8+

Transfer Valve 1 = TV1 planned as OUT3 on the HC-8+
Transfer Valve 2 = TV2 planned as OUT4 on the HC-8+

Transfer Light = TL planned as OUT5 on the HC-8+

Normal Operation
ONE:
Aux Switch 1 = (ON) (momentary)
Transfer Light = (ON) steady or flashing
Pause 1000
Aux Pump 1 = (ON)
Pause 5 minutes
Aux Pump 1 = (OFF)
Transfer Light = (OFF)
TWO:
Aux Switch 2 = (ON) (momentary)
Transfer Light = (ON) steady or flashing
Transfer Valve 1 = (ON)
Pause 1000
Aux Pump 2 = (ON)
Pause 5 minutes
Aux Pump 2 = (OFF)
Pause 1000
Transfer Valve 1 = (OFF)
Transfer Light = (OFF)
THREE:
Aux Switch 3 = (ON) (momentary)
Transfer Light = (ON) steady or flashing
Transfer Valve 2 = (ON)
Pause 1000
Aux Pump 3 = (ON)
Pause 5 minutes
Aux Pump 3 = (OFF)
Pause 1000
Transfer Valve 2 = (OFF)
Transfer Light = (OFF)







JonnyMac

Do the three processes need to operate independently and possibly simultaneously, or are things sequential as you list?

I would suggest getting a PropPlug and programming the HC-8+ directly; no need to tie up your Prop-1 or to use Vixen and the uSD adapter.
Jon McPhalen
EFX-TEK Hollywood Office

JackMan

Just a suggestion, if only 1 pump will be running at any given time and you can do without the 1 second PAUSE between the Transfer Light and the pump turning on, this can be done with just a Prop-1. I would also suggest a separate indicator light for each pump. The way you have it outlined you won't know which pump is running. If there will be more than 1 pump running simultaneously, then you will need the HC-8+. I am assuming you will be using some type of relay for activating the pumps.

JonnyMac

April 24, 2013, 10:12:32 AM #3 Last Edit: April 24, 2013, 10:36:23 AM by JonnyMac
JB and I have always believed the HC-8+ is a great platform for industrial control. I recently wrote a program for a well-known tools company that allows them to do accelerated life-testing using the HC-8+; that program actually runs three simultaneous tests.

Assuming that you want independent access to -- but not simultaneous running of -- each of the processes,  here's a program that you can download into your HC-8+ and run. I'm including the code in the text for those that want to browse, and as an attachment for easier downloading to your computer.

This program uses two of the Propeller's eight processors: The first processor runs the main program and methods (subroutines). A second processor is loaded to flash the transfer light in a manner that indicates which process is running.

I have coded per your instructions. Shouldn't there be some kind of emergency stop input in the middle of the 5-minute delays? If yes, it's easy to add.

'' =================================================================================================
''
''   File....... fluid_transfer_01.spin
''   Purpose....
''   Author..... JonnyMac
''   E-mail..... 
''   Started....
''   Updated.... 24 APR 2013
''
'' =================================================================================================


con

  PCB_REV = "C"


con

  _clkmode = xtal1 + pll16x
  _xinfreq = 5_000_000                                          ' 5MHz crystal

  CLK_FREQ = ((_clkmode - xtal1) >> 6) * _xinfreq
  MS_001   = CLK_FREQ / 1_000
  US_001   = CLK_FREQ / 1_000_000
 

con

  RX1     = 31                                                  ' programming / debug port
  TX1     = 30
 
  SDA     = 29                                                  ' eeprom
  SCL     = 28

  OUT_EN  = 27                                                  ' outputs enable pin (low)     
 
  SIO     = 26                                                  ' TTL serial io
 
  RX2     = 23                                                  ' RS-485 port
  RX2_EN  = 22
  TX2_EN  = 21
  TX2     = 20

  R_LED   = 18                                                  ' bi-color LED
  G_LED   = 17

  OUT7    = 15                                                  ' outputs
  OUT6    = 14   
  OUT5    = 13
  OUT4    = 12
  OUT3    = 11
  OUT2    = 10   
  OUT1    =  9
  OUT0    =  8
         
  OPT_BR  =  7                                                  ' options swithes
  OPT_A1  =  6   
  OPT_A0  =  5
  OPT_SM  =  4

  DMX_A8  =  3                                                  ' high-bit off DMX address

  DO_165  =  2                                                  ' control lines for 74x165
  CLK_165 =  1
  LD_165  =  0



  ' ---------------------------------
  ' Fluid transfer system definitions
  ' ---------------------------------

  AUX_SW1   = %001                                              ' on ttl input header
  AUX_SW2   = %010
  AUX_SW3   = %100

  AUX_PUMP1 = OUT0
  AUX_PUMP2 = OUT1
  AUX_PUMP3 = OUT2

  TR_VALVE1 = OUT3
  TR_VALVE2 = OUT4

  TR_LIGHT  = OUT5
 

con

   #0, OFF, RED, GRN, YEL                                       ' for r/g led

   #0, NOCON, RX, TX, RXTX                                      ' for rs-485

   #0, LSBFIRST, MSBFIRST                                       ' for 74x165 shift-register                                               


con

   #1, HOME, GOTOXY, #8, BKSP, TAB, LF, CLREOL, CLRDN, CR       ' PST formmatting control
  #14, GOTOX, GOTOY, CLS


obj


var


pub main | sw

  setup_io                                                      ' configure HC-8+ io pins

  repeat
    sw := %111                                                  ' arm inputs
    repeat 10                                                   ' scan 10x @10ms (100ms debounce)
      sw &= ttl_inputs(true)                                    ' re-scan inputs
      pause(10)

    case sw
      AUX_SW1 : process_1
      AUX_SW2 : process_2
      AUX_SW3 : process_3 


pub  process_1

  start_transfer_light(1)
  pause(1000)
  high(AUX_PUMP1)
  pause(5 * 60 * 1000)                                          ' 5 minutes
  low(AUX_PUMP1)
  kill_transfer_light


pub  process_2

  start_transfer_light(2)
  high(TR_VALVE1)
  pause(1000)
  high(AUX_PUMP2)
  pause(5 * 60 * 1000)
  low(AUX_PUMP2)
  pause(1000)
  low(TR_VALVE1)
  kill_transfer_light


pub  process_3

  start_transfer_light(3)
  high(TR_VALVE2)
  pause(1000)
  high(AUX_PUMP3)
  pause(5 * 60 * 1000)
  low(AUX_PUMP3)
  pause(1000)
  low(TR_VALVE2)
  kill_transfer_light
 

con

  { Flashing Light Control }


var

  long  lcog
  long  lstack[16]


pri start_transfer_light(n)

'' Starts transfer light flasher cog
'' -- n is process #

  kill_transfer_light                                                   ' stop if already running
  lcog := cognew(flash_transfer_light(n), @lstack) + 1                  ' start flasher cog


pri flash_transfer_light(n)

'' Flashes tranfer light n times every second
'' -- if n not 1-3, light on solid

  repeat
    if ((n => 1) and (n =< 3))
      repeat n                                                          ' flash process #
        high(TR_LIGHT)
        pause(150)
        low(TR_LIGHT)
        pause(150)
      pause(500)

    else
      high(TR_LIGHT)                                                    ' solid


pri kill_transfer_light

'' Turns off transfer light

  if (lcog)
    cogstop(lcog - 1)
    lcog := 0

  low(TR_LIGHT)
   

con

  { --------------------------------- }
  {                                   }
  {  S U P P O R T   R O U T I N E S  }
  {                                   }
  { --------------------------------- }


var

  long  lastscan                                                ' ttl/DMX input scan


pub setup_io

'' Configure for basic IO control

  outa[OUT7..OUT0] := %0000_0000                                ' clear outputs
  dira[OUT7..OUT0] := %1111_1111                                ' output mode                                 
  low(OUT_EN)                                                   ' enable 74x245

  high(LD_165)                                                  ' setup x165 io pins
  low(CLK_165)
  input(DO_165)

  set_rgled(OFF)
 
  set_rs485(NOCON)                                              ' RS-485 not connected


pub pause(ms) | t

'' Delay program in milliseconds

  if (ms < 1)                                                   ' delay must be at least 1
    return
  else
    t := cnt - 1792                                             ' sync with system counter
    repeat ms                                                   ' run delay
      waitcnt(t += MS_001)


pub high(pin)

'' Makes pin output and high

  outa[pin] := 1
  dira[pin] := 1


pub low(pin)

'' Makes pin output and low

  outa[pin] := 0
  dira[pin] := 1


pub toggle(pin)

'' Toggles output pin

  !outa[pin]                                                    ' invert state
  dira[pin] := 1 
 

pub input(pin)

  dira[pin] := 0

  return ina[pin]


pub ttl_pin | btns

'' Reads TTL header for 1-of-8 input
'' -- returns -1 (no input)
'' -- returns 0 to 7 for input on IN0 to IN7
''    * only one input allowed

  btns := ttl_inputs(true)                                      ' read ttl inputs

  if (bit_count(btns) == 1)                                     ' only one button pressed?
    return bit_pos(btns, 0)                                     '  yes, return button #
  else
    return -1                                                   '  none or bad input


pub ttl_inputs(rescan)

'' Return TTL inputs status
'' -- updates global var "lastscan" if rescan is true

  if (rescan)
    lastscan := x165_in | (ina[DMX_A8] << 16)     ' read in0..in7, dmx addresss
   
  return (lastscan & $FF)                                       ' return TTL input bits


pub dmx_address(rescan)

'' Return DMX address switch setting
'' -- updates global var "lastscan" if rescan is true

  if (rescan)
    lastscan := x165_in | (ina[DMX_A8] << 16)     ' read in0..in7, dmx addresss

  return (lastscan >> 8) & $01FF                                ' return DMX address bits


pub x165_in | tmp165

'' Input value from dual 74x165s on board
'' -- bit order is MSBFIRST     
                                                                                         
  outa[LD_165] := 0                                             ' blip Shift/Load line   
  outa[LD_165] := 1
         
  repeat 16                                                   ' read n bits         
    tmp165 := (tmp165 << 1) | ina[DO_165]                       ' get new bit             
    outa[CLK_165] := 1                                          ' blip clock             
    outa[CLK_165] := 0
   
  return tmp165 & $FFFF
 

pub option_inputs

'' Returns state of option switch bits (%0000..%1111, all off to all on)

  dira[OPT_BR..OPT_SM] := %0000                                 ' force to input mode

  return !ina[OPT_BR..OPT_SM]                                   ' return state (1 = on)


pub set_rgled(state)

'' Sets R/G LED
'' -- direct control only
'' -- for red/green/yellow use "efx_rgled" driver and methods

  case state
    OFF : outa[R_LED..G_LED] := %00
    RED : outa[R_LED..G_LED] := %10
    GRN : outa[R_LED..G_LED] := %01
    YEL : outa[R_LED..G_LED] := %00                             ' yellow requires PASM driver

  dira[R_LED..G_LED] := %11
     

pub set_rs485(state)

'' Sets RS-485 RX and TX enable inputs

  case state
    NOCON : outa[RX2_EN..TX2_EN] := %10
    RX    : outa[RX2_EN..TX2_EN] := %00
    TX    : outa[RX2_EN..TX2_EN] := %11   
    RXTX  : outa[RX2_EN..TX2_EN] := %01

  dira[RX2_EN..TX2_EN] := %11


pub bit_count(value) | bc

'' Returns # of bits set (1) in value

  bc := 0                                                       ' clear count
  repeat 32                                                     ' test all bits
    bc += (value & %1)                                          ' add bit value to count
    value >>= 1                                                 ' next bit

  return bc


pub bit_pos(value, mode)

'' Returns position of 1st bit set (0..31)
'' -- mode 0 to scan from lsb, mode 1 to scan from msb
'' -- -1 = no bits set

  if (value == 0)                                               ' if no bits                                   
    return -1                                                   '  return -1

  else
    if (mode == 0)                                              ' check from LSB
      value ><= 32                                              '  flip for >|
      return (32 - >|value)
    else
      return (>|value - 1)


pub bit_val(value, pos)

'' Returns bit (0..1) from pos (0..31) in value

  if ((pos => 0) and (pos =< 31))
    return (value >> pos) & 1
  else
    return 0


dat

{{

  Terms of Use: MIT License

  Permission is hereby granted, free of charge, to any person obtaining a copy of this
  software and associated documentation files (the "Software"), to deal in the Software
  without restriction, including without limitation the rights to use, copy, modify,
  merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
  permit persons to whom the Software is furnished to do so, subject to the following
  conditions:

  The above copyright notice and this permission notice shall be included in all copies
  or substantial portions of the Software.

  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
  INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
  PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
  HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
  CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
  OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

}}     
Jon McPhalen
EFX-TEK Hollywood Office

JonnyMac

This is what process_1 looks like by adding an e-stop input (IN7) to the program.

pub  process_1 | t, pumptimer, exittimer

  start_transfer_light(1)                                       ' flash 1x
  pause(1000)
  high(AUX_PUMP1)                                               ' aux pump 1 on

  ' wait 5 min while monitoring E-Stop input (TTL IN7)

  exittimer := 0                                                ' reset e-stop exit timer
  pumptimer := 5 * 60 * 1000                                    ' 5 minutes in milliseconds
 
  t := cnt                                                      ' sync loop timer
  repeat while (pumptimer > 0)                                  ' run until expired or exit
    if (ttl_pin == E_STOP)
      exittimer += 5
      if (exittimer == 50)                                      ' debounce 50ms
        quit                                                    ' abort loop!
    else
      exittimer := 0                                            ' no input, reset timer
    waitcnt(t += (5 * MS_001))                                  ' run loop every 5ms
    pumptimer -= 5                                              ' update pump delay timer

  low(AUX_PUMP1)                                                ' aux pump 1 off
  kill_transfer_light                                           ' transfer light off
Jon McPhalen
EFX-TEK Hollywood Office

JonnyMac

April 24, 2013, 11:16:43 AM #5 Last Edit: April 24, 2013, 11:20:58 AM by JonnyMac
The thing I love about programming is -- like all art (yes, programming is art) -- one idea will inspire others.

Instead of inserting all of that e-stop monitoring code into each process, it would be better to pull it out and create a method that will do the delay (in ms, like pause) while monitoring the E-Stop input.

Note: All methods, even if you don't tell them to, return a value. In this case we are specifying what to return so that the caller of pgm_hold() can tell if it ran normally (return value is 0) or if the E-Stop input aborted the delay (return value is -1). We don't have to use this return value, but it's there should we want to know.

Note: There is a 5ms granularity to the delay due to the amount of work done in the loop. Spin is pretty fast (75x than the PBASIC2), but still needs a bit of time to scan inputs from the 74x165 shift registers. Even though we're only looking at the TTL pins, the DMX switches are scanned at the same time -- this adds overhead that we cannot remove.

pub pgm_hold(ms) | t, exittimer 

'' Holds ms milliseconds while monitoring e-stop input (TTL IN7)

  t := cnt                                                      ' sync loop timer
  repeat while (ms > 0)                                         ' run until expired or exit
    if (ttl_pin == E_STOP)                                      ' e-stop input active?
      exittimer += 5                                            ' update abort timer
      if (exittimer == 50)                                      ' debounce 50ms
        return -1                                               ' abort delay loop!
    else
      exittimer := 0                                            ' no input, reset timer
    waitcnt(t += (5 * MS_001))                                  ' run loop every 1ms
    ms -= 5                                                     ' update pump delay timer

  return 0                                                      ' normal return

Jon McPhalen
EFX-TEK Hollywood Office

JackMan

Jon's the programming Genius without a doubt but if you don't need more than 1 of the pumps running at any given time, here's a pretty simple program for the Prop-1 that will do what you want. The only thing different from your outline is that you will need to wire an indicator light to each pump circuit. Having 3 separate indicator lights will let you know what pump is running which is probably a good idea. If you need an emergency switch to shut down all of the pumps (another good idea), just wire in a switch to the Prop-1 power supply or to the main power that will supply the pumps.


'   {$STAMP BS1}
'   {$PBASIC 1.0}
'
' =========================================================================


' -----[ Program Description ]---------------------------------------------


' -----[ Revision History ]------------------------------------------------


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

SYMBOL Switch1 = PIN7                 ' SETUP = DN - N.O. switch on P7.R and P7.W
SYMBOL Switch2 = PIN6                 ' SETUP = DN - N.O. switch on P6.R and P6.W
SYMBOL Switch3 = PIN5                 ' ULN acts as pull-down - N.O. switch on P5.R and P5.W
SYMBOL Pump1   = PIN4                 ' Pump 1 relay on V+ and OUT4  (wire indicator Light #1 to Pump 1)
SYMBOL Pump2   = PIN3                 ' Pump 2 relay on V+ and OUT3  (wire indicator Light #2 to Pump 2)
SYMBOL Pump3   = PIN2                 ' Pump 3 relay on V+ and OUT2  (wire indicator Light #3 to Pump 3)
SYMBOL Valve1  = PIN1                 ' Transfer Valve 1 on V+ and OUT1 (might need relay)
SYMBOL Valve2  = PIN0                 ' Transfer Valve 2 on V+ and OUT0 (might need relay)


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

SYMBOL  IsOn      = 1                     ' for active-high switches
SYMBOL  IsOff     = 0

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

SYMBOL  timer     = B2                    ' for debounce loop
SYMBOL  counter   = B3

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

Reset:
  PINS = %00000000                              ' clear all outputs
  DIRS = %00011111                              ' make P0-P4 outputs


' -----[ Program Code ]----------------------------------------------------

Main:
  timer = 0                                     ' reset debounce timer

Check_Switch1:
  IF Switch1 = IsOff THEN Check_Switch2
    timer = timer + 5
  IF timer < 200 THEN Check_Switch1
  Pump1 = IsOn
  GOSUB Run_Pump

Check_Switch2:
  IF Switch2 = IsOff THEN Check_Switch3
    timer = timer + 5
  IF timer < 200 THEN Check_Switch2
  Valve1 = IsOn
  PAUSE 1000
  Pump2 = IsOn
  GOSUB Run_Pump

Check_Switch3:
  IF Switch3 = IsOff THEN Main
    timer = timer + 5
  IF timer < 200 THEN Check_Switch3
  Valve2 = IsOn
  PAUSE 1000
  Pump3 = IsOn
  GOSUB Run_Pump

Run_Pump:
FOR counter = 1 TO 5
  PAUSE 60000
NEXT
  Pump1 = IsOff
  Pump2 = IsOff
  Pump3 = IsOff
  PAUSE 1000
  Valve1 = IsOff
  Valve2 = IsOff
  GOTO Main

JonnyMac

April 24, 2013, 07:30:32 PM #7 Last Edit: April 24, 2013, 07:36:09 PM by JonnyMac
Thanks for the nice words, Jack!

And here's another variation of a Prop-1 program. As with Jack's, there is no output for the transfer status light. As you would be using relays, anyway, you could put the second set of contacts of the pump relays in parallel and use them to route power to the transfer light; if any pump is running, the light would be on.

' =========================================================================
'
'   File......
'   Purpose...
'   Author....
'   E-mail....
'   Started...
'   Updated...
'
'   {$STAMP BS1}
'   {$PBASIC 1.0}
'
' =========================================================================


' -----[ Program Description ]---------------------------------------------


' -----[ Revision History ]------------------------------------------------


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

SYMBOL Switch3          = PIN7
SYMBOL Switch2          = PIN6
SYMBOL Switch1          = PIN5

SYMBOL Valve2           = PIN4
SYMBOL Valve1           = PIN3

SYMBOL Pump3            = PIN2
SYMBOL Pump2            = PIN1
SYMBOL Pump1            = PIN0


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

SYMBOL  YES             = 1
SYMBOL  NO              = 0

SYMBOL  IS_ON           = 1                     ' active-high I/O
SYMBOL  IS_OFF          = 0


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

SYMBOL  timer           = B2                    ' for debounce loop
SYMBOL  switches        = B3                    ' control inputs

SYMBOL  seconds         = W5                    ' for pump run timing


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

Power_Up:
  ' put code here that only happens at power-up/hard reset

Reset:
  PINS = %00000000                              ' all off
  DIRS = %00011111                              ' P4..P0 are outputs


' -----[ Program Code ]----------------------------------------------------

Main:
  switches = %11100000                          ' arm switches
  FOR timer = 1 TO 10                           ' 10x @ 10ms = 100ms
    PAUSE 10                                    ' debounce hold
    switches = switches & PINS                  ' re-scan inputs
  NEXT

  IF switches = %00100000 THEN Process_1
  IF switches = %01000000 THEN Process_2
  IF switches = %10000000 THEN Process_3

  GOTO Main


Process_1:
  Pump1 = IS_ON
  seconds = 5 * 60
  GOSUB Hold_Seconds
  Pump1 = IS_OFF
  GOTO Reset


Process_2:
  Valve1 = IS_ON
  PAUSE 1000
  Pump2 = IS_ON
  seconds = 5 * 60
  GOSUB Hold_Seconds
  Pump2 = IS_OFF
  PAUSE 1000
  Valve1 = IS_OFF
  GOTO Reset


Process_3:
  Valve2 = IS_ON
  PAUSE 1000
  Pump3 = IS_ON
  seconds = 5 * 60
  GOSUB Hold_Seconds
  Pump3 = IS_OFF
  PAUSE 1000
  Valve2 = IS_OFF
  GOTO Reset


' -----[ Subroutines ]-----------------------------------------------------

Hold_Seconds:
  IF seconds = 0 THEN HS_Exit
    PAUSE 1000
    seconds = seconds - 1
    GOTO Hold_Seconds

HS_Exit:
  RETURN

' -------------------------------------------------------------------------


' -----[ User Data ]-------------------------------------------------------
Jon McPhalen
EFX-TEK Hollywood Office

JackMan

April 25, 2013, 05:36:57 AM #8 Last Edit: April 25, 2013, 05:46:45 AM by JackMan
Here's yet another variation for the Prop-1 that would allow you to connect 3 LED's to the Prop-1 OUT terminals for indicator lights. After a Switch is pressed, the program changes that Switch input to an output and lights the LED. I have tested this and it works quite well.
*Note to Jon - should probably move part of this thread to the Prop-1 section.


'   {$STAMP BS1}
'   {$PBASIC 1.0}
'
' =========================================================================


' -----[ Program Description ]---------------------------------------------


' -----[ Revision History ]------------------------------------------------


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

SYMBOL Switch1 = PIN7                 ' SETUP = DN - N.O. switch on P7.R and P7.W - indicator LED w/1K resistor on V+ and OUT7
SYMBOL Switch2 = PIN6                 ' SETUP = DN - N.O. switch on P6.R and P6.W - indicator LED w/1K resistor on V+ and OUT6
SYMBOL Switch3 = PIN5                 ' ULN acts as pull-down - N.O. switch on P5.R and P5.W - indicator LED w/1K resistor on V+ and OUT5
SYMBOL Pump1   = PIN4                 ' Pump 1 relay on V+ and OUT4  (wire indicator Light #1 to Pump 1)
SYMBOL Pump2   = PIN3                 ' Pump 2 relay on V+ and OUT3  (wire indicator Light #2 to Pump 2)
SYMBOL Pump3   = PIN2                 ' Pump 3 relay on V+ and OUT2  (wire indicator Light #3 to Pump 3)
SYMBOL Valve1  = PIN1                 ' Transfer Valve 1 on V+ and OUT1 (might need relay)
SYMBOL Valve2  = PIN0                 ' Transfer Valve 2 on V+ and OUT0 (might need relay)


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

SYMBOL  IsOn      = 1                     ' for active-high switches
SYMBOL  IsOff     = 0

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

SYMBOL  timer     = B2                    ' for debounce loop
SYMBOL  counter   = B3

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

Reset:
  PINS = %00000000                              ' clear all outputs (all off)
  DIRS = %00011111                              ' make P0-P4 outputs, P5-P7 inputs


' -----[ Program Code ]----------------------------------------------------

Main:
  timer = 0                                     ' reset debounce timer

Check_Switch1:
  IF Switch1 = IsOff THEN Check_Switch2
    timer = timer + 5
  IF timer < 200 THEN Check_Switch1
  DIRS = %10011111                              ' change PIN7 to an output
  Switch1 = IsOn                                ' Turn on OUT7 indicator LED for Pump 1
  PAUSE 1000
  Pump1 = IsOn
  GOSUB Run_Pump

Check_Switch2:
  IF Switch2 = IsOff THEN Check_Switch3
    timer = timer + 5
  IF timer < 200 THEN Check_Switch2
  DIRS = %01011111                              ' change PIN6 to an output
  Switch2 = IsOn                                ' Turn on OUT6 indicator LED for Pump 2
  Valve1 = IsOn
  PAUSE 1000
  Pump2 = IsOn
  GOSUB Run_Pump

Check_Switch3:
  IF Switch3 = IsOff THEN Main
    timer = timer + 5
  IF timer < 200 THEN Check_Switch3
  DIRS = %00111111                              ' change PIN5 to an output
  Switch3 = IsOn                                ' Turn on OUT5 indicator LED for Pump 3
  Valve2 = IsOn
  PAUSE 1000
  Pump3 = IsOn
  GOSUB Run_Pump

Run_Pump:
FOR counter = 1 TO 5
  PAUSE 60000
NEXT
  Pump1 = IsOff
  Pump2 = IsOff
  Pump3 = IsOff
  PAUSE 1000
  GOTO Reset

JonnyMac

I cannot move portions of a thread; we should stick to the HC-8+ in this section.
Jon McPhalen
EFX-TEK Hollywood Office

bsnut

April 26, 2013, 09:07:37 AM #10 Last Edit: April 26, 2013, 09:19:59 AM by bsnut
Here's for you to try that is a little different from what Jon did for you. As Jon's acting couch said there are many ways to get Rome. I just took the long or the scenic way to Rome ;D.

Parts of this spin code in this version was compiled by a program called PICoPLC, which is a ladder logic editor. It takes the ladder logic diagram and compiles it into spin code and it allows you run 1, 2, or all 3 pumps at the same time just like a real PLC (Programmable Logic Controller). The cool thing is, that the whole program uses 2 cogs (processors) on the propeller chip - one to scan the ttl header and other cog for the rest of the program.

Here's part of your finished program after it is edited to run on the HC-8. I attached the full program for you, since the forum limits how many characters to post.

'' =================================================================================================
''
''   File....... hc-8_picoplc_fluid_transfer_controller.spin
''   Purpose.... To control the 3 fluid transfer pumps at the
''               the same using PICoPLC generated spin code
''               from the PICoPLC editor 
''               -- digital inputs auto-scanned
''   Author..... William "BSnut" Stefan,
''   E-mail..... williamstefan@hotmail.com
''   Started.... 26 APR 2013
''   Updated....
''
'' =================================================================================================


con

  _clkmode = xtal1 + pll16x
  _xinfreq = 5_000_000

  CLK_FREQ = ((_clkmode - xtal1) >> 6) * _xinfreq
  MS_001   = CLK_FREQ / 1_000
  US_001   = CLK_FREQ / 1_000_000
 

con

  PCB_REV = "C"                                                 ' production boards

  RX1     = 31                                                  ' programming / debug port
  TX1     = 30
 
  SDA     = 29                                                  ' eeprom / i2c
  SCL     = 28

  OUT_EN  = 27                                                  ' output enable     
 
  SIO     = 26                                                  ' TTL serial io

  NC25    = 25                                                  ' not connected
  NC24    = 24
 
  RX2     = 23                                                  ' RS-485 interface
  RX2_EN  = 22
  TX2_EN  = 21
  TX2     = 20

  NC19    = 19
 
  R_LED   = 18                                                  ' bi-color LED
  G_LED   = 17

  NC16    = 16
 
  OUT7    = 15                                                  ' channel outputs
  OUT6    = 14   
  OUT5    = 13
  OUT4    = 12
  OUT3    = 11
  OUT2    = 10   
  OUT1    =  9
  OUT0    =  8
         
  OPT_BR  =  7                                                  ' option inputs
  OPT_A1  =  6   
  OPT_A0  =  5
  OPT_SM  =  4

  DMX_A8  =  3                                                  ' DMX address.8 input

  DO_165  =  2                                                  ' 74x165 IO
  CLK_165 =  1
  LD_165  =  0


  ' for EFX-TEK uSD adapter module
  ' -- must open all option switches when installed

  SD_CS   =  OPT_BR                                       
  SD_DI   =  OPT_A1 
  SD_CLK  =  OPT_A0 
  SD_DO   =  OPT_SM 


con

   #0, NO, YES
   #0, OFF, RED, GRN

   #0, NOCON, RX, TX, RXTX

   #0, LSBFIRST, MSBFIRST

   USE_DIGINS = YES                                             ' set to 0 to disable
 

con

   #1, HOME, GOTOXY, #8, BKSP, TAB, LF, CLREOL, CLRDN, CR       ' PST formmatting control
  #14, GOTOX, GOTOY, CLS
 
con

{ The following varibles and constants were generated by the PICoPLC editor when the
  ladder logic program was compiled and pasted into this file lader on from the
  auto-generated file. The comments were anded later on to show I/0 locations
  and connections related to the HC-8
}
CycleTime = 100 '1/sec
var
BYTE I_mcr
var
BYTE I_rung_top
var
BYTE I_parOut_0000
var
BYTE I_parThis_0000
con                                                             ' on ttl input header IN0
U_XAux_Switch1 = 0
var
BYTE I_scratch
var
BYTE I_oneShot_0000
var
BYTE U_RP1_Started
var
BYTE U_RP1_Stop
con                                                             ' on ttl input header IN3
U_XEStop = 3
var
BYTE I_parOut_0001
var
BYTE I_parThis_0001
var
WORD U_TP1_start_delay
con
U_YAux_Pump1 = 8                                               ' connected to OUT0
var
WORD U_TP1_run_delay
var
BYTE I_parOut_0002
var
BYTE I_parThis_0002
con
U_XAux_Switch2 = 1                                             ' on ttl input header IN1
var
BYTE I_oneShot_0001
var
BYTE U_RP2_Started
var
BYTE U_RP2_Stop
var
BYTE I_parOut_0003
var
BYTE I_parThis_0003
var
WORD U_TP2_start_delay
con
U_YAux_Pump2 = 9                                               ' connected to OUT1
var
BYTE I_parOut_0004
var
BYTE I_parThis_0004
var
WORD U_TP2_run_delay
var
BYTE I_TTV1_Delayoff_antiglitch
var
WORD U_TTV1_Delayoff
con
U_YTransfer_Valve1 = 12                                        ' connected to OUT4
var
BYTE I_parOut_0005
var
BYTE I_parThis_0005
con
U_XAux_Switch3 = 2                                             ' on ttl input header IN2
var
BYTE I_oneShot_0002
var
BYTE U_RP3_Started
var
BYTE U_RP3_Stop
var
BYTE I_parOut_0006
var
BYTE I_parThis_0006
var
WORD U_TP3_start_delay                                   
con
U_YAux_Pump3 = 10                                              ' connected to OUT2
var
BYTE I_parOut_0007
var
BYTE I_parThis_0007
var
WORD U_TP3_run_delay
var
BYTE I_TTV2_Delayoff_antiglitch
var
WORD U_TTV2_Delayoff
con
U_YTransfer_Valve2 = 13                                        ' connected to OUT5
var
BYTE U_Rflash_bit
var
WORD U_Tflash_don
var
BYTE I_Tflash_dof_antiglitch
var
WORD U_Tflash_dof
var
BYTE I_parOut_0008
var
BYTE I_parThis_0008
con
U_YTransfer_Light = 11                                         ' connected to OUT3

obj


var


pub main | timing

  setup_io                                                      ' configure HC-8+ io pins

{ The following code was generated by the PICoPLC editor when the 
  ladder logic program was compiled into spin and changed later and
  pasted into this file so it will work with what's on the HC-8 board
  that is connected directly to the Propeller chip.   
  Also the comments were added later on and comments the made in the
  PICoPLC editor was added since they aren't auto generated by the
  editor itself.
}

  timing := cnt + clkfreq / CycleTime
  repeat
    I_mcr~~
   
    {Transfer Pump 1 control.  }
    { start rung 2 }
    I_rung_top := I_mcr
   
    { start series [ }
    { start parallel [ }
    I_parOut_0000~ 
    I_parThis_0000 := I_rung_top
    { start series [ }
    { Contact }
    ifnot ttl_bit(U_XAux_Switch1)  '' this was edited to work with the HC-8
      I_parThis_0000~
   
   
    { OSR element }
    I_scratch := I_parThis_0000
    if (I_oneShot_0000)
      I_parThis_0000~
   
    I_oneShot_0000 := I_scratch
   
    { ] finish series }
    if (I_parThis_0000)
      I_parOut_0000~~
   
    I_parThis_0000 := I_rung_top
    { start series [ }
    { Contact }
    ifnot (U_RP1_Started)
      I_parThis_0000~
   
   
    { Negated contact }
    if (U_RP1_Stop)
      I_parThis_0000~
   
   
    { ] finish series }
    if (I_parThis_0000)
      I_parOut_0000~~
   
    I_rung_top := I_parOut_0000
    { ] finish parallel }
    { Contact }
    ifnot ttl_bit(U_XEStop)        '' this was edited to work with the HC-8
      I_rung_top~
   
   
    { start parallel [ }
    I_parOut_0001~
    I_parThis_0001 := I_rung_top
    { Normal coil }
    U_RP1_Started := I_parThis_0001
   
    if (I_parThis_0001)
      I_parOut_0001~~
   
    I_parThis_0001 := I_rung_top
    { start series [ }
    { TON element }
    if (I_parThis_0001)
      if (U_TP1_start_delay < 99)
        U_TP1_start_delay++
        I_parThis_0001~
     
    else
      U_TP1_start_delay := 0
   
   
    { Normal coil }
    OUTA[U_YAux_Pump1] := I_parThis_0001
   
    { ] finish series }
    if (I_parThis_0001)
      I_parOut_0001~~
   
    I_parThis_0001 := I_rung_top
    { start series [ }
    { Contact }
    ifnot (OUTA[U_YAux_Pump1])
      I_parThis_0001~
   
   
    { TON element }
    if (I_parThis_0001)
      if (U_TP1_run_delay < 499)
        U_TP1_run_delay++
        I_parThis_0001~
     
    else
      U_TP1_run_delay := 0
   
   
    { Normal coil }
    U_RP1_Stop := I_parThis_0001
   
    { ] finish series }
    if (I_parThis_0001)
      I_parOut_0001~~
   
    I_rung_top := I_parOut_0001
    { ] finish parallel }
    { ] finish series }
   
    {Transfer Pump 2 control.  }
    { start rung 4 }
    I_rung_top := I_mcr
   
    { start series [ }
    { start parallel [ }
    I_parOut_0002~
    I_parThis_0002 := I_rung_top
    { start series [ }
    { Contact }
    ifnot ttl_bit(U_XAux_Switch2)  '' this was edited to work with the HC-8
      I_parThis_0002~
   
   
    { OSR element }
    I_scratch := I_parThis_0002
    if (I_oneShot_0001)
      I_parThis_0002~
   
    I_oneShot_0001 := I_scratch
   
    { ] finish series }
    if (I_parThis_0002)
      I_parOut_0002~~
   
    I_parThis_0002 := I_rung_top
    { start series [ }
    { Contact }
    ifnot (U_RP2_Started)
      I_parThis_0002~
   
   
    { Negated contact }
    if (U_RP2_Stop)
      I_parThis_0002~
   
   
    { ] finish series }
    if (I_parThis_0002)
      I_parOut_0002~~
   
    I_rung_top := I_parOut_0002
    { ] finish parallel }
    { Contact }
    ifnot ttl_bit(U_XEStop)        '' this was edited to work with the HC-8
      I_rung_top~
   
   
    { start parallel [ }
    I_parOut_0003~
    I_parThis_0003 := I_rung_top
    { Normal coil }
    U_RP2_Started := I_parThis_0003
   
    if (I_parThis_0003)
      I_parOut_0003~~
   
    I_parThis_0003 := I_rung_top
    { start series [ }
    { TON element }
    if (I_parThis_0003)
      if (U_TP2_start_delay < 99)
        U_TP2_start_delay++
        I_parThis_0003~
     
    else
      U_TP2_start_delay := 0
   
   
    { Normal coil }
    OUTA[U_YAux_Pump2] := I_parThis_0003
   
    { ] finish series }
    if (I_parThis_0003)
      I_parOut_0003~~
   
    I_parThis_0003 := I_rung_top
    { start series [ }
    { Contact }
    ifnot (OUTA[U_YAux_Pump2])
      I_parThis_0003~
   
   
    { start parallel [ }
    I_parOut_0004~
    I_parThis_0004 := I_parThis_0003
    { start series [ }
    { TON element }
    if (I_parThis_0004)
      if (U_TP2_run_delay < 29999)
        U_TP2_run_delay++
        I_parThis_0004~
     
    else
      U_TP2_run_delay := 0
   
   
    { Normal coil }
    U_RP2_Stop := I_parThis_0004
   
    { ] finish series }
    if (I_parThis_0004)
      I_parOut_0004~~
   
    I_parThis_0004 := I_parThis_0003
    { start series [ }
    { TOFF element }
    ifnot (I_TTV1_Delayoff_antiglitch)
      U_TTV1_Delayoff := 99
   
    I_TTV1_Delayoff_antiglitch~~
    ifnot (I_parThis_0004)
      if (U_TTV1_Delayoff < 99)
        U_TTV1_Delayoff++
        I_parThis_0004~~
     
    else
      U_TTV1_Delayoff := 0
   
   
    { Normal coil }
    OUTA[U_YTransfer_Valve1] := I_parThis_0004
   
    { ] finish series }
    if (I_parThis_0004)
      I_parOut_0004~~
   
    I_parThis_0003 := I_parOut_0004
    { ] finish parallel }
    { ] finish series }
    if (I_parThis_0003)
      I_parOut_0003~~
   
    I_rung_top := I_parOut_0003
    { ] finish parallel }
    { ] finish series }
   
    {Transfer Pump 3 control.  }
    { start rung 6 }
    I_rung_top := I_mcr
   
    { start series [ }
    { start parallel [ }
    I_parOut_0005~
    I_parThis_0005 := I_rung_top
    { start series [ }
    { Contact }
    ifnot ttl_bit(U_XAux_Switch3)  '' this was edited to work with the HC-8
      I_parThis_0005~
   
   
    { OSR element }
    I_scratch := I_parThis_0005
    if (I_oneShot_0002)
      I_parThis_0005~
   
    I_oneShot_0002 := I_scratch
   
    { ] finish series }
    if (I_parThis_0005)
      I_parOut_0005~~
   
    I_parThis_0005 := I_rung_top
    { start series [ }
    { Contact }
    ifnot (U_RP3_Started)
      I_parThis_0005~
   
   
    { Negated contact }
    if (U_RP3_Stop)                   
      I_parThis_0005~
   
   
    { ] finish series }
    if (I_parThis_0005)
      I_parOut_0005~~
   
    I_rung_top := I_parOut_0005
    { ] finish parallel }
    { Contact }
    ifnot ttl_bit(U_XEStop)            '' this was edited to work with the HC-8
      I_rung_top~
   
   
    { start parallel [ }
    I_parOut_0006~
    I_parThis_0006 := I_rung_top
    { Normal coil }
    U_RP3_Started := I_parThis_0006
   
    if (I_parThis_0006)
      I_parOut_0006~~
   
    I_parThis_0006 := I_rung_top
    { start series [ }
    { TON element }
    if (I_parThis_0006)
      if (U_TP3_start_delay < 99)
        U_TP3_start_delay++
        I_parThis_0006~
     
    else
      U_TP3_start_delay := 0
   
   
    { Normal coil }
    OUTA[U_YAux_Pump3] := I_parThis_0006
   
    { ] finish series }
    if (I_parThis_0006)
      I_parOut_0006~~
   
    I_parThis_0006 := I_rung_top
    { start series [ }
    { Contact }
    ifnot (OUTA[U_YAux_Pump3])
      I_parThis_0006~
   
   
    { start parallel [ }
    I_parOut_0007~
    I_parThis_0007 := I_parThis_0006
    { start series [ }
    { TON element }
    if (I_parThis_0007)
      if (U_TP3_run_delay < 29999)
        U_TP3_run_delay++
        I_parThis_0007~
     
    else
      U_TP3_run_delay := 0
   
   
    { Normal coil }
    U_RP3_Stop := I_parThis_0007
   
    { ] finish series }
    if (I_parThis_0007)
      I_parOut_0007~~
   
    I_parThis_0007 := I_parThis_0006
    { start series [ }
    { TOFF element }
    ifnot (I_TTV2_Delayoff_antiglitch)
      U_TTV2_Delayoff := 99
   
    I_TTV2_Delayoff_antiglitch~~
    ifnot (I_parThis_0007)
      if (U_TTV2_Delayoff < 99)
        U_TTV2_Delayoff++
        I_parThis_0007~~
     
    else
      U_TTV2_Delayoff := 0
   
   
    { Normal coil }
    OUTA[U_YTransfer_Valve2] := I_parThis_0007
   
    { ] finish series }
    if (I_parThis_0007)
      I_parOut_0007~~
   
    I_parThis_0006 := I_parOut_0007
    { ] finish parallel }
    { ] finish series }
    if (I_parThis_0006)
      I_parOut_0006~~
   
    I_rung_top := I_parOut_0006
    { ] finish parallel }
    { ] finish series }

    {These 2 rungs control the flashing of the "Transfer Light". Rung 8
     controls the way the "flash_bit" is flashed on and off.
     Rung 9 turns on "Transfer Light" to be flashed by the "flash_bit"
     }
    { start rung 8 }
    I_rung_top := I_mcr
   
    { start series [ }
    { Negated contact }
    if (U_Rflash_bit)
      I_rung_top~
   
   
    { TON element }
    if (I_rung_top)
      if (U_Tflash_don < 49)
        U_Tflash_don++
        I_rung_top~
     
    else
      U_Tflash_don := 0
   
   
    { TOFF element }
    ifnot (I_Tflash_dof_antiglitch)
      U_Tflash_dof := 49
   
    I_Tflash_dof_antiglitch~~
    ifnot (I_rung_top)
      if (U_Tflash_dof < 49)
        U_Tflash_dof++
        I_rung_top~~
     
    else
      U_Tflash_dof := 0
   
   
    { Normal coil }
    U_Rflash_bit := I_rung_top
   
    { ] finish series }
   
    { start rung 9 }
    I_rung_top := I_mcr
   
    { start series [ }
    { start parallel [ }
    I_parOut_0008~
    I_parThis_0008 := I_rung_top
    { Contact }
    ifnot (OUTA[U_YAux_Pump1])
      I_parThis_0008~
   
   
    if (I_parThis_0008)
      I_parOut_0008~~
   
    I_parThis_0008 := I_rung_top
    { Contact }
    ifnot (OUTA[U_YTransfer_Valve1])
      I_parThis_0008~
   
   
    if (I_parThis_0008)
      I_parOut_0008~~
   
    I_parThis_0008 := I_rung_top
    { Contact }
    ifnot (OUTA[U_YTransfer_Valve2])
      I_parThis_0008~
   
   
    if (I_parThis_0008)
      I_parOut_0008~~
   
    I_rung_top := I_parOut_0008
    { ] finish parallel }
    { Contact }
    ifnot (U_Rflash_bit)
      I_rung_top~
   
   
    { Normal coil }
    OUTA[U_YTransfer_Light] := I_rung_top
   
    { ] finish series }
    waitcnt(timing)
    timing += clkfreq / CycleTime

Have fun and enjoy.
BTW, take a look at this http://www.efx-tek.com/php/smf/index.php?topic=2003.0 thread that I started, that tells you how to make it work on the HC-8.

I will also provide the edited spin file and PICoPLC compiled file that was used to for the edited spin file so you don't have copy and paste into your editor.
William Stefan
The Basic Stamp Nut