Shop OBEX P1 Docs P2 Docs Learn Events
bounce baby bounce — Parallax Forums

bounce baby bounce

Zap-oZap-o Posts: 452
edited 2009-06-20 04:18 in Propeller 1
Fellas I wonder if there is a better way to de bounce the three buttons I am working with. here is what I got so far.

Pub CheckButtons 

  Button_temp  := INA [noparse][[/noparse] 0..2 ]  

  Case Button_temp
  
    %111 : Button_idx := 0
     
    %011 :  Button_idx++           
            IF (Button_idx  => 1500)
                                !outa [noparse][[/noparse] Led ]
                                 Button_idx := 0
                                                                    
    %101 : Button_idx++           
           IF (Button_idx  => 950)
                                Scrap := Math.Fadd(Scrap,0.01)
                                UpDateDisplay
                                Button_idx := 0
                                
    %110 : Button_idx++
            IF (Button_idx => 950)
                                Scrap := Math.Fsub(Scrap,0.01)
                                UpDateDisplay  
                                Button_idx := 0




All the buttons are tied high until pressed. Its working but the response is a bit sloppy. Any ideas and other ways I could go about this would be great. I am basically incrementing a number on a display when the y up arrow button is pressed and decrementing a number when the down button is pressed. The on/off toggles an led.

