diff --git a/Examples/CMakeLists.txt b/Examples/CMakeLists.txt index c3c3925d..ab393e0f 100644 --- a/Examples/CMakeLists.txt +++ b/Examples/CMakeLists.txt @@ -14,6 +14,7 @@ add_subdirectory(PropWare_FullDuplexSerial) add_subdirectory(PropWare_HD44780) add_subdirectory(PropWare_I2C) add_subdirectory(PropWare_I2CSlave) +add_subdirectory(PropWare_Keypad) add_subdirectory(PropWare_L3G) add_subdirectory(PropWare_MAX6675) add_subdirectory(PropWare_MCP2515) diff --git a/Examples/PropWare_Keypad/CMakeLists.txt b/Examples/PropWare_Keypad/CMakeLists.txt new file mode 100644 index 00000000..98210c2f --- /dev/null +++ b/Examples/PropWare_Keypad/CMakeLists.txt @@ -0,0 +1,6 @@ +cmake_minimum_required(VERSION 3.3) +find_package(PropWare REQUIRED) + +project(PropWareKeypad_Demo) + +create_simple_executable(${PROJECT_NAME} Keypad_Demo.cpp) diff --git a/Examples/PropWare_Keypad/Keypad_Demo.cpp b/Examples/PropWare_Keypad/Keypad_Demo.cpp new file mode 100644 index 00000000..ff806db8 --- /dev/null +++ b/Examples/PropWare_Keypad/Keypad_Demo.cpp @@ -0,0 +1,71 @@ +/** + * @file Keypad_Demo.cpp + * + * @author David Zemon + * + * @copyright + * The MIT License (MIT)
+ *
Copyright (c) 2013 David Zemon
+ *
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. + */ + +#include +#include + +using namespace PropWare; + +/** + * @example PropWare_Keypad/Keypad_Demo.cpp + * + * Read keys from a common 4x4 keypad to interact with a user + * + * @include PropWare_Keypad/CMakeLists.txt + */ +int main() { + Keypad::Key keys[] = { + Keypad::Key('1'), Keypad::Key('2'), Keypad::Key('3'), Keypad::Key('A'), + Keypad::Key('4'), Keypad::Key('5'), Keypad::Key('6'), Keypad::Key('B'), + Keypad::Key('7'), Keypad::Key('8'), Keypad::Key('9'), Keypad::Key('C'), + Keypad::Key('*'), Keypad::Key('0'), Keypad::Key('#'), Keypad::Key('D') + }; + const Pin rowPins[] = { + Pin(Pin::P19), + Pin(Pin::P20), + Pin(Pin::P21), + Pin(Pin::P22), + }; + const Pin columnPins[] = { + Pin(Pin::P26), + Pin(Pin::P25), + Pin(Pin::P24), + Pin(Pin::P23), + }; + + Keypad keypad(keys, rowPins, columnPins); + + while (1) { + //for (auto key : keys) { + // if (keypad.is_pressed(key.get_character())) + // pwOut << key.get_character() << '\n'; + //} + + keypad.get_keys(); + for (size_t i = 0; i < Utility::size_of_array(keys); ++i) { + if (0 == i % 4) + pwOut << '\n'; + pwOut << (keys[i].get_state() ? keys[i].get_character() : ' ') << ' '; + } + + waitcnt(100*MILLISECOND + CNT); + } +} diff --git a/PropWare/CMakeLists.txt b/PropWare/CMakeLists.txt index 4217d38f..d004116a 100644 --- a/PropWare/CMakeLists.txt +++ b/PropWare/CMakeLists.txt @@ -12,6 +12,7 @@ set(PROPWARE_SOURCES ${CMAKE_CURRENT_LIST_DIR}/gpio/pin.h ${CMAKE_CURRENT_LIST_DIR}/gpio/port.h ${CMAKE_CURRENT_LIST_DIR}/gpio/simpleport.h + ${CMAKE_CURRENT_LIST_DIR}/hmi/input/keypad.h ${CMAKE_CURRENT_LIST_DIR}/hmi/input/scancapable.h ${CMAKE_CURRENT_LIST_DIR}/hmi/input/scanner.cpp ${CMAKE_CURRENT_LIST_DIR}/hmi/input/scanner.h diff --git a/PropWare/hmi/input/keypad.h b/PropWare/hmi/input/keypad.h new file mode 100644 index 00000000..87632684 --- /dev/null +++ b/PropWare/hmi/input/keypad.h @@ -0,0 +1,153 @@ +/** + * @file PropWare/hmi/input/keypad.h + * + * @author David Zemon + * + * @copyright + * The MIT License (MIT)
+ *
Copyright (c) 2013 David Zemon
+ *
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. + */ + +#pragma once + +#include +#include + +namespace PropWare { + +class Keypad { + public: + class Key { + public: + friend class Keypad; + + public: + Key(const char character) + : character(character), + state(false) { + } + + char get_character() const { + return this->character; + } + + + bool get_state() const { + return this->state; + } + + protected: + char character; + bool state; + }; + + public: + /** + * MAPSIZE is the number of rows (times 16 columns) + */ + static const unsigned int DEFAULT_BOUNCE_TIME_MS = 10; + + public: + /** + * Allows custom m_keymap, pin configuration, and keypad sizes + */ + template + Keypad(Key keys[], const Pin (&rowPins)[ROW_SIZE], const Pin (&columnPins)[COLUMN_SIZE]) + : m_keys(keys), + m_rowPins(rowPins), + m_columnPins(columnPins), + m_rows(ROW_SIZE), + m_columns(COLUMN_SIZE), + m_keyCount(this->m_rows * this->m_columns), + m_startTime(CNT - DEFAULT_BOUNCE_TIME_MS * MILLISECOND) { + this->set_debounce_time(Keypad::DEFAULT_BOUNCE_TIME_MS); + } + + /** + * Populate the key list + */ + + bool is_pressed(const char character) { + this->get_keys(); + + for (uint_fast8_t i = 0; i < this->m_keyCount; i++) + if (character == this->m_keys[i].character) { + return this->m_keys[i].state; + } + return false; + } + + bool get_keys() { + bool keyActivity = false; + + // Limit how often the keypad is scanned. This makes the loop() run 10 times as fast. + if ((CNT - this->m_startTime) > this->m_debounceTime) { + this->scan_keys(); + this->m_startTime = CNT; + } + + return keyActivity; + } + + /** + * Minimum debounceTime is 1 mS. + */ + void set_debounce_time(const uint32_t debounceMs) { + if (!debounceMs) + this->m_debounceTime = MILLISECOND; + else + this->m_debounceTime = debounceMs * MILLISECOND; + } + + private: + + /** + * Hardware scan + */ + void scan_keys() { + for (uint_fast8_t row = 0; row < this->m_rows; row++) { + this->m_rowPins[row].set_dir_in(); + this->m_rowPins[row].high(); + } + + // bitMap stores ALL the keys that are being pressed. + for (uint_fast8_t column = 0; column < this->m_columns; ++column) { + // Begin column pulse output. + this->m_columnPins[column].low(); + this->m_columnPins[column].set_dir_out(); + + for (uint_fast8_t row = 0; row < this->m_rows; ++row) { + const uint_fast8_t keyIndex = column * 4 + row; + this->m_keys[keyIndex].state = !this->m_rowPins[row].read(); + } + + // Set pin to high impedance input. Effectively ends column pulse. + this->m_columnPins[column].high(); + this->m_columnPins[column].set_dir_in(); + } + } + + private: + Key *m_keys; + const Pin *m_rowPins; + const Pin *m_columnPins; + const uint_fast8_t m_rows; + const uint_fast8_t m_columns; + const uint_fast8_t m_keyCount; + + uint32_t m_debounceTime; + volatile uint32_t m_startTime; +}; + +}