Monday, April 19, 2010

Got a keypad and an LCD

So I got my keypad and LCD in the mail.  I ended up buying them from Jameco.  The keypad was about $15 and the LCD was only $10.  When you start adding up all of the $10 here and $15 there this project is starting to add up.  I will have to list the total bill when I am done.  

One of the costs that I didn't think that I would have was buying another arduino.  I think that I am going to do just that though.  After playing around with my new stuff I started to think about where I was going to stick this keypad and how I was going to enclose it.  When I figured out where the thing was going I started to think about how I was going to run wire to it and that of course led to how much wire.  17 wires going from the arduino to the components for the keypad.  That is a little bit more then the cat-5 that I was planning.  There is also the problem of if the arduino would be able to drive enough power through 35 feet of wire to make the things work.  I didn't really test this but I am positive that it was going to be a problem.  Of course I still have the problem of the 2 arduinos communicating through 35 feet of wire but I know that people are doing that out there so I am not too worried about it.

There are other benefits to running the keypad on its own arduino.  The biggest is that I don't really have to worry as much about how much code is in the program.  Splitting the user interface code up from the actual security system monitoring code will probably half the code on each.

Another benefit is that I will get to play with making 2 arduinos communicate.  I am thinking that if you are reading this blog you realize that it is more about the process then about the end product.  I am going to assume for now that I will just use a serial connection between the 2.  If I run into problems when I actually get a second arduino I will note the changes here.

So here is the setup.  Fritzing ( the program I use to model my electronics ) didn't have the LCD and keypad components and I didn't want to take the time to make them.  I know... shame on me.  You are going to have to make due with a text description of how to put this together.  What you will have when you are done is a keypad that you can use as a starter for any project that needs a keypad interface.

First of all let me apologize for the picture below.  It looks a lot more complicated than it is because I didn't have a long breadboard.  I ended up using my short one and the one on my protoshield.  The thing attached to the LCD is not another arduino but only the protoshield, and I am only using the breadboard on it.

The keypad is the 4x4 keypad that I bought from Jameco.  It has 9 pins on the back and is set up like a grid.  The first four are the rows and the second are the columns.  The 9th pin is for the electrostatic discharge shield which I am not connecting to anything.  (Should I be?)  Pin 1 is toward the 1 button.  The first 4 pins are connected to the digital IO 12 through 9 on the arduino.  The next 4 pins go through 10K resistors to a ground and also to the analog inputs 0 through 3 on the arduino.  This is basically a big complicated pull down switch.  The program causes a digital IO to go high then checks all of the analog inputs.  If one of them is high then that means that one of the buttons on the row is pressed.  Which analog input is high tells us what column it is and we can map the row and column to a particular key.  The resistors just guarantee that if the button isn't pressed the analog input will be low when we check it.

For the piezo speaker the ground goes to the ground and the positive goes to digital pin 8 on the arduino. 

The LCD I also got from Jameco.  It is a 20 character, 4 row display.  Also needed is a cheapo little potentiometer.  I am using one that I have had for a few decades.  I think that I got it with a intro to electronics kit back in the 80s.  Still works great!  I am using the LiquidCrystal library in the sketch code and the components are set up ALMOST exactly the same as the tutorial on arcuino.cc.  The difference being that I am using pins 6 and 7 instead of 11 and 12.  I am going to refer you to the tutorial for the setup for the LCD because I am lazy.  It is at http://www.arduino.cc/en/Tutorial/LiquidCrystal.  LCDs are super easy to use with the arduino and LiquidCrystal library. 


The code below is what runs everything and it is pretty much self documenting :).  If you don't get the last joke you are probably not a programmer or manager of said programmers.  Just install it an you get to hear the beep and see the key pressed.  After you have played with it for a while search for the "now do something" and start there to implement your user interface.  For instance I am going to use the 2nd key as a start command button so I might do something like:
 
if ( strcmp( newVal, "2ND") == 0 ) state = "StartCmd";
else if ( strcmp( state, "StartCmd" ) == 0 && strcmp( newVal, "1" ) == 0 ) turnOnAlarm();

That little bit of code would run the turnOnAlarm function when the user pressed 2nd then 1.

I will post the completed UI code when I get the rest of the stuff put together and figured out but this is the perfect starting point for any keypad device so I thought that I would throw this out now. 

Another thing to note is that my piezo is a generic one and most out there are exactly like it but if the beep you hear is irritating then play with the tone variable until you like it.  You could even change the program to add a function to change the tone when you press the up or down buttons.  I probably will.  Changing the value and then updating is a pain!

/*
 * arduino keypad/lcd start
 *
 * author: Stacy Brothers
 * http://stacysarduino.blogspot.com
 */

// include the library code:
#include <LiquidCrystal.h>
// debug stuff
boolean debug = true;

// communication stuff
const int MAX_CMD_LEN = 128;
char cmd[MAX_CMD_LEN];

