Continue to Site

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.

  • 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.

Coding a push button on PIC18

Status
Not open for further replies.

gumboguy

New Member
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!
 
If you want it to be and input And you do it should work

TRISB = 0x01;

I use this

if (0 == RB0)
/*do something*/
 
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!

Yep! you can also do:
Code:
TRISBbits.TRISB0 = 1; //Input

if(PORTBbits.RB0 == 0)
{
    //Do Something
}

Better practice would be to define the button:

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

MyButton_Dir = 1; //Input

if(MyButton == 0)
{
    //Do Something
}

or better yet:
Code:
#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
}
 
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:
#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:
#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.
 
i debounce 2 ways:

Code:
#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:
#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:
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:
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:
    while(MyButton == LOW)[B][SIZE="5"];[/SIZE][/B]
    //Small 10ms delay

but

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


hope this helps :)
 

Attachments

  • screenshot1.png
    screenshot1.png
    33.1 KB · Views: 281
OOps had it reversed heh thanks this is what i use with the while

Code:
    //Do Something
    while(MyButton == LOW); //Wait until user lets go of button
    //Small 2ms delay
 
Here is a couple tutorials. First one is in assembler though

**broken link removed**

**broken link removed**
 
This is what I would use
Code:
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:
OOps had it reversed heh thanks this is what i use with the while

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

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:
    //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:
  //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)
 
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)

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
 
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

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 ..
 
... I always had more issues with "you have to touch the switch the right way" for the button not to be read 50 times...

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:
  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:
//
//  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:
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 ..

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:
One nice thing about switch state logic is that you can use simple "parallel" logic to debounce and manage multiple switches;

Code:
//
//  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"
    {                            //
    }                            //
  }

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,
 
Status
Not open for further replies.

New Articles From Microcontroller Tips

Back
Top