{"id":39,"date":"2009-11-23T07:51:54","date_gmt":"2009-11-23T13:51:54","guid":{"rendered":"http:\/\/nootropicdesign.com\/projectlab\/?p=39"},"modified":"2018-11-02T09:41:53","modified_gmt":"2018-11-02T14:41:53","slug":"arduino-controlled-coded-lock","status":"publish","type":"post","link":"https:\/\/nootropicdesign.com\/projectlab\/2009\/11\/23\/arduino-controlled-coded-lock\/","title":{"rendered":"Arduino-Controlled Lock with Keypad"},"content":{"rendered":"<p><strong><em>Difficulty Level = 6<\/em><\/strong>  <a href=\"\/projectlab\/difficulty-levels\/\">[What&#8217;s this?]<\/a><\/p>\n<p>After tearing down an old CD player, I was inspired by the CD laser scanning assembly to build a door lock for my subterranean lab.  The assembly has two motors: one for turning the CD (I&#8217;m not using this one) and one for slowly moving the laser across the CD&#8217;s surface.  This second motor provides a nice linear motion that I wanted to use to build an electronically-controlled dead bolt lock for my lab.<\/p>\n<p>Here&#8217;s the assembled lock.  The circuit board in the middle is an H-bridge circuit I built to allow the motor to move in both directions.  There are two position sensing switches so the Arduino senses when the motor has reached its limit in either direction.  A 9V power supply powers the Arduino board, and a separate 5V supply drives the motor through the H-bridge.  The dead bolt is <em>literally<\/em> a bolt &#8212; connected to the assembly with a piece of scrap circuit board &#8212; that travels through the door jamb and into the door.<\/p>\n<div id=\"attachment_44\" style=\"width: 650px\" class=\"wp-caption alignnone\"><a href=\"https:\/\/nootropicdesign.com\/projectlab\/wp-content\/uploads\/2009\/11\/lockClosed.jpg\"><img loading=\"lazy\" decoding=\"async\" aria-describedby=\"caption-attachment-44\" class=\"size-full wp-image-44\" title=\"lockClosed-sm\" src=\"https:\/\/nootropicdesign.com\/projectlab\/wp-content\/uploads\/2009\/11\/lockClosed-sm.jpg\" alt=\"The lock in the closed (locked) position.\" width=\"640\" height=\"853\" srcset=\"https:\/\/nootropicdesign.com\/projectlab\/wp-content\/uploads\/2009\/11\/lockClosed-sm.jpg 640w, https:\/\/nootropicdesign.com\/projectlab\/wp-content\/uploads\/2009\/11\/lockClosed-sm-225x300.jpg 225w\" sizes=\"auto, (max-width: 640px) 100vw, 640px\" \/><\/a><p id=\"caption-attachment-44\" class=\"wp-caption-text\">The lock in the closed (locked) position.<\/p><\/div>\n<p\/>\n<p\/>\nThe black CAT5 cable connected to pins 2-8 goes through a small hole in the wall (under a desk) to the keypad on the outside of the lab (I wasn&#8217;t sure I wanted to permanently mount the keypad in the wall).  The user types in the correct code and presses the # key to open or close the lock.  The green LED indicates the door is unlocked.  Red indicates locked.  <\/p>\n<div id=\"attachment_29\" style=\"width: 650px\" class=\"wp-caption alignnone\"><a href=\"https:\/\/nootropicdesign.com\/projectlab\/wp-content\/uploads\/2009\/11\/keypad.jpg\"><img loading=\"lazy\" decoding=\"async\" aria-describedby=\"caption-attachment-29\" class=\"size-full wp-image-29\" title=\"keypad\" src=\"https:\/\/nootropicdesign.com\/projectlab\/wp-content\/uploads\/2009\/11\/keypad.jpg\" alt=\"Lock keypad - green indicates that it's unlocked, red indicates locked.\" width=\"640\" height=\"480\" srcset=\"https:\/\/nootropicdesign.com\/projectlab\/wp-content\/uploads\/2009\/11\/keypad.jpg 640w, https:\/\/nootropicdesign.com\/projectlab\/wp-content\/uploads\/2009\/11\/keypad-300x225.jpg 300w\" sizes=\"auto, (max-width: 640px) 100vw, 640px\" \/><\/a><p id=\"caption-attachment-29\" class=\"wp-caption-text\">Lock keypad - green indicates that it&#39;s unlocked, red indicates locked.<\/p><\/div>\n<p\/>\n<p\/>\nLet&#8217;s see the lock in action.  (While recording, I gave instructions to my son to lock and unlock using the keypad off camera.)<\/p>\n<p><iframe loading=\"lazy\" width=\"640\" height=\"505\" src=\"https:\/\/www.youtube.com\/embed\/OC05Hnyc1bo\" frameborder=\"0\" allow=\"accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture\" allowfullscreen><\/iframe><\/p>\n<p><!--more--><br \/>\nReading the keypad is by far the most complicated thing in the Arduino code below.  They keypad has 12 keys but only 10 wires.  Reading the keypad is not as simple as checking to see which of the 12 switches is closed.  The keys must be constantly scanned to see which if any keys are depressed.   Scanning the keypad is done by multiplexing through 6 of the wires on the keypad, alternately setting them LOW and then checking the other 4 wires (blue, green, yellow, red) on the keypad to see if a button is pressed.  <\/p>\n<p>A shift register on the keypad lets me control 8 outputs with only 3 Arduino pins: the latch pin, clock pin and data pin.  The eight outputs are 6 multiplexed wires of the keypad plus one for each LED.  The total number of wires running to the keypad is 3 for the output (latch, clock, data), 4 inputs, 5V, and GND.  That&#8217;s 9 total, and since CAT5 has only 8 wires, I have the 9th wire (GND) taped to the CAT5.  Hey, it got the job done.<\/p>\n<pre class=\"codeblockscroll\">\r\n#define LATCH_PIN 2\r\n#define CLOCK_PIN 3\r\n#define DATA_PIN 4\r\n\r\n\/\/ Keypad inputs (colors are keypad wires, not cat5 wires)\r\n#define BLUE_PIN 5\r\n#define GREEN_PIN 6\r\n#define YELLOW_PIN 7\r\n#define RED_PIN 8\r\n\r\n\/\/ PNP transistors.  LOW to activate.\r\n#define Q1 17\r\n#define Q2 19\r\n\r\n\/\/ NPN transistors.  HIGH to activate.\r\n#define Q3 16\r\n#define Q4 18\r\n\r\n#define LOCK_LIMIT_SWITCH_PIN 15  \/\/ long wires\r\n#define UNLOCK_LIMIT_SWITCH_PIN 14\r\n\r\n#define LOCKED 0\r\n#define UNLOCKED 1\r\n#define LOCKING 2\r\n#define UNLOCKING 3\r\n\r\n#define NO_SCAN 0xFC\r\n#define BLACK 0x80\r\n#define WHITE 0x40\r\n#define GRAY 0x20\r\n#define PURPLE 0x10\r\n#define ORANGE 0x8\r\n#define BROWN 0x4\r\n#define GREEN_LED_ON 0x2\r\n#define RED_LED_ON 0x1\r\n\r\n#define NO_KEY -1\r\n#define STAR 10\r\n#define POUND 11\r\n\r\nint state;\r\nbyte greenLED = 0;\r\nbyte redLED = RED_LED_ON;\r\nint lastKey = -1;\r\n\r\n#define MAX_GUESS 10\r\n#define COMBO_LENGTH 4\r\n\r\nint code[COMBO_LENGTH] = {5, 6, 1, 8};\r\nint guess[MAX_GUESS];\r\nint guessIndex = 0;\r\n\r\nvoid setup() {\r\n  pinMode(LATCH_PIN, OUTPUT);\r\n  pinMode(CLOCK_PIN, OUTPUT);\r\n  pinMode(DATA_PIN, OUTPUT);\r\n\r\n  pinMode(BLUE_PIN, INPUT);\r\n  digitalWrite(BLUE_PIN, HIGH); \/\/ set pull-up resistor\r\n  pinMode(GREEN_PIN, INPUT);\r\n  digitalWrite(GREEN_PIN, HIGH); \/\/ set pull-up resistor\r\n  pinMode(YELLOW_PIN, INPUT);\r\n  digitalWrite(YELLOW_PIN, HIGH); \/\/ set pull-up resistor\r\n  pinMode(RED_PIN, INPUT);\r\n  digitalWrite(RED_PIN, HIGH); \/\/ set pull-up resistor\r\n\r\n  pinMode(Q1, OUTPUT);\r\n  pinMode(Q2, OUTPUT);\r\n  pinMode(Q3, OUTPUT);\r\n  pinMode(Q4, OUTPUT);\r\n\r\n  pinMode(UNLOCK_LIMIT_SWITCH_PIN, INPUT);\r\n  digitalWrite(UNLOCK_LIMIT_SWITCH_PIN, HIGH); \/\/ set pull-up resistor\r\n\r\n  pinMode(LOCK_LIMIT_SWITCH_PIN, INPUT);\r\n  digitalWrite(LOCK_LIMIT_SWITCH_PIN, HIGH); \/\/ set pull-up resistor\r\n\r\n  unlock();\r\n\r\n}\r\n\r\nvoid loop() {\r\n  if ((isUnlocked()) &amp;&amp; (state == UNLOCKING)) {\r\n    stop();\r\n    state = UNLOCKED;\r\n  }\r\n  if ((isLocked()) &amp;&amp; (state == LOCKING)) {\r\n    stop();\r\n    state = LOCKED;\r\n  }\r\n\r\n  if ((state != UNLOCKING) &amp;&amp; (state != LOCKING)) {\r\n    int n = scanKeypad();\r\n    if (n != lastKey) {\r\n      \/\/ something changed\r\n      if (n == NO_KEY) {\r\n        \/\/ key released\r\n        processKey(lastKey);\r\n      }\r\n      lastKey = n;\r\n    }\r\n  }\r\n}\r\n\r\nint scanKeypad() {\r\n\r\n  writeData((NO_SCAN ^ BLACK) | redLED | greenLED);\r\n  if (digitalRead(BLUE_PIN) == LOW) {\r\n    return POUND;\r\n  }\r\n  if (digitalRead(GREEN_PIN) == LOW) {\r\n    return 0;\r\n  }\r\n  if (digitalRead(YELLOW_PIN) == LOW) {\r\n    return STAR;\r\n  }\r\n\r\n  writeData((NO_SCAN ^ WHITE) | redLED | greenLED);\r\n  if (digitalRead(BLUE_PIN) == LOW) {\r\n    return 9;\r\n  }\r\n  if (digitalRead(GREEN_PIN) == LOW) {\r\n    return 8;\r\n  }\r\n  if (digitalRead(YELLOW_PIN) == LOW) {\r\n    return 7;\r\n  }\r\n\r\n  writeData((NO_SCAN ^ GRAY) | redLED | greenLED);\r\n  if (digitalRead(YELLOW_PIN) == LOW) {\r\n    return 4;\r\n  }\r\n\r\n  writeData((NO_SCAN ^ PURPLE) | redLED | greenLED);\r\n  if (digitalRead(BLUE_PIN) == LOW) {\r\n    return 6;\r\n  }\r\n  if (digitalRead(GREEN_PIN) == LOW) {\r\n    return 5;\r\n  }\r\n  if (digitalRead(YELLOW_PIN) == LOW) {\r\n    return 2;\r\n  }\r\n\r\n  writeData((NO_SCAN ^ ORANGE) | redLED | greenLED);\r\n  if (digitalRead(RED_PIN) == LOW) {\r\n    return 3;\r\n  }\r\n\r\n  writeData((NO_SCAN ^ BROWN) | redLED | greenLED);\r\n  if (digitalRead(RED_PIN) == LOW) {\r\n    return 1;\r\n  }\r\n\r\n  return NO_KEY;\r\n}  \r\n\r\nvoid processKey(int k) {\r\n  if ((k != POUND) &amp;&amp; (k != STAR)) {\r\n    guess[guessIndex++] = k;\r\n    if (guessIndex == MAX_GUESS) {\r\n      clearGuess();\r\n      blinkRed(3);\r\n    }\r\n  }\r\n  if (k == POUND) {\r\n    if (guessIsCorrect()) {\r\n      if (state == LOCKED) {\r\n        greenLED = GREEN_LED_ON;\r\n        redLED = 0;\r\n        unlock();\r\n      } else {\r\n        if (state == UNLOCKED) {\r\n          greenLED = 0;\r\n          redLED = RED_LED_ON;;\r\n          lock();\r\n        }\r\n      }\r\n      blinkGreen(3);\r\n      clearGuess();\r\n    } else {\r\n      clearGuess();\r\n      blinkRed(3);\r\n    }\r\n  }\r\n}\r\n\r\nvoid clearGuess() {\r\n  guessIndex = 0;\r\n  for(int i=0; i &lt; MAX_GUESS; i++) {\r\n    guess[i] = -1;\r\n  }\r\n}\r\n\r\nboolean guessIsCorrect() {\r\n  for(int i=0; i &lt; COMBO_LENGTH; i++) {\r\n    if (guess[i] != code[i]) {\r\n      return false;\r\n    }\r\n  }\r\n  return true;\r\n}\r\n\r\nvoid blinkRed(int n) {\r\n  for(int i=0; i &lt; n; i++) {\r\n    writeData(NO_SCAN);\r\n    delay(100);\r\n    writeData(NO_SCAN | RED_LED_ON);\r\n    delay(100);\r\n  }\r\n}\r\n\r\nvoid blinkGreen(int n) {\r\n  for(int i=0; i &lt; n; i++) {\r\n    writeData(NO_SCAN);\r\n    delay(100);\r\n    writeData(NO_SCAN | GREEN_LED_ON);\r\n    delay(100);\r\n  }\r\n}\r\n\r\nvoid writeData(byte data) {\r\n  digitalWrite(LATCH_PIN, LOW);\r\n  shiftOut(DATA_PIN, CLOCK_PIN, MSBFIRST, data);\r\n  digitalWrite(LATCH_PIN, HIGH);\r\n}\r\n\r\nboolean isUnlocked() {\r\n  return (digitalRead(UNLOCK_LIMIT_SWITCH_PIN) == LOW);\r\n}\r\n\r\nboolean isLocked() {\r\n  return (digitalRead(LOCK_LIMIT_SWITCH_PIN) == LOW);\r\n}\r\n\r\nvoid unlock() {\r\n  digitalWrite(Q2, HIGH);  \/\/ OFF\r\n  digitalWrite(Q3, LOW);   \/\/ OFF\r\n  digitalWrite(Q1, LOW);   \/\/ ON\r\n  digitalWrite(Q4, HIGH);  \/\/ ON\r\n  state = UNLOCKING;\r\n}\r\n\r\nvoid lock() {\r\n  digitalWrite(Q1, HIGH);  \/\/ OFF\r\n  digitalWrite(Q4, LOW);   \/\/ OFF\r\n  digitalWrite(Q2, LOW);   \/\/ ON\r\n  digitalWrite(Q3, HIGH);  \/\/ ON\r\n  state = LOCKING;\r\n}\r\n\r\nvoid stop() {\r\n  digitalWrite(Q1, HIGH);  \/\/ OFF\r\n  digitalWrite(Q2, HIGH);  \/\/ OFF\r\n  digitalWrite(Q3, LOW);   \/\/ OFF\r\n  digitalWrite(Q4, LOW);   \/\/ OFF\r\n}<\/pre>\n","protected":false},"excerpt":{"rendered":"<p>Difficulty Level = 6 [What&#8217;s this?] After tearing down an old CD player, I was inspired by the CD laser scanning assembly to build a door lock for my subterranean lab. The assembly has two motors: one for turning the CD (I&#8217;m not using this one) and one for slowly moving the laser across the [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_et_pb_use_builder":"","_et_pb_old_content":"","_et_gb_content_width":"","footnotes":""},"categories":[3],"tags":[],"class_list":["post-39","post","type-post","status-publish","format-standard","hentry","category-arduino"],"_links":{"self":[{"href":"https:\/\/nootropicdesign.com\/projectlab\/wp-json\/wp\/v2\/posts\/39","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/nootropicdesign.com\/projectlab\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/nootropicdesign.com\/projectlab\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/nootropicdesign.com\/projectlab\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/nootropicdesign.com\/projectlab\/wp-json\/wp\/v2\/comments?post=39"}],"version-history":[{"count":20,"href":"https:\/\/nootropicdesign.com\/projectlab\/wp-json\/wp\/v2\/posts\/39\/revisions"}],"predecessor-version":[{"id":1989,"href":"https:\/\/nootropicdesign.com\/projectlab\/wp-json\/wp\/v2\/posts\/39\/revisions\/1989"}],"wp:attachment":[{"href":"https:\/\/nootropicdesign.com\/projectlab\/wp-json\/wp\/v2\/media?parent=39"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/nootropicdesign.com\/projectlab\/wp-json\/wp\/v2\/categories?post=39"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/nootropicdesign.com\/projectlab\/wp-json\/wp\/v2\/tags?post=39"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}