Comments

  • W9GFOW9GFO Posts: 4,010
    edited 2009-06-18 02:52
    My approach was to launch a cog to monitor the buttons continuously. I needed to be able to hold a button down at any point to go back to the main program. I also created a few constants; short, medium, extended and held - so that I can easily check if the duration the button is held meets a condition.


    CON
    
    short = 0
    medium = 5
    extended = 10
    held = 30
    
    IF Button > short
      Do_THIS
    
    IF Button > held
      EXIT
    
    





    PUB Monitor
    
    Repeat
      if ina[noparse][[/noparse]Bt1..Bt3] == 0
        _Pressed := 0
      else
        _Pressed := 1
    
      if ina[noparse][[/noparse]Bt1] == 1
        Button[noparse][[/noparse]0]++
      else
        Button[noparse][[/noparse]0] := 0
    
      if ina[noparse][[/noparse]Bt2] == 1
        Button{1}++
      else
        Button{1} := 0
    
      if ina[noparse][[/noparse]Bt3] == 1
        Button{2}++
      else
        Button{2} := 0
    
      waitcnt(clkfreq/10 +cnt)   
    
    



    Edited to replace vanishing brackets with curly braces.

    Rich H

    Post Edited (W9GFO) : 6/18/2009 2:58:28 AM GMT
  • MagIO2MagIO2 Posts: 2,243
    edited 2009-06-18 07:08
    Hmmm ... wasting a COG for buttons ... I don't like this idea ... time comes when you'll need all available COGs for more important things.

    Well ... the implementation depends on what your button-reading loop is doing. Is it only reading the buttons or does it have other tasks? In other words: Is it OK that the CheckButtons function is blocking or not. If it is allowed to be blocking it's easy:
    1. Read INA
    2. Run whatever you want to run
    3. Wait for 1ms for debouncing - bouncing usually only takes some 100usec
    4. a) wait until the button is released or b) a key-repeat-rate timeout·has been·reached
    if you only implement a) then it's blocking as long as the button is pushed
    if you implement a) and b) it's blocking until the timeout has been reached

    If blocking is not allowed at all CheckButton needs a state so that it knows what to do next:
    state 0 => read INA (initial state), state 1 => debounce, state 2 => wait for release/key-repeat-rate
    with the following transitions:

    state 0 and no button pushed: return immediately
    state 0 and button is pushed: do whatever has to be done and set state to 1 (store cnt for time measurement)
    state 1 and 1ms not passed: return immediately
    state 1 and 1ms passed: set state to 2 (store cnt in case you want the key repeat)
    state 2 and button not released and time not passed: return immediately
    state 2 and button released or time passed: set state to 0

    Post Edited (MagIO2) : 6/18/2009 7:16:43 AM GMT
  • Toby SeckshundToby Seckshund Posts: 2,027
    edited 2009-06-18 07:59
    Making the beast to·listen to you when you want/need it to listen to you, is not a waste. All good equipment notes the button push and gets to action·it as soon as possible. If the button·is not even read because the main program was "busy"·people will just jab away with greater and greater force.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Style and grace : Nil point
  • MagIO2MagIO2 Posts: 2,243
    edited 2009-06-18 11:31
    Have a look at the proposed code. The Monitor function does not help in making the application responsive as it only sets some variables, so it only adds debouncing. No buffering of keystrokes here as well. So the main application still can miss a 'keystroke'.

    It's still a waste of a COG in my opinion to have a simple button-checker running in it's own COG doin nothing else. If you need your application to be responsive, then make the CheckButtons function non-blocking and call it whenever possible. Usually the main program of user-interface-driven applications wastes a lot of time simply for waiting. If you have a number-crunching application which runs for hours, why not add the CheckButtons call in the number crunching loop?

    Other way would be to add this kind of code into a driver - say the keyboard driver for example. So, whenever the driver waits for the next command it simply checks the buttons as well. Implementation of the state machine would simply be self-modifying code in this case.

    Post Edited (MagIO2) : 6/18/2009 11:39:17 AM GMT
  • LeonLeon Posts: 7,620
    edited 2009-06-18 11:32
    It depends on the switch, a debounce delay of several ms might be necessary. Ganssle has written the ultimate document on switch debouncing techniques:

    www.ganssle.com/debouncing.pdf

    Leon

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Amateur radio callsign: G1HSM
    Suzuki SV1000S motorcycle
  • MagIO2MagIO2 Posts: 2,243
    edited 2009-06-18 11:39
    Nice link, thanks Leon!
  • ErNaErNa Posts: 1,752
    edited 2009-06-18 11:48
    If there is a cog over, it's never a waste of cogs!
    And if you run out of cogs, identify tasks, which can be done by one cog. Or attach a second propeller. But when you leave the paradigm of parallel processing, you run into the debris you call "the rest of the world" .

    So "Hello World" in Spin is "hello debris"

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    cmapspublic3.ihmc.us:80/servlet/SBReadResourceServlet?rid=1181572927203_421963583_5511&partName=htmltext
  • MagIO2MagIO2 Posts: 2,243
    edited 2009-06-18 12:22
    8 COGs is not that much ... that's why we have drivers that do support 4 serial ports in ONE COG, keyboard/mouse in ONE COG and so on.

    And even if you have a cog left over, why would you want to consume additional power just for running a button checker COG, when the button checker code can be run in one of the COGs that wait most of the time?
    You say "And if you run out of cogs, identify tasks, which can be done by one cog." - so, I'm only one step ahead when I say "Don't waste a COG for that from the beginning".
    Usually you start with implementation of a project and you don't exactly know where you will end. In terms of COG usage you don't know how much COGs you need for other stuff in advance : ".... oh ... I could add feature x and y to my project. That would be fun." If you now have to rewrite your button input because you have to free the COG again it might be more difficult than doin it clever in the beginning.

    That's only my personal opinion ... so, feel free to do it the wrong way ;o)
  • Toby SeckshundToby Seckshund Posts: 2,027
    edited 2009-06-18 14:11
    I suppose it comes down to what the button does. If it is a request for the pretty blue LED, instead of the green LED·the it would be a waste of resources. If it was a request for those numbers to stop counting down, on that suspicious package, it might not be.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Style and grace : Nil point
  • Zap-oZap-o Posts: 452
    edited 2009-06-18 14:36
    Well the buttons are used to increment a number on a display and turn on / off the device. That said I cant afford to sit in a loop or waste clock cycles (counting how long the button is in a low sate). I need to keep processing, but at the same time de-bounce the button.

    I am going to try to use a timer of some kind today Ill keep you all updated.
  • pgbpsupgbpsu Posts: 460
    edited 2009-06-18 15:12
    @Zap-o

    At the risk of drawing MAGIO2's ire, I did exactly what you propose to do. I agree with him that dedicating an entire cog to watching for buttons is wasteful. I was charged with re-doing a piece of equipment. The biggest complaint with the old equipment was the buttons weren't responsive. So my first design decision was not to miss any presses. And I did it by dedicating an entire cog. In my application the when a button is pressed, it drives a line high.
    PUB BUTTONS
    {{ BUTTONS - method, to be launched in sepearte cog which only watches for presses
    on the 4 front panel buttons.  Presses are limited to 0 = FALSE; 1 = TRUE
    If any of these buttons are pressed, this method should catch it and update the global variable:
    CLEAR_PRESSES, UP_PRESSES, DOWN_PRESSES, ENTER_PRESSES
    
    This method DOES NOT CLEAR THE TRUE VALUES!  That is the responsibility of the other methods.
    }}
    
      repeat                               'Repeat the following
        if ( INA[noparse][[/noparse]CLEAR] == 1 )
          CLEAR_PRESSES := 1
          DelayMS(250)      ' software debounce
          
        if ( INA[noparse][[/noparse]UP]    == 1 )
          UP_PRESSES    := 1
          DelayMS(250)      ' software debounce
          
        if ( INA[noparse][[/noparse]DOWN]  == 1 )
          DOWN_PRESSES  := 1
          DelayMS(250)      ' software debounce
          
        if ( INA[noparse][[/noparse]ENTER] == 1 )
          ENTER_PRESSES := 1
          DelayMS(250)      ' software debounce
          
    '    uarts.str(DEBUG,string(13,"CUDE",13))         'display it and
    '    uarts.str(DEBUG,string(13))         'display it and
    '    uarts.dec(DEBUG,CLEAR_PRESSES)
    '    uarts.dec(DEBUG,UP_PRESSES)
    '    uarts.dec(DEBUG,DOWN_PRESSES)
    '    uarts.dec(DEBUG,ENTER_PRESSES)
    
    




    And here's an example dealing with those buttons and a 4x20 LCD
    PUB MAIN_MENU 
    '' Display the Main menu options
        matrix.cls
        matrix.gotoxy(10,0)
        matrix.str(string("Set Intvl"))
        matrix.gotoxy(10,1)
        matrix.str(string("GPS Info"))
        matrix.gotoxy(10,2)
        matrix.str(string("Countdown"))
        matrix.gotoxy(10,3)
        matrix.str(string("Next Menu"))
        matrix.gotoxy(0,3)
        matrix.str(string("CLEAR"))
        DRAW_ARROW(arrow_location1)
    
      repeat
        if ( CLEAR_PRESSES == 1 )
          CLEAR_PRESSES := UP_PRESSES := DOWN_PRESSES := ENTER_PRESSES := 0
          INIT_SCREEN       ' go back to main menu with Initial settings
    
        if ( UP_PRESSES ==  1 )
          CLEAR_PRESSES := UP_PRESSES := DOWN_PRESSES := ENTER_PRESSES := 0
          CLEAR_ARROW(arrow_location1)
          arrow_location1 := ( arrow_location1 - 1 ) #> 0 ' add one to arrow_location1 but limit to max of 3
          DRAW_ARROW(arrow_location1)
          
        if ( DOWN_PRESSES == 1 )
          CLEAR_PRESSES := UP_PRESSES := DOWN_PRESSES := ENTER_PRESSES := 0
          CLEAR_ARROW(arrow_location1)
          arrow_location1 := ( arrow_location1 + 1 ) <# 3 ' add one to arrow_location1 but limit to min of 3
          DRAW_ARROW(arrow_location1)
          
        if ( ENTER_PRESSES == 1 )
          CLEAR_PRESSES := UP_PRESSES := DOWN_PRESSES := ENTER_PRESSES := 0
          CASE arrow_location1
            0  :  SET_INTERVAL
            1  :  GPS_SCREEN
            2  :  COUNTDOWN_MENU
            3  :  SECOND_MENU
    
    
    



    Peter
  • MagIO2MagIO2 Posts: 2,243
    edited 2009-06-19 06:36
    Thank you pgbpsu! This is a perfect example for a waste ;o) You did not draw me ire, you made me smile and I have this strange feeling of mercy. lol.gif

    Waste of COG, waste of memory, waste of runtime ... all nicely packed in one little program. Let me guess: You learned programming on megabyte machines and did not realize yet, that the propeller has less memory.

    Now .. let's start to analyse:

    MAIN_MENU
    =========
    I guess the first lines of code repeat in the other MENU functions as well (SECOND_MENU and COUNTDOWN_MENU). So, what I would have done is create a function PRINT_MENU which prints any menu. So, all the .cls, .gotoxy and .str function calls are only needed once even if you have multiple menus. The strings including the positions can be arranged in a dat section. So, when you call PRINT_MENU you only pass the adress of the menu you want to print.

    repeat loop .... what does it do? Most of the time NOTHING but wait for the button variables to change. So, please tell me why can't you call a non-blocking getButton function there? No need for an extra·COG that watches the buttons,·your main·COG has plenty of time to do this. The code behind the CLEAR_PRESSES, UP_PRESSES and DOWN_PRESSES is done in microseconds, so the buttons will be pretty responsive.
    In the other menus you add the same getButton, so no problem there as well.
    I guess SET_INTERVAL needs it's own button handling, so getButton will be needed there too.
    And GPS_SCREEN looks like you have a loop there which reads GPS data and displays that. Loop ... loop ... hmmm ... easy to call the getButton there as well for stopping the loop, go back to the menu or whatever.

    In each of the functions you have to check for CLEAR_PRESSES, UP_PRESSES... anyway if you want it to respond to the buttons. So, what's the difference to calling getButton?

    CLEAR_PRESSES, UP_PRESSES, DOWN_PRESSES ... at least one byte each where one bit would be enough.

    BUTTONS
    =======
    Please read the PDF that Leon mentioned. Your BUTTON function only debounces but it doesn't protect against EMI (my suggestions from the earlier posts didn't as well). Switching on a fluorescent lamp·might be·enough to·confuse your application.
    Why do you call delay in each if? It would be enough to call it in the end once.
    CON
       CLEAR = |< 0
       UP = |< 1
       DOWN = |< 2
       ENTER = |< 3
     
    VAR
       byte buttons
     
     
    PUB MAIN_MENU
      ...
      repeat
        if buttons & CLEAR
          buttons := 0
          ...
        if buttons & UP
          ...
        ...
     
     
    PUB BUTTONS
      repeat
        buttons |= INA[noparse][[/noparse]3..0]
        DelayMS( 100 )
    

    This would be an equivalent to your implementation with no noticable differences regarding look and feel. (But it's still not how I'd do it) Maybe I'll find some time this weekend to
    ·code a demo for you.

    ·
  • pgbpsupgbpsu Posts: 460
    edited 2009-06-19 14:50
    @MagIO2

    I'm glad I did at least one thing right
    MagIO2 said...

    all nicely packed in one little program

    You have to admit that at least there was efficiency in that.

    I don't mind your deconstruction of my code. Just for the record, I didn't learn programming on a megabyte machine. I've been learning it on the Prop (although some may argue with how successful I've been at that). I appreciate that rather then saying what an awful example of coding I've provided, you are willing to make a few suggestions. For that I thank you.

    I'm aware of the Prop's memory limitations, but also feel that readable and simple code makes life easier for me when writing, debugging, and maintaining code. Which is why I opted for byte long variables for the buttons rather than having to mask them off. But I don't think that's what's at the heart of your critique and the example you provided shows using bits can still be a clear way of coding.

    As I mentioned in my original post, my charge was not to miss button presses. I knew full well I this design would have one entire cog simply waiting for buttons to be pressed. And I can honestly say that I did so knowingly (please don't have a heart attack). Not because I fail to recognize the value or scarcity of resources on the Prop but because I knew I could get the rest of my program into the remaining space, and more importantly, because I couldn't/didn't think of a better way. I'm not sure the example you showed
    PUB BUTTONS
      repeat
        buttons |= INA[noparse][[/noparse]3..0]
        DelayMS( 100 )
    
    


    can solve my particular problem. If it can, I hope you're patient (and merciful [noparse];)[/noparse] ) enough to show me how. I think there are 2 problems:

    1. When the user enters the COUNTDOWN or GPS screens (menu may not be a good choice of name) the display needs to update even while no buttons are pressed. I believe that the way you coded it below, once I call BUTTON I don't return until a button is pressed (which would achieve my stated goal of not missing button presses) but it would leave the GPS screen (for instance) stuck until the next button press, wouldn't it? The GPS screen needs to refresh every second to show the new time,date, position, etc. Likewise for the COUNTDOWN screen.

    2. I don't see how, using a nonBlocking getButton function, you can be sure to check the current state of the buttons frequently enough to assure you haven't missed one. The things the main cog needs to do while in screens other than the MAIN_MENU may require that cog's attention for many, even hundreds of milliseconds. The arrangement I have allows the prop to notice buttons presses while the main cog is away doing something else. And because it's running in a separate cog it is watching for button presses ALL THE TIME. I realize my MAIN_MENU method (and others like it) only do something ABOUT those presses when they get around to it. But that's the whole point. It can be busy when a button is pressed (and released) but it finds out about it when it gets back. I'm not sure I see a nonBlocking solution to that. If you can show me, I'll be more than happy to incorporate that into my code (with appropriate credit, of course).

    The only line from the first chunk that repeats (exactly as it is) in each menu is the cls. That's certainly shouldn't get it's own function. However you seem to suggest a way that I could populate a DAT section with whatever I want printed, then simply print that. That's what I wanted to do originally- have the different methods put what they wanted printed into a "buffer" and then simple call a method which prints that buffer to the LCD. Is this what you're getting at? I didn't get it working so I moved back to each method printing strings to the LCD where and when it was needed.

    You suggest moving the delay in my BUTTONS method from within each IF statement to the end. But I don't want to wait every time through the repeat loop (that would defeat the purpose of putting this method in it's own cog). I simply want to wait a bit only WHEN a button has been pressed. I'm using this as a software debounce. If I move it to the end I save a couple lines of code, but to make it work the same way I need another IF statement. You'll have a hard time convincing me that another if and Delay statement at the end of the BUTTONS method are any more efficient than what I've got.


    I may be asking too much, but if you're going to pan my code I can hope you offer a functionally equivalent alternative smile.gif
    Peter
  • pgbpsupgbpsu Posts: 460
    edited 2009-06-19 14:51
    I'll have a look at the link Leon suggested. If it is important to forums vets like MagIO2 and Leon, then it surely worth reading.
  • MagIO2MagIO2 Posts: 2,243
    edited 2009-06-19 18:39
    @Peter:
    Guess with all the topics this will be what forum users call 'hitchhiking a thread'
    Why is everybody so negative ... deconstructing your code ... I don't deconstruct, I step on it to reach the next higher level ... and it's not an awful example, it's a good lesson ;o)

    As I stated, the code I quickly wrote down is equivalent to yours, which means that you still have to run BUTTONS in it's own COG. The delay of 100ms does not hurt even if you delay when no button is pressed. The loop is watching the port 10 times per second. That's usually fast enough at least at my age and when you don't plan to use it as a fire button in an ego shooter. The advantage is that waitcnt saves power and the loop is easier to read. (One of the advantages you seem to like ;o)

    "The GPS screen needs to refresh every second to show the new time,date, position, etc. Likewise for the COUNTDOWN screen." So, refreshing the screen needs how much COG-time? 100%? Don't think so. So even those parts of the program should have plenty of time to do the check-button job from time to time at a rate where you don't miss a button.

    Later this evening I might go and code a bit for this problem. So long ...
  • pgbpsupgbpsu Posts: 460
    edited 2009-06-19 19:55
    @MagIO2 -

    I'm glad you can read the humor into my posts. It's hard to know what people's intent/nature is without intonation but you seem to have picked up the correct tone from my post.

    I suppose you are right; this thread has been hijacked, but an example of how to do what you propose would put us back to Zap-o's original question. Stable and dependable monitoring of buttons with a software debounce.

    I didn't realize that the BUTTONS method you proposed was intended to run in a separate cog.

    I still think moving the delay outside the if produces a different behavior. Your loop does look at the state of the buttons 10x per second, but it spends almost all of its time waiting (I realize this reduces current consumption, and therefore saves resources). But this construction spends only a small fraction of its time reading the button states. My version spends nearly all its time looking at the state of the buttons and only waits if a button is pressed. I realize for buttons these may be functionally equivalent and that's enough for me to consider it (for these buttons). But for other signals (say a 1PPS from GPS which is only 100uS wide) your construction could miss a signal that we wanted to catch since the entire signal could have come and gone in the time the cog is sitting in the delay.

    Believe it or not this isn't a ego shooter, it's a seismic detonation unit. And the fire button is monitored in PASM in its own cog. No way you are talking me out of that. smile.gif Checking the fire line only 10x per second is not good enough and would not pass the engineering group even though there are hardware checks before actually firing.

    What you've posted so far is educational and points out a possible shortcut in the code but so far isn't an improvement enough for me to give up what I've got working. I'm looking forward to a non blocking button read that won't miss button presses and any suggestions/example you might have for speeding/simplifying getting messages to the display.

    Like most folks, I'm here to learn (and teach even if it's what NOT to do).
    Regards,
    Peter
  • MagIO2MagIO2 Posts: 2,243
    edited 2009-06-19 21:12
    Are you serious? Having no EMI protection passes the engeneering group????? So, the mobile phone that's close to your device can trigger the detonation only because someone called at the wrong moment? WoW.

    But you know what you do currently? You massively changed scope of the problem. We started with a simple button for doing some menu stuff or somthing like that ... nothing really critical.

    Anyway ... I don't really understand your concerns about the 100ms waittime. I measured the time of faster button pushes and the signal duration was ~200-300ms. For a push at normal speed I measured 600 to 900ms. So, you won't miss a real life button push .. but who knows ... maybe if you trigger a detonation you are in a hurry.

    Quick fix for that :
    PUB BUTTONS
    repeat
    buttons |= INA[noparse][[/noparse] 3..0 ]
    DelayMS( 10-150*(buttons==0) )

    Now it waits 10ms if no button pushed and 160ms if button is pushed. (You see why I said -150... ?)

    "1PPS from GPS which is only 100uS wide". I declare that being totally out of scope ;o)
  • pgbpsupgbpsu Posts: 460
    edited 2009-06-19 21:40
    @MagIO2-

    This is a unit still in development so no, the functionality has not yet passed the engineering group. I've read Leon's link and fully agree that a debounce (something I thought was being implemented in software but was not) is necessary. Thank you for helping me see I was not doing what I thought I was. There is a hardware debounce FYI.

    I measured the response time of the buttons we are using. One can successfully press and release in less < 50msec, which should be recognized as a press. So while your original code waited around for 100ms, users started wondering if I took seriously their complaints about missing button presses. I see your newest snippet does better, (and yes I know that 150*zero equals and adding 10 still equals 10; I don't mind instruction and I appreciate your suggestions, but please don't talk down to me). However the better and better your snippet gets (with regard to response time) the more it looks like my original one : ( .

    I'm still looking forward to the non Blocking read....
    p
  • MagIO2MagIO2 Posts: 2,243
    edited 2009-06-19 21:42
    < BEGIN HITCHHIKE >
    Hope this is of interest for others as well ;o)

    pub MAIN_MENU
     
      printMenu( @menu1 )
      ....
     
    pub SUB_MENU
      printMenu( @menu2 )
      ....
     
    pub printMenu( madress ) | i,y
      matrix.cls
      y:=byte[noparse][[/noparse] madress++ ]
      repeat i from 1 to y
        matrix.gotoxy( byte[noparse][[/noparse] madress++ ], byte[noparse][[/noparse] madress++ ] )
        matrix.str( madress )
        madress+=strsize( madress )+1
        
    dat
    menu1  byte  4 ' number of entries
           ' here come the enries with position and null terminated string
           byte  10,0,"Set Intvl",0
           byte  10,1,"GPS Info",0
           byte  10,2,"Countdown",0
           byte  10,3,"Next Menu",0
     
    menu2  byte  3
           ....
    
    

    If your menu·does not have empty lines, then you can save the y coordinate in the dat section and use the counter i·in the gotoxy instead. (Hey ... that saves a byte per menu-entry!)
    < END HITCHHIKE >
  • MagIO2MagIO2 Posts: 2,243
    edited 2009-06-19 21:57
    First of all: I don't look down to someone who is willing to learn. Everybody has to learn his lessons - including me.

    And I'm not sure if you understood the question correctly. What I wanted to point out is why I said 10 MINUS 150... and not 10 PLUS 150... Bet there are newbies out here which would be confused about that. You know .. I like question and answer games .. and usually prefere giving tips over giving completed code. Because things you find out by yourself are much better to remember later on.
  • W9GFOW9GFO Posts: 4,010
    edited 2009-06-19 22:00
    I'm confused - don't hold back. : D

    Rich H
  • MagIO2MagIO2 Posts: 2,243
    edited 2009-06-19 22:12
    10-150*([color=red]buttons==0[/color])
    

    The red part is a boolean expression which has the result true or false.
    false = 0··makes the expression to 10 - 150*0
    true = -1 makes the expression to 10 - 150*-1· or ·10+150 in the end.
  • kuronekokuroneko Posts: 3,623
    edited 2009-06-19 23:56
    You'll save a byte when you use (NOT buttons) instead, SCNR.
  • pgbpsupgbpsu Posts: 460
    edited 2009-06-20 04:18
    @MagIO2-

    Sorry if I took offense where none was intended. I was feeling a bit defensive because everytime I post something I get ripped rather than rather than constructively criticized.
    MagIO2 said...

    Are you serious? Having no EMI protection passes the engeneering group????? So, the mobile phone that's close to your device can trigger the detonation only because someone called at the wrong moment? WoW.

    I'm not sure where you got the idea that there is no EMI protection. EMI considerations are too important in this application to be left to software alone. The 4 buttons that my example code deals with have a hardware debounce. The two buttons (ARM and CHARGE) which are both required to be pressed while a shot is fired, are 12" apart (requiring 2 hands) in protected button shells (to avoid accidental pressing) and are Double pole-double throw to avoid accidental firing because of bounce issues and are NOT handled by the code above. EMI is certainly considered in the hardware design as is ESD. There are no cell phones allowed at the shooting sitenono.gif. Not because they will accidentally set off a charge, but because they distract people who CAN and MIGHT set off a charge.

    Now that I've defended our design, let's get on to more interesting things....

    < CONTINUE HITCHHIKE >
    The string-to-LCD printing code you provided is certainly not something I'd thought of. I went with what was obvious, mostly because it was obvious and because it was straightforward (in case that's not obvious enough). After reading over your example several times, I understand how it works but I'm not sure what one gains by doing it this way. Maybe this isn't the right metric, but printing out things the way I did it requires 102 bytes; your's 85. There's no denying that your code takes less space. Well done. It's less clear to me what's going on. For maintainability (by me and by others that may work with this code in the future), I'll gladly give up the 17 bytes to have something more readable. What's the reason to chose one over the other?

    < END HITCHHIKE >

    In an effort to get the thread back on topic and help Zap-o (and me), let's get back to the original challenge: a way to read button presses that is dependable and doesn't require its own cog. I'll admit you've met the challenge when you've provided code or pseudo-code which:
    1. does not need its own cog
    2. will catch button presses as narrow as 50ms
    3. and may not be callable by the main cog for times as long as 100ms.

    You may call that last restriction unfair, but that's the problem I was faced with. Maybe I should say that's what my solution provides (and I need it). I never said the methods called from my main menu were only display methods and returned immediately. You assumed that somewhere back there when you said "what a waste of resources..." . I didn't give all my requirements, because I was simply trying to give Zap-o an example that works for my application.

    I don't think this is a simple task. I avoided it by giving up on the first requirement and I'm lucky enough to have the cogs available to do it. I look forward to seeing what you come up with. I agree with your philosophy that using cogs unnecessarily is wasteful and poor coding practice. (But I do value some things over efficiency (like readability when resources allow for it - such as the printing code discussed above)). I'd be happy to incorporate what you come up with in my project as long as it's not susceptible to EMI wink.gif

    I'm gone all weekend, but I'm eager to see what people come up with....
    Regards,
    Peter
Sign In or Register to comment.