From b29a876fa29c4a7e9c33d6913380218e9ae570e2 Mon Sep 17 00:00:00 2001 From: ratnadiraw <ratnadiraw@gmail.com> Date: Sat, 1 Apr 2017 10:41:08 +0700 Subject: [PATCH] add lib --- Keypad/Keypad.cpp | 293 +++++++++++ Keypad/Keypad.h | 156 ++++++ Keypad/examples/CustomKeypad/CustomKeypad.ino | 37 ++ .../examples/DynamicKeypad/DynamicKeypad.ino | 213 ++++++++ Keypad/examples/EventKeypad/EventKeypad.ino | 73 +++ Keypad/examples/HelloKeypad/HelloKeypad.ino | 35 ++ Keypad/examples/HelloKeypad3/HelloKeypad3.ino | 68 +++ Keypad/examples/MultiKey/MultiKey.ino | 78 +++ Keypad/examples/loopCounter/loopCounter.ino | 46 ++ Keypad/keywords.txt | 38 ++ Keypad/utility/Key.cpp | 61 +++ Keypad/utility/Key.h | 73 +++ .../Examples/HelloPassword/HelloPassword.pde | 35 ++ .../PasswordKeypad/PasswordKeypad.pde | 67 +++ .../Examples/SerialMonitor/SerialMonitor.pde | 56 ++ Password/Password.cpp | 120 +++++ Password/Password.h | 81 +++ Password/keywords.txt | 6 + RFID/RFID.cpp | 485 ++++++++++++++++++ RFID/RFID.h | 151 ++++++ Ultrasonic/LICENSE | 21 + Ultrasonic/README.md | 82 +++ .../MultipleUltrasonicSensors.ino | 58 +++ .../UltrasonicSimple/UltrasonicSimple.ino | 54 ++ Ultrasonic/extras/HC-SR04-with-Arduino.jpg | Bin 0 -> 61223 bytes Ultrasonic/extras/Ultrasonic.fzz | Bin 0 -> 3813 bytes Ultrasonic/keywords.txt | 23 + Ultrasonic/library.properties | 10 + Ultrasonic/src/Ultrasonic.cpp | 59 +++ Ultrasonic/src/Ultrasonic.h | 39 ++ 30 files changed, 2518 insertions(+) create mode 100644 Keypad/Keypad.cpp create mode 100644 Keypad/Keypad.h create mode 100644 Keypad/examples/CustomKeypad/CustomKeypad.ino create mode 100644 Keypad/examples/DynamicKeypad/DynamicKeypad.ino create mode 100644 Keypad/examples/EventKeypad/EventKeypad.ino create mode 100644 Keypad/examples/HelloKeypad/HelloKeypad.ino create mode 100644 Keypad/examples/HelloKeypad3/HelloKeypad3.ino create mode 100644 Keypad/examples/MultiKey/MultiKey.ino create mode 100644 Keypad/examples/loopCounter/loopCounter.ino create mode 100644 Keypad/keywords.txt create mode 100644 Keypad/utility/Key.cpp create mode 100644 Keypad/utility/Key.h create mode 100644 Password/Examples/HelloPassword/HelloPassword.pde create mode 100644 Password/Examples/PasswordKeypad/PasswordKeypad.pde create mode 100644 Password/Examples/SerialMonitor/SerialMonitor.pde create mode 100644 Password/Password.cpp create mode 100644 Password/Password.h create mode 100644 Password/keywords.txt create mode 100644 RFID/RFID.cpp create mode 100644 RFID/RFID.h create mode 100644 Ultrasonic/LICENSE create mode 100644 Ultrasonic/README.md create mode 100644 Ultrasonic/examples/MultipleUltrasonicSensors/MultipleUltrasonicSensors.ino create mode 100644 Ultrasonic/examples/UltrasonicSimple/UltrasonicSimple.ino create mode 100644 Ultrasonic/extras/HC-SR04-with-Arduino.jpg create mode 100644 Ultrasonic/extras/Ultrasonic.fzz create mode 100644 Ultrasonic/keywords.txt create mode 100644 Ultrasonic/library.properties create mode 100644 Ultrasonic/src/Ultrasonic.cpp create mode 100644 Ultrasonic/src/Ultrasonic.h diff --git a/Keypad/Keypad.cpp b/Keypad/Keypad.cpp new file mode 100644 index 0000000..f146a6d --- /dev/null +++ b/Keypad/Keypad.cpp @@ -0,0 +1,293 @@ +/* +|| +|| @file Keypad.cpp +|| @version 3.1 +|| @author Mark Stanley, Alexander Brevig +|| @contact mstanley@technologist.com, alexanderbrevig@gmail.com +|| +|| @description +|| | This library provides a simple interface for using matrix +|| | keypads. It supports multiple keypresses while maintaining +|| | backwards compatibility with the old single key library. +|| | It also supports user selectable pins and definable keymaps. +|| # +|| +|| @license +|| | This library is free software; you can redistribute it and/or +|| | modify it under the terms of the GNU Lesser General Public +|| | License as published by the Free Software Foundation; version +|| | 2.1 of the License. +|| | +|| | This library is distributed in the hope that it will be useful, +|| | but WITHOUT ANY WARRANTY; without even the implied warranty of +|| | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +|| | Lesser General Public License for more details. +|| | +|| | You should have received a copy of the GNU Lesser General Public +|| | License along with this library; if not, write to the Free Software +|| | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +|| # +|| +*/ +#include <Keypad.h> + +// <<constructor>> Allows custom keymap, pin configuration, and keypad sizes. +Keypad::Keypad(char *userKeymap, byte *row, byte *col, byte numRows, byte numCols) { + rowPins = row; + columnPins = col; + sizeKpd.rows = numRows; + sizeKpd.columns = numCols; + + begin(userKeymap); + + setDebounceTime(10); + setHoldTime(500); + keypadEventListener = 0; + + startTime = 0; + single_key = false; +} + +// Let the user define a keymap - assume the same row/column count as defined in constructor +void Keypad::begin(char *userKeymap) { + keymap = userKeymap; +} + +// Returns a single key only. Retained for backwards compatibility. +char Keypad::getKey() { + single_key = true; + + if (getKeys() && key[0].stateChanged && (key[0].kstate==PRESSED)) + return key[0].kchar; + + single_key = false; + + return NO_KEY; +} + +// Populate the key list. +bool Keypad::getKeys() { + bool keyActivity = false; + + // Limit how often the keypad is scanned. This makes the loop() run 10 times as fast. + if ( (millis()-startTime)>debounceTime ) { + scanKeys(); + keyActivity = updateList(); + startTime = millis(); + } + + return keyActivity; +} + +// Private : Hardware scan +void Keypad::scanKeys() { + // Re-intialize the row pins. Allows sharing these pins with other hardware. + for (byte r=0; r<sizeKpd.rows; r++) { + pin_mode(rowPins[r],INPUT_PULLUP); + } + + // bitMap stores ALL the keys that are being pressed. + for (byte c=0; c<sizeKpd.columns; c++) { + pin_mode(columnPins[c],OUTPUT); + pin_write(columnPins[c], LOW); // Begin column pulse output. + for (byte r=0; r<sizeKpd.rows; r++) { + bitWrite(bitMap[r], c, !pin_read(rowPins[r])); // keypress is active low so invert to high. + } + // Set pin to high impedance input. Effectively ends column pulse. + pin_write(columnPins[c],HIGH); + pin_mode(columnPins[c],INPUT); + } +} + +// Manage the list without rearranging the keys. Returns true if any keys on the list changed state. +bool Keypad::updateList() { + + bool anyActivity = false; + + // Delete any IDLE keys + for (byte i=0; i<LIST_MAX; i++) { + if (key[i].kstate==IDLE) { + key[i].kchar = NO_KEY; + key[i].kcode = -1; + key[i].stateChanged = false; + } + } + + // Add new keys to empty slots in the key list. + for (byte r=0; r<sizeKpd.rows; r++) { + for (byte c=0; c<sizeKpd.columns; c++) { + boolean button = bitRead(bitMap[r],c); + char keyChar = keymap[r * sizeKpd.columns + c]; + int keyCode = r * sizeKpd.columns + c; + int idx = findInList (keyCode); + // Key is already on the list so set its next state. + if (idx > -1) { + nextKeyState(idx, button); + } + // Key is NOT on the list so add it. + if ((idx == -1) && button) { + for (byte i=0; i<LIST_MAX; i++) { + if (key[i].kchar==NO_KEY) { // Find an empty slot or don't add key to list. + key[i].kchar = keyChar; + key[i].kcode = keyCode; + key[i].kstate = IDLE; // Keys NOT on the list have an initial state of IDLE. + nextKeyState (i, button); + break; // Don't fill all the empty slots with the same key. + } + } + } + } + } + + // Report if the user changed the state of any key. + for (byte i=0; i<LIST_MAX; i++) { + if (key[i].stateChanged) anyActivity = true; + } + + return anyActivity; +} + +// Private +// This function is a state machine but is also used for debouncing the keys. +void Keypad::nextKeyState(byte idx, boolean button) { + key[idx].stateChanged = false; + + switch (key[idx].kstate) { + case IDLE: + if (button==CLOSED) { + transitionTo (idx, PRESSED); + holdTimer = millis(); } // Get ready for next HOLD state. + break; + case PRESSED: + if ((millis()-holdTimer)>holdTime) // Waiting for a key HOLD... + transitionTo (idx, HOLD); + else if (button==OPEN) // or for a key to be RELEASED. + transitionTo (idx, RELEASED); + break; + case HOLD: + if (button==OPEN) + transitionTo (idx, RELEASED); + break; + case RELEASED: + transitionTo (idx, IDLE); + break; + } +} + +// New in 2.1 +bool Keypad::isPressed(char keyChar) { + for (byte i=0; i<LIST_MAX; i++) { + if ( key[i].kchar == keyChar ) { + if ( (key[i].kstate == PRESSED) && key[i].stateChanged ) + return true; + } + } + return false; // Not pressed. +} + +// Search by character for a key in the list of active keys. +// Returns -1 if not found or the index into the list of active keys. +int Keypad::findInList (char keyChar) { + for (byte i=0; i<LIST_MAX; i++) { + if (key[i].kchar == keyChar) { + return i; + } + } + return -1; +} + +// Search by code for a key in the list of active keys. +// Returns -1 if not found or the index into the list of active keys. +int Keypad::findInList (int keyCode) { + for (byte i=0; i<LIST_MAX; i++) { + if (key[i].kcode == keyCode) { + return i; + } + } + return -1; +} + +// New in 2.0 +char Keypad::waitForKey() { + char waitKey = NO_KEY; + while( (waitKey = getKey()) == NO_KEY ); // Block everything while waiting for a keypress. + return waitKey; +} + +// Backwards compatibility function. +KeyState Keypad::getState() { + return key[0].kstate; +} + +// The end user can test for any changes in state before deciding +// if any variables, etc. needs to be updated in their code. +bool Keypad::keyStateChanged() { + return key[0].stateChanged; +} + +// The number of keys on the key list, key[LIST_MAX], equals the number +// of bytes in the key list divided by the number of bytes in a Key object. +byte Keypad::numKeys() { + return sizeof(key)/sizeof(Key); +} + +// Minimum debounceTime is 1 mS. Any lower *will* slow down the loop(). +void Keypad::setDebounceTime(uint debounce) { + debounce<1 ? debounceTime=1 : debounceTime=debounce; +} + +void Keypad::setHoldTime(uint hold) { + holdTime = hold; +} + +void Keypad::addEventListener(void (*listener)(char)){ + keypadEventListener = listener; +} + +void Keypad::transitionTo(byte idx, KeyState nextState) { + key[idx].kstate = nextState; + key[idx].stateChanged = true; + + // Sketch used the getKey() function. + // Calls keypadEventListener only when the first key in slot 0 changes state. + if (single_key) { + if ( (keypadEventListener!=NULL) && (idx==0) ) { + keypadEventListener(key[0].kchar); + } + } + // Sketch used the getKeys() function. + // Calls keypadEventListener on any key that changes state. + else { + if (keypadEventListener!=NULL) { + keypadEventListener(key[idx].kchar); + } + } +} + +/* +|| @changelog +|| | 3.1 2013-01-15 - Mark Stanley : Fixed missing RELEASED & IDLE status when using a single key. +|| | 3.0 2012-07-12 - Mark Stanley : Made library multi-keypress by default. (Backwards compatible) +|| | 3.0 2012-07-12 - Mark Stanley : Modified pin functions to support Keypad_I2C +|| | 3.0 2012-07-12 - Stanley & Young : Removed static variables. Fix for multiple keypad objects. +|| | 3.0 2012-07-12 - Mark Stanley : Fixed bug that caused shorted pins when pressing multiple keys. +|| | 2.0 2011-12-29 - Mark Stanley : Added waitForKey(). +|| | 2.0 2011-12-23 - Mark Stanley : Added the public function keyStateChanged(). +|| | 2.0 2011-12-23 - Mark Stanley : Added the private function scanKeys(). +|| | 2.0 2011-12-23 - Mark Stanley : Moved the Finite State Machine into the function getKeyState(). +|| | 2.0 2011-12-23 - Mark Stanley : Removed the member variable lastUdate. Not needed after rewrite. +|| | 1.8 2011-11-21 - Mark Stanley : Added decision logic to compile WProgram.h or Arduino.h +|| | 1.8 2009-07-08 - Alexander Brevig : No longer uses arrays +|| | 1.7 2009-06-18 - Alexander Brevig : Every time a state changes the keypadEventListener will trigger, if set. +|| | 1.7 2009-06-18 - Alexander Brevig : Added setDebounceTime. setHoldTime specifies the amount of +|| | microseconds before a HOLD state triggers +|| | 1.7 2009-06-18 - Alexander Brevig : Added transitionTo +|| | 1.6 2009-06-15 - Alexander Brevig : Added getState() and state variable +|| | 1.5 2009-05-19 - Alexander Brevig : Added setHoldTime() +|| | 1.4 2009-05-15 - Alexander Brevig : Added addEventListener +|| | 1.3 2009-05-12 - Alexander Brevig : Added lastUdate, in order to do simple debouncing +|| | 1.2 2009-05-09 - Alexander Brevig : Changed getKey() +|| | 1.1 2009-04-28 - Alexander Brevig : Modified API, and made variables private +|| | 1.0 2007-XX-XX - Mark Stanley : Initial Release +|| # +*/ diff --git a/Keypad/Keypad.h b/Keypad/Keypad.h new file mode 100644 index 0000000..e1676b9 --- /dev/null +++ b/Keypad/Keypad.h @@ -0,0 +1,156 @@ +/* +|| +|| @file Keypad.h +|| @version 3.1 +|| @author Mark Stanley, Alexander Brevig +|| @contact mstanley@technologist.com, alexanderbrevig@gmail.com +|| +|| @description +|| | This library provides a simple interface for using matrix +|| | keypads. It supports multiple keypresses while maintaining +|| | backwards compatibility with the old single key library. +|| | It also supports user selectable pins and definable keymaps. +|| # +|| +|| @license +|| | This library is free software; you can redistribute it and/or +|| | modify it under the terms of the GNU Lesser General Public +|| | License as published by the Free Software Foundation; version +|| | 2.1 of the License. +|| | +|| | This library is distributed in the hope that it will be useful, +|| | but WITHOUT ANY WARRANTY; without even the implied warranty of +|| | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +|| | Lesser General Public License for more details. +|| | +|| | You should have received a copy of the GNU Lesser General Public +|| | License along with this library; if not, write to the Free Software +|| | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +|| # +|| +*/ + +#ifndef KEYPAD_H +#define KEYPAD_H + +#include "utility/Key.h" + +// Arduino versioning. +#if defined(ARDUINO) && ARDUINO >= 100 +#include "Arduino.h" +#else +#include "WProgram.h" +#endif + +// bperrybap - Thanks for a well reasoned argument and the following macro(s). +// See http://arduino.cc/forum/index.php/topic,142041.msg1069480.html#msg1069480 +#ifndef INPUT_PULLUP +#warning "Using pinMode() INPUT_PULLUP AVR emulation" +#define INPUT_PULLUP 0x2 +#define pinMode(_pin, _mode) _mypinMode(_pin, _mode) +#define _mypinMode(_pin, _mode) \ +do { \ + if(_mode == INPUT_PULLUP) \ + pinMode(_pin, INPUT); \ + digitalWrite(_pin, 1); \ + if(_mode != INPUT_PULLUP) \ + pinMode(_pin, _mode); \ +}while(0) +#endif + + +#define OPEN LOW +#define CLOSED HIGH + +typedef char KeypadEvent; +typedef unsigned int uint; +typedef unsigned long ulong; + +// Made changes according to this post http://arduino.cc/forum/index.php?topic=58337.0 +// by Nick Gammon. Thanks for the input Nick. It actually saved 78 bytes for me. :) +typedef struct { + byte rows; + byte columns; +} KeypadSize; + +#define LIST_MAX 10 // Max number of keys on the active list. +#define MAPSIZE 10 // MAPSIZE is the number of rows (times 16 columns) +#define makeKeymap(x) ((char*)x) + + +//class Keypad : public Key, public HAL_obj { +class Keypad : public Key { +public: + + Keypad(char *userKeymap, byte *row, byte *col, byte numRows, byte numCols); + + virtual void pin_mode(byte pinNum, byte mode) { pinMode(pinNum, mode); } + virtual void pin_write(byte pinNum, boolean level) { digitalWrite(pinNum, level); } + virtual int pin_read(byte pinNum) { return digitalRead(pinNum); } + + uint bitMap[MAPSIZE]; // 10 row x 16 column array of bits. Except Due which has 32 columns. + Key key[LIST_MAX]; + unsigned long holdTimer; + + char getKey(); + bool getKeys(); + KeyState getState(); + void begin(char *userKeymap); + bool isPressed(char keyChar); + void setDebounceTime(uint); + void setHoldTime(uint); + void addEventListener(void (*listener)(char)); + int findInList(char keyChar); + int findInList(int keyCode); + char waitForKey(); + bool keyStateChanged(); + byte numKeys(); + +private: + unsigned long startTime; + char *keymap; + byte *rowPins; + byte *columnPins; + KeypadSize sizeKpd; + uint debounceTime; + uint holdTime; + bool single_key; + + void scanKeys(); + bool updateList(); + void nextKeyState(byte n, boolean button); + void transitionTo(byte n, KeyState nextState); + void (*keypadEventListener)(char); +}; + +#endif + +/* +|| @changelog +|| | 3.1 2013-01-15 - Mark Stanley : Fixed missing RELEASED & IDLE status when using a single key. +|| | 3.0 2012-07-12 - Mark Stanley : Made library multi-keypress by default. (Backwards compatible) +|| | 3.0 2012-07-12 - Mark Stanley : Modified pin functions to support Keypad_I2C +|| | 3.0 2012-07-12 - Stanley & Young : Removed static variables. Fix for multiple keypad objects. +|| | 3.0 2012-07-12 - Mark Stanley : Fixed bug that caused shorted pins when pressing multiple keys. +|| | 2.0 2011-12-29 - Mark Stanley : Added waitForKey(). +|| | 2.0 2011-12-23 - Mark Stanley : Added the public function keyStateChanged(). +|| | 2.0 2011-12-23 - Mark Stanley : Added the private function scanKeys(). +|| | 2.0 2011-12-23 - Mark Stanley : Moved the Finite State Machine into the function getKeyState(). +|| | 2.0 2011-12-23 - Mark Stanley : Removed the member variable lastUdate. Not needed after rewrite. +|| | 1.8 2011-11-21 - Mark Stanley : Added test to determine which header file to compile, +|| | WProgram.h or Arduino.h. +|| | 1.8 2009-07-08 - Alexander Brevig : No longer uses arrays +|| | 1.7 2009-06-18 - Alexander Brevig : This library is a Finite State Machine every time a state changes +|| | the keypadEventListener will trigger, if set +|| | 1.7 2009-06-18 - Alexander Brevig : Added setDebounceTime setHoldTime specifies the amount of +|| | microseconds before a HOLD state triggers +|| | 1.7 2009-06-18 - Alexander Brevig : Added transitionTo +|| | 1.6 2009-06-15 - Alexander Brevig : Added getState() and state variable +|| | 1.5 2009-05-19 - Alexander Brevig : Added setHoldTime() +|| | 1.4 2009-05-15 - Alexander Brevig : Added addEventListener +|| | 1.3 2009-05-12 - Alexander Brevig : Added lastUdate, in order to do simple debouncing +|| | 1.2 2009-05-09 - Alexander Brevig : Changed getKey() +|| | 1.1 2009-04-28 - Alexander Brevig : Modified API, and made variables private +|| | 1.0 2007-XX-XX - Mark Stanley : Initial Release +|| # +*/ diff --git a/Keypad/examples/CustomKeypad/CustomKeypad.ino b/Keypad/examples/CustomKeypad/CustomKeypad.ino new file mode 100644 index 0000000..659c186 --- /dev/null +++ b/Keypad/examples/CustomKeypad/CustomKeypad.ino @@ -0,0 +1,37 @@ +/* @file CustomKeypad.pde +|| @version 1.0 +|| @author Alexander Brevig +|| @contact alexanderbrevig@gmail.com +|| +|| @description +|| | Demonstrates changing the keypad size and key values. +|| # +*/ +#include <Keypad.h> + +const byte ROWS = 4; //four rows +const byte COLS = 4; //four columns +//define the cymbols on the buttons of the keypads +char hexaKeys[ROWS][COLS] = { + {'0','1','2','3'}, + {'4','5','6','7'}, + {'8','9','A','B'}, + {'C','D','E','F'} +}; +byte rowPins[ROWS] = {3, 2, 1, 0}; //connect to the row pinouts of the keypad +byte colPins[COLS] = {7, 6, 5, 4}; //connect to the column pinouts of the keypad + +//initialize an instance of class NewKeypad +Keypad customKeypad = Keypad( makeKeymap(hexaKeys), rowPins, colPins, ROWS, COLS); + +void setup(){ + Serial.begin(9600); +} + +void loop(){ + char customKey = customKeypad.getKey(); + + if (customKey){ + Serial.println(customKey); + } +} diff --git a/Keypad/examples/DynamicKeypad/DynamicKeypad.ino b/Keypad/examples/DynamicKeypad/DynamicKeypad.ino new file mode 100644 index 0000000..530b523 --- /dev/null +++ b/Keypad/examples/DynamicKeypad/DynamicKeypad.ino @@ -0,0 +1,213 @@ +/* @file DynamicKeypad.pde +|| @version 1.2 +|| @author Mark Stanley +|| @contact mstanley@technologist.com +|| +|| 07/11/12 - Re-modified (from DynamicKeypadJoe2) to use direct-connect kpds +|| 02/28/12 - Modified to use I2C i/o G. D. (Joe) Young +|| +|| +|| @dificulty: Intermediate +|| +|| @description +|| | This is a demonstration of keypadEvents. It's used to switch between keymaps +|| | while using only one keypad. The main concepts being demonstrated are: +|| | +|| | Using the keypad events, PRESSED, HOLD and RELEASED to simplify coding. +|| | How to use setHoldTime() and why. +|| | Making more than one thing happen with the same key. +|| | Assigning and changing keymaps on the fly. +|| | +|| | Another useful feature is also included with this demonstration although +|| | it's not really one of the concepts that I wanted to show you. If you look +|| | at the code in the PRESSED event you will see that the first section of that +|| | code is used to scroll through three different letters on each key. For +|| | example, pressing the '2' key will step through the letters 'd', 'e' and 'f'. +|| | +|| | +|| | Using the keypad events, PRESSED, HOLD and RELEASED to simplify coding +|| | Very simply, the PRESSED event occurs imediately upon detecting a pressed +|| | key and will not happen again until after a RELEASED event. When the HOLD +|| | event fires it always falls between PRESSED and RELEASED. However, it will +|| | only occur if a key has been pressed for longer than the setHoldTime() interval. +|| | +|| | How to use setHoldTime() and why +|| | Take a look at keypad.setHoldTime(500) in the code. It is used to set the +|| | time delay between a PRESSED event and the start of a HOLD event. The value +|| | 500 is in milliseconds (mS) and is equivalent to half a second. After pressing +|| | a key for 500mS the HOLD event will fire and any code contained therein will be +|| | executed. This event will stay active for as long as you hold the key except +|| | in the case of bug #1 listed above. +|| | +|| | Making more than one thing happen with the same key. +|| | If you look under the PRESSED event (case PRESSED:) you will see that the '#' +|| | is used to print a new line, Serial.println(). But take a look at the first +|| | half of the HOLD event and you will see the same key being used to switch back +|| | and forth between the letter and number keymaps that were created with alphaKeys[4][5] +|| | and numberKeys[4][5] respectively. +|| | +|| | Assigning and changing keymaps on the fly +|| | You will see that the '#' key has been designated to perform two different functions +|| | depending on how long you hold it down. If you press the '#' key for less than the +|| | setHoldTime() then it will print a new line. However, if you hold if for longer +|| | than that it will switch back and forth between numbers and letters. You can see the +|| | keymap changes in the HOLD event. +|| | +|| | +|| | In addition... +|| | You might notice a couple of things that you won't find in the Arduino language +|| | reference. The first would be #include <ctype.h>. This is a standard library from +|| | the C programming language and though I don't normally demonstrate these types of +|| | things from outside the Arduino language reference I felt that its use here was +|| | justified by the simplicity that it brings to this sketch. +|| | That simplicity is provided by the two calls to isalpha(key) and isdigit(key). +|| | The first one is used to decide if the key that was pressed is any letter from a-z +|| | or A-Z and the second one decides if the key is any number from 0-9. The return +|| | value from these two functions is either a zero or some positive number greater +|| | than zero. This makes it very simple to test a key and see if it is a number or +|| | a letter. So when you see the following: +|| | +|| | if (isalpha(key)) // this tests to see if your key was a letter +|| | +|| | And the following may be more familiar to some but it is equivalent: +|| | +|| | if (isalpha(key) != 0) // this tests to see if your key was a letter +|| | +|| | And Finally... +|| | To better understand how the event handler affects your code you will need to remember +|| | that it gets called only when you press, hold or release a key. However, once a key +|| | is pressed or held then the event handler gets called at the full speed of the loop(). +|| | +|| # +*/ +#include <Keypad.h> +#include <ctype.h> + +const byte ROWS = 4; //four rows +const byte COLS = 3; //three columns +// Define the keymaps. The blank spot (lower left) is the space character. +char alphaKeys[ROWS][COLS] = { + { 'a','d','g' }, + { 'j','m','p' }, + { 's','v','y' }, + { ' ','.','#' } +}; + +char numberKeys[ROWS][COLS] = { + { '1','2','3' }, + { '4','5','6' }, + { '7','8','9' }, + { ' ','0','#' } +}; + +boolean alpha = false; // Start with the numeric keypad. + +byte rowPins[ROWS] = {5, 4, 3, 2}; //connect to the row pinouts of the keypad +byte colPins[COLS] = {8, 7, 6}; //connect to the column pinouts of the keypad + +// Create two new keypads, one is a number pad and the other is a letter pad. +Keypad numpad( makeKeymap(numberKeys), rowPins, colPins, sizeof(rowPins), sizeof(colPins) ); +Keypad ltrpad( makeKeymap(alphaKeys), rowPins, colPins, sizeof(rowPins), sizeof(colPins) ); + + +unsigned long startTime; +const byte ledPin = 13; // Use the LED on pin 13. + +void setup() { + Serial.begin(9600); + pinMode(ledPin, OUTPUT); + digitalWrite(ledPin, LOW); // Turns the LED on. + ltrpad.begin( makeKeymap(alphaKeys) ); + numpad.begin( makeKeymap(numberKeys) ); + ltrpad.addEventListener(keypadEvent_ltr); // Add an event listener. + ltrpad.setHoldTime(500); // Default is 1000mS + numpad.addEventListener(keypadEvent_num); // Add an event listener. + numpad.setHoldTime(500); // Default is 1000mS +} + +char key; + +void loop() { + + if( alpha ) + key = ltrpad.getKey( ); + else + key = numpad.getKey( ); + + if (alpha && millis()-startTime>100) { // Flash the LED if we are using the letter keymap. + digitalWrite(ledPin,!digitalRead(ledPin)); + startTime = millis(); + } +} + +static char virtKey = NO_KEY; // Stores the last virtual key press. (Alpha keys only) +static char physKey = NO_KEY; // Stores the last physical key press. (Alpha keys only) +static char buildStr[12]; +static byte buildCount; +static byte pressCount; + +static byte kpadState; + +// Take care of some special events. + +void keypadEvent_ltr(KeypadEvent key) { + // in here when in alpha mode. + kpadState = ltrpad.getState( ); + swOnState( key ); +} // end ltrs keypad events + +void keypadEvent_num( KeypadEvent key ) { + // in here when using number keypad + kpadState = numpad.getState( ); + swOnState( key ); +} // end numbers keypad events + +void swOnState( char key ) { + switch( kpadState ) { + case PRESSED: + if (isalpha(key)) { // This is a letter key so we're using the letter keymap. + if (physKey != key) { // New key so start with the first of 3 characters. + pressCount = 0; + virtKey = key; + physKey = key; + } + else { // Pressed the same key again... + virtKey++; // so select the next character on that key. + pressCount++; // Tracks how many times we press the same key. + } + if (pressCount > 2) { // Last character reached so cycle back to start. + pressCount = 0; + virtKey = key; + } + Serial.print(virtKey); // Used for testing. + } + if (isdigit(key) || key == ' ' || key == '.') + Serial.print(key); + if (key == '#') + Serial.println(); + break; + + case HOLD: + if (key == '#') { // Toggle between keymaps. + if (alpha == true) { // We are currently using a keymap with letters + alpha = false; // Now we want a keymap with numbers. + digitalWrite(ledPin, LOW); + } + else { // We are currently using a keymap with numbers + alpha = true; // Now we want a keymap with letters. + } + } + else { // Some key other than '#' was pressed. + buildStr[buildCount++] = (isalpha(key)) ? virtKey : key; + buildStr[buildCount] = '\0'; + Serial.println(); + Serial.println(buildStr); + } + break; + + case RELEASED: + if (buildCount >= sizeof(buildStr)) buildCount = 0; // Our string is full. Start fresh. + break; + } // end switch-case +}// end switch on state function + diff --git a/Keypad/examples/EventKeypad/EventKeypad.ino b/Keypad/examples/EventKeypad/EventKeypad.ino new file mode 100644 index 0000000..4c8d27e --- /dev/null +++ b/Keypad/examples/EventKeypad/EventKeypad.ino @@ -0,0 +1,73 @@ +/* @file EventSerialKeypad.pde + || @version 1.0 + || @author Alexander Brevig + || @contact alexanderbrevig@gmail.com + || + || @description + || | Demonstrates using the KeypadEvent. + || # + */ +#include <Keypad.h> + +const byte ROWS = 4; //four rows +const byte COLS = 3; //three columns +char keys[ROWS][COLS] = { + {'1','2','3'}, + {'4','5','6'}, + {'7','8','9'}, + {'*','0','#'} +}; + +byte rowPins[ROWS] = {5, 4, 3, 2}; //connect to the row pinouts of the keypad +byte colPins[COLS] = {8, 7, 6}; //connect to the column pinouts of the keypad + +Keypad keypad = Keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS ); +byte ledPin = 13; + +boolean blink = false; +boolean ledPin_state; + +void setup(){ + Serial.begin(9600); + pinMode(ledPin, OUTPUT); // Sets the digital pin as output. + digitalWrite(ledPin, HIGH); // Turn the LED on. + ledPin_state = digitalRead(ledPin); // Store initial LED state. HIGH when LED is on. + keypad.addEventListener(keypadEvent); // Add an event listener for this keypad +} + +void loop(){ + char key = keypad.getKey(); + + if (key) { + Serial.println(key); + } + if (blink){ + digitalWrite(ledPin,!digitalRead(ledPin)); // Change the ledPin from Hi2Lo or Lo2Hi. + delay(100); + } +} + +// Taking care of some special events. +void keypadEvent(KeypadEvent key){ + switch (keypad.getState()){ + case PRESSED: + if (key == '#') { + digitalWrite(ledPin,!digitalRead(ledPin)); + ledPin_state = digitalRead(ledPin); // Remember LED state, lit or unlit. + } + break; + + case RELEASED: + if (key == '*') { + digitalWrite(ledPin,ledPin_state); // Restore LED state from before it started blinking. + blink = false; + } + break; + + case HOLD: + if (key == '*') { + blink = true; // Blink the LED when holding the * key. + } + break; + } +} diff --git a/Keypad/examples/HelloKeypad/HelloKeypad.ino b/Keypad/examples/HelloKeypad/HelloKeypad.ino new file mode 100644 index 0000000..261f044 --- /dev/null +++ b/Keypad/examples/HelloKeypad/HelloKeypad.ino @@ -0,0 +1,35 @@ +/* @file HelloKeypad.pde +|| @version 1.0 +|| @author Alexander Brevig +|| @contact alexanderbrevig@gmail.com +|| +|| @description +|| | Demonstrates the simplest use of the matrix Keypad library. +|| # +*/ +#include <Keypad.h> + +const byte ROWS = 4; //four rows +const byte COLS = 3; //three columns +char keys[ROWS][COLS] = { + {'1','2','3'}, + {'4','5','6'}, + {'7','8','9'}, + {'*','0','#'} +}; +byte rowPins[ROWS] = {5, 4, 3, 2}; //connect to the row pinouts of the keypad +byte colPins[COLS] = {8, 7, 6}; //connect to the column pinouts of the keypad + +Keypad keypad = Keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS ); + +void setup(){ + Serial.begin(9600); +} + +void loop(){ + char key = keypad.getKey(); + + if (key){ + Serial.println(key); + } +} diff --git a/Keypad/examples/HelloKeypad3/HelloKeypad3.ino b/Keypad/examples/HelloKeypad3/HelloKeypad3.ino new file mode 100644 index 0000000..5605b72 --- /dev/null +++ b/Keypad/examples/HelloKeypad3/HelloKeypad3.ino @@ -0,0 +1,68 @@ +#include <Keypad.h> + + +const byte ROWS = 2; // use 4X4 keypad for both instances +const byte COLS = 2; +char keys[ROWS][COLS] = { + {'1','2'}, + {'3','4'} +}; +byte rowPins[ROWS] = {5, 4}; //connect to the row pinouts of the keypad +byte colPins[COLS] = {7, 6}; //connect to the column pinouts of the keypad +Keypad kpd( makeKeymap(keys), rowPins, colPins, ROWS, COLS ); + + +const byte ROWSR = 2; +const byte COLSR = 2; +char keysR[ROWSR][COLSR] = { + {'a','b'}, + {'c','d'} +}; +byte rowPinsR[ROWSR] = {3, 2}; //connect to the row pinouts of the keypad +byte colPinsR[COLSR] = {7, 6}; //connect to the column pinouts of the keypad +Keypad kpdR( makeKeymap(keysR), rowPinsR, colPinsR, ROWSR, COLSR ); + + +const byte ROWSUR = 4; +const byte COLSUR = 1; +char keysUR[ROWSUR][COLSUR] = { + {'M'}, + {'A'}, + {'R'}, + {'K'} +}; +// Digitran keypad, bit numbers of PCF8574 i/o port +byte rowPinsUR[ROWSUR] = {5, 4, 3, 2}; //connect to the row pinouts of the keypad +byte colPinsUR[COLSUR] = {8}; //connect to the column pinouts of the keypad + +Keypad kpdUR( makeKeymap(keysUR), rowPinsUR, colPinsUR, ROWSUR, COLSUR ); + + +void setup(){ +// Wire.begin( ); + kpdUR.begin( makeKeymap(keysUR) ); + kpdR.begin( makeKeymap(keysR) ); + kpd.begin( makeKeymap(keys) ); + Serial.begin(9600); + Serial.println( "start" ); +} + +//byte alternate = false; +char key, keyR, keyUR; +void loop(){ + +// alternate = !alternate; + key = kpd.getKey( ); + keyUR = kpdUR.getKey( ); + keyR = kpdR.getKey( ); + + if (key){ + Serial.println(key); + } + if( keyR ) { + Serial.println( keyR ); + } + if( keyUR ) { + Serial.println( keyUR ); + } +} diff --git a/Keypad/examples/MultiKey/MultiKey.ino b/Keypad/examples/MultiKey/MultiKey.ino new file mode 100644 index 0000000..850dc1a --- /dev/null +++ b/Keypad/examples/MultiKey/MultiKey.ino @@ -0,0 +1,78 @@ +/* @file MultiKey.ino +|| @version 1.0 +|| @author Mark Stanley +|| @contact mstanley@technologist.com +|| +|| @description +|| | The latest version, 3.0, of the keypad library supports up to 10 +|| | active keys all being pressed at the same time. This sketch is an +|| | example of how you can get multiple key presses from a keypad or +|| | keyboard. +|| # +*/ + +#include <Keypad.h> + +const byte ROWS = 4; //four rows +const byte COLS = 3; //three columns +char keys[ROWS][COLS] = { +{'1','2','3'}, +{'4','5','6'}, +{'7','8','9'}, +{'*','0','#'} +}; +byte rowPins[ROWS] = {5, 4, 3, 2}; //connect to the row pinouts of the kpd +byte colPins[COLS] = {8, 7, 6}; //connect to the column pinouts of the kpd + +Keypad kpd = Keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS ); + +unsigned long loopCount; +unsigned long startTime; +String msg; + + +void setup() { + Serial.begin(9600); + loopCount = 0; + startTime = millis(); + msg = ""; +} + + +void loop() { + loopCount++; + if ( (millis()-startTime)>5000 ) { + Serial.print("Average loops per second = "); + Serial.println(loopCount/5); + startTime = millis(); + loopCount = 0; + } + + // Fills kpd.key[ ] array with up-to 10 active keys. + // Returns true if there are ANY active keys. + if (kpd.getKeys()) + { + for (int i=0; i<LIST_MAX; i++) // Scan the whole key list. + { + if ( kpd.key[i].stateChanged ) // Only find keys that have changed state. + { + switch (kpd.key[i].kstate) { // Report active key state : IDLE, PRESSED, HOLD, or RELEASED + case PRESSED: + msg = " PRESSED."; + break; + case HOLD: + msg = " HOLD."; + break; + case RELEASED: + msg = " RELEASED."; + break; + case IDLE: + msg = " IDLE."; + } + Serial.print("Key "); + Serial.print(kpd.key[i].kchar); + Serial.println(msg); + } + } + } +} // End loop diff --git a/Keypad/examples/loopCounter/loopCounter.ino b/Keypad/examples/loopCounter/loopCounter.ino new file mode 100644 index 0000000..695e489 --- /dev/null +++ b/Keypad/examples/loopCounter/loopCounter.ino @@ -0,0 +1,46 @@ +#include <Keypad.h> + + +const byte ROWS = 4; //four rows +const byte COLS = 3; //three columns +char keys[ROWS][COLS] = { + {'1','2','3'}, + {'4','5','6'}, + {'7','8','9'}, + {'*','0','#'} +}; +byte rowPins[ROWS] = {5, 4, 3, 2}; //connect to the row pinouts of the keypad +byte colPins[COLS] = {8, 7, 6}; //connect to the column pinouts of the keypad + +Keypad kpd = Keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS ); + +unsigned long loopCount = 0; +unsigned long timer_t = 0; + +void setup(){ + Serial.begin(9600); + + // Try playing with different debounceTime settings to see how it affects + // the number of times per second your loop will run. The library prevents + // setting it to anything below 1 millisecond. + kpd.setDebounceTime(10); // setDebounceTime(mS) +} + +void loop(){ + char key = kpd.getKey(); + + // Report the number of times through the loop in 1 second. This will give + // you a relative idea of just how much the debounceTime has changed the + // speed of your code. If you set a high debounceTime your loopCount will + // look good but your keypresses will start to feel sluggish. + if ((millis() - timer_t) > 1000) { + Serial.print("Your loop code ran "); + Serial.print(loopCount); + Serial.println(" times over the last second"); + loopCount = 0; + timer_t = millis(); + } + loopCount++; + if(key) + Serial.println(key); +} diff --git a/Keypad/keywords.txt b/Keypad/keywords.txt new file mode 100644 index 0000000..e400940 --- /dev/null +++ b/Keypad/keywords.txt @@ -0,0 +1,38 @@ +# Keypad Library data types +KeyState KEYWORD1 +Keypad KEYWORD1 +KeypadEvent KEYWORD1 + +# Keypad Library constants +NO_KEY LITERAL1 +IDLE LITERAL1 +PRESSED LITERAL1 +HOLD LITERAL1 +RELEASED LITERAL1 + +# Keypad Library methods & functions +addEventListener KEYWORD2 +bitMap KEYWORD2 +findKeyInList KEYWORD2 +getKey KEYWORD2 +getKeys KEYWORD2 +getState KEYWORD2 +holdTimer KEYWORD2 +isPressed KEYWORD2 +keyStateChanged KEYWORD2 +numKeys KEYWORD2 +pin_mode KEYWORD2 +pin_write KEYWORD2 +pin_read KEYWORD2 +setDebounceTime KEYWORD2 +setHoldTime KEYWORD2 +waitForKey KEYWORD2 + +# this is a macro that converts 2d arrays to pointers +makeKeymap KEYWORD2 + +# List of objects created in the example sketches. +kpd KEYWORD3 +keypad KEYWORD3 +kbrd KEYWORD3 +keyboard KEYWORD3 diff --git a/Keypad/utility/Key.cpp b/Keypad/utility/Key.cpp new file mode 100644 index 0000000..4c9718d --- /dev/null +++ b/Keypad/utility/Key.cpp @@ -0,0 +1,61 @@ +/* +|| @file Key.cpp +|| @version 1.0 +|| @author Mark Stanley +|| @contact mstanley@technologist.com +|| +|| @description +|| | Key class provides an abstract definition of a key or button +|| | and was initially designed to be used in conjunction with a +|| | state-machine. +|| # +|| +|| @license +|| | This library is free software; you can redistribute it and/or +|| | modify it under the terms of the GNU Lesser General Public +|| | License as published by the Free Software Foundation; version +|| | 2.1 of the License. +|| | +|| | This library is distributed in the hope that it will be useful, +|| | but WITHOUT ANY WARRANTY; without even the implied warranty of +|| | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +|| | Lesser General Public License for more details. +|| | +|| | You should have received a copy of the GNU Lesser General Public +|| | License along with this library; if not, write to the Free Software +|| | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +|| # +|| +*/ +#include <Key.h> + + +// default constructor +Key::Key() { + kchar = NO_KEY; + kstate = IDLE; + stateChanged = false; +} + +// constructor +Key::Key(char userKeyChar) { + kchar = userKeyChar; + kcode = -1; + kstate = IDLE; + stateChanged = false; +} + + +void Key::key_update (char userKeyChar, KeyState userState, boolean userStatus) { + kchar = userKeyChar; + kstate = userState; + stateChanged = userStatus; +} + + + +/* +|| @changelog +|| | 1.0 2012-06-04 - Mark Stanley : Initial Release +|| # +*/ diff --git a/Keypad/utility/Key.h b/Keypad/utility/Key.h new file mode 100644 index 0000000..140f8da --- /dev/null +++ b/Keypad/utility/Key.h @@ -0,0 +1,73 @@ +/* +|| +|| @file Key.h +|| @version 1.0 +|| @author Mark Stanley +|| @contact mstanley@technologist.com +|| +|| @description +|| | Key class provides an abstract definition of a key or button +|| | and was initially designed to be used in conjunction with a +|| | state-machine. +|| # +|| +|| @license +|| | This library is free software; you can redistribute it and/or +|| | modify it under the terms of the GNU Lesser General Public +|| | License as published by the Free Software Foundation; version +|| | 2.1 of the License. +|| | +|| | This library is distributed in the hope that it will be useful, +|| | but WITHOUT ANY WARRANTY; without even the implied warranty of +|| | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +|| | Lesser General Public License for more details. +|| | +|| | You should have received a copy of the GNU Lesser General Public +|| | License along with this library; if not, write to the Free Software +|| | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +|| # +|| +*/ + +#ifndef KEY_H +#define KEY_H + +// Arduino versioning. +#if defined(ARDUINO) && ARDUINO >= 100 +#include "Arduino.h" // for digitalRead, digitalWrite, etc +#else +#include "WProgram.h" +#endif + +#define OPEN LOW +#define CLOSED HIGH + +typedef unsigned int uint; +typedef enum{ IDLE, PRESSED, HOLD, RELEASED } KeyState; + +const char NO_KEY = '\0'; + +class Key { +public: + // members + char kchar; + int kcode; + KeyState kstate; + boolean stateChanged; + + // methods + Key(); + Key(char userKeyChar); + void key_update(char userKeyChar, KeyState userState, boolean userStatus); + +private: + +}; + +#endif + +/* +|| @changelog +|| | 1.0 2012-06-04 - Mark Stanley : Initial Release +|| # +*/ diff --git a/Password/Examples/HelloPassword/HelloPassword.pde b/Password/Examples/HelloPassword/HelloPassword.pde new file mode 100644 index 0000000..80b46da --- /dev/null +++ b/Password/Examples/HelloPassword/HelloPassword.pde @@ -0,0 +1,35 @@ +/* +|| +|| @file HelloPassword.pde +|| @version 1.0 +|| @author Alexander Brevig +|| @contact alexanderbrevig@gmail.com +|| +|| @description +|| | A demonstration of the simple API of the Password library +|| # +|| +*/ + +//http://www.arduino.cc/playground/uploads/Code/Password.zip +#include <Password.h> + +Password password = Password( "1234" ); + +void setup(){ + Serial.begin(9600); + + password.append('1'); //add 1 to the guessed password + password.append('2'); //add 2 to the guessed password + password << '3' << '4'; //add 3 and 4 to the guessed password + Serial.println( password.evaluate() ? "true":"false" ); //should print true, since 1234 == 1234 + + password.reset(); //reset the guessed password to NULL + Serial.println( password.evaluate() ? "true":"false" ); //should print false, since 1234 != NULL + + password.set("qwerty"); //set target password to qwerty + Serial.println( password.is("qwerty") ? "true":"false" ); //should print true, since qwerty == qwerty + Serial.println( password == "qwirty" ? "true":"false" ); //should print false, since qwerty != qwirty +} + +void loop(){/*nothing to loop*/} \ No newline at end of file diff --git a/Password/Examples/PasswordKeypad/PasswordKeypad.pde b/Password/Examples/PasswordKeypad/PasswordKeypad.pde new file mode 100644 index 0000000..47a856b --- /dev/null +++ b/Password/Examples/PasswordKeypad/PasswordKeypad.pde @@ -0,0 +1,67 @@ +/* +|| Simple Password Entry Using Matrix Keypad +|| 4/5/2012 Updates Nathan Sobieck: Nathan@Sobisource.com +|| +*/ + + +//* is to validate password +//# is to reset password attempt + +///////////////////////////////////////////////////////////////// + +#include <Password.h> //http://www.arduino.cc/playground/uploads/Code/Password.zip +#include <Keypad.h> //http://www.arduino.cc/playground/uploads/Code/Keypad.zip + +Password password = Password( "1234" ); + +const byte ROWS = 4; // Four rows +const byte COLS = 4; // columns +// Define the Keymap +char keys[ROWS][COLS] = { + {'1','2','3','A'}, + {'4','5','6','B'}, + {'7','8','9','C'}, + {'*','0','#','D'} +}; + +byte rowPins[ROWS] = { 9,8,7,6 };// Connect keypad ROW0, ROW1, ROW2 and ROW3 to these Arduino pins. +byte colPins[COLS] = { 5,4,3,2, };// Connect keypad COL0, COL1 and COL2 to these Arduino pins. + + +// Create the Keypad +Keypad keypad = Keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS ); + +void setup(){ + + Serial.begin(9600); + keypad.addEventListener(keypadEvent); //add an event listener for this keypad +} + +void loop(){ + keypad.getKey(); +} + +//take care of some special events +void keypadEvent(KeypadEvent eKey){ + switch (keypad.getState()){ + case PRESSED: + Serial.print("Pressed: "); + Serial.println(eKey); + switch (eKey){ + case '*': checkPassword(); break; + case '#': password.reset(); break; + default: password.append(eKey); + } + } +} + +void checkPassword(){ + if (password.evaluate()){ + Serial.println("Success"); + //Add code to run if it works + }else{ + Serial.println("Wrong"); + //add code to run if it did not work + } +} \ No newline at end of file diff --git a/Password/Examples/SerialMonitor/SerialMonitor.pde b/Password/Examples/SerialMonitor/SerialMonitor.pde new file mode 100644 index 0000000..ac29231 --- /dev/null +++ b/Password/Examples/SerialMonitor/SerialMonitor.pde @@ -0,0 +1,56 @@ +/* +|| +|| @file SerialMonitor.pde +|| @version 1.1 +|| @author Alexander Brevig +|| @contact alexanderbrevig@gmail.com +|| +|| @description +|| | A simple password application that uses the serial monitor as input source. +|| # +|| +*/ + +//http://www.arduino.cc/playground/uploads/Code/Password.zip +#include <Password.h> + +Password password = Password( "1234" ); + +byte currentLength = 0; + +void setup(){ + Serial.begin(9600); + Serial.println("Try to guess the password!"); + Serial.println("Reset with ! evaluate with ?"); + Serial.print("Enter password: "); +} + +void loop(){ + if (Serial.available()){ + char input = Serial.read(); + switch (input){ + case '!': //reset password + password.reset(); + currentLength = 0; + Serial.println("\tPassword is reset!"); + break; + case '?': //evaluate password + if (password.evaluate()){ + Serial.println("\tYou guessed the correct password!"); + }else{ + Serial.println("\tYou did not guess the correct password!"); + } + break; + default: //append any keypress that is not a '!' nor a '?' to the currently guessed password. + password << input; + currentLength++; + + //Print some feedback. + Serial.print("Enter password: "); + for (byte i=0; i<currentLength; i++){ + Serial.print('*'); + } + Serial.println(); + } + } +} diff --git a/Password/Password.cpp b/Password/Password.cpp new file mode 100644 index 0000000..8412afe --- /dev/null +++ b/Password/Password.cpp @@ -0,0 +1,120 @@ +/* +|| +|| @file Password.cpp +|| @version 1.2 +|| @author Alexander Brevig +|| @contact alexanderbrevig@gmail.com +|| +|| 4/5/2012 Updates Nathan Sobieck: Nathan@Sobisource.com +|| Now v1.2 Arduino IDE v1.0 With BAckwards compatibility +|| +|| @description +|| | Handle passwords easily +|| # +|| +|| @license +|| | This library is free software; you can redistribute it and/or +|| | modify it under the terms of the GNU Lesser General Public +|| | License as published by the Free Software Foundation; version +|| | 2.1 of the License. +|| | +|| | This library is distributed in the hope that it will be useful, +|| | but WITHOUT ANY WARRANTY; without even the implied warranty of +|| | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +|| | Lesser General Public License for more details. +|| | +|| | You should have received a copy of the GNU Lesser General Public +|| | License along with this library; if not, write to the Free Software +|| | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +|| # +|| +*/ + +#include "Password.h" + +//construct object in memory, set all variables +Password::Password(char* pass){ + set( pass ); + reset(); +} + +//set the password +void Password::set(char* pass){ + target = pass; +} + +//evaluate a string, is it equal to the password? +bool Password::is(char* pass){ + byte i=0; + while (*pass && i<MAX_PASSWORD_LENGTH){ + guess[i] = pass[i]; + i++; + } + return evaluate(); +} + +//append a char to the guessed password +bool Password::append(char character){ + if (currentIndex+1==MAX_PASSWORD_LENGTH){ + return false; + }else{ + guess[currentIndex++] = character; + guess[currentIndex] = STRING_TERMINATOR; //ensure a valid c string + } + return true; +} + +//reset the guessed password, one can guess again +void Password::reset(){ + currentIndex = 0; + guess[currentIndex] = STRING_TERMINATOR; +} + +//is the current guessed password equal to the target password? +bool Password::evaluate(){ + char pass = target[0]; + char guessed = guess[0]; + for (byte i=1; i<MAX_PASSWORD_LENGTH; i++){ + + //check if guessed char is equal to the password char + if (pass==STRING_TERMINATOR && guessed==STRING_TERMINATOR){ + return true; //both strings ended and all previous characters are equal + }else if (pass!=guessed || pass==STRING_TERMINATOR || guessed==STRING_TERMINATOR){ + return false; //difference OR end of string has been reached + } + + //read next char + pass = target[i]; + guessed = guess[i]; + } + return false; //a 'true' condition has not been met +} + +//set password using operator = +Password &Password::operator=(char* pass){ + set( pass ); + return *this; +} + +//test password using == +bool Password::operator==(char* pass){ + return is( pass ); +} + +//test password using != +bool Password::operator!=(char* pass){ + return !is( pass ); +} + +//append to currently guessed password using operator << +Password &Password::operator<<(char character){ + append( character ); + return *this; +} + +/* +|| @changelog +|| | 2009-06-17 - Alexander Brevig : Added assignment operator =, equality operators == != and insertion operator << +|| | 2009-06-17 - Alexander Brevig : Initial Release +|| # +*/ \ No newline at end of file diff --git a/Password/Password.h b/Password/Password.h new file mode 100644 index 0000000..e7533be --- /dev/null +++ b/Password/Password.h @@ -0,0 +1,81 @@ +/* +|| +|| @file Password.h +|| @version 1.2 +|| @author Alexander Brevig +|| @contact alexanderbrevig@gmail.com +|| +|| 4/5/2012 Updates Nathan Sobieck: Nathan@Sobisource.com +|| Now v1.2 Arduino IDE v1.0 With BAckwards compatibility +|| +|| +|| +|| @description +|| | Handle passwords easily +|| # +|| +|| @license +|| | This library is free software; you can redistribute it and/or +|| | modify it under the terms of the GNU Lesser General Public +|| | License as published by the Free Software Foundation; version +|| | 2.1 of the License. +|| | +|| | This library is distributed in the hope that it will be useful, +|| | but WITHOUT ANY WARRANTY; without even the implied warranty of +|| | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +|| | Lesser General Public License for more details. +|| | +|| | You should have received a copy of the GNU Lesser General Public +|| | License along with this library; if not, write to the Free Software +|| | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +|| # +|| +*/ + +#ifndef PASSWORD_H +#define PASSWORD_H + +// Arduino versioning. +#if defined(ARDUINO) && ARDUINO >= 100 +#include "Arduino.h" // for digitalRead, digitalWrite, etc +#else +#include "WProgram.h" +#endif + +#define MAX_PASSWORD_LENGTH 20 + +#define STRING_TERMINATOR '\0' + +class Password { +public: + Password(char* pass); + + void set(char* pass); + bool is(char* pass); + bool append(char character); + void reset(); + bool evaluate(); + + //char* getPassword(); + //char* getGuess(); + + //operators + Password &operator=(char* pass); + bool operator==(char* pass); + bool operator!=(char* pass); + Password &operator<<(char character); + +private: + char* target; + char guess[ MAX_PASSWORD_LENGTH ]; + byte currentIndex; +}; + +#endif + +/* +|| @changelog +|| | 1.1 2009-06-17 - Alexander Brevig : Added assignment operator =, equality operators == != and insertion operator << +|| | 1.0 2009-06-17 - Alexander Brevig : Initial Release +|| # +*/ \ No newline at end of file diff --git a/Password/keywords.txt b/Password/keywords.txt new file mode 100644 index 0000000..b7cd72f --- /dev/null +++ b/Password/keywords.txt @@ -0,0 +1,6 @@ +Password KEYWORD1 +set KEYWORD2 +is KEYWORD2 +append KEYWORD2 +reset KEYWORD2 +evaluate KEYWORD2 \ No newline at end of file diff --git a/RFID/RFID.cpp b/RFID/RFID.cpp new file mode 100644 index 0000000..84d5e8c --- /dev/null +++ b/RFID/RFID.cpp @@ -0,0 +1,485 @@ +/* + * RFID.cpp - Library to use ARDUINO RFID MODULE KIT 13.56 MHZ WITH TAGS SPI W AND R BY COOQROBOT. + * Based on code Dr.Leong ( WWW.B2CQSHOP.COM ) + * Created by Miguel Balboa, Jan, 2012. + * Released into the public domain. + */ + +/****************************************************************************** + * Includes + ******************************************************************************/ +#include <Arduino.h> +#include <RFID.h> + +/****************************************************************************** + * User API + ******************************************************************************/ + +/** + * Construct RFID + * int chipSelectPin RFID /ENABLE pin + */ +RFID::RFID(int chipSelectPin, int NRSTPD) +{ + _chipSelectPin = chipSelectPin; + + pinMode(_chipSelectPin,OUTPUT); // Set digital as OUTPUT to connect it to the RFID /ENABLE pin + digitalWrite(_chipSelectPin, LOW); + + + pinMode(NRSTPD,OUTPUT); // Set digital pin, Not Reset and Power-down + digitalWrite(NRSTPD, HIGH); + _NRSTPD = NRSTPD; +} +/****************************************************************************** + * User API + ******************************************************************************/ + + bool RFID::isCard() + { + unsigned char status; + unsigned char str[MAX_LEN]; + + status = MFRC522Request(PICC_REQIDL, str); + if (status == MI_OK) { + return true; + } else { + return false; + } + } + + bool RFID::readCardSerial(){ + + unsigned char status; + unsigned char str[MAX_LEN]; + + // Anti-colisión, devuelva el número de serie de tarjeta de 4 bytes + status = anticoll(str); + memcpy(serNum, str, 5); + + if (status == MI_OK) { + return true; + } else { + return false; + } + + } + +/****************************************************************************** + * Dr.Leong ( WWW.B2CQSHOP.COM ) + ******************************************************************************/ + +void RFID::init() +{ + digitalWrite(_NRSTPD,HIGH); + + reset(); + + //Timer: TPrescaler*TreloadVal/6.78MHz = 24ms + writeMFRC522(TModeReg, 0x8D); //Tauto=1; f(Timer) = 6.78MHz/TPreScaler + writeMFRC522(TPrescalerReg, 0x3E); //TModeReg[3..0] + TPrescalerReg + writeMFRC522(TReloadRegL, 30); + writeMFRC522(TReloadRegH, 0); + + writeMFRC522(TxAutoReg, 0x40); //100%ASK + writeMFRC522(ModeReg, 0x3D); // CRC valor inicial de 0x6363 + + //ClearBitMask(Status2Reg, 0x08); //MFCrypto1On=0 + //writeMFRC522(RxSelReg, 0x86); //RxWait = RxSelReg[5..0] + //writeMFRC522(RFCfgReg, 0x7F); //RxGain = 48dB + + antennaOn(); //Abre la antena + + +} +void RFID::reset() +{ + writeMFRC522(CommandReg, PCD_RESETPHASE); +} + +void RFID::writeMFRC522(unsigned char addr, unsigned char val) +{ + digitalWrite(_chipSelectPin, LOW); + + //0XXXXXX0 formato de dirección + SPI.transfer((addr<<1)&0x7E); + SPI.transfer(val); + + digitalWrite(_chipSelectPin, HIGH); +} + +void RFID::antennaOn(void) +{ + unsigned char temp; + + temp = readMFRC522(TxControlReg); + if (!(temp & 0x03)) + { + setBitMask(TxControlReg, 0x03); + } +} + +/* + * Read_MFRC522 Nombre de la función: Read_MFRC522 + * Descripción: Desde el MFRC522 leer un byte de un registro de datos + * Los parámetros de entrada: addr - la dirección de registro + * Valor de retorno: Devuelve un byte de datos de lectura + */ +unsigned char RFID::readMFRC522(unsigned char addr) +{ + unsigned char val; + digitalWrite(_chipSelectPin, LOW); + SPI.transfer(((addr<<1)&0x7E) | 0x80); + val =SPI.transfer(0x00); + digitalWrite(_chipSelectPin, HIGH); + return val; +} + +void RFID::setBitMask(unsigned char reg, unsigned char mask) +{ + unsigned char tmp; + tmp = readMFRC522(reg); + writeMFRC522(reg, tmp | mask); // set bit mask +} + +void RFID::clearBitMask(unsigned char reg, unsigned char mask) +{ + unsigned char tmp; + tmp = readMFRC522(reg); + writeMFRC522(reg, tmp & (~mask)); // clear bit mask +} + +void RFID::calculateCRC(unsigned char *pIndata, unsigned char len, unsigned char *pOutData) +{ + unsigned char i, n; + + clearBitMask(DivIrqReg, 0x04); //CRCIrq = 0 + setBitMask(FIFOLevelReg, 0x80); //Claro puntero FIFO + //Write_MFRC522(CommandReg, PCD_IDLE); + + //Escribir datos en el FIFO + for (i=0; i<len; i++) + { + writeMFRC522(FIFODataReg, *(pIndata+i)); + } + writeMFRC522(CommandReg, PCD_CALCCRC); + + // Esperar a la finalización de cálculo del CRC + i = 0xFF; + do + { + n = readMFRC522(DivIrqReg); + i--; + } + while ((i!=0) && !(n&0x04)); //CRCIrq = 1 + + //Lea el cálculo de CRC + pOutData[0] = readMFRC522(CRCResultRegL); + pOutData[1] = readMFRC522(CRCResultRegM); +} + +unsigned char RFID::MFRC522ToCard(unsigned char command, unsigned char *sendData, unsigned char sendLen, unsigned char *backData, unsigned int *backLen) +{ + unsigned char status = MI_ERR; + unsigned char irqEn = 0x00; + unsigned char waitIRq = 0x00; + unsigned char lastBits; + unsigned char n; + unsigned int i; + + switch (command) + { + case PCD_AUTHENT: // Tarjetas de certificación cerca + { + irqEn = 0x12; + waitIRq = 0x10; + break; + } + case PCD_TRANSCEIVE: //La transmisión de datos FIFO + { + irqEn = 0x77; + waitIRq = 0x30; + break; + } + default: + break; + } + + writeMFRC522(CommIEnReg, irqEn|0x80); //De solicitud de interrupción + clearBitMask(CommIrqReg, 0x80); // Borrar todos los bits de petición de interrupción + setBitMask(FIFOLevelReg, 0x80); //FlushBuffer=1, FIFO de inicialización + + writeMFRC522(CommandReg, PCD_IDLE); //NO action;Y cancelar el comando + + //Escribir datos en el FIFO + for (i=0; i<sendLen; i++) + { + writeMFRC522(FIFODataReg, sendData[i]); + } + + //???? ejecutar el comando + writeMFRC522(CommandReg, command); + if (command == PCD_TRANSCEIVE) + { + setBitMask(BitFramingReg, 0x80); //StartSend=1,transmission of data starts + } + + // A la espera de recibir datos para completar + i = 2000; //i????????,??M1???????25ms ??? i De acuerdo con el ajuste de frecuencia de reloj, el tiempo máximo de espera operación M1 25ms tarjeta?? + do + { + //CommIrqReg[7..0] + //Set1 TxIRq RxIRq IdleIRq HiAlerIRq LoAlertIRq ErrIRq TimerIRq + n = readMFRC522(CommIrqReg); + i--; + } + while ((i!=0) && !(n&0x01) && !(n&waitIRq)); + + clearBitMask(BitFramingReg, 0x80); //StartSend=0 + + if (i != 0) + { + if(!(readMFRC522(ErrorReg) & 0x1B)) //BufferOvfl Collerr CRCErr ProtecolErr + { + status = MI_OK; + if (n & irqEn & 0x01) + { + status = MI_NOTAGERR; //?? + } + + if (command == PCD_TRANSCEIVE) + { + n = readMFRC522(FIFOLevelReg); + lastBits = readMFRC522(ControlReg) & 0x07; + if (lastBits) + { + *backLen = (n-1)*8 + lastBits; + } + else + { + *backLen = n*8; + } + + if (n == 0) + { + n = 1; + } + if (n > MAX_LEN) + { + n = MAX_LEN; + } + + //??FIFO??????? Lea los datos recibidos en el FIFO + for (i=0; i<n; i++) + { + backData[i] = readMFRC522(FIFODataReg); + } + } + } + else + { + status = MI_ERR; + } + + } + + //SetBitMask(ControlReg,0x80); //timer stops + //Write_MFRC522(CommandReg, PCD_IDLE); + + return status; +} + + +/* + * Nombre de la función: MFRC522_Request + * Descripción: Buscar las cartas, leer el número de tipo de tarjeta + * Los parámetros de entrada: reqMode - encontrar el modo de tarjeta, + * Tagtype - Devuelve el tipo de tarjeta + * 0x4400 = Mifare_UltraLight + * 0x0400 = Mifare_One(S50) + * 0x0200 = Mifare_One(S70) + * 0x0800 = Mifare_Pro(X) + * 0x4403 = Mifare_DESFire + * Valor de retorno: el retorno exitoso MI_OK + */ +unsigned char RFID::MFRC522Request(unsigned char reqMode, unsigned char *TagType) +{ + unsigned char status; + unsigned int backBits; // Recibió bits de datos + + writeMFRC522(BitFramingReg, 0x07); //TxLastBists = BitFramingReg[2..0] ??? + + TagType[0] = reqMode; + status = MFRC522ToCard(PCD_TRANSCEIVE, TagType, 1, TagType, &backBits); + + if ((status != MI_OK) || (backBits != 0x10)) + { + status = MI_ERR; + } + + return status; +} + +/** + * MFRC522Anticoll -> anticoll + * Anti-detección de colisiones, la lectura del número de serie de la tarjeta de tarjeta + * @param serNum - devuelve el número de tarjeta 4 bytes de serie, los primeros 5 bytes de bytes de paridad + * @return retorno exitoso MI_OK + */ +unsigned char RFID::anticoll(unsigned char *serNum) +{ + unsigned char status; + unsigned char i; + unsigned char serNumCheck=0; + unsigned int unLen; + + + //ClearBitMask(Status2Reg, 0x08); //TempSensclear + //ClearBitMask(CollReg,0x80); //ValuesAfterColl + writeMFRC522(BitFramingReg, 0x00); //TxLastBists = BitFramingReg[2..0] + + serNum[0] = PICC_ANTICOLL; + serNum[1] = 0x20; + status = MFRC522ToCard(PCD_TRANSCEIVE, serNum, 2, serNum, &unLen); + + if (status == MI_OK) + { + //?????? Compruebe el número de serie de la tarjeta + for (i=0; i<4; i++) + { + serNumCheck ^= serNum[i]; + } + if (serNumCheck != serNum[i]) + { + status = MI_ERR; + } + } + + //SetBitMask(CollReg, 0x80); //ValuesAfterColl=1 + + return status; +} + +/* + * MFRC522Auth -> auth + * Verificar la contraseña de la tarjeta + * Los parámetros de entrada: AuthMode - Modo de autenticación de contraseña + 0x60 = A 0x60 = validación KeyA + 0x61 = B 0x61 = validación KeyB + BlockAddr-- bloque de direcciones + Sectorkey-- sector contraseña + serNum--,4? Tarjeta de número de serie, 4 bytes + * MI_OK Valor de retorno: el retorno exitoso MI_OK + */ +unsigned char RFID::auth(unsigned char authMode, unsigned char BlockAddr, unsigned char *Sectorkey, unsigned char *serNum) +{ + unsigned char status; + unsigned int recvBits; + unsigned char i; + unsigned char buff[12]; + + //????+???+????+???? Verifique la dirección de comandos de bloques del sector + + contraseña + número de la tarjeta de serie + buff[0] = authMode; + buff[1] = BlockAddr; + for (i=0; i<6; i++) + { + buff[i+2] = *(Sectorkey+i); + } + for (i=0; i<4; i++) + { + buff[i+8] = *(serNum+i); + } + status = MFRC522ToCard(PCD_AUTHENT, buff, 12, buff, &recvBits); + + if ((status != MI_OK) || (!(readMFRC522(Status2Reg) & 0x08))) + { + status = MI_ERR; + } + + return status; +} + +/* + * MFRC522Read -> read + * Lectura de datos de bloque + * Los parámetros de entrada: blockAddr - dirección del bloque; recvData - leer un bloque de datos + * MI_OK Valor de retorno: el retorno exitoso MI_OK + */ +unsigned char RFID::read(unsigned char blockAddr, unsigned char *recvData) +{ + unsigned char status; + unsigned int unLen; + + recvData[0] = PICC_READ; + recvData[1] = blockAddr; + calculateCRC(recvData,2, &recvData[2]); + status = MFRC522ToCard(PCD_TRANSCEIVE, recvData, 4, recvData, &unLen); + + if ((status != MI_OK) || (unLen != 0x90)) + { + status = MI_ERR; + } + + return status; +} + +/* + * MFRC522Write -> write + * La escritura de datos de bloque + * blockAddr - dirección del bloque; WriteData - para escribir 16 bytes del bloque de datos + * Valor de retorno: el retorno exitoso MI_OK + */ +unsigned char RFID::write(unsigned char blockAddr, unsigned char *writeData) +{ + unsigned char status; + unsigned int recvBits; + unsigned char i; + unsigned char buff[18]; + + buff[0] = PICC_WRITE; + buff[1] = blockAddr; + calculateCRC(buff, 2, &buff[2]); + status = MFRC522ToCard(PCD_TRANSCEIVE, buff, 4, buff, &recvBits); + + if ((status != MI_OK) || (recvBits != 4) || ((buff[0] & 0x0F) != 0x0A)) + { + status = MI_ERR; + } + + if (status == MI_OK) + { + for (i=0; i<16; i++) //?FIFO?16Byte?? Datos a la FIFO 16Byte escribir + { + buff[i] = *(writeData+i); + } + calculateCRC(buff, 16, &buff[16]); + status = MFRC522ToCard(PCD_TRANSCEIVE, buff, 18, buff, &recvBits); + + if ((status != MI_OK) || (recvBits != 4) || ((buff[0] & 0x0F) != 0x0A)) + { + status = MI_ERR; + } + } + + return status; +} + + +/* + * MFRC522Halt -> halt + * Cartas de Mando para dormir + * Los parámetros de entrada: Ninguno + * Valor devuelto: Ninguno + */ +void RFID::halt() +{ + unsigned char status; + unsigned int unLen; + unsigned char buff[4]; + + buff[0] = PICC_HALT; + buff[1] = 0; + calculateCRC(buff, 2, &buff[2]); + + status = MFRC522ToCard(PCD_TRANSCEIVE, buff, 4, buff,&unLen); +} \ No newline at end of file diff --git a/RFID/RFID.h b/RFID/RFID.h new file mode 100644 index 0000000..a30ac32 --- /dev/null +++ b/RFID/RFID.h @@ -0,0 +1,151 @@ +/* RFID.h - Library to use ARDUINO RFID MODULE KIT 13.56 MHZ WITH TAGS SPI W AND R BY COOQROBOT. + * Based on code Dr.Leong ( WWW.B2CQSHOP.COM ) + * Created by Miguel Balboa (circuitito.com), Jan, 2012. + */ +#ifndef RFID_h +#define RFID_h + +#include <Arduino.h> +#include <SPI.h> + + + +/****************************************************************************** + * Definitions + ******************************************************************************/ +#define MAX_LEN 16 // Largo máximo de la matriz + +//MF522 comando palabra +#define PCD_IDLE 0x00 // NO action; Y cancelar el comando +#define PCD_AUTHENT 0x0E // autenticación de clave +#define PCD_RECEIVE 0x08 // recepción de datos +#define PCD_TRANSMIT 0x04 // Enviar datos +#define PCD_TRANSCEIVE 0x0C // Enviar y recibir datos +#define PCD_RESETPHASE 0x0F // reajustar +#define PCD_CALCCRC 0x03 // CRC calcular + +//Mifare_One Tarjeta Mifare_One comando palabra +#define PICC_REQIDL 0x26 // Área de la antena no está tratando de entrar en el estado de reposo +#define PICC_REQALL 0x52 // Todas las cartas para encontrar el área de la antena +#define PICC_ANTICOLL 0x93 // anti-colisión +#define PICC_SElECTTAG 0x93 // elección de tarjeta +#define PICC_AUTHENT1A 0x60 // verificación key A +#define PICC_AUTHENT1B 0x61 // verificación Key B +#define PICC_READ 0x30 // leer bloque +#define PICC_WRITE 0xA0 // Escribir en el bloque +#define PICC_DECREMENT 0xC0 // cargo +#define PICC_INCREMENT 0xC1 // recargar +#define PICC_RESTORE 0xC2 // Transferencia de datos de bloque de buffer +#define PICC_TRANSFER 0xB0 // Guardar los datos en el búfer +#define PICC_HALT 0x50 // inactividad + +//MF522 Código de error de comunicación cuando regresó +#define MI_OK 0 +#define MI_NOTAGERR 1 +#define MI_ERR 2 + +//------------------ MFRC522 registro--------------- +//Page 0:Command and Status +#define Reserved00 0x00 +#define CommandReg 0x01 +#define CommIEnReg 0x02 +#define DivlEnReg 0x03 +#define CommIrqReg 0x04 +#define DivIrqReg 0x05 +#define ErrorReg 0x06 +#define Status1Reg 0x07 +#define Status2Reg 0x08 +#define FIFODataReg 0x09 +#define FIFOLevelReg 0x0A +#define WaterLevelReg 0x0B +#define ControlReg 0x0C +#define BitFramingReg 0x0D +#define CollReg 0x0E +#define Reserved01 0x0F +//Page 1:Command +#define Reserved10 0x10 +#define ModeReg 0x11 +#define TxModeReg 0x12 +#define RxModeReg 0x13 +#define TxControlReg 0x14 +#define TxAutoReg 0x15 +#define TxSelReg 0x16 +#define RxSelReg 0x17 +#define RxThresholdReg 0x18 +#define DemodReg 0x19 +#define Reserved11 0x1A +#define Reserved12 0x1B +#define MifareReg 0x1C +#define Reserved13 0x1D +#define Reserved14 0x1E +#define SerialSpeedReg 0x1F +//Page 2:CFG +#define Reserved20 0x20 +#define CRCResultRegM 0x21 +#define CRCResultRegL 0x22 +#define Reserved21 0x23 +#define ModWidthReg 0x24 +#define Reserved22 0x25 +#define RFCfgReg 0x26 +#define GsNReg 0x27 +#define CWGsPReg 0x28 +#define ModGsPReg 0x29 +#define TModeReg 0x2A +#define TPrescalerReg 0x2B +#define TReloadRegH 0x2C +#define TReloadRegL 0x2D +#define TCounterValueRegH 0x2E +#define TCounterValueRegL 0x2F +//Page 3:TestRegister +#define Reserved30 0x30 +#define TestSel1Reg 0x31 +#define TestSel2Reg 0x32 +#define TestPinEnReg 0x33 +#define TestPinValueReg 0x34 +#define TestBusReg 0x35 +#define AutoTestReg 0x36 +#define VersionReg 0x37 +#define AnalogTestReg 0x38 +#define TestDAC1Reg 0x39 +#define TestDAC2Reg 0x3A +#define TestADCReg 0x3B +#define Reserved31 0x3C +#define Reserved32 0x3D +#define Reserved33 0x3E +#define Reserved34 0x3F +//----------------------------------------------- + +class RFID +{ + public: + RFID(int chipSelectPin, int NRSTPD); + + bool isCard(); + bool readCardSerial(); + + void init(); + void reset(); + void writeMFRC522(unsigned char addr, unsigned char val); + void antennaOn(void); + unsigned char readMFRC522(unsigned char addr); + void setBitMask(unsigned char reg, unsigned char mask); + void clearBitMask(unsigned char reg, unsigned char mask); + void calculateCRC(unsigned char *pIndata, unsigned char len, unsigned char *pOutData); + unsigned char MFRC522Request(unsigned char reqMode, unsigned char *TagType); + unsigned char MFRC522ToCard(unsigned char command, unsigned char *sendData, unsigned char sendLen, unsigned char *backData, unsigned int *backLen); + unsigned char anticoll(unsigned char *serNum); + unsigned char auth(unsigned char authMode, unsigned char BlockAddr, unsigned char *Sectorkey, unsigned char *serNum); + unsigned char read(unsigned char blockAddr, unsigned char *recvData); + unsigned char write(unsigned char blockAddr, unsigned char *writeData); + void halt(); + + unsigned char serNum[5]; // Constante para guardar el numero de serie leido. + unsigned char AserNum[5]; // Constante para guardar el numero d serie de la secion actual. + + private: + int _chipSelectPin; + int _NRSTPD; + +}; + +#endif \ No newline at end of file diff --git a/Ultrasonic/LICENSE b/Ultrasonic/LICENSE new file mode 100644 index 0000000..b0f0575 --- /dev/null +++ b/Ultrasonic/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2017 Erick Simões + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/Ultrasonic/README.md b/Ultrasonic/README.md new file mode 100644 index 0000000..caa189c --- /dev/null +++ b/Ultrasonic/README.md @@ -0,0 +1,82 @@ +Ultrasonic +=========== + +_Minimalist library for ultrasound module to Arduino_ + +### Compatible with **HC-SR04**, **Ping)))** and **Seeed SEN136B5B** (_from Seeed Studio_) + +Work with **ultrasonic modules** is fairly simple, but can be even more practical if you abstract the control of some features. This library aims to resource efficiency and to simplify access to data. + +Where necessary use the ultrasonic module **HC-SR04** (one of the most common on the market), **Ping)))** and/or **Seeed SEN136B5B** (_from Seeed Studio_), there are hundreds of libraries that purport to provide the most diverse roles for the user, however, the vast majority of the time, we just need to find out the distance and is that's what does this library. + +This library is minimalist, reduces code execution, validation and unnecessary use of global variables, prioritizing smaller data types. + +Wiring: +--------------- +It is very easy to connect an ultrasound module to the Arduino. For example, if you are using **HC-SR04**, connect the **trigger** and **echo** pin module on pin **12** and **13** of the Arduino, respectively. As in the picture: + + +If you are using a module with three pins (like **Ping)))** or **Seeed SEN136B5B**), you can conect the **sig** pin module on pin **13** of the Arduino. + +#### You can use the [Fritzing](http://fritzing.org/home/)(_.fzz_) files inside [extras](https://github.com/ErickSimoes/Ultrasonic/tree/master/extras) to draw your prototypes. + +How to use: +--------------- +The idea is to provide a simpler environment possible. To do this, simply follow the steps: + +1. **Installing** + + First you need to import the library so that the IDE recognizes it. The simplest way is importing through the IDE itself: + - Click in ```Sketch > Include Library > Manage Libraries...```; + - In the search field type: ```ultrasonic```; + - In the list, look for ```Ultrasonic by Erick Simões```; + - Click on ```Install```. + + Alternatively, you can download the library [here](https://github.com/ErickSimoes/Ultrasonic/archive/v1.0.1.zip) and import the ```.zip``` file into the IDE (see how to import a library [here](https://www.arduino.cc/en/Guide/Libraries#toc4)). +2. **Importing on code** + + To import the library to your code, just write at the beginning of the code ```#include <Ultrasonic.h>``` or, in the Arduino IDE, click in ```Sketch > Include Library > Ultrasonic``` (_will have the same result_). +3. **Starting** (the most exciting part) + + Now is simply create a variable of type Ultrasonic passing as parameters two values representing, respectively, the Trig (emitter) and Echo (receiver) pins. Like this: + ```c++ + Ultrasonic ultrasonic(12, 13); + ``` + If you are using a module with three pins (like **Ping)))** or **Seeed SEN136B5B**), pass as a parameter only the signal pin. Like this: + ```c++ + Ultrasonic ultrasonic(13); + ``` +4. **Discovering the distance** + + Having initialized a variable, you can run hers from the method that returns the distance read by module Ultrasonic: ```distanceRead()``` + ```c++ + ultrasonic.distanceRead() + ``` +5. **Only this?** + + Yes. That's it. By default, the value returned from the function ```distanceRead()``` is the distance in centimeters. + +6. **Seriously?** + + You can still do a little more determining the unit of measurement that will be returned (centimeters (CM) or inches (INC)). + ```c++ + ultrasonic.distanceRead() // distance in CM + ultrasonic.distanceRead(CM) // distance in CM + ultrasonic.distanceRead(INC) // distance in INC + ``` + You can also use more than one ultrasound module: + ```c++ + ultrasonic ultrasound1(12, 13); + ultrasonic ultrasound2(10, 11); + ultrasonic ultrasound3(5); + ``` + +#### See the examples [here](https://github.com/ErickSimoes/Ultrasonic/tree/master/examples). + +License +---- +Ultrasonic by [Erick Simões](http://ericksimoes.com.br/ "Erick Simões") is licensed under a MIT License. +Based on the work of Carl John Nobile available [here](http://wiki.tetrasys-design.net/HCSR04Ultrasonic). +Feel free to contact the author on Twitter: [@AloErickSimoes](https://twitter.com/AloErickSimoes) + +See [LICENSE](https://github.com/ErickSimoes/Ultrasonic/blob/master/LICENSE) for details. diff --git a/Ultrasonic/examples/MultipleUltrasonicSensors/MultipleUltrasonicSensors.ino b/Ultrasonic/examples/MultipleUltrasonicSensors/MultipleUltrasonicSensors.ino new file mode 100644 index 0000000..4f7d940 --- /dev/null +++ b/Ultrasonic/examples/MultipleUltrasonicSensors/MultipleUltrasonicSensors.ino @@ -0,0 +1,58 @@ +/* + * Miltiple Ultrasonic Sensors + * Prints the distance read by many ultrasonic sensors in + * centimeters and inches. They are supported to four pins + * ultrasound sensors (liek HC-SC04) and three pins + * (like PING))) and Seeed Studio sesores). + * + * The circuit: + * * In this circuit there is an ultrasonic module HC-SC04, + * PING))) and a Seeed Studio (4 pins, 3 pins, 3 pins, + * respectively), attached to digital pins as follows: + * --------------------- --------------------- --------------------- + * | HC-SC04 | Arduino | | PING))) | Arduino | | Seeed | Arduino | + * --------------------- --------------------- --------------------- + * | Vcc | 5V | | Vcc | 5V | | Vcc | 5V | + * | Trig | 12 | AND | SIG | 10 | AND | SIG | 8 | + * | Echo | 13 | | Gnd | GND | | Gnd | GND | + * | Gnd | GND | --------------------- --------------------- + * --------------------- + * Note: You need not obligatorily use the pins defined above + * + * By default, the distance returned by the distanceRead() + * method is in centimeters, to get the distance in inches, + * pass INC as a parameter. + * Example: ultrasonic.distanceRead(INC) + * + * created 3 Mar 2017 + * by Erick Simões (github: @ErickSimoes | twitter: @AloErickSimoes) + * + * This example code is released into the MIT License. + */ + +#include <Ultrasonic.h> + +Ultrasonic ultrasonic1(12, 13); // An ultrasonic sensor HC-04 +Ultrasonic ultrasonic2(10); // An ultrasonic sensor PING))) +Ultrasonic ultrasonic3(8); // An Seeed Studio ultrasonic sensor + + +void setup() { + Serial.begin(9600); +} + +void loop() { + Serial.print("Sensor 01: "); + Serial.print(ultrasonic1.distanceRead()); // Prints the distance on the default unit (centimeters) + Serial.println("cm"); + + Serial.print("Sensor 02: "); + Serial.print(ultrasonic2.distanceRead(CM)); // Prints the distance making the unit explicit + Serial.println("cm"); + + Serial.print("Sensor 03: "); + Serial.print(ultrasonic3.distanceRead(INC)); // Prints the distance in inches + Serial.println("inc"); + + delay(1000); +} diff --git a/Ultrasonic/examples/UltrasonicSimple/UltrasonicSimple.ino b/Ultrasonic/examples/UltrasonicSimple/UltrasonicSimple.ino new file mode 100644 index 0000000..271f2b9 --- /dev/null +++ b/Ultrasonic/examples/UltrasonicSimple/UltrasonicSimple.ino @@ -0,0 +1,54 @@ +/* + * Ultrasonic Simple + * Prints the distance read by an ultrasonic sensor in + * centimeters. They are supported to four pins ultrasound + * sensors (liek HC-SC04) and three pins (like PING))) + * and Seeed Studio sesores). + * + * The circuit: + * * Module HR-SC04 (four pins) or PING))) (and other with + * three pins), attached to digital pins as follows: + * --------------------- --------------------- + * | HC-SC04 | Arduino | | 3 pins | Arduino | + * --------------------- --------------------- + * | Vcc | 5V | | Vcc | 5V | + * | Trig | 12 | OR | SIG | 13 | + * | Echo | 13 | | Gnd | GND | + * | Gnd | GND | --------------------- + * --------------------- + * Note: You need not obligatorily use the pins defined above + * + * By default, the distance returned by the distanceRead() + * method is in centimeters, to get the distance in inches, + * pass INC as a parameter. + * Example: ultrasonic.distanceRead(INC) + * + * created 3 Apr 2014 + * by Erick Simões (github: @ErickSimoes | twitter: @AloErickSimoes) + * modified 23 Jan 2017 + * by Erick Simões (github: @ErickSimoes | twitter: @AloErickSimoes) + * modified 03 Mar 2017 + * by Erick Simões (github: @ErickSimoes | twitter: @AloErickSimoes) + * + * This example code is released into the MIT License. + */ + +#include <Ultrasonic.h> + +/* + * Pass as a parameter the trigger and echo pin, respectively, + * or only the signal pin (for sensors 3 pins), like: + * Ultrasonic ultrasonic(13); + */ +Ultrasonic ultrasonic(12, 13); + +void setup() { + Serial.begin(9600); +} + +void loop() { + Serial.print("Distance in CM: "); + // Pass INC as a parameter to get the distance in inches + Serial.println(ultrasonic.distanceRead()); + delay(1000); +} diff --git a/Ultrasonic/extras/HC-SR04-with-Arduino.jpg b/Ultrasonic/extras/HC-SR04-with-Arduino.jpg new file mode 100644 index 0000000000000000000000000000000000000000..6b60790c81318bb81769240dbc987556ac24f744 GIT binary patch literal 61223 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 bN+=<!rZ`q{|KEoT$>Ojh{wp9f?(5(m!2=cQ literal 0 HcmV?d00001 diff --git a/Ultrasonic/extras/Ultrasonic.fzz b/Ultrasonic/extras/Ultrasonic.fzz new file mode 100644 index 0000000000000000000000000000000000000000..7321228ceab755eff9ee5c4be77290bcac81685b GIT binary patch literal 3813 zcmV<B4jS=LO9KQH0000804R_*O8&1xsb>xV0ANP}01f~E099;sa$$3CZfRp{E@pb| zon4RHHWr5O7uf$GcyD$uO!He(G1DSV)1ufdw#cUKW#EzJi4fZw$ezqhe*KdA8p)Dn z$F`&+o6bcnn<E_`Q7`%M9FjLbJTDj47e87D;p%oo5FT0n$_r<~>i%~0$A_QC&gh5l z|Ngg|WjK3W_|`lMHec0ue`bGyk&D<J!W<D73D0rGj8WU;e98#nzL<NSJ9DVSv*{dr zcXxt1SdP>gE%my&3#ZX+ogTe@VkKAmb#^=Y@D%=M`r=3LeQz^e-7oy#-~RYp^6gI} zYZGi1{_QCJ@^LYZEcLxLw%+^e;Oq2m;g76fwN_txs+jtUjI5_%w)u2BauAnN+TL<x zee#3*Pn+A3K$5GM`e>3FI4N0p^Cj?~O6KYhtkra>&VCp9(^*{nPxax*x|@2R@1yW> zHG3N_!svGNk9qtWS@%&e`(N<Y*WM$+YGkcHg-^ez57iAAS<^*uzxoj7$NCaKN8$2E ze-S>ZKgo^THel_2@|V+1;PrI<2k&mzm0A2c`O4PxaTBT&Z~PC@)bsyJ?j+@f`&GO{ zH`%Q(-LmY%ypp~5=lklJD(WwOUCsPwRZDEiN7lnsU;4XA<gdfWNL^y`FpW0ri5Et` z`Y=7oN9B``o2T&OLZ5q$=3gI11zTc!9-{EUk2Wu<7n73e$4?iJ>X4S)UH1oZea_1} z9LeI#CVNkiRR8=8LLy#zvFaJ(=k9y`Jl#x^_ge+FAC%W?CzZsCf2Mk9^z*XqlDzP} zA1?h(^kRM0(j-QfazCetW31}Zi*io<mRIacszQ3Hy6?)*YGzE}g{y;X!LcPcwgK<B zdifG{MM}?WD>js_uziar6)~G+kH-GT<&!sFN0@(nTx_E0Jb2!IL|mCYB5%K&{IOOw zdg4cc_j&SD=shm|m3mTskHY(Cx}2^jS)-D_85f?V?JLzjLrEQsi+*#Btgj2NpB{8K zXj(f7cabga_^ym?f?UF@PjG$)b+1=SD#EDFuxcqQf2Ui<{6Hz?!A4h&-&2X|ENQZK zyKLF!H+H$ANQ~>OFZ_<ZHcbvNDlZg9r#PAp$kEP_9nA*hXm`kt<^ysx!9YD-C{f$M z9NQJhKm4W^D7hnJj5xE!?xrVhBY(;M{!6e9?lehlqDMbz$gq<(V#$g0C1iYw|IX)Y zf0LESj>byaH~#Y`>+$3GHL~X6YLoQ%MN`GPnFZ?y^}GM=zgVArb=}6BS1GOg3)bp! zdFMyFfAXaCo4ab0_uj?)oTf?MY4QP0GI&2<NQ(^K&ll1lgZJ}r+v6rIj!SF}Qh4FR zgCF68nqiSP!vZ7eI7u5Ski@67#STY|5Sp~d1TmK;?J=RH2AMG=ss5__M!Bc9b<d5d z-XPPmZkv2S%L?4f7t*c*_wt3bs=&QG+%~m-u>G__X7&3XgH`zPaTWeE^1rZujRSA} zur<`|Fy~xD&Gpx77;t_YE+4{`x`coBQRi<Qe<n!axUM|wE&{=bvb4XzC~}zUJT%?@ zO*CDt=V7$8mW0F=eo1H?f?E=n98;oCtl!Y|gY*lgzM#}jF1Tb=U((S>LLV}HmfgLE z`%XFxLN-4`FvXzQ-zjMVp>^Y<e+7{bN_2JS_kz5RX<aP>=XD_l?e$9gXV(o;gY&v$ z58CUMy3Xr<PnTXl!<hPM5TCcE3gn4RNRn@09}n@=Wr%0z!8yMtm&t&ga)v0sc!Do9 z$gn%)2erY;Paqqek_1bYoT0n9*yw_FbD_x{h?|>QS+H&{w6Ozmb5pb0hntUt`1rds zMyQER5ltFGNs%pB10n8fRT;Lka|w~0D~(jEW>OZT)vT9+@!HbhqSb}=7<$<0pcXm* z5g)**7<0RJbz{{$dq-oi^{3d?09=0xosGe`x~aPX*wuv&$6#FD)aB^M)h9*cPm3S? z7Oa9F^KpXu*&IoP<vj6&W$Ahiaf8=F-yAon?T4KhHlWGG3XGAY$;1lB-P12Sso(L= z9rS3~www`MlZ6IG&fW}r7@pS6EUBn61V0bEQnR7>`JIlD57^Pw2tQ<Qc{gnJsC0*% zn#61{&VDoSs?7(ZA;S*WRV0K#mXJ5Yb~b@jsZURBZYA%CrgL8za=07cB91t9g){*1 ztpEWp$>D+l0#>@}1rr1;M_)2Rz|)TlMhJM$zGQ>|CL+V`);2K&z-m2gXE!kfz_}dX zoLhPJ_ybYzZBbo#DnE(AhkAT~mc4bs@Q@{;LGbdhD|8b%0P^xBV*@nZxL|02=ITpE z21x2L>@I8*FMzAj!*+EOEp%L=dztpFp>t=l7TdG*?vwiC+RUriq6sLIlFToC?z2xH zkHP&A0%K`XK4m<~qUQ)>qJGkIG7<bG`R`fJ`bJc`uC3>l(<IvCy77A2k^l2zdcRiA zs9%aVzNjwt?pbNX+FAySwVpJNsCtdmQ;;O#bFBZ3tngv#1)G<6{`uWhxp~&~0G=rY ze&?VbaIvW9GJzaRDw;hccfT9%!W^eAKAGeZ93myz(pN+hWRqM@Y|2HQoQwrQQfN17 zIT>Rl33nWNyr8)1QULYjFi%!J3Qteq<(Aaw$spW4U_Ci*@w^lc4v`VJXBi;`5uzvR zXF4*cp2Yp@$RUobIuxFYK%>PP4H<x|2dp4nGo$ttFlN+`!^N2Nim@C5#v+<*zd>AE z0V=I+GZ<Bv%URN9V8gJ`T8p}PmSNbof)l-`kHLc2eCa1DUF5PfBO&XJ)~Jd8E-4ou zVOy1ChGW5Mis9I@H7#q(0Oy^@CC&h{eM^a9*>;u0uxw{4GN1*sT0~hF9ycCs(knOG zy>sJOuXte}K#mkSoD$m~$0L)8NK+(CAhd7osL1p%)@!~Pi0nP?3=SgGS+NdAMDFeQ z*;JLn+%ROVPvJ?5VaT#IElbLEGi0AiVi2-jAu$NqnTQyKOsgI+ggoA)LIy2{#gMK* zd`BKFm02+peC%H^oUQ!>lMTfH<WUrDzXE*hJLC%vA6dFsK1MFHvn)7*^<<EmUZ148 z7|pZb2zD4dVNl8dWZT*TYDK&YgvY+)y-?t>UmY>{*s_cOn&NtK=-6+d7aTe=c#|)W zH>rS*tWR{zhxaJX)wy8?CK1GT(;1k8sbhXdfb=}V^$86?)|EYUaF6eVGME}Y2zTq{ z6NWk6p=)mBiJEZra7&i$jK-K-A1z>5DiKL%Pcav{(l%j7xPoHBj%91EQBXSK#y)k# zP-D9?VuFs>Eg@Z#BZoHy^LUdA<S3z#qXxrtYx(qjUGA#mAU$$)?zp4D#-_4|%Cq1G z8+TaK#^7G>>s^BbN0E2<9NS6K%$Pvb-qqm~X}S2wRR=n!!H^?RO)=zHwx(rGx$c-_ zuTo;*v0WuG@YtD(n6P8Ig*h~MJldoJJh~v@aqK9$lss8y&5=8^R*91pGxXTMXgIdX zS_L50y)!#Fh?I$_xDIk%xi1r5^$C+wr%8%o$F>#4<f?WhBiGH1eW-`Q#g@gxWT<u_ z90nCre*i<p<4t-+MM~kJVnd)2XLHXfMvh5P?OQdfi6C|RBbi8JTO!?iJ}@{)v@6{_ zr6kCqJJv)*oD%F7m)ugq!l~IR1g@@_Xk*!$mUZR2sj+uCF$meNnwW@VXG&r)Qu#v? za2RRB+cCt32iwP+^a|Uo*Oi1`C+y=SaYnM8(?O}7q|~HS^{JkzFV9HZRCpc}y|-e+ z!oNy8=F|md4Q-#v-9i8jgoA@_H<J}a^}+^PT3o~(Qo9Za;R5Arl#Nwy+I6IBcpI#; z7~U>h)3&m79uSAZ+I^~s!R&TL#9(%J0@86%92{ah@DTfWlM3+I_gX>;Jm%w{%`-1B zBDQcuw%wFNRKZhbUKoNrWj499T_J(YCNG+Nar{^r3w4Ew)|S9A-M~&zM06g=OS147 z!S(A$>J=j?vD37?vFoa1ZdMdBin7b(i{r*7MY-xYZNEZd;PL8pWB{%{NJUJHHXXNs z29QUaQ~=1nmlR5)j~O)T0X~ZCc+uINnZ7nfLdbJ&foZ_8sqCR+d%d$v(df%ZN88K> z-9pEt%a?ca)E%-3ayhBpTQ|?&Q}6Sc28J7f3W|w1maS=7P_COC`_mDFjqS>ai8*#A zAqE@Mss{`kk2k4+jeRdBRK>=IxTAxS;QD8udo3Y@jZI|_P6^rhOJEB0u-sjd=-v~A z!C@n<boUw}1;y^3Swsk~lo((vThp?XTsJWGp&$ko+Z7Olik*pvLB)}blN4Z~;t3|b zq9X5mF`;y0DJoE$N3d_pOUxB3rgI1!7dg&3<Baq9+yNlb!y=e%ktWzRz_`Pj6S8hx zpjkKIa52q!mjp2?GC{E^uiphpcLcKy&Ly%XGrN|+l@kMvWoxccPC7!y{#3+(W4j_^ z!11~Tq;qg|;eq4PCKbR@zyU|SIGEN&&J+;VW`T^)G^%Hiu@!mN3kDcuthJ_vvAuZU z$ix_n(3pye#K<OlCnFI-lVY*3U^Az&|0>?3D25u#*0iiB*Bxr?QAi9pwyPrs96Qqx z6LCzd9x!k`-lPIJIv~K2P>HZ0`@j)rtKr14MiXp=rq7faa@=7}D;nK*Y!@6kCYzh* z3bLoi$Am7%3_I336`rOTb}U=dvZh=&JN7Cih928h5<`!jsfeM+wCVw)$Ky?UrAI-) z(PKlt>X<mHSiE<Ki97Z$8bSiy9-?Ub<wIoe(Oz&6DJwm{hGn+OJ-=k9AG7-<U}foi zdx)aJm(P#AhkBv#W1lKw@UdkP>3EBXqPdrjjy=bC!J#9=;LwqS+aQDpc;Q(AFV$Fr zn>I@^xJ93+-n1H;N#N=dCE!GWQg}Cx!n<({-i>1|4v)Tmpj+pgNn(_G`+rbN0RjL3 z6aWAK2mmOMH%k7mLaApC003Y|0RRpF00000000310000000000Rcv%}VRLV8X=7_H bW_nOd1qJ{B000310RTJz005H?00000A75hi literal 0 HcmV?d00001 diff --git a/Ultrasonic/keywords.txt b/Ultrasonic/keywords.txt new file mode 100644 index 0000000..bcc908a --- /dev/null +++ b/Ultrasonic/keywords.txt @@ -0,0 +1,23 @@ +####################################### +# Syntax Coloring Map Ultrasonic +# by Erick Simões +# github: @ErickSimoes +# twitter: @AloErickSimoes +####################################### + +####################################### +# Datatypes (KEYWORD1) +####################################### + +Ultrasonic KEYWORD1 + +####################################### +# Methods and Functions (KEYWORD2) +####################################### +distanceRead KEYWORD2 + +####################################### +# Constants (LITERAL1) +####################################### +CM LITERAL1 Constants +INC LITERAL1 Constants diff --git a/Ultrasonic/library.properties b/Ultrasonic/library.properties new file mode 100644 index 0000000..da0656a --- /dev/null +++ b/Ultrasonic/library.properties @@ -0,0 +1,10 @@ +name=Ultrasonic +version=2.0.1 +author=Erick Simões <erick.simoes@live.com> +maintainer=Erick Simões <erick.simoes@live.com> +sentence=Minimalist library for ultrasound module to Arduino +paragraph=Work with ultrasound module in a simple and light way. Compatible with the modules HC-SR04, Ping))) and Seeed Studio sensor. This library aims to resource efficiency and to simplify access to data. +category=Sensors +url=https://github.com/ErickSimoes/Ultrasonic +architectures=* +includes=Ultrasonic.h \ No newline at end of file diff --git a/Ultrasonic/src/Ultrasonic.cpp b/Ultrasonic/src/Ultrasonic.cpp new file mode 100644 index 0000000..927c3a9 --- /dev/null +++ b/Ultrasonic/src/Ultrasonic.cpp @@ -0,0 +1,59 @@ +/* + * Ultrasonic.cpp + * + * Library for Ultrasonic Ranging Module in a minimalist way + * + * created 3 Apr 2014 + * by Erick Simões (github: @ErickSimoes | twitter: @AloErickSimoes) + * modified 23 Jan 2017 + * by Erick Simões (github: @ErickSimoes | twitter: @AloErickSimoes) + * modified 04 Mar 2017 + * by Erick Simões (github: @ErickSimoes | twitter: @AloErickSimoes) + * + * Released into the MIT License. + */ + +#include <Arduino.h> +#include "Ultrasonic.h" + +Ultrasonic::Ultrasonic(uint8_t sigPin) { + trig = sigPin; + echo = sigPin; + threePins = true; +} + +Ultrasonic::Ultrasonic(uint8_t trigPin, uint8_t echoPin) { + trig = trigPin; + echo = echoPin; + pinMode(trig, OUTPUT); + pinMode(echo, INPUT); +} + +unsigned int Ultrasonic::timing() { + if (threePins) + pinMode(trig, OUTPUT); + + digitalWrite(trig, LOW); + delayMicroseconds(2); + digitalWrite(trig, HIGH); + delayMicroseconds(10); + digitalWrite(trig, LOW); + + if (threePins) + pinMode(trig, INPUT); + + return pulseIn(echo, HIGH); // duration +} + +unsigned int Ultrasonic::distanceRead() { + /* + * If the unit of measure is not passed as a parameter, + * by default, it will return the distance in centimeters. + * To change the default, replace CM by INC. + */ + return distanceRead(CM); +} + +unsigned int Ultrasonic::distanceRead(uint8_t und) { + return timing() / und / 2; //distance by divisor +} diff --git a/Ultrasonic/src/Ultrasonic.h b/Ultrasonic/src/Ultrasonic.h new file mode 100644 index 0000000..9f42efd --- /dev/null +++ b/Ultrasonic/src/Ultrasonic.h @@ -0,0 +1,39 @@ +/* + * Ultrasonic.h + * + * Library for Ultrasonic Ranging Module in a minimalist way + * + * created 3 Apr 2014 + * by Erick Simões (github: @ErickSimoes | twitter: @AloErickSimoes) + * modified 23 Jan 2017 + * by Erick Simões (github: @ErickSimoes | twitter: @AloErickSimoes) + * modified 04 Mar 2017 + * by Erick Simões (github: @ErickSimoes | twitter: @AloErickSimoes) + * + * Released into the MIT License. + */ + +#ifndef Ultrasonic_h +#define Ultrasonic_h + +/* + * Values of divisors + */ +#define CM 28 +#define INC 71 + +class Ultrasonic { + public: + Ultrasonic(uint8_t sigPin); + Ultrasonic(uint8_t trigPin, uint8_t echoPin); + unsigned int distanceRead(); + unsigned int distanceRead(uint8_t und); + + private: + uint8_t trig; + uint8_t echo; + boolean threePins = false; + unsigned int timing(); +}; + +#endif // Ultrasonic_h -- GitLab