Shop OBEX P1 Docs P2 Docs Learn Events
Pushing the Evelope — Parallax Forums

Pushing the Evelope

alnajjar1alnajjar1 Posts: 110
edited 2013-08-26 18:37 in BASIC Stamp
I need help with some tricky coding!

We have 8 push-buttons that visitors trigger, each of which turns on a 12VDC water valve to activate a portion of an exhibit. I want this done very quickly so when a visitor pushes the buttons, the valve opens for a certain short period of time and closes.

To achieve this, I used a HC595 for outputs and HC165 to read the inputs. This gives me a byte showing the status of the push-buttons, and an output byte from the BS2 to trigger the valves via the 595. I also added a 5k pot to control the amount of time the valves stay on.

I developed a simple code to do this - attachedCombined Pumps.bs2. The circuit and code work but it is sluggish unless the value of the pot (the wait time or the rate the switches are being read) is very low. The problem here is that if the wait is too short, the valve don't stay on long enough.

Further, it would be ideal if I can have different on-time for each valve.

I can write the code by looking at each input individually but that slows things down. Also, having BS2 circuits is not an option!

Any ingenious way of doing this?

Many thanks in advance,

Al

Comments

  • Tracy AllenTracy Allen Posts: 6,662
    edited 2013-08-24 18:08
    The trick is to make the RCTIME very fast by using a smaller value of capacitor. Then multiply the RCTIME by a scale factor to make it right for the Valve. You can use a different scale factor for each button/valve.
  • alnajjar1alnajjar1 Posts: 110
    edited 2013-08-24 20:42
    The problem is that I have up to 8 independent user pushing these buttons. It would be very easy if I only have one button pushed at a time.
  • Beau SchwabeBeau Schwabe Posts: 6,559
    edited 2013-08-24 20:59
    If you move the RCTIME to an external hardware function, say with a 555 or 1/6th of a 74HC14 and use the COUNT command instead of the RCTIME command, then the amount of time spent reading the POT would always be the same within your code, and somewhat predictable.
  • Phil Pilgrim (PhiPi)Phil Pilgrim (PhiPi) Posts: 23,514
    edited 2013-08-24 21:03
    I would dispense with the pot altogether and replace it with a "program" switch that's not accessible to the public. With the program switch on, pressing a button and holding it will cause the BS2 to count how many button-read and pump-write cycles the pump is suposed to stay on for that button. This value can be stored in the BS2's EEPROM for each button. With the program switch off, pressing a button or buttons will initiate the "on" cycle for the button(s) pressed, turning the pump(s) off after the prescribed number of read/write cycles.

    -Phil
  • UnsoundcodeUnsoundcode Posts: 1,532
    edited 2013-08-25 08:01
    Hi, it seems to me that the "getswitches" routine could be made more efficient.

    Whether a button is pressed or not pressed the "getswitches" will scan and then goto "sendout". So if no button has been pressed the Stamp is just going to be unresponsive for as long as 2 seconds until it comes back to scan the switches again. During that time it is possible it may miss the users input.

    Also the switches must be in a pressed state when "inload" receives its pulse, this means that if you had for example 5 users pressing buttons any small difference in time between when they pressed the buttons would give you an apparent error on the output, in other words you would read some but not all of the user inputs.

    I think it would be better if you verified there actually was user input before moving into the output routine. Something like the following might work, the first read checks for input and the second read gives time for everyone to press. The pause can be adjusted to whatever works best.
    getSwitches:
    
      newSW=0
    
      Do While newSW < 1
         PULSOUT inLoad, 5                               ' load switch inputs
         SHIFTIN inData, inClock, MSBPRE, [newSW]     ' shift them in
      Loop
    
         PAUSE 20                                     ' allow time for all users to press
         PULSOUT inLoad, 5                               ' load switch inputs
         SHIFTIN inData, inClock, MSBPRE, [newSW]     ' shift them in
    
    RETURN
    

    Jeff T.
  • SapphireSapphire Posts: 496
    edited 2013-08-25 10:50
    Al,

    What time range do you want to have for the individual pump run times? Do you need to have these individual pump run times field programmable, or could they be fixed?

    If you maintain 8 separate timers for each pump, you could have different times for each of them and they could run simultaneously. Eliminating the re-reading of the POT will speed processing up, and if the pump run times don't change (or are only changed by you) then they can be done outside of the normal loop.
  • alnajjar1alnajjar1 Posts: 110
    edited 2013-08-25 11:08
    Brilliant! thanks Jeff. I will try this and report back. The challeng for me is how to turn individual valves without using the Pause command and tying up the BS2 from monitoring other switches. Your suggestion and what Phil suggested may get me closer to the desired goal.

    Al
  • alnajjar1alnajjar1 Posts: 110
    edited 2013-08-26 12:46
    The pot is only checked at start up and not as part of the main loop and therefore the run-times for individual pumps are meant to remain fixed unless the pot value is changed and the BS2 is reset. I am not sure how I can maintain 8 timers and make these timers consistent. Using the Pause command is out of the questions as it will stop the BS2 from checking the switches continuously. Could you craft a quick example of how to maintain the individual timer? I can setup 8 different counters counting the number of cycles the button has been in a certain state, but that will not give a consistent time.

    Thanks for your thought...
  • SapphireSapphire Posts: 496
    edited 2013-08-26 14:05
    Al,

    What I'm suggesting is to setup 8 counters that all run in parallel, and only one pause to set the timing on them. I've added that to your original program. Take a look and see if it works for you.
    ' {$STAMP BS2}
    ' {$PBASIC 2.5}
    
    ' pin assignment
    outData       PIN          2             ' Data pin to 74HC595.
    outClock      PIN          0             ' Shift clock to '595.
    outLoad       PIN          1             ' Moves data from shift register to output latch.
    inData        PIN          7             ' shift clock (74HC165.2)
    inClock       PIN          9             ' serial data (74HC165.7)
    inLoad        PIN          8             ' input load (74HC165.1)
    LED           PIN          14            ' red indicator LED
    Pot           PIN          15            ' adjust water valve on-time
    
    ' variables
    onTime        VAR          Word          ' calibrated pot value in ms
                                             ' pot rane 0-6000.  max on time = 2000ms
    i             VAR          Byte          ' general counter
    oldSW         VAR          Byte          ' previous reading from the HC165
    newSW         VAR          Byte          ' current value of switches
    valves        VAR          Byte          ' binary represetatio of the output to the HC595
    switches      VAR          Byte          ' switches that just turned on
    counter       VAR          Byte(8)       ' counters for each switch
    
    DATA 10,20,30,40,50,60,70,80             ' valve run times in multiples of onTime
                                             ' onTime should be small, like 1/10 second
    
    Reset:
      HIGH inLoad
      GOSUB readPot
      FOR i = 1 TO 3
        HIGH LED : PAUSE onTime : LOW LED : PAUSE 500
      NEXT
      valves = 0 : GOSUB sendOut
      oldSW = 0 : newSW = 0
    
    monitor:
        GOSUB getSwitches                      ' get switch inputs
        DEBUG HOME, BIN8 newSW                 ' display current status
        switches = oldSW ^ newSW & newSW       ' new switch presses in switches
        oldSW = newSW                          ' update old value
        'DEBUG HOME, BIN8 ? oldSW, BIN8 ? newSW, BIN8 ? valves
        'valves = newSW : GOSUB sendOut
        GOSUB ticker                           ' check the counters
        GOSUB sendOut                          ' update valve status
        PAUSE onTime                           ' pause a short time (onTime should be small, try 100ms)
    GOTO monitor                               ' start over
    
    ticker:
      valves = 0                                 ' all valves off unless set by a timer
      FOR i = 0 TO 7                             ' eight timers
        IF 1<<i & switches THEN                  ' switch just pressed
          READ i,counter(i)                      ' loads a unique time for each counter, stored in EEPROM
        ENDIF
        IF counter(i) > 0 THEN                   ' counter not zero
          valves = 1<<i | valves                 ' turn on valve
          counter(i) = counter(i) - 1            ' decrement counter
        ENDIF
      NEXT
    RETURN
    
    sendOut:
      SHIFTOUT outData,outClock,MSBFIRST,[valves]
      PULSOUT OUTLoad,1
    RETURN
    
    getSwitches:
      PULSOUT inLoad, 5                            ' load switch inputs
      SHIFTIN inData, inClock, MSBPRE, [newSW]     ' shift them in
    RETURN
    
    readPot:
      HIGH pot ' charge the cap
      PAUSE 1
      RCTIME pot, 1, onTime
      onTime = onTime/3
      DEBUG DEC ? onTime
    RETURN
    
  • alnajjar1alnajjar1 Posts: 110
    edited 2013-08-26 18:37
    This is awesome! it makes perfect sense...very elegant.

    I will try it and report back.

    Many thanks Sapphire.

    Al
Sign In or Register to comment.