Shop OBEX P1 Docs P2 Docs Learn Events
one shot — Parallax Forums

one shot

DannyDanny Posts: 56
edited 2005-05-26 20:30 in BASIC Stamp
I've been searching the forums for a way have a switch or button ONLY trigger a routine once for each press of the button.

I have purchased several BS2's and NX-1000 and printed or purchased most of your manuals, I have found that I learn best by example, but
haven't found any examples of what I am trying to do, and you guys have sooooo much information available I'm getting yelled at by my
wife for reading in bed.

I'm working on an interface to a lighting control system, where motion detectors will trigger a serial string to the lighting controller.
The issue is that the motion detectors will provide a closure for as long as they are triggered, so I will be recieving a contact closure
lasting anywhere from 1 second to minutes, depending on how long someone is in the sensing range of the detectors.

I have the 232 strings set up and tested, but I am getting multiple sends, from one trigger.

I have tried two versions of a program for a BS2, but both behave in the same way, this is a device that I am planning to market if I can get the
multiple signal issue resolved (especially since the super carrier board is so inexpensive now!).

I'm attaching the two programs below, any help would be greatly appreciated!

[noparse][[/noparse]code]'{$STAMP BS2}
'{$PBASIC 2.5}
'Program description here
'This program is designed TO interface radio receivers TO
'a Crestron STCOM module

'Declare Variables Here
workvariable VAR Byte
delay VAR Byte
rate VAR Byte
downstate VAR Byte

workvariable = 0
delay = 0
rate = 255
downstate = 1

'Serial info here
TxD CON 16
baud CON 16468
pace CON 10

'Main program here

Reloop: BUTTON 0,downstate,delay,rate,workvariable,1,Next1
DEBUG "button 1",CR
SEROUT TxD, baud, pace,[noparse][[/noparse]"1", CR]

Next1: BUTTON 1,downstate,delay,rate,workvariable,1,Next2
DEBUG "button 2",CR
SEROUT TxD, baud, pace, [noparse][[/noparse]"2", CR]

Next2: BUTTON 2,downstate,delay,rate,workvariable,1,Next3
DEBUG "button 3",CR
SEROUT TxD, baud, pace, [noparse][[/noparse]"3", CR]

Next3: BUTTON 3,downstate,delay,rate,workvariable,1,Next4
DEBUG "button 4",CR
SEROUT TxD, baud, pace, [noparse][[/noparse]"4", CR]

Next4: BUTTON 4,downstate,delay,rate,workvariable,1,RePoll
DEBUG "button 5",CR
SEROUT TxD, baud, pace, [noparse][[/noparse]"5", CR]

RePoll: PAUSE 100
GOTO Reloop

Second version

' {$STAMP BS2}
' {$PBASIC 2.5}
'Program description here
'This program is designed TO interface radio receivers TO
'a Crestron STCOM module


'Declare Variables Here

'Serial info here
TxD CON 16
baud CON 16468
pace CON 10

'Main program here

MainLoop: IF IN0=1 THEN Next1
DEBUG "button 1",CR
SEROUT TxD, baud, pace,[noparse][[/noparse]"1", CR]
GOTO Next1

Next1: IF IN1=1 THEN Next2
DEBUG "button 2",CR
SEROUT TxD, baud, pace, [noparse][[/noparse]"2", CR]
GOTO Next2

Next2: IF IN2=1 THEN Next3
DEBUG "button 3",CR
SEROUT TxD, baud, pace, [noparse][[/noparse]"3", CR]
GOTO Next3

Next3: IF IN3=1 THEN Next4
DEBUG "button 4",CR
SEROUT TxD, baud, pace, [noparse][[/noparse]"4", CR]
GOTO Next4

Next4: IF IN4=1 THEN Repoll
DEBUG "button 5",CR
SEROUT TxD, baud, pace, [noparse][[/noparse]"5", CR]
GOTO Repoll

Repoll: PAUSE 100
GOTO MainLoop

▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
"Never create anything you can't control"
"The amount of intelligence on the planet is fixed... the population is growing"

