Watch the video Tutorial

Push Buttons and Switches are digital inputs and are widely used in electronic projects as most systems need to respond to user commands or sensors. Reading a switch is very useful because a switch is widely used and can also represent a wide range of digital devices in real world like push buttons, limit sensors, level switches, proximity switches, keypads (a combination of switches) etc. 

Connecting a switch to a microcontroller is straight forward, all we need is a pull-up or pull-down resistor.

Figure 1: A switch with a Pull-up resistor        Figure 2: A switch with a Pull-down resistor          
Pull-up Resistors

The pull-up or pull-down resistor is very important, if there is no resistor it will be difficult to determine the state of the pin, this is called floating.
let’s say the microcontroller pin is configured as an input. If there is nothing connected to the pin and the microcontroller program reads the state of the pin, will it be high (pulled to VCC) or low (pulled to ground)? It is difficult to tell. But with a resistor connected to VCC (pull-up) as in figure 2, or connected to ground (pull-down) as in figure 3, will ensure that the pin is in either a high or low state.
Pull-up resistors are the more common so we will focus on them.
In figure 1, if the switch is open, the input of the PIC will be high (+5V) and when the switch is closed, the input of the PIC will be low. If there was no resistor, then it could have been a short circuit.
Internal pull-up resistors can also be enabled in software if external resistors are not going to be used, refer to the datasheet to find out more.

Now we know the reasons why we should use a pull-up or pull-down resistor, the next question is what should be the value of this resistor?
The larger the resistance of this pull-up resistor, the slower the pin is to respond to voltage changes, this is because the system that feeds the input pin is essentially a capacitor coupled with the pull-up resistor, thus this forms an RC filter, and RC filters take some time to charge and discharge. So if you have a very fast changing signal (like USB), a high value pull-up resistor can limit the speed at which the pin can reliably change state.
And on the other hand if you select a lower resistance, when the switch is closed, more current will be routed to ground which is not a good idea especially if the circuit is battery powered.
Generally a value of 10KΩ should do the job fine.

Switch Debouncing

As mechanically the metal contacts of the switch are not perfectly smooth, when a switch is closed, it doesn’t perfectly close immediately, in fact in bounces open and close so fast before it can stabilise and stay open. Figure 4 below shows the operation of a bounceless switch, when the switch is closed, it closes immediately and the current flowing through it rises immediately from 0 to maximum. In reality this kind of switch doesn’t exist, with a close-up look with an oscilloscope, it revealed that, in practice, the switch bounces close and open for a short period of time before stabising as shown on figure 4.
In normal situation, this bouncing period is so short that it won’t even be noticed, but a microcontroller can detect it, and if high speed switching is involved, the circuit won’t be accurate if this bouncing effect is not taken into consideration.

Figure 3: A Bounceless Switch operation.                   Figure 4: A normal real Switch operation

There are many ways this can be eliminated in software, one can use a counting algorithm where the switch is read periodically (e.g. every 1 ms) and it can only be considered to have changed state if it has been in the new state for some number of successive samples (e.g. 10), by which time it is considered to have settled.

The other method and the easiest one is to read a switch then after a short delay, let say 10ms, read it again, if the state of the switch is still the same, then the switch is considered to have settled in that state. 

MPLAB XC8 Code  

The TRISx register control the direction of the PORT. If the value if the TRISx register is “1”, then the PORT/PIN becomes input, any input device like a switch can be read then.
When the value if the TRISx register is “0”, then the PORT/PIN becomes output, any output device like a diode can be controlled then.
            1. Set PORTB (all bits) to input: TRISB = 0xFF
            2. Set PORTD bit 0 to input:      TRISDbits.RD0 = 1
            3. Set PORTB bits 0 to 3 to input and bits 4 to 7 to output: TRISB= 0x0F
            4. To remove the effect of switch bouncing, we can read the switch twice with a short delay in between to make sure the switch has completely changed its status:

 if(PORTCbits.RC0 == 0)                          //check if the switch is closed
for(int c=0;c<=20;c++)__delay_ms(5);   //wait for 100ms 
if(PORTCbits.RC0 == 0)                      //check if the switch is still closed
 // Switch is indeed closed. Do something here. 


   Figure 1: A switch and a 7-segment display connected to PIC microcontroller

The circuit in figure 1 shows a decimal counter counting from 0 to 9 with 1 second delay in between when switch  SW1 is closed. when this switch is open, the counter stops and resume counting when it closed again. Use the switch deboucing technic to read the state of the switch.        

Figure 4: Reading a switch example source code

You can download the full project files (MPLAB XC8 source code and Proteus Schematic design) below here.
All the files are zipped, you will need to unzip them (Download a free version of the Winzip utility to unzip files).

Download MPLAB XC8 Project: 7-Segment.X

Download Proteus Schematic: 7-Segment Proteus