diff --git a/libraries/PinInGroup/LICENSE b/libraries/PinInGroup/LICENSE new file mode 100644 index 00000000..ed401f22 --- /dev/null +++ b/libraries/PinInGroup/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2017-2020 Rob Tillaart + +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/libraries/PinInGroup/PinInGroup.cpp b/libraries/PinInGroup/PinInGroup.cpp index 460e4ffe..bd3c3afc 100644 --- a/libraries/PinInGroup/PinInGroup.cpp +++ b/libraries/PinInGroup/PinInGroup.cpp @@ -1,57 +1,59 @@ // // FILE: PinInGroup.cpp // AUTHOR: Rob Tillaart -// VERSION: 0.1.0 +// VERSION: 0.1.1 // DATE: 2017-04-26 // PURPOSE: PinInGroup library for Arduino -// goal is to easily change a group of pins that logically +// goal is to easily read a group of pins that logically // belong to each other. // The pins can be in any order. -// URL: http://forum.arduino.cc/index.php?topic=469599.0 +// URL: https://github.com/RobTillaart/PinInGroup +// http://forum.arduino.cc/index.php?topic=469599.0 // -// Released to the public domain -// -// 0.1.0 - initial version (based upon pinGroup) -// +// 0.1.0 2017-08-20 initial version (based upon pinGroup) +// 0.1.1 2020-05-19 refactor; added clear(); added param for INPUT or INPUT_PULLUP #include "PinInGroup.h" PinInGroup::PinInGroup() +{ + clear(); +} + +void PinInGroup::clear() { _size = 0; } -bool PinInGroup::add(uint8_t size, int* ar) +uint8_t PinInGroup::add(uint8_t sz, uint8_t * ar, uint8_t value) { - bool b = true; - for (uint8_t i = 0; i < size; i++) + int n = 0; + for (uint8_t i = 0; i < sz; i++) { - b = b && add(ar[i]); + n += add(ar[i], value); } - return b; + return n; } -bool PinInGroup::add(uint8_t pin) +uint8_t PinInGroup::add(uint8_t pin, uint8_t value) { - if (_size < PININGROUP_MAXSIZE) - { - _pins[_size] = pin; - pinMode(pin, INPUT); - _size++; - return true; - } - return false; + if (_size >= PININGROUP_MAXSIZE) return 0; + _pins[_size] = pin; + pinMode(pin, value); + _size++; + return 1; } uint16_t PinInGroup::read() { uint16_t value = 0; + uint16_t mask = 0x01; for (uint8_t i = 0; i < _size; i++) { - value <<= 1; - value = value | (digitalRead(_pins[i]) > 0 ? 1: 0); + if (digitalRead(_pins[i])) value |= mask; + mask <<= 1; } return value; } -// --- END OF FILE --- \ No newline at end of file +// --- END OF FILE --- diff --git a/libraries/PinInGroup/PinInGroup.h b/libraries/PinInGroup/PinInGroup.h index 2485a1d6..368ad13b 100644 --- a/libraries/PinInGroup/PinInGroup.h +++ b/libraries/PinInGroup/PinInGroup.h @@ -1,41 +1,55 @@ -#ifndef PININGROUP_H +#pragma once // FILE: PinInGroup.h // AUTHOR: Rob dot Tillaart at gmail dot com -// VERSION: 0.1.0 +// VERSION: 0.1.1 +// DATE: 2017-04-26 // PURPOSE: PinInGroup library for Arduino // HISTORY: See PinInGroup.cpp // -// Released to the public domain +// Note: ESP32 has some dedicated IO pins that cannot be used in a group. +// FLASH: pin 6 - 11 (maybe more) // + #include "Arduino.h" -#define PININGROUP_LIB_VERSION "0.1.0" -#define PININGROUP_MAXSIZE 16 +#define PININGROUP_LIB_VERSION "0.1.1" + +// smaller MAXSIZE will reduce memory footprint with ditto bytes. +#ifndef PININGROUP_MAXSIZE +#define PININGROUP_MAXSIZE 16 +#endif + -// -// a PinInGroup is a group of up to sixteen input pins that can be read -// by means of one read command and combined into one uint16_t. -// class PinInGroup { -public: - PinInGroup(); - - // adds a predefined array of pinnumbers to the PinInGroup - bool add(uint8_t s, int* ar); - // adds a single pin to the PinInGroup - bool add(uint8_t pin); + public: + PinInGroup(); - // read up to 8 pins "simultaneously" into one byte. - uint16_t read(); + // enables one to reset the pinGroup and repopulate it + void clear(); - // get the current size of the PinInGroup. - uint8_t size() { return _size; }; - // check how many free slots there are... - uint8_t free() { return PININGROUP_MAXSIZE - _size; }; - -private: - uint8_t _pins[PININGROUP_MAXSIZE]; // should be malloced dynamically - uint8_t _size = 0; + // adds a predefined array of pin numbers to the PinInGroup + // sets all to either INPUT or INPUT_PULLUP. + uint8_t add(uint8_t sz, uint8_t * ar, uint8_t value = INPUT); + + // adds a single pin to the PinInGroup + uint8_t add(uint8_t pin, uint8_t value = INPUT); + + // read up to 16 pins "simultaneously" in one call. + uint16_t read(); + + uint8_t size() { + return _size; + }; + + // check how many free "slots" there are... + uint8_t free() { + return PININGROUP_MAXSIZE - _size; + }; + + private: + uint8_t _pins[PININGROUP_MAXSIZE]; + uint8_t _size = 0; }; -#endif + +// -- END OF FILE -- diff --git a/libraries/PinInGroup/README.md b/libraries/PinInGroup/README.md new file mode 100644 index 00000000..d9acc7e5 --- /dev/null +++ b/libraries/PinInGroup/README.md @@ -0,0 +1,37 @@ +# PinInGroup + +Arduino library to group reading to 16 input pins in one command + +# Description + +A PinInGroup holds a number of input pins that can be read by means of a single **read()** command. +The PinInGroup makes it easier to work with a number of inputs that are a logical unit, +e.g. think of reading a parallel bus or read 4 lines from a matrix keyboard, or just +read an array of switches. + +### Performace + +The PinInGroup is not much more efficient as reading the pins in a loopyourself. +Hoewever it is less programming and gives clearer code. + +There exist some ideas to optimize the low level reading e.g. only reading +the registers only once, or hold register and bit info per pin. +These ideas will be explored when time permits. + +Note: The current ideas are platform specific. + +### interface + +**clear()** sets the size to zero so one can repopulate. + +**add()** adds a predefined array of pins of a single pin to the group. +Note one can set a 2nd parameter mode to **INPUT**(default) or **INPUT_PULLUP**. + +**read(value)** reads a 16 bits unsigned int from max 16 pins. + +**size()** and **free()** give information about the group. + +# Operation + +See examples + diff --git a/libraries/PinInGroup/examples/testPinInGroup/testPinInGroup.ino b/libraries/PinInGroup/examples/testPinInGroup/testPinInGroup.ino index c7870f1c..04079eb7 100644 --- a/libraries/PinInGroup/examples/testPinInGroup/testPinInGroup.ino +++ b/libraries/PinInGroup/examples/testPinInGroup/testPinInGroup.ino @@ -2,26 +2,34 @@ // AUTHOR: Rob dot Tillaart at gmail dot com // VERSION: 0.1.0 // PURPOSE: demo PinInGroup library for Arduino -// HISTORY: 20-08-2017 +// HISTORY: 20-08-2017 // // Released to the public domain // #include "PinInGroup.h" -int ar[4] = {2, 3, 4, 13}; +uint8_t ar[4] = {2, 3, 4, 23}; +uint8_t alt[] = {23, 22, 1, 3, 21, 19, 18, 5, 23, 22, 1, 3, 21, 19, 18, 5}; void setup() { Serial.begin(115200); - Serial.print("\nPININGROUP_LIB_VERSION: "); + Serial.println(__FILE__); + + Serial.print(F("\nPININGROUP_LIB_VERSION: ")); Serial.println(PININGROUP_LIB_VERSION); + Serial.println(); test0(); test1(); test2(); - - Serial.println("done..."); + test3(); + test4(); + test5(); + test6(); + + Serial.println(F("done...")); } void loop() @@ -31,24 +39,38 @@ void loop() // TEST1 verifies and times basic working void test0() { - pinMode(2, INPUT); + Serial.println(); + Serial.println(__FUNCTION__); + delay(20); + + uint16_t n1 = 0; + uint32_t t1 = micros(); - digitalRead(2); - digitalRead(2); - digitalRead(2); - digitalRead(2); + n1 = digitalRead(2) > 0; + n1 <<= 1; + n1 |= digitalRead(3) > 0; + n1 <<= 1; + n1 |= digitalRead(4) > 0; + n1 <<= 1; + n1 |= digitalRead(13) > 0; uint32_t t2 = micros(); - Serial.print("time: "); + Serial.print(F(" val: ")); + Serial.println(n1, BIN); + Serial.print(F("time: ")); Serial.println(t2 - t1); - Serial.println("Test0 done..."); + Serial.print(F("time: ")); + Serial.println((1.0 * (t2 - t1)) / 4, 1); + Serial.println(F("Test0 done...")); Serial.println(); } void test1() { + Serial.println(); + Serial.println(__FUNCTION__); uint16_t n1; - + PinInGroup PIG; PIG.add(2); PIG.add(4); @@ -59,41 +81,230 @@ void test1() Serial.println(PIG.size()); Serial.print("free: "); Serial.println(PIG.free()); + delay(20); uint32_t t1 = micros(); n1 = PIG.read(); uint32_t t2 = micros(); - Serial.print(" val: "); - Serial.println(n1); - Serial.print("time: "); + Serial.print(F(" val: ")); + Serial.println(n1, BIN); + Serial.print(F("time: ")); Serial.println(t2 - t1); - Serial.println("Test1 done..."); + Serial.print(F("time: ")); + Serial.println((1.0 * (t2 - t1)) / PIG.size(), 1); + Serial.println(F("Test1 done...")); Serial.println(); } void test2() { - uint16_t n1; - - PinInGroup PIG; - for (int p=2; p<14; p++) PIG.add(p); + Serial.println(); + Serial.println(__FUNCTION__); - Serial.print("size: "); + uint16_t n1; + + PinInGroup PIG; + +#if defined(ESP32) || defined(ESP8266) + // be carefull which pins you use for ESP32 (and probably 8266 too, not tested) + // note: GPIO06 through GPIO11 are reserved for the FLASH. + // You cannot use them. ==> pinMode() fails. + // https://github.com/espressif/arduino-esp32/issues/1411 + // + for (uint8_t p = 20; p < 36; p++) PIG.add(p); +#else + for (uint8_t p = 2; p < 14; p++) PIG.add(p); +#endif + + Serial.print(F("size: ")); Serial.println(PIG.size()); - Serial.print("free: "); + Serial.print(F("free: ")); Serial.println(PIG.free()); + delay(20); uint32_t t1 = micros(); n1 = PIG.read(); uint32_t t2 = micros(); - Serial.print(" val: "); - Serial.println(n1); - Serial.print("time: "); + Serial.print(F(" val: ")); + Serial.println(n1, BIN); + Serial.print(F("time: ")); Serial.println(t2 - t1); - Serial.println("Test1 done..."); + Serial.print(F("time: ")); + Serial.println((1.0 * (t2 - t1)) / PIG.size(), 1); + Serial.println(F("Test2 done...")); Serial.println(); } -// END OF FILE \ No newline at end of file +void test3() +{ + Serial.println(); + Serial.println(__FUNCTION__); + + uint16_t n1; + + PinInGroup PIG; + PIG.add(4, ar, INPUT_PULLUP); + PIG.add(4, ar, INPUT_PULLUP); + PIG.add(4, ar, INPUT_PULLUP); + PIG.add(4, ar, INPUT_PULLUP); + + Serial.print(F("size: ")); + Serial.println(PIG.size()); + Serial.print(F("free: ")); + Serial.println(PIG.free()); + + PIG.add(4, ar, INPUT_PULLUP); // should not be added + + Serial.print(F("size: ")); + Serial.println(PIG.size()); + Serial.print(F("free: ")); + Serial.println(PIG.free()); + Serial.println(); + delay(20); + PIG.clear(); + + for (int i = 1; i <= 16; i++) + { + PIG.add(23); + uint32_t t1 = micros(); + n1 = PIG.read(); + uint32_t t2 = micros(); + float timePerPin2 = (1.0 * t2 - t1) / i; + + Serial.print(i); + Serial.print('\t'); + Serial.print(t2 - t1); + Serial.print('\t'); + Serial.print(timePerPin2); + Serial.print('\t'); + Serial.println(n1, BIN); + delay(20); + } + + Serial.println(F("Test3 done...")); + Serial.println(); +} + +void test4() +{ + Serial.println(); + Serial.println(__FUNCTION__); + + uint16_t n1; + + PinInGroup PIG; + PIG.add(4, ar, INPUT_PULLUP); + PIG.add(4, ar, INPUT_PULLUP); + PIG.add(4, ar, INPUT_PULLUP); + PIG.add(4, ar, INPUT_PULLUP); + + Serial.print(F("size: ")); + Serial.println(PIG.size()); + Serial.print(F("free: ")); + Serial.println(PIG.free()); + + PIG.clear(); + PIG.add(4, ar, INPUT_PULLUP); // should not be added + + Serial.print(F("size: ")); + Serial.println(PIG.size()); + Serial.print(F("free: ")); + Serial.println(PIG.free()); + delay(20); + + uint32_t t1 = micros(); + n1 = PIG.read(); + uint32_t t2 = micros(); + + Serial.print(F(" val: ")); + Serial.println(n1, BIN); + Serial.print(F("time: ")); + Serial.println(t2 - t1); + Serial.print(F("time: ")); + Serial.println((1.0 * (t2 - t1)) / PIG.size(), 1); + Serial.println(F("Test4 done...")); + Serial.println(); +} + +void test5() +{ + Serial.println(); + Serial.println(__FUNCTION__); + + uint16_t n1 = 0; + + uint32_t t1 = micros(); + n1 = digitalRead(2) > 0; + n1 <<= 1; + n1 |= digitalRead(3) > 0; + n1 <<= 1; + n1 |= digitalRead(4) > 0; + n1 <<= 1; + n1 |= digitalRead(13) > 0; + uint32_t t2 = micros(); + float timePerPin = (1.0 * t2 - t1) / 4; + + Serial.print(F(" val: ")); + Serial.println(n1, BIN); + Serial.print(F("time: ")); + Serial.println(t2 - t1); + Serial.print(F("time: ")); + Serial.println(timePerPin); + Serial.println(); + + PinInGroup PIG; + + for (int i = 1; i <= 16; i++) + { + PIG.add(2); + t1 = micros(); + n1 = PIG.read(); + t2 = micros(); + float timePerPin2 = (1.0 * t2 - t1) / i; + + Serial.print(i); + Serial.print('\t'); + Serial.print(t2 - t1); + Serial.print('\t'); + Serial.print(timePerPin2); + Serial.print('\t'); + Serial.println(timePerPin2 / timePerPin * 100.0); + delay(20); + } + + + Serial.println(F("Test5 done...")); + Serial.println(); +} + + +void test6() +{ + Serial.println(); + Serial.println(__FUNCTION__); + + uint16_t n1 = 0; + + PinInGroup PIG; + + // verify pin stays same place in output. + // connect selected pin to GND and it should stay on same spot. + // even when pins are added. + for (int i = 1; i <= 10; i++) + { + PIG.add(i, INPUT_PULLUP); + n1 = PIG.read() + 32768; + + Serial.print(i); + Serial.print('\t'); + Serial.print(n1, BIN); + Serial.print('\n'); + } + + Serial.println(F("Test6 done...")); + Serial.println(); +} + +// -- END OF FILE -- \ No newline at end of file diff --git a/libraries/PinInGroup/library.json b/libraries/PinInGroup/library.json index ecdc883b..fa96f2f7 100644 --- a/libraries/PinInGroup/library.json +++ b/libraries/PinInGroup/library.json @@ -1,6 +1,6 @@ { "name": "PinInGroup", - "keywords": "PinInGroup,pin,group", + "keywords": "PinInGroup, pin, group, INPUT", "description": "A class that groups input pins so they can be read in one logical step", "authors": [ @@ -13,12 +13,12 @@ "repository": { "type": "git", - "url": "https://github.com/RobTillaart/Arduino.git" + "url": "https://github.com/RobTillaart/PinInGroup.git" }, - "version":"0.1.0", + "version":"0.1.1", "frameworks": "arduino", "platforms": "*", "export": { - "include": "libraries/PinInGroup + "include": "PinInGroup } } diff --git a/libraries/PinInGroup/library.properties b/libraries/PinInGroup/library.properties index 6af2de9c..93b325ce 100644 --- a/libraries/PinInGroup/library.properties +++ b/libraries/PinInGroup/library.properties @@ -1,9 +1,11 @@ -name=pinGroup -version=0.1.0 +name=PinInGroup +version=0.1.1 author=Rob Tillaart maintainer=Rob Tillaart sentence=A class that groups input pins so they can be read in one logical step. paragraph= -category=Uncategorized -url=https://github.com/RobTillaart/Arduino/tree/master/libraries -architectures=* \ No newline at end of file +category=Communication +url=https://github.com/RobTillaart/PinInGroup +architectures=* +includes=PinInGroup.h +depends=