There are many technics to implement multiple switches into PIC microcontroller.This technic requires only one ADC pin to detect volatge level when each switch for each state is pressed and each switch is associated
with a voltage.
For example : If we need to connect 16 switches with 10 bit PIC.First we need to implement the circuit as Figure 1.
Figure 1.
In the figure 1. Rup is a pull-up resistor. So, when no switch is pressed, Vsw is equal to Vcc.
When is pressed (where is in the range 1 to 15), the resistor Ri-1 is connected to ground.
Then we have a resistive divider
and Vsw is given by the formula:
So the corresponding voltage of each switch is given by the values of the resistors. An equal distribution
of voltage between Vcc and ground is usually recommended.
To recognize a switch, the user will measure Vsw and will be able to decide which switch was
pressed.
Theoretically, with an 10-bit ADC, 1023 switches can be decoded. But potential errors must be
taken into account. They can come from the power supply, the switch resistivity, the resistor tolerance,
the ADC conversion errors.
The resistor tolerance is the main limitation as usually 5% tolerance resistors are used. It is
advised to use a 1% tolerance resistor for the pull-up. Changing this resistor greatly improves
this technic as the pull-up has an influence on every switch.
So, it has to be
taken into account to avoid any switch decision error.
These parameters will reduce the number of switches that can be efficiently decoded.
From the figure 1. assume that SW2 is pressed.
We can detect which switch is pressed by detect Vsw which we can determined by the formula:
The problem is that you cannot choose the perfect values for the resistors. In our application,
the following resistor values were used (see Table 1):
TABLE 1.
| resistor |
value |
resisitor |
value |
| Rup |
1K |
R7 |
220 |
| R0 |
68 |
R8 |
270 |
| R1 |
75 |
R9 |
390 |
| R2 |
82 |
R10 |
560 |
| R3 |
100 |
R11 |
820 |
| R4 |
120 |
R12 |
1.2K |
| R5 |
150 |
R13 |
2.7K |
| R6 |
180 |
R14 |
75 |
The digital values of the switches after conversion are given in Table 2.
When a SWi is pressed and after conversion, a decision must be taken on its value. Upper and
lower limits of the detection for each switch must be defined. These values are the middle of two subsequent typical values, which gives the best noise margin between switches.
TABLE 2.

click to enlarge
Example program writen in CCS C compiler.
#include "16F877.h"
#device ADC=10
#use delay(clock=4000000)
#fuses NOWDT,XT, NOPUT, NOPROTECT
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7)
int16 Vsw;
void main()
{
while(true)
{
setup_adc_ports(RA0_ANALOG); // set RA0 as ADC
setup_adc(ADC_CLOCK_INTERNAL );
set_adc_channel(0);
Vsw = read_adc();
if ((Vsw==0x3FF) && (Vsw > 0x3FD))
printf("This key = No key");
else
if ((Vsw<=0x3C0) && (Vsw > 0x38E))
printf("This key = F");
else
if ((Vsw<=0x37E) && (Vsw > 0x35E))
printf("This key = E");
else
if ((Vsw<=0x33D) && (Vsw > 0x31D))
printf("This key = D");
else
if ((Vsw<=0x303) && (Vsw > 0x3E3))
printf("This key = C");
else
if ((Vsw<=0x2C2) && (Vsw > 0x2A2))
printf("This key = B");
else
if ((Vsw<=0x27E) && (Vsw > 0x25E))
printf("This key = A");
else
if ((Vsw<=0x23D) && (Vsw > 0x21D))
printf("This key = 9");
else
if ((Vsw<=0x200) && (Vsw > 0x1E0))
printf("This key = 8");
else
if ((Vsw<=0x1C0) && (Vsw > 0x1A0))
printf("This key = 7");
else
if ((Vsw<=0x17E) && (Vsw > 0x15E))
printf("This key = 6");
else
if ((Vsw<=0x13C) && (Vsw > 0x11C))
printf("This key = 5");
else
if ((Vsw<=0x0FB) && (Vsw > 0x0DB))
printf("This key = 4");
else
if ((Vsw<=0x0BC) && (Vsw > 0x09C))
printf("This key = 3");
else
if ((Vsw<=0x080) && (Vsw > 0x060))
printf("This key = 2");
else
if ((Vsw<=0x041) && (Vsw > 0x021))
printf("This key = 1");
else
if ((Vsw<=0x021) && (Vsw == 0x000))
printf("This key = 0");
}
}
|