Translate

Wednesday, April 1, 2020

A DIP switch for Arduino

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.
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:
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.
Figure 2
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.
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
I used a 3-pin strip connector for wiring with Arduino. The resistors must have a low tolerance, I used those with 1/4W metal film with a tolerance of ± 1%, very common and easy to find. Figure 5 shows the wiring between the DIP card and Arduino Uno.
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
2.       “Only Three Pins for a 4x3 Keypad”, Giovanni Carrera,  November 19, 2018, https://www.hackster.io

5 comments:

  1. I put back the figures that someone had fun obscuring them.

    ReplyDelete
  2. Very well done my friend! Grazie!

    ReplyDelete
  3. I'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