1. Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.
    Dismiss Notice

Coding a push button on PIC18

Discussion in 'Microcontrollers' started by gumboguy, Nov 12, 2010.

  1. gumboguy

    gumboguy New Member

    Joined:
    Nov 12, 2010
    Messages:
    3
    Likes:
    0
    Hi I am using the PIC18F4520 and have am trying to figure out how to use the push button. It is RB0 on the board. I looked through the posts and resources but couldn't find what I need.

    So would the C code to initialize it be:
    TRISB = 0x01;

    and code to detect a press:
    if (!PORTBbits.RB0)
    /*do something*/

    Debouncing is necessary, just want to check if this code is correct.

    Thanks!
     
  2. be80be

    be80be Well-Known Member

    Joined:
    Aug 23, 2008
    Messages:
    4,869
    Likes:
    144
    Location:
    morristown,tn
    If you want it to be and input And you do it should work

    TRISB = 0x01;

    I use this

    if (0 == RB0)
    /*do something*/
     
  3. AtomSoft

    AtomSoft Well-Known Member

    Joined:
    Feb 7, 2008
    Messages:
    5,670
    Likes:
    41
    Location:
    Brooklyn, NY US
    Yep! you can also do:
    Code (text):

    TRISBbits.TRISB0 = 1; //Input

    if(PORTBbits.RB0 == 0)
    {
        //Do Something
    }
     
    Better practice would be to define the button:

    Code (text):

    #define MyButton PORTBbits.RB0
    #define MyButton_Dir TRISBbits.TRISB0

    MyButton_Dir = 1; //Input

    if(MyButton == 0)
    {
        //Do Something
    }
     
    or better yet:
    Code (text):

    #define MyButton PORTBbits.RB0
    #define MyButton_Dir TRISBbits.TRISB0

    #define IN 1
    #define OUT 0

    #define HIGH 1
    #define LOW 0

    MyButton_Dir = IN;

    if(MyButton == LOW)
    {
        //Do Something
    }
     
     
  4. dave

    Dave New Member

    Joined:
    Jan 12, 1997
    Messages:
    -
    Likes:
    0


     
  5. arhi

    arhi Member

    Joined:
    Apr 17, 2008
    Messages:
    887
    Likes:
    12
    Location:
    Belgrade, .rs

    you need to debounce that switch if you don't have hw debouncing circuit already (or if the button pin is not on schmidt input pin)

    Code (text):

    #define T_button0   TRISB
    #define P_button0   PORTBbits.RB0


    bool is_pressed()
    {
      bool press;
      volatile unsigned int8 i;

      press = !P_button0;
      for (i=0;i<255;i++); //you can use delay_us(100); here for example
      return press & !P_button0;
    }


    int main(){
      T_button0 = 1;

    // ...

    if (is_pressed()){
      //TODO: if pressed
    }

    // ...
    }
     

    now, if you have a code that check for a keypress in a loop then there's even better approach

    Code (text):

    #define T_button0   TRISB
    #define P_button0   PORTBbits.RB0

    bool is_pressed()
    {
      static unsigned int16 status = 0;
     
      status = (status<<1) | !P_button0 | 0xe000;
      if (status == 0xf000) return TRUE;
      return FALSE;
    }

    int main(){
      T_button0 = 1;

    // ...

    while (!is_pressed()); //wait for a key press
    //TODO: if pressed


    // ...
    }
     

    Also note, depending on your compiler you might have software debouncing already done ... for e.g. if you use mikroe c compiler, they have function button() that does software debouncing.
     
  6. AtomSoft

    AtomSoft Well-Known Member

    Joined:
    Feb 7, 2008
    Messages:
    5,670
    Likes:
    41
    Location:
    Brooklyn, NY US
    i debounce 2 ways:

    Code (text):

    #define MyButton PORTBbits.RB0
    #define MyButton_Dir TRISBbits.TRISB0

    #define IN 1
    #define OUT 0

    #define HIGH 1
    #define LOW 0

    MyButton_Dir = IN;

    if(MyButton == LOW)
    {
        while(MyButton == LOW); //Wait until user lets go of button
        //Small 2ms delay
        //Do Something
    }
     
    The above will wait until user releases button. Good for single presses... not good for navigation like up/down



    Code (text):

    #define MyButton PORTBbits.RB0
    #define MyButton_Dir TRISBbits.TRISB0

    #define IN 1
    #define OUT 0

    #define HIGH 1
    #define LOW 0

    MyButton_Dir = IN;

    if(MyButton == LOW)
    {
        //Small 10ms delay or longer like 100ms
        //Do Something
    }
     
    The above works great for navigation purpose. Play with the delay speeds until you think its a good value.
     
    Last edited: Nov 12, 2010
  7. arhi

    arhi Member

    Joined:
    Apr 17, 2008
    Messages:
    887
    Likes:
    12
    Location:
    Belgrade, .rs
    Jason, recheck the source, you pasted same code twice and in both cases you miss the debouncing part
     
    • Like Like x 1
  8. AtomSoft

    AtomSoft Well-Known Member

    Joined:
    Feb 7, 2008
    Messages:
    5,670
    Likes:
    41
    Location:
    Brooklyn, NY US
    look carefully heh

    there first has a WHILE loop and 2ms delay

    The second has a 10ms loop without the while loop

    I edited it to have longer comments so you can see the difference :D
     
    Last edited: Nov 12, 2010
  9. arhi

    arhi Member

    Joined:
    Apr 17, 2008
    Messages:
    887
    Likes:
    12
    Location:
    Belgrade, .rs
    the only difference is time value in the comment?!

    anyhow, the problem there is:

    if(MyButton == LOW)
    {
    while(MyButton == LOW);

    There is no "time passed" between if () and while (), so as the "bouncing" signal will on the first bounce exit the while() loop and it will continue to bounce...

    if you are going to check the myButton in the while, then the example with shifting (second example in my post) is ideal as it stacks the ones to get 0xF000 .. the other example is simpler as it just check the value twice in 2 different moments in time. With your example even if myButton is LOW only during if() everything will just go trough (while will finish immediately etc..)

    It all depends what type of debouncing you need, just adding a simple delay after reading the button often solves most of the problems ... but if you want to wait button to be released you have to add delay inside the while so not

    Code (text):
        while(MyButton == LOW)[B][SIZE="5"];[/SIZE][/B]
        //Small 10ms delay
    but

    Code (text):
        while(MyButton == LOW)
          delay_ms(1);

    hope this helps :)
     

    Attached Files:

  10. AtomSoft

    AtomSoft Well-Known Member

    Joined:
    Feb 7, 2008
    Messages:
    5,670
    Likes:
    41
    Location:
    Brooklyn, NY US
    OOps had it reversed heh thanks this is what i use with the while

    Code (text):

        //Do Something
        while(MyButton == LOW); //Wait until user lets go of button
        //Small 2ms delay
     
     
  11. bryan

    bryan Member

    Joined:
    Jun 21, 2003
    Messages:
    416
    Likes:
    3
    Location:
    Vancouver, Canada
  12. be80be

    be80be Well-Known Member

    Joined:
    Aug 23, 2008
    Messages:
    4,869
    Likes:
    144
    Location:
    morristown,tn
    This is what I would use
    Code (text):

    while(1 == 1)               //  Loop Forever
        {
            i = 0;                  //  Wait 20 ms for Button Up
            while (i < Twentyms)
            {
                if (0 == RB0)       //  Button Down/Start over
                {
                    i = 0;
                }
                else                //  Button Up/Increment Count
                {
                    i = i + 1;
                }  //  fi
            }  //

            NOP();
            i = 0;                  //  Wait 20 ms for Button Down
            while (i < Twentyms)
                if (1 == RB0)       //  Button Up/Start over
                    i = 0;
                else                //  Button Down/Increment Count
                    i = i + 1;

            RB1 = RB1 ^ 1;          //  Toggle RB1 to Turn ON/OFF LED

        }  //  
    }  //  End
     
    And I added a little led to see it happen It's H-tech C
     
    Last edited: Nov 12, 2010
  13. arhi

    arhi Member

    Joined:
    Apr 17, 2008
    Messages:
    887
    Likes:
    12
    Location:
    Belgrade, .rs
    you still want to put delay "inside" while loop so that you actually "skip" the bounces, just waiting for the button to go high works ok but does not do any debouncing, so here you expect your button to be with a capacitor and resistor and/or on a schmidt input ... if you want to also debounce it you need to add some more tests

    Code (text):

        //Do Something

        while(MyButton == LOW) delay_ms(1); //Wait until user lets go of button
        delay_ms(1); //wait a bit

        //continue
     
    and even this is not always enough (it usually is but if you have nasty contact then it is not) and you have to:

    Code (text):

      //Do Something
      while(MyButton == LOW){
        while(MyButton == LOW) delay_us(100); //Wait for the "bounce"
        delay_ms(1); //give it bit more time to stabilize
      } //if it is still bouncing, loop more

      //continue
     
    this might look like "overdoing it" but you had no idea how many times I had to use it (for e.g. with poker like switches)
     
  14. be80be

    be80be Well-Known Member

    Joined:
    Aug 23, 2008
    Messages:
    4,869
    Likes:
    144
    Location:
    morristown,tn
    How true you are there some bad switches that 10 20 and even 100 bounce to much and boy can a pic tell that even a old 8 bitter at 4 mhz
     
  15. arhi

    arhi Member

    Joined:
    Apr 17, 2008
    Messages:
    887
    Likes:
    12
    Location:
    Belgrade, .rs
    yup, there are some very nasty ones out there :( .... the worse part is - most switches go from bad to worse durigng time, so you really have to overdo it ... I for e.g. do capacitor+resisor to the schmidt and on top of that I do a 50-100ms debounce in sw. It does make the switches "sluggish" (you need to hold switch pressed for 50-100ms in order for the key to be recognised) but I never had problem with that, I always had more issues with "you have to touch the switch the right way" for the button not to be read 50 times... that shifting routine is among best and it can also be modified a bit more ... but it is short and works fairly nice... of course, for "home projects" any debounce will work, the simple "read/wait 10ms/read again" - if both reads are same it is "proper" value .. for production - one has to raise the bar ..
     
  16. gumboguy

    gumboguy New Member

    Joined:
    Nov 12, 2010
    Messages:
    3
    Likes:
    0
    Rb0

    Thanks for everything guys! Very helpful.
     
  17. Mike - K8LH

    Mike - K8LH Well-Known Member

    Joined:
    Jan 22, 2005
    Messages:
    3,642
    Likes:
    109
    Location:
    Michigan, USA
    Use of a simple switch state latch would allow you to detect a "new press" state change and ignore the other switch states. No more false presses and no more waiting for the switch to be released;

    Code (text):

      while(1)
      { delay_ms(20);                     // 20-msec debounce interval
        swold = swnew;                    // update switch state latch
        swnew = ~portb;                   // sample active lo switches
        if(swnew.0 == 1 && swold.0 == 0)  // if RB0 "new press"
        {                                 // do RB0 "new press" code
        }
        if(swnew.1 == 1 && swold.1 == 0)  // if RB1 "new press"
        {                                 // do RB1 "new press" code
        }
      }
     
    All you really need to debounce a switch press and release is to sample the switches at some suitable interval (10 to 32 msecs). If the switch is bouncing during the first sample interval it should be stable by the second sample interval. That means with a 10-msec sample interval you will catch the state change either at the first 10 msec interval or at the second 10 msec interval. The only time you really need to use a counter and faster sample times is to filter out noise, which is entirely different from switch bounce.

    One nice thing about switch state logic is that you can use simple "parallel" logic to debounce and manage multiple switches;

    Code (text):
    //
    //  swnew  __---____---____---____  sample active lo switches
    //  swold  ___---____---____---___  switch state latch
    //  swnew  __-__-___-__-___-__-___  changes, press or release
    //  swnew  __-______-______-______  filter out 'release' bits
    //
      while(1)
      { delay_ms(20);                // 20-msec debounce interval
        swnew = ~portb;              // sample active lo switches
        swnew ^= swold;              // changes, press or release
        swold ^= swnew;              // update switch state latch
        swnew &= swold;              // filter out 'release' bits

        if(swnew.0)                  // if RB0 "new press"
        {                            //
        }                            //
        if(swnew.1)                  // if RB1 "new press"
        {                            //
        }                            //
      }
     
    Cheerful regards, Mike
     
    Last edited: Nov 17, 2010
  18. Mosaic

    Mosaic Well-Known Member

    Joined:
    Jun 3, 2010
    Messages:
    2,621
    Likes:
    129
    Location:
    Caribbean
    My first attempt at asm switch debounce coding did involve a state change latch and also incorporated a cumulative sampling of the switch bounce.

    The algorithm required that the switch accumulate a 35 count (at 1 ms per count) 'closed' total before deciding on a keypress. Every time the bounce occurred the cumulative count was reduced by 1. The converse applied to a switch release.

    This would result in the software 'judging' the switch condition based on it's behaviour.

    The useful part of this is that if a switch bounced for 100ms or more the algorithm would perceive this thru the cumulative counting. It's possible that a switch can bounce so much the cumulative count would take quite long to achieve the '35', but always accurately determine the switch state. The cost was about 100 asm commands for 2 switches. About 50 cmds per switch.


    Mike K8LH, however, pointed out that the approach, while valid, required significant processor cycles and use of several persistent GPR variables. Since then I have adopted his parallel bitwise approach to debouncing.

    I now use a derivative of his core code to have simultaneous PORT wide (8 bits/switches) debounce AND to determine the following switch states. Cost= 35 asm commands for 8 switches. Abt 4.5 cmds /switch, a lot more efficient than the 50 cmds/switch.

    1) Switch Press (short)
    2) Switch press (long)
    3) Switch press (short) and Release
    4) switch press (long) and Release
    5) Switch not pressed.

    Thus I can have a full featured hierarchical PIC programme menu system with just 2 tactile switches given the 5 switch states mentioned.
     
    Last edited: Nov 13, 2010
  19. AtomSoft

    AtomSoft Well-Known Member

    Joined:
    Feb 7, 2008
    Messages:
    5,670
    Likes:
    41
    Location:
    Brooklyn, NY US
    i think he gets it now heh.. Your welcome on my part
     
  20. arhi

    arhi Member

    Joined:
    Apr 17, 2008
    Messages:
    887
    Likes:
    12
    Location:
    Belgrade, .rs
  21. crocu

    crocu Member

    Joined:
    Feb 20, 2009
    Messages:
    118
    Likes:
    1
    Location:
    France
    Hello Mike, all

    In your code snippet, i do not see where you initialized "swold" state, did i miss something ?

    In my project i have 3 push buttons : + / - / Enter
    I would like to use them to navigate into menus, increase & decreased settings values and display them on LCD.

    '+' key will be used to go next menu ahead and increase manually entered values.
    '-' key will be used to decrease manually entered values
    'enter' key will be used to validate entries but also to return back in the menu hierarchy.

    I did not find such working code for PIC yet and would like to inspire from your code snippet.

    Thanks,
     

Share This Page