In the previous article on GPIO, we learned how to set a GPIO module in output mode, set its state to logic high or low, and the purpose of special function registers in microcontroller programming. To use a GPIO pin as an input, we need to use 2 new registers:
- PORT registers can be queried to read the status of an input pin. Of course they need to be set as input pins first, using the appropriate TRIS register
- By default, some pins are set as analog inputs. We’ll learn more about analog inputs later, but for now let’s just say that we use the ANSEL registers to enable or disable a pin’s analog functionality.
Let’s take a second to look at the schematic of the circuit we’re working with and make sure we understand it. When we push the button, pin RC7 is shorted to ground, but what happens when we release the button? Without the resistor connecting the pushbutton to VDD (the “pull-up resistor”), RC7 would not be connected — it would “float”. What voltage would be on the pin? Who knows.
The point is that we tend to think of the microcontroller as “reading the button”, but we need to remember that all the microcontroller is really reading is a voltage. This is important to keep in mind when troubleshooting: any time a microcontroller system doesn’t work, the problem could be due to hardware or firmware (or both!) Your author has on many occasions spent hours debugging code, trying to fix what ended up being a signal integrity problem. The correct way to test the pushbutton circuit we’re using is to read the same voltage that the microcontroller will read — using a multimeter, ensure that the voltage on pin RC7 is 0V when the button is pressed and 5V when the button is released.
Let’s update our code to read the button.
void main(void)
{
TRISC = 0b11111100; //set pin RC7 (the pushbutton) as an input and pins 0 and 1 (the LEDs) as outputs
ANSELCbits.ANSC7 = 0b0; //disable analog input functionality on pin RC7
while(1)
{
if(PORTCbits.RC7 == 0b0) //read the pushbutton voltage
{
LATCbits.LATC0 = 0b1;
LATCbits.LATC1 = 0b0;
}
else
{
LATCbits.LATC0 = 0b0;
LATCbits.LATC1 = 0b1;
}
}
return;
}
On line 4, we see the use of the ANSELC register to disable analog input functionality on pin RC7. Line 8 is where we’re reading the voltage on the pin with the PORTC register. Nothing too fancy here.
You might be wondering how we know which registers to use — for example, how do we figure out in the first place that we need to use the ANSEL register for a digital input? The short answer is that we find this information in the microcontroller’s datasheet. This topic will be covered in the next tutorial.
Going further
With digital inputs under our belt, we can read any device that’s fully on or off:
- Other types of switches and buttons, like toggle switches, tilt switches, and many more. You can use a limit switch to build machines, where your micro will detect when the machine’s reached its limit.
- If electronics is your thing, you can read the output of a comparator or Schmitt trigger — if you want to know if some analog voltage is above or below some threshold, compare it to that voltage and read the digital output.
Troubleshooting
As discussed earlier, the best way to troubleshoot a problematic digital input device is with a multimeter, by measuring the voltage directly at the microcontroller’s pin. If the device is working correctly, the voltage should be at one logic level (5V or 0V) in one state (i.e. when the button is pressed), and it should switch to the opposite logic level in the other state. If it’s not doing this, it’s a hardware problem; if it is, it’s a firmware problem.
(If you don’t have a multimeter, you can also use a LED to determine if the device’s voltage is what it should be)