Continue to Site

Welcome to EDAboard.com

Welcome to our site! EDAboard.com is an international Electronics Discussion Forum focused on EDA software, circuits, schematics, books, theory, papers, asic, pld, 8051, DSP, Network, RF, Analog Design, PCB, Service Manuals... and a whole lot more! To participate you need to register. Registration is free. Click here to register now.

[SOLVED] push button input not working

Status
Not open for further replies.

PoS080

Junior Member level 3
Joined
Apr 2, 2017
Messages
26
Helped
0
Reputation
0
Reaction score
0
Trophy points
1
Activity points
243
Hello EE friends,



I am trying to pick up input from a push button connected to RB5, and toggle an LED based on that input. I am not getting a response by pressed or releasing the button. Not sure how my code is wrong.

Compiler: XC8
PIC:16f1829
Button pressed = logic 0;
Button not pressed = logic 1;
Button location RB 5;
LED Location RA5;

Code:
int main(int argc, char** argv) {

    TRISA = 0x00; //All of A to output
    ANSELB = 0x00; // All of B to digital 
    TRISB = 0b00100000; // RB5 to Input


    while(1){
        if(RB5 == 1){       //if button pressed turn on light
            RA5 = 1; 
          __delay_ms(2000);
        }
        else{                   //else off light
            RA5 = 0;
            __delay_ms(2000);
        }

    }
    return (EXIT_SUCCESS);
}

thanks
 
Last edited:

Hello!

I am trying to pick up input from a push button connected to RB5, and toggle an LED based on that input. I am not getting a response by pressed or releasing the button. Not sure how my code is wrong.

You are not getting a response? Yes, but what do you get exactly?
Your program is setting RA5 to 1 in any case (in both if and else parts), so my impression is
that it will be difficult to see a difference between pressed / not pressed.

Next, suppose you set one of them to RA=0, you are using a software timer (delay_ms).
So your program will be always stuck in the 2nd software timer. Just follow the flow:
You start, you enter the while loop. Since the buttton is not yet presed, it will enter the else,
set RA to 1, and wait 2 seconds. If you press less than 2 seconds, then you will loop once more
to the same part (the else). If you press more than 2 seconds, then you will (at last) entre the
if(RB5 == 1)...

Some other comments:
- Your return will never be reached. I know that some compilers force you to have a return value to main...
- Return does not need parentheses.

Another comment:
You should not use software delays in a runtime loop. You may use them at initialization time
because it's simpler, but not at runtime. Use a timer and timer interrupts.

Dora.
 

Hello thanks for a quick response. I mistyped my code, I did a quick edit to fix the turn off. Also if I don't use delays wont the LED blink so fast I wont be able to see it with my eyes?


In this setup the LED turns on and stays on regardless of button press, which doesn't make sense since the condition for turn on is never met.
Code:
    while(1){
        if(RB5 == 1){       //if button pressed turn on light
            RA5 = 1; 
          __delay_ms(2000);
        }
        else{                   //else off light
            RA5 = 0;
            __delay_ms(2000);
        }


Have I configured RB5 to be a digital input correctly using TRIS and ANSEL? 
    }
 

Try this and also check the datasheet and see if your PIC has ADC function on PORTA. If yes, then use ANSELA and disable it.

Changes made are:

Debounce delay added to buttons.


