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;
}

5 comments:

  1. Hey, great blog chronicling your tinkering with the Arduino. I was wondering though if you ever came up with a way to mount the LCD and keypad as a replacement for a security system keypad. I'd love to do the same but can't come up with a way to do it that doesn't look horrible.

    ReplyDelete
  2. Actually the cover to make this look good is probably my biggest frustration. It is probably why I haven't done anything on the system for a while. I would like to find a place that could build me a plastic cover as per my design but first I have to figure out how to design it. If I could figure out how to manufacture a cover I actually might be willing to scrape up some cash to manufacture a bunch of them and sell the whole keypad as a kit for a generic keypad. I know I would have bought one if there was one that was as functional as what I have build is.

    ReplyDelete
  3. Thanks for responding! Glad to hear I'm not the only one with this frustration. I found these guys (http://www.tekoenclosures.com/technical/customising.html) and it appears that they'll do a custom enclosure. I've actually ordered some free samples from them to see what their stuff looks like. In the mean time, I actually bought a cheap used HID ProxPro RFID reader with keypad off of eBay that I was going to try and use. Apparently it's pretty easy to interface them with the Arduinos. If you decide to get back into it and want to collaborate on something, feel free to get in touch!

    ReplyDelete
  4. This comment has been removed by the author.

    ReplyDelete
  5. Hi!
    I am just starting with arduino & I want to build a project like yours. I found your blog
    by searching around for ideas/tips/tricks etc. You've done a very good job I have to say!
    So, how is your system doing? Still using it? Have you found any bugs/holes? Have you
    added anything else, like RFID?

    ReplyDelete