Wednesday, January 18, 2012

Arduino DIP Switches and Binary

I'm working on an Arduino project to read in some DIP switches to set a starting address. I'm using 8 bits for the address (0-255), and using an 8 switch DIP array. One way to read the switch settings would be to simply hook up each switch to an input pin on the Arduino, but that is very wasteful. After some research, I ran across the 74165 (or more modern, 74HC165) chip. This is a Parallel In/Serial Out (PISO) chip. Or more simply, takes in an input (like a switch) and outputs a shifted bit stream of the values (e.g. 1 or 0). Even more simply put, if you have a bank of switches set ON OFF OFF ON ON hooked up to the inputs, it would output a but stream of 10011 (or reversed, depending on the order the switches are connected to the 74165 inputs). Soooo, only one input pin is needed on the Arduino to read up to 8 switches (or more if you cascade multiple 74165's). Well, you actually need a few more pins on the Arduino, but as outputs. That's because the 74165 also needs CLOCK and SHIFT/LOAD to trigger the reading and bit shifting the the inputs.

With this cool little chip, you simply connect as follows:
1 (Shift/Load) -> Arduino #13
2 (Clock) -> Arduino #12
3-6, 11-14 (Inputs) -> DIP Switches
8 (GND) - Ground
9 (DATA) -> Arduino 11
15 (Clock INHB) -> Ground
16 (Vcc) -> Power +5v

For the DIP switches:
GND -> 10k resistor -> DIP -> 74165 A pin
GND -> 10k resistor -> DIP -> 74165 B pin
...
GND -> 10k resistor -> DIP -> 74165 H pin

As for the actual code, I started with the example at http://wardyprojects.blogspot.com/2011/05/74hc165-piso-shift-register-arduino.html (great blog, BTW). Because of the way my switches were labeled and being read, switch ON was being interpretted as OFF in the code. Never fear! A little bitwise NOT was in order.

- Keep recording the input into a byte until all 8 'bits' (or rather, inputs) have been read.:
byte dip;
'loop through 8 times' {
digitalWrite(PIN_CP, HIGH);
digitalWrite(PIN_CP, LOW);
// Keep stuffing the input value in as a bit, shifting along the way
// In the end, 'dip' will be a binary representation of the switch on/off
dip = (dip << 1) | digitalRead(PIN_Q7);
}

- Now, simply NOT dip: dip = ~dip;

In my application, I need a starting address of at least 1. If all the switches are 'OFF', the Arduino reads 0. I can either force myself to always set a switch ON, or I can be a nice and assume that all off really means default, or 1.
if(dip == 0) dip=1;

Since I'm tired of writing this, I hope you get the idea. Below is the full source of what I'm talking about (along with the usage of my dynamic DEBUG() routine).


#define DEBUGPIN 2
int START_DMX_ADDR=1;


int DEBUG(){
return(digitalRead(DEBUGPIN));
} // End DEBUG()

void read_dip(){
// From http://wardyprojects.blogspot.com/2011/05/74hc165-piso-shift-register-arduino.html
//The terminology used here (PL, CP, Q7 and so on) are taken DIRECTLY from the 74HC165's datasheet.
#define PIN_PL (13) //pin 13 on arduino goes to pin 1 of 74HC165
#define PIN_CP (12) //pin 12 on arduino goes to pin 2 of 74HC165
#define PIN_Q7 (11) //pin 11 on arduino goes to pin 9 of 74HC165
//Hardwire pin 15 of both 74HC165 chips to ground to enable them all the time.

//For peace of mind I also hardwired pin 10 of the upstream chip to
//GND to force zeroes to be shifted in instead of allowing it to float.
//Given that the arduino is "downstream".

pinMode(PIN_PL, OUTPUT);
pinMode(PIN_CP, OUTPUT);
pinMode(PIN_Q7, INPUT);

digitalWrite(PIN_PL, HIGH);
digitalWrite(PIN_CP, LOW);

int i;
int j;
int value;
byte dip;

//read the switches 10 times to prove
//that the system is stable
for(i = 0 ; i < 11 ; i++)
{
//load logic bits from the DIP switches
digitalWrite(PIN_PL, LOW); //LOAD BITS
//reset "load" line, this freezes the internal buffer on both chips
digitalWrite(PIN_PL, HIGH);

for(j = 0 ; j < 8 ; j++)
{
value = digitalRead(PIN_Q7);
//read next "switch"
digitalWrite(PIN_CP, HIGH);
digitalWrite(PIN_CP, LOW);

//print switch's value
if(DEBUG())
Serial.print(value);

// Fill the values as 'bits'
dip = (dip << 1) | value;
}

if(DEBUG()){
Serial.println("");
Serial.println("----------------");
}
// Slight delay to let things settle down
delay(200);
}
// NOT the switch since it comes in as
// 11111110 instead of 00000001 (for value 1)
dip = ~dip;

// If the idiot didn't set a start address, assume 1
if(dip == 0) dip=1;

START_DMX_ADDR = dip;
if(DEBUG()){
Serial.print("DIP BIN Value: ");
Serial.println(START_DMX_ADDR);
}
} // End read_dip()

void setup()
{
Serial.begin(9600);
digitalWrite(DEBUGPIN, LOW);
read_dip();
} // End setup()

void loop()
{
} // End loop()

1 comments:

fatmi said...

All the binary coding are infinite numbers..:P Thanks I found my way by reading all instructions.
what is arduino