boolean connected = false;
long pingWait = 0; // this is the counter to send the ping
const long pingSend = 50000L; // when to send the ping
long pingCount = 0; // how many times this has received a ping.
long pongCount = 0; // how many times this has received a pong.

// initialize the library with the numbers of the interface pins
LiquidCrystal lcd(7,6,5,4,3,2);

// keypad stuff
int kppins[] = {12,11,10,9,0,1,2,3};
int keyWait = 0;
int keyDelay = 100; // If the last time this key was pressed < this then ignore
char* key[]={"1","2","3","UP",
             "4","5","6","DOWN",
             "7","8","9","2ND",
             "CLEAR","0","HELP","ENTER"};
// noise maker stuff
int tone = 195;  

// led stuff
int ledPin = 13;
    
void setup() {
  // setup communications stuff
  Serial.begin(9600);
  
  // keypad pins
  pinMode(kppins[0], OUTPUT);   
  pinMode(kppins[1], OUTPUT);
  pinMode(kppins[2], OUTPUT);
  pinMode(kppins[3], OUTPUT);
  
  // set up the LCD
  lcd.begin(20, 4);  // 20 columns and 4 rows
  
  // beeper 
  pinMode(8, OUTPUT);
 
}

void loop() {
  if ( Serial.available() != 0 ) { 
      // something is on the line so read it
      readln(cmd);
      if ( debug && strcmp(cmd,"") != 0 ) {  
        Serial.print("Arduino got *");
        Serial.print(cmd);
        Serial.println("*");
      }
  }

  if (strcmp(cmd,"") == 0 && pingWait > pingSend) { 
    // haven't sent or received any thing for a while so do a ping to see if anything is (still) there.
    Serial.println("ping");
    pingWait = 0;
  } else if (strcmp(cmd, "pong") == 0) { 
    // received a pong response so something is connected
    connected = true;
    pingWait = 0;
    pongCount++;
  } else if (strcmp(cmd, "ping") == 0) {
    // something wants to know if the arduino is still here.  I must be connected.  send a pong back. 
    Serial.println("pong");
    connected = true;
    pingWait = 0;
    pingCount++;
  } 
    
  cmd[0]= NULL;  // what ever the command was reset it
  
  // see if the keyboard has been pressed
  int newVal = checkKeypad();
  if ( newVal > -1 && keyWait > keyDelay ) {
    keyBeep();
    
    // now do something
    lcd.clear();
    lcd.setCursor(0, 1);
    lcd.print("Key pressed:");
    lcd.print(key[newVal]);
    
    keyWait = 0;
  }
  pingWait++;
  keyWait ++;
}

void readln( char buffer[] ) {
  char c;  
  int i = 0;  
  int quiet = 0;
  while( true ) {
    if ( Serial.available() ) {
      quiet = 0;
      c = Serial.read();
      if ( c == 13 ) {  // carriage return
        Serial.read();  // line feed
        break;
      }
      buffer[i++] = c;    
      if ( i == (MAX_CMD_LEN-1) ) break;
    } else {
      if ( quiet > 10000 ) break;
      quiet ++;
    }
    delay(10); // short delay         
  } 
  buffer[i] = NULL;     
}

void keyBeep() { 
  // beep and flash
  digitalWrite(ledPin, HIGH);  
  for (long i = 0; i < 80000L; i += tone * 2.5) {
    digitalWrite(8, HIGH);
    delayMicroseconds(tone);
    digitalWrite(8, LOW);
    delayMicroseconds(tone);
  }
  digitalWrite(ledPin, LOW);
}

int checkKeypad() { 
  int rtn = -1;
  for ( int i = 0; i < 4; i++ ) { 
    digitalWrite(kppins[i],HIGH);
    for (int j = 0; j < 4; j ++) { 
      int pushed = map( analogRead(j), 0, 1024, 0, 2 );
      if ( pushed == 1 ) { 
        rtn = (i<<2) + j;
      }
    }
    digitalWrite(kppins[i],LOW);
  }
  return rtn;
}

Wednesday, March 10, 2010

Driving Mrs. Ademco



The siren on my current security system is made by Ademco.


It needs a half an amp at 12 volts to sound 106 decibels.  This is a problem since the output on the Arduino is around 5 volts max. Since I decided to use as much of my current system as I can I need to figure out how to drive the siren with what I have.  Fortunately my current system also has a 12 Volt sealed lead acid rechargeable battery for backup.


To get these three things working together I am going to need something called a driver.  A driver is basically a switch except the switch is flipped by a small positive input current.  Drivers are used a lot for doing the same thing with motors.

My driver is actually a pretty simple circuit.  The Arduino is connected to the base of a transistor (TIP31) through a resistor (10K). The Vcc of the 12 V battery goes to the siren. The siren goes to the collector of the transistor.  The emitter of the transistor is connected to the ground of the battery and the ground on the Arduino.



