How to read a quad dip switch with only one analog pin with Arduino
The DIP switch is a set of
small switches in a Dual In-line Package. It finds numerous applications, such
as address configurator, select a type of operation, enter a remote control
code.
Normally the dip switches
require as many digital input pins as there are dip switches used and also with
pull-up resistors enabled. In the proposed circuit I use only one analog input
for four dip switches.
This article is also
particularly useful for applications with ESP8266 which has few I/O pins but
has an analog input with a full-scale of 1V.
After developing a project to
read a 4x3 keypad with three analog inputs [1], I was thinking of applying this
methodology to dip switches too but things are not at all similar. The buttons
close only one at a time and are monostable while the dip are bistable and also
can close all together.
After several attempts,
simulated at computer, I arrived at the synthesis of the circuit shown in
figure 1.
In theory, the values of the
R1-R4 resistors should be 1, 2, 4, 8 kΩ, but even with the standard values I
used, good results are obtained. If we measure the resistance between Vo and
Gnd, we have a value that is proportional to the binary number set, but the Vo
voltage will be equal to:
Figure 1 |
Vo = Vcc*R14/(R5+R14)
Where with R14 I indicated the
sum of the resistors R1 to R4 not short-circuited by the dip switches. As can
be seen, now the law is not linear, but it suffices to put R5 large enough to
minimize the current variation. This will reduce the output voltage, but by setting
the Arduino reference voltage as "INTERNAL" we get a full-scale
Arduino UNO ADC converter equal to about 1.1V.
Indicating with "ON"
the closed switches and with "OFF" the open ones and setting Vcc = 5V
the following table is obtained.
D4
|
D3
|
D2
|
D1
|
N
|
R14
|
I [mA]
|
Vo [mV]
|
DV [mV]
|
NADC
|
DN
|
NADC_L
|
NADC_H
|
ON
|
ON
|
ON
|
ON
|
0
|
0
|
0.073
|
0.00
|
0
|
0
|
0
|
0
|
30
|
ON
|
ON
|
ON
|
OFF
|
1
|
1000
|
0.072
|
72.36
|
72.36
|
67
|
67
|
47
|
87
|
ON
|
ON
|
OFF
|
ON
|
2
|
2000
|
0.071
|
142.65
|
70.29
|
133
|
66
|
113
|
153
|
ON
|
ON
|
OFF
|
OFF
|
3
|
3000
|
0.070
|
210.97
|
68.32
|
196
|
63
|
176
|
216
|
ON
|
OFF
|
ON
|
ON
|
4
|
3920
|
0.069
|
272.15
|
61.18
|
253
|
57
|
233
|
273
|
ON
|
OFF
|
ON
|
OFF
|
5
|
4920
|
0.068
|
336.89
|
64.75
|
313
|
60
|
293
|
333
|
ON
|
OFF
|
OFF
|
ON
|
6
|
5920
|
0.068
|
399.89
|
63.00
|
372
|
59
|
352
|
392
|
ON
|
OFF
|
OFF
|
OFF
|
7
|
6920
|
0.067
|
461.21
|
61.32
|
429
|
57
|
409
|
449
|
OFF
|
ON
|
ON
|
ON
|
8
|
8200
|
0.066
|
537.35
|
76.14
|
500
|
71
|
480
|
520
|
OFF
|
ON
|
ON
|
OFF
|
9
|
9200
|
0.065
|
595.08
|
57.73
|
553
|
53
|
533
|
573
|
OFF
|
ON
|
OFF
|
ON
|
10
|
10200
|
0.064
|
651.34
|
56.26
|
606
|
53
|
586
|
626
|
OFF
|
ON
|
OFF
|
OFF
|
11
|
11200
|
0.063
|
706.18
|
54.84
|
657
|
51
|
637
|
677
|
OFF
|
OFF
|
ON
|
ON
|
12
|
12120
|
0.062
|
755.42
|
49.24
|
703
|
46
|
683
|
723
|
OFF
|
OFF
|
ON
|
OFF
|
13
|
13120
|
0.062
|
807.68
|
52.26
|
751
|
48
|
731
|
771
|
OFF
|
OFF
|
OFF
|
ON
|
14
|
14120
|
0.061
|
858.67
|
50.99
|
799
|
48
|
779
|
819
|
OFF
|
OFF
|
OFF
|
OFF
|
15
|
15120
|
0.060
|
908.44
|
49.76
|
845
|
46
|
825
|
865
|
Where NADC is the output
number of the 10-bit ADC converter. With four dip we represent 2^4 = 16
different states that must be identified precisely. The program must
discriminate each state with two thresholds NADC_L (lower) and NADC_H (upper).
The number of 10 bits, at the converter output, must be between these two
limits which I determined with ± 20 units with respect to the NADC value. The
diagram in figure 2 clearly shows the intervals and the output voltage Vo as a
function of the number set on the four dip.
As can be seen, the trend is
fairly linear and the intervals DN range from a
minimum of 46 to a maximum of 71, so the thresholds of ± 20 do not overlap.
Figure 2 |
As shown in the table, by powering
the circuit with Vcc = 5V, the maximum output voltage is 908.44 mV, lower than
the maximum voltage (1100 mV) accepted by the converter.
If you need an 8-pin dip
switch, just duplicate the circuit and use a second analog input. Figure 3
shows a connection diagram of the individual components.
Figure 3 |
The circuit is realized with few soldered joints and it is also easy to draw the printed circuit. Figure 4 shows the appearance of my prototype seen from the component side and from the soldered side. I used a small perforated circuit board of about 40x30 mm.
I have optimized the
circuit for Arduino / Genuino Uno and the program is fine for MCU type
ATmega328 / 168. But it can also be used, with minor modifications, with other
MCUs, such as SAMD21G18 mounted on Arduino Zero and Arduino MKR1000 boards and
also ESP8266 and 32.
Figure 4 |
Figure 5 |
List of components
component
|
description
|
component
|
description
|
R1
|
1 kW
± 1% metal film
|
R5
|
68.1 kW
± 1% metal film
|
R2
|
2 kW ± 1% s metal
film
|
-
|
0.1” perforated
circuit board
|
R3
|
3.92 kW
± 1% metal film
|
-
|
3 pin strip
connector
|
R4
|
8.2 kW
± 1% metal film
|
Dip4
|
DIP switch with 4 positions
|
The program
The sketch is an example of
use of the circuit and provides both the number and the individual dip arranged
in the DipSw char array. In this example I use Arduino Uno's pin A0 as an
analogue input and in the setup I insert the analogReference (INTERNAL)
instruction to set the internal Vref at 1.1V, more stable and less noisy than
the default at 5V.
In the loop () function I set
the discrimination to thresholds and in the readDIP function (byte mybyte) I
create the array of characters ordered as the dip switches. This last function
is useful to use every single switch.
/* program DIP4to1.ino
* only one
analog input for 4 dip switches
* Giovanni Carrera - 20/08/2019
*/
int DipPin = A0;// DIP4 analog input
//
limits of DIP4 output values:
const
int NADC_L[16] =
{0,47,113,176,233,293,352,409,480,533,586,637,683,731,779,825};
const
int NADC_H[16] = {30,87,153,216,273,333,392,449,520,573,626,677,723,771,819,865};
char
DipSw[5];
void
setup(){
analogReference(INTERNAL); // internal ADC
reference input = 1100V
Serial.begin(115200); // used with serial
monitor
}
void
loop() {
int val = analogRead(DipPin);// read analog
keyboard
for (int i=0; i < 16; i++){
if (val >= NADC_L[i] && val
<= NADC_H[i]){// has found the right value
Serial.print(val);
Serial.print(" , N = ");
Serial.print(i);
Serial.print(" , Dip = ");
readDIP(i);
Serial.println(DipSw);
break;
}
}
delay(500);
}
void
readDIP(byte mybyte){
byte mask = 0x01;
for(int i=3; i >= 0; --i){
if(mask & mybyte)
DipSw[i]= '1';
else
DipSw[i]= '0';
mask <<= 1;
}
}
References
1.
“Very few wires for a numeric keypad for Arduino”,
Giovanni Carrera, 10/11/18, http://ardupiclab.blogspot.it
Where is the images?
ReplyDeleteI put back the figures that someone had fun obscuring them.
ReplyDeleteVery well done my friend! Grazie!
ReplyDeleteElegant!
ReplyDeleteI'm facing the same project and will let the controller calculate R_14 = R_5 / ((V_CC/V_0) - 1) to get the exact value of the switched on/off resistor sum.
ReplyDelete