From 912f782940456e39befa399006af63471041ee2b Mon Sep 17 00:00:00 2001 From: monkeybiscuits Date: Tue, 7 Feb 2017 22:49:15 +0900 Subject: [PATCH 1/3] DisplayString() using no delays The DisplayString function has been updated to eliminate any delay. Rather than iterating through the digits in a for loop every time the function is called, this approach iterates on a static variable only after a given time has elapsed regardless of how often the function is called. In order to get this working while preserving all other functionality (brightness, different numbers/types of digits, etc.) the function has become a little harder to follow. Here it is in a nutshell. /********************************************************************/ static byte digit = 0; if (time is up) //do something if (digit == numberOfDigits +1) //only used when there's a colon and/or apos turn off the final digit //the one equal to numberOfDigits turn on the colon and/or apos digit = 0 //reset static variable for the next cycle set timer to brightness else if (digit == numberOfDigits) turn off previous digit turn on final digit //the one equal to numberOfDigits if (there's a colon) digit++ //is there a colon/apos? else digit=0 //or should we reset? set timer to brightness else if (digit == 0) if (there's a colon/apos) turn off colon/apos else turn off the final digit //the one equal to numberOfDigits set timer to brightnessDelay else if (digit != 1); //digits that can be iterated upon normally turn off the previous digit turn on the current digit set timer to brightness digit++; else do nothing until time is up /********************************************************************/ The sections for turning digits/segments on and off have been broken out into void turnDigitOff(byte digit); void turnDigitOn(char* toDisplay, byte digit); Variables for keeping track of time have also been added. unsigned long previousMicros, timer; I hadn't originally intended to edit SetBrightness() but because the new approach entirely foregoes the FRAMEPERIOD, I had to find a workaround. I think it makes the code a bit cleaner and I haven't noticed any kind of flickering but it's only been tested properly on a 4-digit display. --- src/SevSeg.cpp | 259 ++++++++++++++++++++++++++++--------------------- src/SevSeg.h | 16 +-- 2 files changed, 155 insertions(+), 120 deletions(-) diff --git a/src/SevSeg.cpp b/src/SevSeg.cpp index 51cfa2c..2a8f256 100644 --- a/src/SevSeg.cpp +++ b/src/SevSeg.cpp @@ -65,7 +65,6 @@ SevSeg::SevSeg() { //Initial values DecAposColon = 0; //This variable tracks the decimal place, apostrophe, and colon (if the display has support) - } void SevSeg::Begin(boolean mode_in, byte numOfDigits, byte dig1, byte dig2, byte dig3, byte dig4, @@ -152,6 +151,9 @@ void SevSeg::Begin(boolean mode_in, byte numOfDigits, digitalWrite(segmentApostrophe, SegOff); pinMode(segmentApostrophe, OUTPUT); } + + previousMicros = 0; + timer = 0; } //Begin @@ -174,9 +176,10 @@ void SevSeg::Begin(boolean mode_in, byte numOfDigits, //We need to error check and map the incoming value void SevSeg::SetBrightness(byte percentBright) { - //Error check and scale brightnessLevel - if(percentBright > 100) percentBright = 100; - brightnessDelay = map(percentBright, 0, 100, 0, FRAMEPERIOD); //map brightnessDelay to 0 to the max which is framePeriod + //Error check brightnessLevel + if(percentBright > 100){brightness = 100;} + + brightnessDelay = (100-brightness)*numberOfDigits*100/brightness; } @@ -189,113 +192,153 @@ void SevSeg::SetBrightness(byte percentBright) void SevSeg::DisplayString(char* toDisplay, byte DecAposColon) { //For the purpose of this code, digit = 1 is the left most digit, digit = 4 is the right most digit - for(byte digit = 1 ; digit < (numberOfDigits+1) ; digit++) - { - switch(digit) - { - case 1: - digitalWrite(digit1, DigitOn); - break; - case 2: - digitalWrite(digit2, DigitOn); - break; - case 3: - digitalWrite(digit3, DigitOn); - break; - case 4: - digitalWrite(digit4, DigitOn); - break; - //This only currently works for 4 digits - } - - //Here we access the array of segments - //This could be cleaned up a bit but it works - //displayCharacter(toDisplay[digit-1]); //Now display this digit - // displayArray (defined in SevSeg.h) decides which segments are turned on for each number or symbol - char characterToDisplay = toDisplay[digit-1]; - if (characterToDisplay & 0x80) // bit 7 enables bit-per-segment control - { // Each bit of characterToDisplay turns on a single segment (from A-to-G) - if (characterToDisplay & 0x01) digitalWrite(segmentA, SegOn); - if (characterToDisplay & 0x02) digitalWrite(segmentB, SegOn); - if (characterToDisplay & 0x04) digitalWrite(segmentC, SegOn); - if (characterToDisplay & 0x08) digitalWrite(segmentD, SegOn); - if (characterToDisplay & 0x10) digitalWrite(segmentE, SegOn); - if (characterToDisplay & 0x20) digitalWrite(segmentF, SegOn); - if (characterToDisplay & 0x40) digitalWrite(segmentG, SegOn); - } - else - { - const uint8_t chr = pgm_read_byte(&characterArray[characterToDisplay]); - if (chr & (1<<6)) digitalWrite(segmentA, SegOn); - if (chr & (1<<5)) digitalWrite(segmentB, SegOn); - if (chr & (1<<4)) digitalWrite(segmentC, SegOn); - if (chr & (1<<3)) digitalWrite(segmentD, SegOn); - if (chr & (1<<2)) digitalWrite(segmentE, SegOn); - if (chr & (1<<1)) digitalWrite(segmentF, SegOn); - if (chr & (1<<0)) digitalWrite(segmentG, SegOn); - } - //Service the decimal point, apostrophe and colon - if ((DecAposColon & (1<<(digit-1))) && (digit < 5)) //Test DecAposColon to see if we need to turn on a decimal point - digitalWrite(segmentDP, SegOn); - - delayMicroseconds(brightnessDelay + 1); //Display this digit for a fraction of a second (between 1us and 5000us, 500-2000 is pretty good) - //The + 1 is a bit of a hack but it removes the possible zero display (0 causes display to become bright and flickery) - //If you set this too long, the display will start to flicker. Set it to 25000 for some fun. + static byte digit = 0; // to be incremented to cycle through digits + if(micros() - previousMicros > timer) + { + if (digit == numberOfDigits + 1) // meaning the display has a colon or apostrophe + { + turnDigitOff(numberOfDigits); + //After we've gone through the digits, we control the colon and apostrophe (if the display supports it) + //Turn on the colon and/or apostrophe + if ((digitColon != 255) || (digitApostrophe != 255)) + { + if (DecAposColon & (1<<4)) //Test to see if we need to turn on the Colon + { + digitalWrite(digitColon, DigitOn); + digitalWrite(segmentColon, SegOn); + } + if (DecAposColon & (1<<5)) //Test DecAposColon to see if we need to turn on Apostrophe + { + digitalWrite(digitApostrophe, DigitOn); + digitalWrite(segmentApostrophe, SegOn); + } + } + digit = 0; + previousMicros = micros(); + timer = brightness; //Display this digit for a fraction of a second (between 1us and 5000us, 500-2000 is pretty good) + } - //Turn off all segments - digitalWrite(segmentA, SegOff); - digitalWrite(segmentB, SegOff); - digitalWrite(segmentC, SegOff); - digitalWrite(segmentD, SegOff); - digitalWrite(segmentE, SegOff); - digitalWrite(segmentF, SegOff); - digitalWrite(segmentG, SegOff); - digitalWrite(segmentDP, SegOff); + else if(digit == numberOfDigits) + { + turnDigitOff(numberOfDigits-1); + turnDigitOn(toDisplay, numberOfDigits); + digit = digitColon != 255 || digitApostrophe != 255 ? digit+1 : 0; + previousMicros = micros(); + timer = brightness; //Display this digit for a fraction of a second (between 1us and 5000us, 500-2000 is pretty good) + } - //Turn off this digit - switch(digit) - { - case 1: - digitalWrite(digit1, DigitOff); - break; - case 2: - digitalWrite(digit2, DigitOff); - break; - case 3: - digitalWrite(digit3, DigitOff); - break; - case 4: - digitalWrite(digit4, DigitOff); - break; - //This only currently works for 4 digits - } - // The display is on for microSeconds(brightnessLevel + 1), now turn off for the remainder of the framePeriod - delayMicroseconds(FRAMEPERIOD - brightnessDelay + 1); //the +1 is a hack so that we can never have a delayMicroseconds(0), causes display to flicker + else + { + if (digit == 0) + { + if ((digitColon != 255) || (digitApostrophe != 255)) + { + digitalWrite(digitColon, DigitOff); + digitalWrite(segmentColon, SegOff); + digitalWrite(digitApostrophe, DigitOff); + digitalWrite(segmentApostrophe, SegOff); + } + else + { + turnDigitOff(numberOfDigits); + } + // The display is on for microSeconds(brightnessLevel + 1), now turn off for the remainder of the framePeriod + previousMicros = micros(); + timer = brightnessDelay; + } + else + { + if (digit != 1) + { + turnDigitOff(digit-1); + } + turnDigitOn(toDisplay, digit); + previousMicros = micros(); + timer = brightness; //Display this digit for a fraction of a second (between 1us and 5000us, 500-2000 is pretty good) + } + digit++; + } } +} - //After we've gone through the digits, we control the colon and apostrophe (if the display supports it) - - //Turn on the colon and/or apostrophe - if ((digitColon != 255) || (digitApostrophe != 255)) - { - if (DecAposColon & (1<<4)) //Test to see if we need to turn on the Colon - { - digitalWrite(digitColon, DigitOn); - digitalWrite(segmentColon, SegOn); - } - if (DecAposColon & (1<<5)) //Test DecAposColon to see if we need to turn on Apostrophe - { - digitalWrite(digitApostrophe, DigitOn); - digitalWrite(segmentApostrophe, SegOn); - } - delayMicroseconds(brightnessDelay + 1); //Display this digit for a fraction of a second (between 1us and 5000us, 500-2000 is pretty good) +void SevSeg::turnDigitOff(byte digit) +{ + //Turn off all segments + digitalWrite(segmentA, SegOff); + digitalWrite(segmentB, SegOff); + digitalWrite(segmentC, SegOff); + digitalWrite(segmentD, SegOff); + digitalWrite(segmentE, SegOff); + digitalWrite(segmentF, SegOff); + digitalWrite(segmentG, SegOff); + digitalWrite(segmentDP, SegOff); - //Turn off the colon and/or apostrophe - digitalWrite(digitColon, DigitOff); - digitalWrite(segmentColon, SegOff); - digitalWrite(digitApostrophe, DigitOff); - digitalWrite(segmentApostrophe, SegOff); - delayMicroseconds(FRAMEPERIOD - brightnessDelay + 1); //the +1 is a hack so that we can never have a delayMicroseconds(0), causes display to flicker - } - + //Turn off this digit + switch(digit) + { + case 1: + digitalWrite(digit1, DigitOff); + break; + case 2: + digitalWrite(digit2, DigitOff); + break; + case 3: + digitalWrite(digit3, DigitOff); + break; + case 4: + digitalWrite(digit4, DigitOff); + break; + //This only currently works for 4 digits + } + +void SevSeg::turnDigitOn(char* toDisplay, byte digit) +{ + switch(digit) + { + case 1: + digitalWrite(digit1, DigitOn); + break; + case 2: + digitalWrite(digit2, DigitOn); + break; + case 3: + digitalWrite(digit3, DigitOn); + break; + case 4: + digitalWrite(digit4, DigitOn); + break; + //This only currently works for 4 digits + } + + //Here we access the array of segments + //This could be cleaned up a bit but it works + //displayCharacter(toDisplay[digit-1]); //Now display this digit + // displayArray (defined in SevSeg.h) decides which segments are turned on for each number or symbol + char characterToDisplay = toDisplay[digit-1]; + if (characterToDisplay & 0x80) // bit 7 enables bit-per-segment control + { // Each bit of characterToDisplay turns on a single segment (from A-to-G) + if (characterToDisplay & 0x01) digitalWrite(segmentA, SegOn); + if (characterToDisplay & 0x02) digitalWrite(segmentB, SegOn); + if (characterToDisplay & 0x04) digitalWrite(segmentC, SegOn); + if (characterToDisplay & 0x08) digitalWrite(segmentD, SegOn); + if (characterToDisplay & 0x10) digitalWrite(segmentE, SegOn); + if (characterToDisplay & 0x20) digitalWrite(segmentF, SegOn); + if (characterToDisplay & 0x40) digitalWrite(segmentG, SegOn); + } + else + { + const uint8_t chr = pgm_read_byte(&characterArray[characterToDisplay]); + if (chr & (1<<6)) digitalWrite(segmentA, SegOn); + if (chr & (1<<5)) digitalWrite(segmentB, SegOn); + if (chr & (1<<4)) digitalWrite(segmentC, SegOn); + if (chr & (1<<3)) digitalWrite(segmentD, SegOn); + if (chr & (1<<2)) digitalWrite(segmentE, SegOn); + if (chr & (1<<1)) digitalWrite(segmentF, SegOn); + if (chr & (1<<0)) digitalWrite(segmentG, SegOn); + } + //Service the decimal point + if ((DecAposColon & (1<<(digit-1))) && (digit < 5)) //Test DecAposColon to see if we need to turn on a decimal point + { + digitalWrite(segmentDP, SegOn); + } } diff --git a/src/SevSeg.h b/src/SevSeg.h index 153008d..9984811 100644 --- a/src/SevSeg.h +++ b/src/SevSeg.h @@ -17,17 +17,6 @@ #define BLANK 16 //Special character that turns off all segments (we chose 16 as it is the first spot that has this) -// framePeriod controls the length of time between display refreshes -// It's also closely linked to the brightness setting -#define FRAMEPERIOD 2000 -//Total amount of time (in microseconds) for the display frame. 1,000us is roughly 1000Hz update rate -//A framePeriod of: -//5000 is flickery -//3000 has good low brightness vs full brightness -//2000 works well -//500 seems like the low brightness is pretty bright, not great - - //This is the combined array that contains all the segment configurations for many different characters and symbols const uint8_t characterArray[] PROGMEM = { // ABCDEFG Segments 7-segment map: @@ -180,6 +169,8 @@ class SevSeg { //Private Functions void displayCharacter(byte characterToDisplay); //Illuminates the correct segments void SplitNumber(int); + void turnDigitOff(byte digit); + void turnDigitOn(char* toDisplay, byte digit); //Private Variables boolean mode, DigitOn, DigitOff, SegOn, SegOff; @@ -190,7 +181,8 @@ class SevSeg { byte numberOfDigits; - unsigned int brightnessDelay; + unsigned int brightness, brightnessDelay; + unsigned long previousMicros, timer; byte DigitPins[4]; byte SegmentPins[8]; From f7221ba0e344348f358cceaf169a6936ac87eac7 Mon Sep 17 00:00:00 2001 From: monkeybiscuits Date: Sat, 11 Feb 2017 23:25:37 +0900 Subject: [PATCH 2/3] fixed decimal point previous update caused the decimal point to stop working. --- src/SevSeg.cpp | 11 +++++++---- src/SevSeg.h | 2 +- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/SevSeg.cpp b/src/SevSeg.cpp index 2a8f256..155a263 100644 --- a/src/SevSeg.cpp +++ b/src/SevSeg.cpp @@ -178,6 +178,8 @@ void SevSeg::SetBrightness(byte percentBright) { //Error check brightnessLevel if(percentBright > 100){brightness = 100;} + else if(percentBright < 1){brightness = 1;} + else{brightness = percentBright;} brightnessDelay = (100-brightness)*numberOfDigits*100/brightness; } @@ -221,7 +223,7 @@ void SevSeg::DisplayString(char* toDisplay, byte DecAposColon) else if(digit == numberOfDigits) { turnDigitOff(numberOfDigits-1); - turnDigitOn(toDisplay, numberOfDigits); + turnDigitOn(toDisplay, numberOfDigits, DecAposColon); digit = digitColon != 255 || digitApostrophe != 255 ? digit+1 : 0; previousMicros = micros(); timer = brightness; //Display this digit for a fraction of a second (between 1us and 5000us, 500-2000 is pretty good) @@ -252,7 +254,7 @@ void SevSeg::DisplayString(char* toDisplay, byte DecAposColon) { turnDigitOff(digit-1); } - turnDigitOn(toDisplay, digit); + turnDigitOn(toDisplay, digit, DecAposColon); previousMicros = micros(); timer = brightness; //Display this digit for a fraction of a second (between 1us and 5000us, 500-2000 is pretty good) } @@ -290,8 +292,9 @@ void SevSeg::turnDigitOff(byte digit) break; //This only currently works for 4 digits } +} -void SevSeg::turnDigitOn(char* toDisplay, byte digit) +void SevSeg::turnDigitOn(char* toDisplay, byte digit, byte DecAposColon) { switch(digit) { @@ -341,4 +344,4 @@ void SevSeg::turnDigitOn(char* toDisplay, byte digit) { digitalWrite(segmentDP, SegOn); } -} +} \ No newline at end of file diff --git a/src/SevSeg.h b/src/SevSeg.h index 9984811..e7cf200 100644 --- a/src/SevSeg.h +++ b/src/SevSeg.h @@ -170,7 +170,7 @@ class SevSeg { void displayCharacter(byte characterToDisplay); //Illuminates the correct segments void SplitNumber(int); void turnDigitOff(byte digit); - void turnDigitOn(char* toDisplay, byte digit); + void turnDigitOn(char* toDisplay, byte digit, byte DecAposColon); //Private Variables boolean mode, DigitOn, DigitOff, SegOn, SegOff; From 855874be635d967ff2d4df06f6693243f2c1f782 Mon Sep 17 00:00:00 2001 From: monkeybiscuits Date: Sun, 13 May 2018 20:10:13 +0900 Subject: [PATCH 3/3] added 'a' sometimes a lower case 'a' looks better --- src/SevSeg.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/SevSeg.h b/src/SevSeg.h index e7cf200..c9793b4 100644 --- a/src/SevSeg.h +++ b/src/SevSeg.h @@ -117,7 +117,7 @@ const uint8_t characterArray[] PROGMEM = { 0b0000000, // 94 '^' NO DISPLAY 0b0001000, // 95 '_' 0b0000010, // 96 '`' - 0b1110111, // 97 'a' SAME AS CAP + 0b1111101, // 97 'a' 0b0011111, // 98 'b' SAME AS CAP 0b0001101, // 99 'c' 0b0111101, // 100 'd' SAME AS CAP