Code C - [expand]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
int main(int argc, char** argv) {
 
    ANSELB = 0x00;
    TRISA = 0x00; 
    TRISB = 0x20;
 
 
    while(1){
        
    if(RB5 == 1){       //if button pressed turn on light
            __delay_ms(50);
        if(RB5 == 1) {
        RA5 = 1;           
        }
        else if(RB5 == 0){       //if button pressed turn off light
            __delay_ms(50);
        if(RB5 == 0) {
        RA5 = 0;           
        }
 
    }
 
    return (EXIT_SUCCESS);
}

 
  • Like
Reactions: PoS080

    PoS080

    Points: 2
    Helpful Answer Positive Rating
Hello!

Hello thanks for a quick response. I mistyped my code, I did a quick edit to fix the turn off. Also if I don't use delays wont the
LED blink so fast I wont be able to see it with my eyes?

Why would it blink?
If you rewrite your while function without the delays, it will just copy the state of RB5 into RA5. So the LED will be lit if you
press and will be off if not pressed. What the delay brings you is that the state might change on a button press if you happen
to press when one delay is over. In this case, you will enter the if(RB5 == 1) and set the LED on for 2 seconds.

Now what I wanted to say with the delays: if you use that kind of delay, then your processor will spend its time counting
(i.e. doing nothing). That's where you should use interrupts. Your program uses polling, which means it constantly checks
the input. Just suppose your phone works the same way (no ringtone): you would have to constantly check if somebody is
talking to you.
The interrupt is like your phone ring tone. You do nothing (or you do something more useful) when the phone is not ringing,
and you process the phone call only when your phone rings.
So, for the "To Do" list: try to find out how to enable interrupts on PB5, write an interrupt routine to process your interrupt.

Dora.
 
  • Like
Reactions: PoS080

    PoS080

    Points: 2
    Helpful Answer Positive Rating
Try this and also check the datasheet and see if your PIC has ADC function on PORTA. If yes, then use ANSELA and disable it.

Changes made are:

Debounce delay added to buttons.


Code C - [expand]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
int main(int argc, char** argv) {
 
    ANSELB = 0x00;
    TRISA = 0x00; 
    TRISB = 0x20;
 
 
    while(1){
        
    if(RB5 == 1){       //if button pressed turn on light
            __delay_ms(50);
        if(RB5 == 1) {
        RA5 = 1;           
        }
        else if(RB5 == 0){       //if button pressed turn off light
            __delay_ms(50);
        if(RB5 == 0) {
        RA5 = 0;           
        }
 
    }
 
    return (EXIT_SUCCESS);
}


This works, can you explain the difference between my original code and yours? What do you mean by debounces delay? Thanks.
 

Hello!



Why would it blink?
If you rewrite your while function without the delays, it will just copy the state of RB5 into RA5. So the LED will be lit if you
press and will be off if not pressed. What the delay brings you is that the state might change on a button press if you happen
to press when one delay is over. In this case, you will enter the if(RB5 == 1) and set the LED on for 2 seconds.
Dora.

Oh so in that case I dont need any delays right?

I am reading the datasheet on interrupts now, I see your point. What you are saying is that if I use a timer + interrupt my processor is free to do something else in that time? correct?
 

HellO!

Oh so in that case I dont need any delays right?

You may need delays, but not for the same reason. When you push a button, the theoretical voltage
should go from 0 to 1 or from 1 to 0 at once. But in practice, it doesn't. There can be myriads of rebounds,
depending on how you press, on the quality of the switch, etc. So usually what you have to do is to eliminate
these rebounds. One thing you can do is to consider that after a certain time, the button voltage is stable.
So the idea is to measure once, then wait for stability and measure again. If you have the same value, then
it was a valid push.

I am reading the datasheet on interrupts now, I see your point. What you are saying is that if I use a
timer + interrupt my processor is free to do something else in that time? correct?

Not exactly. But partly right.
The main purpose of the interrupt in this case is to detect the rising or falling edge of the button.
So in this case, your processor will do nothing but wait for interrupts.
The flow should be like this (we will suppose that you want to toggle the LED with a button):

The main should be like this in pseudo code:

Code:
main() {
    InitializeInterrupt();
    Loop();
}
And you will also have an interrupt receiving function:

Code:
void ButtonInterruptReceived() {
    ToggleLed();
}
Now this will work most of the time, but you haven't processed the rebounds yet. So the
idea is to use a timer. Main will have to setup a timer that you can fire anytime. The interrupts become:

Code:
void ButtonInterruptReceived() {
    DisableButtonInterrupt();
    FireTimer();
}

void TimerInterruptReceived() {
    EnableButtonInterrupt();
}
What it does:
- At first edge of the button, you disable the button and you start a timer.
Therefore you will have no other button interrupt as long as the timer is not elapsed.
- When the timer is elapsed, then the timer interrupt routine is called, in which you re-enable the button interrupts.

Dora.
 
  • Like
Reactions: PoS080

    PoS080

    Points: 2
    Helpful Answer Positive Rating
I removed all delays and ran this code adapted from Okada , it works perfectly for my board. Will work on interrupt and timers now, but this is a quick fix.

Code:
while(1){
        
    if(RB5 == 1){       //if button pressed turn on light
        RA5 = 1;           
        }
        else if(RB5 == 0){       //if button pressed turn off light
        RA5 = 0;           
        }
 
    }
 

Status
Not open for further replies.

Similar threads

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top