Shop OBEX P1 Docs P2 Docs Learn Events
Way to make the basic stamp wait for an input? — Parallax Forums

Way to make the basic stamp wait for an input?

TboneHTboneH Posts: 2
edited 2013-08-14 10:44 in BASIC Stamp
Hey guys, I need some help. I'm no expert, so don't kill me if I say something stupid. What I have is a slide carriage and switch system. I want the carriage to slide along until it hits a switch (wired normally open), and then stop. I'm using a plain old BS2 stamp, and I already have my switch and carriage motor wired to it. For now, we'll just assume that my motor output is pin 15, and my switch input is pin 0. I've tried using an IF THEN system that looks kinda like this:

IF (IN0 = 0) THEN
HIGH 15
ELSE
LOW 15
ENDIF

However, my carriage motor is very fast (it's out of an inkjet printer if that helps you imagine it). What ends up happening is that by the time the stamp recognizes that switch has been pressed, the motor is past it, and it doesn't shut off. What I want is for the stamp to send a high to 15 until it receives an input at pin 0 and then continue with the rest of the program. Any suggestions?

Comments

  • Phil Pilgrim (PhiPi)Phil Pilgrim (PhiPi) Posts: 23,514
    edited 2012-05-11 20:37
    Try this to wait until IN0 goes low:
    DO WHILE IN0: LOOP
    

    It that's still not fast enough, you will probably have to hardwire something to stop the motor on time.

    -Phil
  • tobdectobdec Posts: 267
    edited 2012-05-12 00:28
    TboneH, is is a good ol fashioned brushed motor or a stepper? If its a stepper then that is why your overhead is eating all your resources. Although even then it should recognize that switch in due time. Maybe put the switch ahead of where it should be...I know it sounds ghetto but it might just be what you need.
  • TboneHTboneH Posts: 2
    edited 2012-05-12 16:29
    Thanks guys. Phil, that appears to be what I need. Right now, this is what I've got:
    DO WHILE IN0=0:
    HIGH 15
    LOOP
    

    Is that correct syntax? I can't test fully test it right now because I'm missing some necessary resistors, but experimenting with it it seemed to do the job.

    And to tobdec, it is a brushed motor, but I think you misunderstood my problem. My problem was that using the IF THEN code, if the slide carriage didn't stop exactly on the switch, it would send a 0 again and the carriage would continue due to the way the code was written.
  • tobdectobdec Posts: 267
    edited 2012-05-12 17:45
    TboneH wrote: »
    Thanks guys. Phil, that appears to be what I need. Right now, this is what I've got:
    DO WHILE IN0=0:
    HIGH 15
    LOOP
    

    Is that correct syntax? I can't test fully test it right now because I'm missing some necessary resistors, but experimenting with it it seemed to do the job.

    And to tobdec, it is a brushed motor, but I think you misunderstood my problem. My problem was that using the IF THEN code, if the slide carriage didn't stop exactly on the switch, it would send a 0 again and the carriage would continue due to the way the code was written.
    Ah my bad I did misunderstand you...in that case yes Phil is correct.
  • Duane DegnDuane Degn Posts: 10,588
    edited 2012-05-12 20:48
    I think you'd get even less delay when the switch is detected if you move the setting the pin high outside of the loop (Phil's code didn't have it in the loop).
    HIGH 15
    DO WHILE IN0 == 0: LOOP
    LOW 15
    

    Since pin 15 only needs to be set high once, setting it high inside each loop will cause an unneeded delay.

    This extra delay will cause the Stamp to be a little slower to sense the button press.
  • Tracy AllenTracy Allen Posts: 6,664
    edited 2012-05-15 20:51
    A fine point is that this syntax:
    [SIZE=1][FONT=courier new]DO : LOOP WHILE IN0=0[/FONT][/SIZE]
    
    is faster than
    [SIZE=1][FONT=courier new]DO WHILE IN0=0 : LOOP[/FONT][/SIZE]
    
    .

    The BASIC Stamp implements the loop internally using GOTO primitives that were part of PBASIC 2.0 and earlier, and it is easy to see the time difference.
    [SIZE=1][FONT=courier new]' primitives for DO WHILE condition : LOOP
    L1: IF IN0=0 THEN L2   GOTO L3 
    L2: GOTO L1 
    L3: [/FONT][/SIZE]
    
    [SIZE=1][FONT=courier new]' primitives for DO : LOOP WHILE condition  
    L1: IF IN1=1 THEN L1[/FONT][/SIZE]
    

    Another to try for speed would be
    [SIZE=1][FONT=courier new]DO : LOOP UNTIL in0[/FONT][/SIZE]
    
    That gains speed because it does not have to evaluate the math of in0=0. The simple fact that in0=1 counts as TRUE. But the microcode for the DO UNTIL syntax is not as fast as the DO : LOOP WHILE syntax.

    Yet another, and probably the fastest option is the BRANCH instruction, which is itself a Stamp primitive.
    [SIZE=1][FONT=courier new]here: BRANCH in0, [here, there]  ' loops at here until in0=1
    there: HIGH 15[/FONT][/SIZE]
    
  • Tracy AllenTracy Allen Posts: 6,664
    edited 2012-05-16 21:05
    I meant to add that the BS2p series stamps have faster ways to do what you want. The POLLIN and POLLOUT instructions can couple an output to an input, and the POLLWAIT instruction can pause without LOOPing, until a pin goes to a certain state. I know you said you have a plain old BS2, but it's just an option if the other isn't fast enough.
  • CuriousOneCuriousOne Posts: 931
    edited 2013-07-22 05:08
    Well, I have almost similar problem, the code needed is like this: stamp waits for pulse on port, as port gets high, counter starts to increase, as port gets low, loop is terminated and counter variable feed to next program code. By my understanding, I should do it like this:
    BUT PIN 5
    CNT VAR WORD
    CNT=1
    WTR:
    IF BUT=0 THEN GOTO WTR ELSE GOTO NXT 'wait untill button is pressed
    NXT:
    DO
    CNT=CNT+1 'count button pressed time
    LOOP UNTIL BUT=0
    DEBUG CR, CNT 'display the counted value
    

    Is above correct? have no chance to verify now.
  • Tracy AllenTracy Allen Posts: 6,664
    edited 2013-07-22 07:56
    That looks okay. It could be a bit faster with the following syntax:
    [SIZE=1][FONT=courier new]BUT PIN 5
    CNT VAR WORD
    CNT=1
    WTR:  
      BRANCH BUT, [WTR,NXT] 'wait until pressed, [COLOR=#0000ff]BRANCH is fast[/COLOR]
    NXT:
      DO
        CNT=CNT+1 'count button pressed time
      LOOP WHILE BUT    ' [COLOR=#0000ff]BUT=1 [SIZE=1]qualifies as TRUE[SIZE=1][/SIZE][/SIZE][/COLOR]
    DEBUG CR, CNT 'display the counted value
    [/FONT][/SIZE]
    

    Note that the minimum count will be CNT=2.
  • Tracy AllenTracy Allen Posts: 6,664
    edited 2013-07-22 12:35
    Actually the following has a slight edge. On a BS2pe the loop came in at 1693 counts per second, whereas the one in my previous post came in at 1685 per second. Either one gives you better than 1ms resolution.
    [SIZE=1][FONT=courier new]CNT=0
    Wtr2: 
     DO : LOOP UNTIL but  ' wait for [SIZE=1]pre[SIZE=1]ss[SIZE=1]ed, high level[/SIZE][/SIZE][/SIZE]
     DO
       CNT=CNT+1 'count button pressed high time
     LOOP WHILE BUT
    DEBUG CR, "DoDo: ", DEC CNT 'display the counted value
    [/FONT][/SIZE]
    
  • the_0utsider1the_0utsider1 Posts: 13
    edited 2013-07-27 18:10
    Duane Degn wrote: »
    I think you'd get even less delay when the switch is detected if you move the setting the pin high outside of the loop (Phil's code didn't have it in the loop).
    HIGH 15
    DO WHILE IN0 == 0: LOOP
    LOW 15
    

    ok am i missing something? i copied this line (except i have pin 6 as input so i have in6) and try to run it i get the error:

    Expected ':' or end-of-line

    ??????
  • SapphireSapphire Posts: 496
    edited 2013-07-27 19:14
    The code is wrong. The "==" should be "=". And as Tracy said, this is faster:
    HIGH 15
    DO : LOOP WHILE IN6=0
    LOW 15
    
  • wespiecewespiece Posts: 6
    edited 2013-08-08 11:09
    ok I have a question along these same lines but im using serin command - how can I interrupt a loop - seems when in a loop it ignores my writes to data storage as well and anything else from serin. below is my code - task 7 and 8 are my focus. I want to create a flasher circuit that I trigger via pc input and need to cancel them in the same manner. but right now its ignoring all my request to interrupt the loop... hope this helps.
    Main:
      SERIN 16, 16468, [STR command\1]    ' Get 1-byte string
    
    CheckCommand:
      IF command = "1" THEN
         GOTO Task1
      ENDIF
      IF command = "2" THEN
         GOTO Task2
      ENDIF
      IF command = "3" THEN
         GOTO Task3
      ENDIF
      IF command = "4" THEN
         GOTO Task4
      ENDIF
      IF command = "5" THEN
         GOTO Task5
      ENDIF
      IF command = "6" THEN
         GOTO Task6
      ENDIF
      IF command = "7" THEN
         GOTO Task7
         ENDIF
      IF command = "8" THEN
         GOTO Task8
         ENDIF
    GOTO Main
    
    Task1:
    TOGGLE 0
    GOTO Main
    Task2:
    TOGGLE 1
    GOTO Main
    Task3:
    TOGGLE 2
    GOTO Main
    Task4:
    DO
    HIGH 3
    PAUSE 500
    LOW 3
    PAUSE 500
    reps = reps + 1
    LOOP UNTIL (reps >=8)
    GOTO Main
    Task5:
    DO
    HIGH 4
    PAUSE 500
    LOW 4
    PAUSE 500
    reps2 = reps2 + 1
    LOOP UNTIL (reps2 >=8)
    GOTO Main
    Task6:
    HIGH 5
    PAUSE 100
    LOW 5
    GOTO Main
    Task7:
    reps4 = 1
    WRITE 0, reps4
    DEBUG DEC reps4
    PAUSE 1000
    reps4 = 0
    WRITE 0, reps4
    DEBUG DEC reps4
    GOTO Main
    Task8:
    DO
    HIGH 3
    HIGH 4
    PAUSE 500
    LOW 3
    LOW 4
    PAUSE 1000
    READ 0, reps4
    DEBUG DEC reps4
    LOOP UNTIL (reps4 >=1)
    PAUSE 100
    GOTO Main
    
  • Mike GreenMike Green Posts: 23,101
    edited 2013-08-08 12:12
    The Stamps can only do one thing at a time. When you do a SERIN, the Stamp stops and waits for a character to be received. When it's doing a PAUSE, all it's doing is waiting for the specified time to be up and it ignores everything else including any characters being send to an I/O pin. When your program is doing its tasks, it's ignoring any serial input.

    In your Task8, the LOOP continues unless the data read from location 0 is non-zero. If you've just done Task7, that location will be left with a zero in it and the next time you do Task8, the LOOP will never exit.

    Print out your program and take a pencil and point it at the Main label. Then advance the pencil one statement at a time pretending that your pencil is the Stamp executing the program. There's only one pencil and the Stamp does only what the pencil is pointing to. It's as if the rest of the program doesn't exist ... only that one statement.
  • wespiecewespiece Posts: 6
    edited 2013-08-14 06:40
    Ok so is there a way? I want to have a method via serial to activate and cancel a flashing circuit. Thoughts???
  • Mike GreenMike Green Posts: 23,101
    edited 2013-08-14 07:45
    Not really. You need to move some of the work out of the Stamp into another microprocessor.

    You can use an external co-processor (another special purpose microcontroller) like these from ProteanLogic. These are pre-programmed microcontrollers that handle the serial input while the Stamp is doing something else. When the Stamp is ready, it can retrieve any characters that have come in while it was busy.

    Alternatively, you can use some kind of external flasher that the Stamp can turn off and on, but the Stamp doesn't have to do the actual flashing and timing and it can sit there waiting for serial input characters.
  • Tracy AllenTracy Allen Posts: 6,664
    edited 2013-08-14 10:44
    wespiece,
    The BS2 has flow control capabilities, for example, if you add the \15 as follows, then the Stamp generates a "not ready" level on pin p15 when it is busy in other routines, and that level will go to "ready" when it comes to the SERIN and is ready to receive. If the PC is also set up for RTS/CTS flow control, it will automatically hold off on sending the command until it gets the go ahead from the Stamp.

    SERIN 16[COLOR=#020FC0]\15[/COLOR], 16468, [STR command\1]    ' Get 1-byte string
    


    The PC can't preemptively take over at any time. However, SERIN also has a timeout option. For example, the following adds a 500ms timeout, with a branch out to label "nextup" if no data is received within 500ms.
    As a workaround, to give the illusion of instant response, you can replace a PAUSE 500 with a SERIN + timeout. That might even work without flow control, because your program has lots of long pauses.

    SERIN 16\15, 16468, [COLOR=#020FC0]500, nextup1,[/COLOR] [STR command\1]    ' Get 1-byte string
    
Sign In or Register to comment.