From 59141d6116e9800df37c6264b46ccedb187c46d0 Mon Sep 17 00:00:00 2001 From: DeanIsMe Date: Mon, 19 Dec 2016 22:12:14 +1000 Subject: [PATCH] Version 3.2.0 A major update - but backwards compatible with version 3.1. See SevSeg.cpp or README.md for a full list of changes. --- README.md | 62 ++- SevSeg.cpp | 509 ++++++++++++++------- SevSeg.h | 40 +- examples/SevSeg_Counter/SevSeg_Counter.ino | 9 +- keywords.txt | 3 + library.properties | 10 + 6 files changed, 424 insertions(+), 209 deletions(-) create mode 100644 library.properties diff --git a/README.md b/README.md index e2d4195..49bdcd3 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ SevSeg ====== - Copyright 2014 Dean Reading + Copyright 2016 Dean Reading Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -16,17 +16,23 @@ SevSeg This library turns your Arduino into a seven segment display controller! Use it to easily display numbers on your seven segment display without any additional controllers. -It supports common cathode and common anode displays, and the use of switching transistors. Displays with 1 to 9 digits can be used, and decimal places are supported. Characters and strings are not supported. +It supports common cathode and common anode displays, and the use of switching transistors. Numbers can be displayed in decimal or hexadecimal representation, with decimal places. Characters can be displayed (as accurately as possible). It also supports multiple displays, of varying dimensions. Shift registers and similar devices are NOT supported. [Download it from GitHub][1]. Direct any questions or suggestions to deanreading@hotmail.com. If I have the time, I'm happy to help you get things working. -#### Previous Versions Note +#### Update Version 3.2.0 (December 2016) -This version is not compatible with previous versions of the SevSeg library, which have been available since 2012. You can download the [old version][2] for compatibility with previously written programs. - -Thanks to Mark Chambers and Nathan Seidle for code used in updates. + Backwards compatible with version 3.1 + Updated to Arduino 1.5 Library Specification + New display function - no longer consumes processor time with delay() + Now supports hexadecimal number printing + The decimal point can now be omitted with a negative decPlaces + Alphanumeric strings can be displayed (inaccurately) with setChars + Removed #define RESISTORS_ON_SEGMENTS. Now a begin() input + Can now blank() the display + Now 'heavier' - uses more PROGMEM and RAM * * * @@ -46,7 +52,7 @@ All digit pins and segment pins can be connected to any of the Arduino's digital #### Current-limiting Resistors -Don't forget that the display uses LEDs, so you should use current-limiting resistors in series with the *digit pins*. 330 ohms is a safe value if you're unsure. If you use current-limiting resistors on the *segment pins* instead, then open up the SevSeg.h file and set RESISTORS_ON_SEGMENTS to 1 for optimal brightness. +Don't forget that the display uses LEDs, so you should use current-limiting resistors in series with the *digit pins*. 330 ohms is a safe value if you're unsure. If you use current-limiting resistors on the *segment pins* instead, then set resistorsOnSegments to true (see the example SevSeg_Counter.ino). #### Hardware Configuration @@ -83,6 +89,7 @@ Bottom Row: E D DP C G 4 ### SOFTWARE To install, copy the SevSeg folder into your arduino sketchbook\-libraries folder. More detailed instructions are [here][3]. +The Library Manager can be used from arduino version 1.6.2. #### Setting Up @@ -92,10 +99,12 @@ To install, copy the SevSeg folder into your arduino sketchbook\-libraries folde SevSeg sevseg; //Instantiate a seven segment object void setup() { - byte numDigits = 4; + byte numDigits = 4; byte digitPins[] = {2, 3, 4, 5}; byte segmentPins[] = {6, 7, 8, 9, 10, 11, 12, 13}; - sevseg.begin(COMMON_ANODE, numDigits, digitPins, segmentPins); + bool resistorsOnSegments = false; // Use 'true' if on digit pins + byte hardwareConfig = COMMON_ANODE; // See README.md for options + sevseg.begin(hardwareConfig, numDigits, digitPins, segmentPins, resistorsOnSegments); ... @@ -104,42 +113,59 @@ segmentPins is an array that stores the arduino pin numbers that the segments ar If you wish to use more than 8 digits, increase MAXNUMDIGITS in SevSeg.h. -#### Setting the Number +#### Setting a Number sevseg.setNumber(3141,3); // Displays '3.141' The first argument is the number to display. The second argument indicates where the decimal place should be, counted from the least significant digit. E.g. to display an integer, the second argument is 0. -Floats are supported. In this case, the second argument indicated how many decimal places of precision you want to display. E.g: +Floats are supported. In this case, the second argument indicates how many decimal places of precision you want to display. E.g: + + + sevseg.setNumber(3.14159f,3); //Displays '3.141' + + +Out of range numbers are shown as '----'. + +If the second argument is -1 or omitted, there will be no decimal place. +Enter 'true' as the third agument to display the number in hexadecimal representation. - sevseg.setNumber(3.141f,3); //Displays '3.141' +#### Setting a Character String -Out of range numbers show up as ------. + sevseg.setChars("abcd"); -#### Displaying the Number +Character arrays can be displayed - as accurately as possible on a seven segment display. See SevSeg.cpp digitCodeMap[] to notes on each character. Only alphanumeric characters, plus ' ' and '-' are supported. The character array should be NULL terminated. + + +#### Displaying sevseg.refreshDisplay(); -Your program must run the refreshDisplay() function repeatedly to display the number. +Your program must run the refreshDisplay() function repeatedly to display the number. Note that any delays introduced by other functions will produce undesirable effects on the display. + +To blank the display, call: + + sevseg.blank(); + -#### Set the Brightness +#### Setting the Brightness sevseg.setBrightness(90); The brightness can be adjusted using a value between 0 and 100. -Note that a 0 does not correspond to no brightness. If you wish for the display to be any dimmer than 0, run `sevseg.refreshDisplay();` less frequently. If your display has noticeable flickering, reducing the brightness level may correct it. +Note that a 0 does not correspond to no brightness. If your display has noticeable flickering, reducing the brightness level may correct it. [1]: https://github.com/DeanIsMe/SevSeg [2]: https://docs.google.com/file/d/0Bwrp4uluZCpNdE9oWTY0M3BncTA/edit?usp=sharing [3]: http://arduino.cc/en/Guide/Libraries [4]: https://en.wikipedia.org/wiki/File:7_segment_display_labeled.svg [5]: http://www.ebay.com/sch/i.html?LH_BIN=1&_from=R40&_sacat=0&_nkw=7+segment+display+4+digit+2+pcs&_sop=15 - + \ No newline at end of file diff --git a/SevSeg.cpp b/SevSeg.cpp index dff14f3..75484ee 100644 --- a/SevSeg.cpp +++ b/SevSeg.cpp @@ -1,48 +1,57 @@ /* SevSeg Library - - Copyright 2014 Dean Reading - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - - - This library allows an Arduino to easily display numbers in decimal format on - a 7-segment display without a separate 7-segment display controller. - - Direct any questions or suggestions to deanreading@hotmail.com - See the included readme for instructions. - - CHANGELOG - - Version 3.1 - September 2016 - Bug Fixes. No longer uses dynamic memory allocation. - Version 3.0 - November 2014 - Library re-design. A display with any number of digits can be used. - Floats are supported. Support for using transistors for switching. - Much more user friendly. No backwards compatibility. - Uploaded to GitHub to simplify any further development. - Version 2.3; Allows for brightness control. - Version 2.2; Allows 1, 2 or 3 digit displays to be used. - Version 2.1; Includes a bug fix. - Version 2.0; Now works for any digital pin arrangement. - Supports both common anode and common cathode displays. - */ -#include "SevSeg.h" + Copyright 2016 Dean Reading + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + + This library allows an Arduino to easily display numbers in decimal format on + a 7-segment display without a separate 7-segment display controller. + + Direct any questions or suggestions to deanreading@hotmail.com + See the included readme for instructions. + https://github.com/DeanIsMe/SevSeg + + CHANGELOG + Version 3.2.0 - December 2016 + Updated to Arduino 1.5 Library Specification + New display function - no longer consumes processor time with delay() + Now supports hexadecimal number printing + The decimal point can now be omitted with a negative decPlaces + decPlaces is now optional in setNumber + Alphanumeric strings can be displayed (inaccurately) with setChars() + Removed #define RESISTORS_ON_SEGMENTS. Now a begin() input + Can now blank() the display + + Version 3.1 - September 2016 + Bug Fixes. No longer uses dynamic memory allocation. + Version 3.0 - November 2014 + Library re-design. A display with any number of digits can be used. + Floats are supported. Support for using transistors for switching. + Much more user friendly. No backwards compatibility. + Uploaded to GitHub to simplify any further development. + Version 2.3; Allows for brightness control. + Version 2.2; Allows 1, 2 or 3 digit displays to be used. + Version 2.1; Includes a bug fix. + Version 2.0; Now works for any digital pin arrangement. + Supports both common anode and common cathode displays. +*/ -#define BLANK 10 // Must match with 'digitCodeMap', defined in 'setDigitCodes' -#define DASH 11 +#include "SevSeg.h" +#define BLANK_IDX 36 // Must match with 'digitCodeMap' +#define DASH_IDX 37 -const long SevSeg::powersOf10[] = { +static const long powersOf10[] = { 1, // 10^0 10, 100, @@ -52,51 +61,120 @@ const long SevSeg::powersOf10[] = { 1000000, 10000000, 100000000, - 1000000000}; // 10^9 - - -// SevSeg + 1000000000 +}; // 10^9 + +static const long powersOf16[] = { + 0x1, // 16^0 + 0x10, + 0x100, + 0x1000, + 0x10000, + 0x100000, + 0x1000000, + 0x10000000 +}; // 16^7 + +// The codes below indicate which segments must be illuminated to display +// each number. +static const byte digitCodeMap[] = { + // GFEDCBA Segments 7-segment map: + B00111111, // 0 "0" AAA + B00000110, // 1 "1" F B + B01011011, // 2 "2" F B + B01001111, // 3 "3" GGG + B01100110, // 4 "4" E C + B01101101, // 5 "5" E C + B01111101, // 6 "6" DDD + B00000111, // 7 "7" + B01111111, // 8 "8" + B01101111, // 9 "9" + B01110111, // 65 'A' + B01111100, // 66 'b' + B00111001, // 67 'C' + B01011110, // 68 'd' + B01111001, // 69 'E' + B01110001, // 70 'F' + B00111101, // 71 'G' + B01110110, // 72 'H' + B00000110, // 73 'I' + B00001110, // 74 'J' + B01110110, // 75 'K' Same as 'H' + B00111000, // 76 'L' + B00000000, // 77 'M' NO DISPLAY + B01010100, // 78 'n' + B00111111, // 79 'O' + B01110011, // 80 'P' + B01100111, // 81 'q' + B01010000, // 82 'r' + B01101101, // 83 'S' + B01111000, // 84 't' + B00111110, // 85 'U' + B00111110, // 86 'V' Same as 'U' + B00000000, // 87 'W' NO DISPLAY + B01110110, // 88 'X' Same as 'H' + B01101110, // 89 'y' + B01011011, // 90 'Z' Same as '2' + B00000000, // 32 ' ' BLANK + B01000000, // 45 '-' DASH +}; + +// Constant pointers to constant data +const byte * const numeralCodes = digitCodeMap; +const byte * const alphaCodes = digitCodeMap + 10; + +// SevSeg Constructor /******************************************************************************/ SevSeg::SevSeg() { // Initial value ledOnTime = 2000; // Corresponds to a brightness of 100 numDigits = 0; + prevUpdateIdx = 0; + prevUpdateTime = 0; + resOnSegments = 0; + updateWithDelays = 0; } // begin /******************************************************************************/ // Saves the input pin numbers to the class and sets up the pins to be used. +// If you use current-limiting resistors on your segment pins instead of the +// digit pins, then set resOnSegments as true. +// Set updateWithDelays to true if you want to use the 'pre-2017' update method +// That method occupies the processor with delay functions. +void SevSeg::begin(byte hardwareConfig, byte numDigitsIn, byte digitPinsIn[], + byte segmentPinsIn[], bool resOnSegmentsIn, bool updateWithDelaysIn) { + + resOnSegments = resOnSegmentsIn; + updateWithDelays = updateWithDelaysIn; -void SevSeg::begin(byte hardwareConfig, byte numDigitsIn, - byte digitPinsIn[], byte segmentPinsIn[]) { - numDigits = numDigitsIn; //Limit the max number of digits to prevent overflowing if (numDigits > MAXNUMDIGITS) numDigits = MAXNUMDIGITS; - switch (hardwareConfig){ + switch (hardwareConfig) { - case 0: // Common cathode - digitOn = LOW; - segmentOn = HIGH; - break; + case 0: // Common cathode + digitOn = LOW; + segmentOn = HIGH; + break; - case 1: // Common anode - digitOn = HIGH; - segmentOn = LOW; - break; + case 1: // Common anode + digitOn = HIGH; + segmentOn = LOW; + break; - case 2: // With active-high, low-side switches (most commonly N-type FETs) - digitOn = HIGH; - segmentOn = HIGH; - break; + case 2: // With active-high, low-side switches (most commonly N-type FETs) + digitOn = HIGH; + segmentOn = HIGH; + break; - case 3: // With active low, high side switches (most commonly P-type FETs) - digitOn = LOW; - segmentOn = LOW; - break; + case 3: // With active low, high side switches (most commonly P-type FETs) + digitOn = LOW; + segmentOn = LOW; + break; } digitOff = !digitOn; @@ -112,84 +190,150 @@ void SevSeg::begin(byte hardwareConfig, byte numDigitsIn, } // Set the pins as outputs, and turn them off - for (byte digit=0 ; digit < numDigits ; digit++) { + for (byte digit = 0 ; digit < numDigits ; digit++) { pinMode(digitPins[digit], OUTPUT); digitalWrite(digitPins[digit], digitOff); } - for (byte segmentNum=0 ; segmentNum < 8 ; segmentNum++) { + for (byte segmentNum = 0 ; segmentNum < 8 ; segmentNum++) { pinMode(segmentPins[segmentNum], OUTPUT); digitalWrite(segmentPins[segmentNum], segmentOff); } - setNewNum(0,0); // Initialise the number displayed to 0 + setNewNum(0, 0); // Initialise the number displayed to 0 } // refreshDisplay /******************************************************************************/ -// Flashes the output on the seven segment display. -// This is achieved by cycling through all segments and digits, turning the -// required segments on as specified by the array 'digitCodes'. -// There are 2 versions of this function, with the choice depending on the -// location of the current-limiting resistors. - -#if !(RESISTORS_ON_SEGMENTS) -//For resistors on *digits* we will cycle through all 8 segments (7 + period), turning on the *digits* as appropriate -//for a given segment, before moving on to the next segment -void SevSeg::refreshDisplay(){ - for (byte segmentNum=0 ; segmentNum < 8 ; segmentNum++) { - - // Illuminate the required digits for this segment - digitalWrite(segmentPins[segmentNum], segmentOn); - for (byte digitNum=0 ; digitNum < numDigits ; digitNum++){ - if (digitCodes[digitNum] & (1 << segmentNum)) { // Check a single bit - digitalWrite(digitPins[digitNum], digitOn); +// Turns on the segments specified in 'digitCodes[]' +// There are 4 versions of this function, with the choice depending on the +// location of the current-limiting resistors, and whether or not you wish to +// use 'update delays' (the standard method until 2017). +// For resistors on *digits* we will cycle through all 8 segments (7 + period), +// turning on the *digits* as appropriate for a given segment, before moving on +// to the next segment. +// For resistors on *segments* we will cycle through all __ # of digits, +// turning on the *segments* as appropriate for a given digit, before moving on +// to the next digit. +// If using update delays, refreshDisplay has a delay between each digit/segment +// as it cycles through. It exits with all LEDs off. +// If not using updateDelays, refreshDisplay exits with a single digit/segment +// on. It will move to the next digit/segment after being called again (if +// enough time has passed). + +void SevSeg::refreshDisplay() { + + if (!updateWithDelays) { + + // Exit if it's not time for the next display change + if (micros() - prevUpdateTime < ledOnTime) return; + prevUpdateTime = micros(); + + if (!resOnSegments) { + /**********************************************/ + // RESISTORS ON DIGITS, UPDATE WITHOUT DELAYS + + + // Turn all lights off for the previous segment + for (byte digitNum = 0 ; digitNum < numDigits ; digitNum++) { + digitalWrite(digitPins[digitNum], digitOff); + } + digitalWrite(segmentPins[prevUpdateIdx], segmentOff); + + prevUpdateIdx++; + if (prevUpdateIdx >= 8) prevUpdateIdx = 0; + + byte segmentNum = prevUpdateIdx; + + // Illuminate the required digits for the new segment + digitalWrite(segmentPins[segmentNum], segmentOn); + for (byte digitNum = 0 ; digitNum < numDigits ; digitNum++) { + if (digitCodes[digitNum] & (1 << segmentNum)) { // Check a single bit + digitalWrite(digitPins[digitNum], digitOn); + } } } + else { + /**********************************************/ + // RESISTORS ON SEGMENTS, UPDATE WITHOUT DELAYS + + + // Turn all lights off for the previous digit + for (byte segmentNum = 0 ; segmentNum < 8 ; segmentNum++) { + digitalWrite(segmentPins[segmentNum], segmentOff); + } + digitalWrite(digitPins[prevUpdateIdx], digitOff); + + prevUpdateIdx++; + if (prevUpdateIdx >= numDigits) prevUpdateIdx = 0; - //Wait with lights on (to increase brightness) - delayMicroseconds(ledOnTime); + byte digitNum = prevUpdateIdx; - //Turn all lights off - for (byte digitNum=0 ; digitNum < numDigits ; digitNum++){ - digitalWrite(digitPins[digitNum], digitOff); + // Illuminate the required segments for the new digit + digitalWrite(digitPins[digitNum], digitOn); + for (byte segmentNum = 0 ; segmentNum < 8 ; segmentNum++) { + if (digitCodes[digitNum] & (1 << segmentNum)) { // Check a single bit + digitalWrite(segmentPins[segmentNum], segmentOn); + } + } } - digitalWrite(segmentPins[segmentNum], segmentOff); } -} -#else -//For resistors on *segments* we will cycle through all __ # of digits, turning on the *segments* as appropriate -//for a given digit, before moving on to the next digit -void SevSeg::refreshDisplay(){ - for (byte digitNum=0 ; digitNum < numDigits ; digitNum++){ + else { + if (!resOnSegments) { + /**********************************************/ + // RESISTORS ON DIGITS, UPDATE WITH DELAYS + for (byte segmentNum = 0 ; segmentNum < 8 ; segmentNum++) { - // Illuminate the required segments for this digit - digitalWrite(digitPins[digitNum], digitOn); - for (byte segmentNum=0 ; segmentNum < 8 ; segmentNum++) { - if (digitCodes[digitNum] & (1 << segmentNum)) { // Check a single bit + // Illuminate the required digits for this segment digitalWrite(segmentPins[segmentNum], segmentOn); + for (byte digitNum = 0 ; digitNum < numDigits ; digitNum++) { + if (digitCodes[digitNum] & (1 << segmentNum)) { // Check a single bit + digitalWrite(digitPins[digitNum], digitOn); + } + } + + //Wait with lights on (to increase brightness) + delayMicroseconds(ledOnTime); + + //Turn all lights off + for (byte digitNum = 0 ; digitNum < numDigits ; digitNum++) { + digitalWrite(digitPins[digitNum], digitOff); + } + digitalWrite(segmentPins[segmentNum], segmentOff); } } + else { + /**********************************************/ + // RESISTORS ON SEGMENTS, UPDATE WITH DELAYS + for (byte digitNum = 0 ; digitNum < numDigits ; digitNum++) { - //Wait with lights on (to increase brightness) - delayMicroseconds(ledOnTime); - - //Turn all lights off - for (byte segmentNum=0 ; segmentNum < 8 ; segmentNum++) { - digitalWrite(segmentPins[segmentNum], segmentOff); + // Illuminate the required segments for this digit + digitalWrite(digitPins[digitNum], digitOn); + for (byte segmentNum = 0 ; segmentNum < 8 ; segmentNum++) { + if (digitCodes[digitNum] & (1 << segmentNum)) { // Check a single bit + digitalWrite(segmentPins[segmentNum], segmentOn); + } + } + + //Wait with lights on (to increase brightness) + delayMicroseconds(ledOnTime); + + //Turn all lights off + for (byte segmentNum = 0 ; segmentNum < 8 ; segmentNum++) { + digitalWrite(segmentPins[segmentNum], segmentOff); + } + digitalWrite(digitPins[digitNum], digitOff); + } } - digitalWrite(digitPins[digitNum], digitOff); } } -#endif - // setBrightness /******************************************************************************/ -void SevSeg::setBrightness(int brightness){ +void SevSeg::setBrightness(int brightness) { brightness = constrain(brightness, 0, 100); ledOnTime = map(brightness, 0, 100, 1, 2000); } @@ -201,42 +345,59 @@ void SevSeg::setBrightness(int brightness){ // It is overloaded for all number data types, so that floats can be handled // correctly. -void SevSeg::setNumber(long numToShow, byte decPlaces) //long +void SevSeg::setNumber(long numToShow, char decPlaces, bool hex) //long { - setNewNum(numToShow, decPlaces); + setNewNum(numToShow, decPlaces, hex); } -void SevSeg::setNumber(unsigned long numToShow, byte decPlaces) //unsigned long +void SevSeg::setNumber(unsigned long numToShow, char decPlaces, bool hex) //unsigned long { - setNewNum(numToShow, decPlaces); + setNewNum(numToShow, decPlaces, hex); } -void SevSeg::setNumber(int numToShow, byte decPlaces) //int +void SevSeg::setNumber(int numToShow, char decPlaces, bool hex) //int { - setNewNum(numToShow, decPlaces); + setNewNum(numToShow, decPlaces, hex); } -void SevSeg::setNumber(unsigned int numToShow, byte decPlaces) //unsigned int +void SevSeg::setNumber(unsigned int numToShow, char decPlaces, bool hex) //unsigned int { - setNewNum(numToShow, decPlaces); + setNewNum(numToShow, decPlaces, hex); } -void SevSeg::setNumber(char numToShow, byte decPlaces) //char +void SevSeg::setNumber(char numToShow, char decPlaces, bool hex) //char { - setNewNum(numToShow, decPlaces); + setNewNum(numToShow, decPlaces, hex); } -void SevSeg::setNumber(byte numToShow, byte decPlaces) //byte +void SevSeg::setNumber(byte numToShow, char decPlaces, bool hex) //byte { - setNewNum(numToShow, decPlaces); + setNewNum(numToShow, decPlaces, hex); } -void SevSeg::setNumber(float numToShow, byte decPlaces) //float +void SevSeg::setNumber(float numToShow, char decPlaces, bool hex) //float { - numToShow = numToShow * powersOf10[decPlaces]; + char decPlacesPos = constrain(decPlaces, 0, MAXNUMDIGITS); + if (hex) { + numToShow = numToShow * powersOf16[decPlacesPos]; + } + else { + numToShow = numToShow * powersOf10[decPlacesPos]; + } // Modify the number so that it is rounded to an integer correctly numToShow += (numToShow >= 0) ? 0.5f : -0.5f; - setNewNum(numToShow, decPlaces); + setNewNum(numToShow, decPlaces, hex); +} + + +// setNewNum +/******************************************************************************/ +// Changes the number that will be displayed. + +void SevSeg::setNewNum(long numToShow, char decPlaces, bool hex) { + byte digits[numDigits]; + findDigits(numToShow, decPlaces, hex, digits); + setDigitCodes(digits, decPlaces); } @@ -260,59 +421,90 @@ void SevSeg::setNumber(float numToShow, byte decPlaces) //float void SevSeg::setSegments(byte segs[]) { for (byte digit = 0; digit < numDigits; digit++) { - digitCodes[digit] = segs[digit]; + digitCodes[digit] = segs[digit]; } } - -// setNewNum +// setChars /******************************************************************************/ -// Changes the number that will be displayed. +// Displays the string on the display, as best as possible. +// Only alphanumeric characters plus '-' and ' ' are supported +void SevSeg::setChars(char str[]) +{ + for (byte digit = 0; digit < numDigits; digit++) { + digitCodes[digit] = 0; + } -void SevSeg::setNewNum(long numToShow, byte decPlaces){ - byte digits[numDigits]; - findDigits(numToShow, decPlaces, digits); - setDigitCodes(digits, decPlaces); + for (byte digitNum = 0; digitNum < numDigits; digitNum++) { + char ch = str[digitNum]; + if (ch == '\0') break; // NULL string terminator + if (ch >= '0' && ch <= '9') { // Numerical + digitCodes[digitNum] = numeralCodes[ch - '0']; + } + else if (ch >= 'A' && ch <= 'Z') { + digitCodes[digitNum] = alphaCodes[ch - 'A']; + } + else if (ch >= 'a' && ch <= 'z') { + digitCodes[digitNum] = alphaCodes[ch - 'a']; + } + else if (ch == ' ') { + digitCodes[digitNum] = digitCodeMap[BLANK_IDX]; + } + else { + // Every unknown character is shown as a dash + digitCodes[digitNum] = digitCodeMap[DASH_IDX]; + } + } } +// blank +/******************************************************************************/ +void SevSeg::blank(void) { + for (byte digitNum = 0 ; digitNum < numDigits ; digitNum++) { + digitCodes[digitNum] = digitCodeMap[BLANK_IDX]; + } + refreshDisplay(); +} // findDigits /******************************************************************************/ // Decides what each digit will display. // Enforces the upper and lower limits on the number to be displayed. -void SevSeg::findDigits(long numToShow, byte decPlaces, byte digits[]) { - static const long maxNum = powersOf10[numDigits] - 1; - static const long minNum = -(powersOf10[numDigits - 1] - 1); +void SevSeg::findDigits(long numToShow, char decPlaces, bool hex, byte digits[]) { + const long * powersOfBase = hex ? powersOf16 : powersOf10; + const long maxNum = powersOfBase[numDigits] - 1; + const long minNum = -(powersOfBase[numDigits - 1] - 1); // If the number is out of range, just display dashes if (numToShow > maxNum || numToShow < minNum) { - for (byte digitNum = 0 ; digitNum < numDigits ; digitNum++){ - digits[digitNum] = DASH; + for (byte digitNum = 0 ; digitNum < numDigits ; digitNum++) { + digits[digitNum] = DASH_IDX; } } - else{ + else { byte digitNum = 0; // Convert all number to positive values if (numToShow < 0) { - digits[0] = DASH; + digits[0] = DASH_IDX; digitNum = 1; // Skip the first iteration numToShow = -numToShow; } - // Find all digits for the base 10 representation, starting with the most + // Find all digits for base's representation, starting with the most // significant digit - for ( ; digitNum < numDigits ; digitNum++){ - long factor = powersOf10[numDigits - 1 - digitNum]; + for ( ; digitNum < numDigits ; digitNum++) { + long factor = powersOfBase[numDigits - 1 - digitNum]; digits[digitNum] = numToShow / factor; numToShow -= digits[digitNum] * factor; } // Find unnnecessary leading zeros and set them to BLANK - for (digitNum = 0 ; digitNum < (numDigits - 1 - decPlaces) ; digitNum++){ + if (decPlaces < 0) decPlaces = 0; + for (digitNum = 0 ; digitNum < (numDigits - 1 - decPlaces) ; digitNum++) { if (digits[digitNum] == 0) { - digits[digitNum] = BLANK; + digits[digitNum] = BLANK_IDX; } // Exit once the first non-zero number is encountered else if (digits[digitNum] <= 9) { @@ -328,33 +520,16 @@ void SevSeg::findDigits(long numToShow, byte decPlaces, byte digits[]) { /******************************************************************************/ // Sets the 'digitCodes' that are required to display the input numbers -void SevSeg::setDigitCodes(byte digits[], byte decPlaces) { - - // The codes below indicate which segments must be illuminated to display - // each number. - static const byte digitCodeMap[] = { - // Segments: [see setSegments() for bit/segment mapping] - // HGFEDCBA // Char: - B00111111, // 0 - B00000110, // 1 - B01011011, // 2 - B01001111, // 3 - B01100110, // 4 - B01101101, // 5 - B01111101, // 6 - B00000111, // 7 - B01111111, // 8 - B01101111, // 9 - B00000000, // BLANK - B01000000, // DASH - }; +void SevSeg::setDigitCodes(byte digits[], char decPlaces) { // Set the digitCode for each digit in the display for (byte digitNum = 0 ; digitNum < numDigits ; digitNum++) { digitCodes[digitNum] = digitCodeMap[digits[digitNum]]; // Set the decimal place segment - if (digitNum == numDigits - 1 - decPlaces) { - digitCodes[digitNum] |= B10000000; + if (decPlaces >= 0) { + if (digitNum == numDigits - 1 - decPlaces) { + digitCodes[digitNum] |= B10000000; + } } } } diff --git a/SevSeg.h b/SevSeg.h index 054d685..7d9eaae 100644 --- a/SevSeg.h +++ b/SevSeg.h @@ -1,6 +1,6 @@ /* SevSeg Library - Copyright 2014 Dean Reading + Copyright 2016 Dean Reading Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -21,11 +21,7 @@ See the included readme for instructions. */ -// If you use current-limiting resistors on your segment pins instead of the -// digit pins, then change the '0' in the line below to a '1' -#define RESISTORS_ON_SEGMENTS 0 -#define MAXNUMDIGITS 8 //Increase this number to support larger displays - +#define MAXNUMDIGITS 8 // Can be increased, but the max number is 2^31 #ifndef SevSeg_h #define SevSeg_h @@ -51,32 +47,36 @@ class SevSeg SevSeg(); void refreshDisplay(); - void begin(byte hardwareConfig, byte numDigitsIn, byte digitPinsIn[], byte segmentPinsIn[]); + void begin(byte hardwareConfig, byte numDigitsIn, byte digitPinsIn[], + byte segmentPinsIn[], bool resOnSegmentsIn=0, bool updateWithDelaysIn=0); void setBrightness(int brightnessIn); // A number from 0..100 - void setNumber(long numToShow, byte decPlaces); - void setNumber(unsigned long numToShow, byte decPlaces); - void setNumber(int numToShow, byte decPlaces); - void setNumber(unsigned int numToShow, byte decPlaces); - void setNumber(char numToShow, byte decPlaces); - void setNumber(byte numToShow, byte decPlaces); - void setNumber(float numToShow, byte decPlaces); + void setNumber(long numToShow, char decPlaces=-1, bool hex=0); + void setNumber(unsigned long numToShow, char decPlaces=-1, bool hex=0); + void setNumber(int numToShow, char decPlaces=-1, bool hex=0); + void setNumber(unsigned int numToShow, char decPlaces=-1, bool hex=0); + void setNumber(char numToShow, char decPlaces=-1, bool hex=0); + void setNumber(byte numToShow, char decPlaces=-1, bool hex=0); + void setNumber(float numToShow, char decPlaces=-1, bool hex=0); void setSegments(byte segs[]); + void setChars(char str[]); + void blank(void); private: - void setNewNum(long numToShow, byte decPlaces); - void findDigits(long numToShow, byte decPlaces, byte nums[]); - void setDigitCodes(byte nums[], byte decPlaces); + void setNewNum(long numToShow, char decPlaces, bool hex=0); + void findDigits(long numToShow, char decPlaces, bool hex, byte digits[]); + void setDigitCodes(byte nums[], char decPlaces); - boolean digitOn,digitOff,segmentOn,segmentOff; + bool digitOn,digitOff,segmentOn,segmentOff; + bool resOnSegments, updateWithDelays; byte digitPins[MAXNUMDIGITS]; byte segmentPins[8]; byte numDigits; + byte prevUpdateIdx; byte digitCodes[MAXNUMDIGITS]; int ledOnTime; - const static long powersOf10[10]; - + unsigned long prevUpdateTime; }; #endif //SevSeg_h diff --git a/examples/SevSeg_Counter/SevSeg_Counter.ino b/examples/SevSeg_Counter/SevSeg_Counter.ino index 6c4f2cc..90456c7 100644 --- a/examples/SevSeg_Counter/SevSeg_Counter.ino +++ b/examples/SevSeg_Counter/SevSeg_Counter.ino @@ -1,6 +1,6 @@ /* SevSeg Counter Example - Copyright 2014 Dean Reading + Copyright 2016 Dean Reading Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -19,15 +19,16 @@ */ #include "SevSeg.h" - SevSeg sevseg; //Instantiate a seven segment controller object void setup() { byte numDigits = 4; byte digitPins[] = {2, 3, 4, 5}; byte segmentPins[] = {6, 7, 8, 9, 10, 11, 12, 13}; - - sevseg.begin(COMMON_ANODE, numDigits, digitPins, segmentPins); + bool resistorsOnSegments = false; // Use 'true' if on digit pins + byte hardwareConfig = COMMON_ANODE; // See README.md for options + + sevseg.begin(hardwareConfig, numDigits, digitPins, segmentPins, resistorsOnSegments); sevseg.setBrightness(90); } diff --git a/keywords.txt b/keywords.txt index 385af9e..5ac5249 100644 --- a/keywords.txt +++ b/keywords.txt @@ -2,6 +2,9 @@ SevSeg KEYWORD1 setNumber KEYWORD2 refreshDisplay KEYWORD2 setBrightness KEYWORD2 +setSegments KEYWORD2 +setChars KEYWORD2 +blank KEYWORD2 COMMON_CATHODE LITERAL1 COMMON_ANODE LITERAL1 N_TRANSISTORS LITERAL1 diff --git a/library.properties b/library.properties new file mode 100644 index 0000000..315a60b --- /dev/null +++ b/library.properties @@ -0,0 +1,10 @@ +name=SevSeg +version=3.2.0 +author=Dean Reading +maintainer=Dean Reading +sentence=Turns your Arduino into a seven segment display controller! +paragraph=Use it to easily display numbers on your seven segment display without any additional hardware. Supports common cathode and common anode displays, the use of switching transistors, decimal numbers, hexadecimal numbers, and alphanumeric characters. +category=Display +url=https://github.com/DeanIsMe/SevSeg +architectures=* +includes=SevSeg.h \ No newline at end of file