Comments

  • Jon WilliamsJon Williams Posts: 6,491
    edited 2005-05-20 18:10
    The best way to do this is NOT to use the internal BUTTON function.· Since you're looking at five buttons, what you may want to do is scan them all in a loop like this:

    Get_Buttons:
    · btns = %00011111
    · FOR idx = 1 TO·10
    ··· btns = btns & INL
    ··· PAUSE·5
    · NEXT
    · RETURN

    This routine debounces the button inputs for about 50 ms, scanning 10 times·during the process to make sure that a button was not released and pressed again (contact bounce).· The advantage of using a subroutine like this is that all buttons are scanned at the same time, and the value is held (in the variable btns) until you call the subroutine again.

    On your question about doing something just once on·the press of a button,·on way to handle this is:

    ··GOSUB·Get_Buttons
    · IF (btns.BIT0 = 1) THEN
    ····' do something
    ····DO
    ····· GOSUB Get_Buttons
    ··· LOOP UNTIL (btns.BIT0 = 0)
    ··ENDIF

    If you want to do this kind of thing for multiple simultaneous events, then you'll need a different strategy: you'll have to have a set of flags that keeps track of the state of all the buttons such that a process is blocked until that button has been released then repressed.
    ·


    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Jon Williams
    Applications Engineer, Parallax
    Dallas, TX· USA


    Post Edited (Jon Williams) : 5/20/2005 6:56:42 PM GMT
  • Chris SavageChris Savage Parallax Engineering Posts: 14,406
    edited 2005-05-20 18:17
    Danny,

    ·· The GOTO in each section to the next section is not needed.· The routine you are going to is right below it, so the program will go there anyway.· The extra GOTOs will simply take up extra memory and add a small delay (loading time) to the loop.··

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Chris Savage
    Parallax Tech Support
    csavage@parallax.com
  • Jon WilliamsJon Williams Posts: 6,491
    edited 2005-05-20 18:55
    After re-reading your post and thinking about the term "one shot" it occured to me that if you had the memory, you could add timers to each input so that they could not be retripped until expired.· Perhaps something like this:

    Main:
    · DO
    ····GOSUB Get_Buttons···················· ' scan buttons
    ··· FOR chan = 0 TO 4···················· ' loop through all channels
    ····· IF (timer(chan) = 0) THEN···········' check channel timer
    ······· IF (btns.LOWBIT(chan) = 1) THEN·· ' input active?
    ········· GOSUB Send_Msg··················' -- send message for this channel·
    ········· timer(chan) = 600·············· ' -- reload timer with one minute
    ······· ENDIF
    ····· ELSE
    ······· timer(chan) = timer(chan) - 1···· ' update·running timer
    ····· ENDIF
    ··· NEXT
    ··· PAUSE 100···························· ' loop pad (0.1 sec)
    · LOOP
    · END

    The Send_Msg subroutine would use the variable chan to send the appropriate message.· This example uses the same timer value for all channels, but you could update it by embedding default timer values into a DATA statement.· To keep it easy, enter the timing in seconds (1 to 255) and change...

    ······· timer(chan) = 600·············· ' -- reload timer with one minute

    to...

    ········READ DfltTime + chan, timer(chan) ' read default seconds
    ······· timer(chan) = timer(chan)·* 10····' convert to tenths

    Of course, you'd need to add this to your program as well:

    DfltTime··· DATA··· 60, 60, 90, 30, 60

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Jon Williams
    Applications Engineer, Parallax
    Dallas, TX· USA


    Post Edited (Jon Williams) : 5/20/2005 7:02:13 PM GMT
  • DannyDanny Posts: 56
    edited 2005-05-20 19:45
    Thanx guys!
    I'll be trying all of these to see how they work and to apply them to my project.

    BTW, I'll be watching 16 motion detectors with each of these units, so being able to use the onboard serial port for communications is a serious bonus!!

    Thanx Again!

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    "Never create anything you can't control"
    "The amount of intelligence on the planet is fixed... the population is growing"
  • Jon WilliamsJon Williams Posts: 6,491
    edited 2005-05-20 20:06
    If you've got to monitor 16 inputs you may consider daisy-chaining a couple 75HC165 shift registers -- it will simplify debouncing and allow you to use standard IO pins for the serial connection in the event you need flow control.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Jon Williams
    Applications Engineer, Parallax
    Dallas, TX· USA
  • DannyDanny Posts: 56
    edited 2005-05-20 22:38
    Actually, I have already had the test system sending commands to the lighting processor, it works great without flow control, the lighting system just ignores anything that doesn't match it's protocol. And I'm not concerned with anything coming out of the lighting processor, so life is great!
    THanx again for the help and have a great weekend!

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    "Never create anything you can't control"
    "The amount of intelligence on the planet is fixed... the population is growing"
  • Tracy AllenTracy Allen Posts: 6,658
    edited 2005-05-21 00:24
    Hi Danny,

    I highly recommend using a "state machine" written in PBASIC for this kind of thing. You want to detect and take action when a key changes state from 1 to 0, only at the transition. The secret is to harness logic operators, AND (& in Stampese) and XOR (^ in stampese.) Those operators compare the present state of a key with its prior state. Consider the following logic statement, where all the variables are bits:

    newKey VAR Bit
    oldKey VAR Bit
    xKey VAR Bit  
      
    oldKey=in0    ' capture the initial state   
    DO
        newKey=in0   ' read an input 
         xkey = newKey ^ oldKey & oldKey
        oldKey=newKey   ' update the internal variable
        IF xKey THEN DEBUG "key pressed",cr
       pause 10   ' your program can go off and do other stuff here
     LOOP
    



    The message prints out only when you press the key, and you have to release it before it can print again. The XOR operator detects the change between past and present state. The AND operator imposes the condition that the past state was 1.

    The beauty of this comes when you need to scan lots of keys, because you can do them all in parallel with exactly the same number of lines of code. See, here is the same code scanning all 16 keys at once:

    newKey VAR Word   ' now words instead of bits
    oldKey VAR Word
    xKey VAR Word
    oldKey=ins   ' capture the initial state of all 16 keys
    DO
        newKey=ins   ' read all 16 inputs 
         xkey = newKey ^ oldKey & oldKey  ' compare all 16
        oldKey=newKey   ' update the internal variable
        IF xKey THEN DEBUG "keys pressed=", BIN16 xKey,cr
       pause 10  ' your program can go off and do other stuff here
     LOOP
    



    In your application, you'd let bits in the xKey variable trigger the messages to your lighting controller. It can easily handle the condition where two or more keys happen to activate at once.

    I have other tutorials on State machines at this URL
    www.emesystems.com/BS2fsm.htm

    I agree with Jon, the BUTTON command is not too useful for things like this.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Tracy Allen
    www.emesystems.com
  • DannyDanny Posts: 56
    edited 2005-05-26 19:29
    Guys:
    In experimenting I came upon the following after reading the industrial controls manual.
    It seems to work perfectly, I'm planning on extending it to all 16 inputs, with all but the last module pointing to the one after it so the
    stamp will poll all 16 inputs.

    Do you forsee any issues with this program??



    ' {$STAMP BS2}
    ' {$PBASIC 2.5}
    'Program description here

    'Declare I/O Here
    INPUT 0
    INPUT 1
    INPUT 2
    INPUT 3
    INPUT 4
    INPUT 5
    'Declare Variables Here
    PB1 VAR IN0
    PB2 VAR IN1
    PB3 VAR IN2
    PB4 VAR IN3
    PB5 VAR IN4

    Flag1 VAR Bit
    Flag2 VAR Bit
    Flag3 VAR Bit
    Flag4 VAR Bit
    Flag5 VAR Bit
    'Declare Constants Here

    'Set Serial port info here

    'Main program here
    Flag1 = 0
    Flag2 = 0

    Start:
    'DEBUG "I'm Alive", CR
    PAUSE 10

    Check1: IF PB1 = 0 THEN Do1
    Flag1 = 0
    GOTO Start

    Do1: IF Flag1 = 1 THEN Start
    'Put task here
    DEBUG "Button Pressed", CR
    TOGGLE 10
    Flag1 = 1
    GOTO Start

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    "Never create anything you can't control"
    "The amount of intelligence on the planet is fixed... the population is growing"
  • Jon WilliamsJon Williams Posts: 6,491
    edited 2005-05-26 19:40
    Danny,

    All BASIC Stamp pins are made inputs on reset, so you don't need to declare them as you're doing at the top of your program -- this just consumes space. And in your program you're using TOGGLE but the state of the pin was not preset on start-up; this can lead to unexpected results (see TOGGLE in the manual or help file for an explanation). Let me suggest you use the OUTS and DIRS variables to preset everything before your operational code gets started. The NCD operator will also be helpful in your application; use it with BRANCH to streamline multipe inputs/code segments.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Jon Williams
    Applications Engineer, Parallax
  • DannyDanny Posts: 56
    edited 2005-05-26 20:30
    The toggle was just in there to turn an LED on and off for testing, it will be replaced with a serial string for the final.
    For some reason I tought OUTS and DIRS only applied to the BS1.
    Will have to read up on NCD and BRANCH, more time reading in bed and less sleep for me!!!
    Thanx!

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    "Never create anything you can't control"
    "The amount of intelligence on the planet is fixed... the population is growing"
Sign In or Register to comment.