The only difference between driving a motor and a siren is that I don't think that I need to worry about feedback with a siren.  With a motor, when you turn the circuit off, you sometimes get a jolt of feedback from the motor.  Simple motor drivers just bridge between the collector and emitter with a diode to give the jolt somewhere to drain to.  I haven't seen any feed back from my circuit so hopefully this isn't going to be a problem.  I probably could do it anyway, it is just a diode, but what I have works.

Another thing that I need is a charger for the battery.  The charger on my current system is built into the board of the system so I can't use it and I don't know much about building a charger so I will probably just buy one.  The place where I am getting all of my sensors, www.homesecuritystore.com, has them starting at 14 bucks and going to 130. This is a little confusing because they seem to be similar systems.  Why the difference in prices?  I am not going to worry about that until I buy the sensors.

It seems that I can also use the battery to run my Arduino when the power goes south.  I was a little worried about it being too much for the regulator on the Arduino but a guy name Mike Cook at www.thebox.myzen.co.uk did the calculations and they look right, so I am going to trust him.  This seems to be working out pretty good.

Now I need to get rid of the code to make the siren sound in my current Arduino code and replace it with a simple cause the output to go high.

Next thing to think about is a keypad and display.

Monday, March 1, 2010

Mux

So having a security system that has only 6 analog inputs is kind of a bummer.  Of course the Arduino has 15 digital inputs along with the 6 analog but the way that I wanted to do the sensors was analog.

There are a couple of things that I could do to get more inputs.

One would be to upgrade to the Arduino Mega which has 16 analog and 54 digital.  This is better than my 6 and 16 and I probably could use the digital inputs for some of the sensors.  The Mega also has a lot more memory which would be cool but really don't need it (yet).  The big problem with this solution is that the Mega is about 60 bucks.

Since I already have a Arduino I am a little hesitant to go buy another even if it is bigger and better.  Fortunately you can make a few IOs into a bunch more IOs using a multiplexer ( mux for short ).  Look at the wikipedia link to see what a mux really is but basically it allows me to scrunch a bunch of input down to one or a few.  The circuit is more complicated than just reading a value on a wire but not too much so.

I went out looking for a mux.  There aren't a lot of places you can get these ICs on the web but I was able to find them for under a couple of bucks before shipping.  Add to that shipping and then I also need a board or shield to put it on with the pin connectors and I am up to at least 15 bucks.  It seemed like a big pain.

Then I came upon the Mux Shield from Mayhew Labs.  20 bucks for a shield that turns 4 digital and 3 analog IOs into 48.  It is designed to work with the Arduino and the only assembly is soldering a few headers on.

About 4 days later I got it in the mail.  The Mayhew Labs site has some example code on their site but it is so simple to use that I just took a line or two from their stuff and ripped out something a little more compact to test the board with.  Very cool, very easy.  Now I have gone from having to worry about "how I am going to access all of the sensors that I am planning" to "what can I do with all of these IOs".  I think that I will have to play with some other home automation after I finish the security system.

The code below reads inputs 16 and 17.  These are the 0th and 1st IOs on M1 which is the middle multiplexer.  Plug a couple potentiometers into these headers.  One row of headers is ground, one is Vcc and the bottom is the one that will be read.

void setup() { 
  pinMode(5, OUTPUT);
  pinMode(4, OUTPUT);
  pinMode(3, OUTPUT);
  pinMode(2, OUTPUT); 
  
  Serial.begin(9600);
}

void loop() { 
  int val = getSensorValue(16);
  Serial.print( "16:" );
  Serial.println( val );
  val = getSensorValue(17);
  Serial.print( "17:" );
  Serial.println( val );
  delay(200);
}

int getSensorValue( int sensor ) { 
  int muxId = sensor >> 4;
  int inputId = sensor % 16;
  
  digitalWrite(5, (inputId&15)>>3); 
  digitalWrite(4, (inputId&7)>>2);  
  digitalWrite(3, (inputId&3)>>1);  
  digitalWrite(2, (inputId&1));
  
  return analogRead(muxId);
}


I don't know if this is the best code but it works great.  I will post the security system code change for the new shield next post along with the change with for the real siren. 

I had to think about how to plug the sensors into the mux shield in a more secure way.  If I just plug the wires into the header like I would when I am prototyping they will probably fall out.  I probably should have ordered the mux shield without the headers on and soldered in male headers instead of the female headers. I will have to find out if he sells them that way.  Then I found some 4 pin female connectors to put on the ends of my sensor wires.  That will probably stay pretty secure.  UPDATE:  The mux shield without headers is what I was thinking it was.  If I were starting this from the beginning I might have just bought it and then soldered on the male headers.  Maybe Mark will offer a "Production Version" of his mux shield already assembled like this.

Pics of the mux shield on the Arduino, breakaway male headers and headers in the shield with a connector plugged in to input 17 or the input 1 on M1.