Skip to content

DisplayString() using no delays #14

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
262 changes: 154 additions & 108 deletions src/SevSeg.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -152,6 +151,9 @@ void SevSeg::Begin(boolean mode_in, byte numOfDigits,
digitalWrite(segmentApostrophe, SegOff);
pinMode(segmentApostrophe, OUTPUT);
}

previousMicros = 0;
timer = 0;
}

//Begin
Expand All @@ -174,9 +176,12 @@ 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;}
else if(percentBright < 1){brightness = 1;}
else{brightness = percentBright;}

brightnessDelay = (100-brightness)*numberOfDigits*100/brightness;
}


Expand All @@ -189,113 +194,154 @@ 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, 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)
}

//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, DecAposColon);
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, byte DecAposColon)
{
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);
}
}
18 changes: 5 additions & 13 deletions src/SevSeg.h
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down Expand Up @@ -128,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
Expand Down Expand Up @@ -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, byte DecAposColon);

//Private Variables
boolean mode, DigitOn, DigitOff, SegOn, SegOff;
Expand All @@ -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];
Expand Down