Fixed character output
Added placeholders for centered/right-aligned text Added text mode toggle for testing purposes Added serial debug option
This commit is contained in:
parent
8cc217b168
commit
b4e971cc4a
|
@ -1,11 +1,18 @@
|
||||||
#include "SegmentDisplay.h"
|
#include "SegmentDisplay.h"
|
||||||
|
|
||||||
|
#define ASCIIUppercaseA 65
|
||||||
|
#define ASCIIUppercaseZ 90
|
||||||
|
|
||||||
SegmentDisplay* display;
|
SegmentDisplay* display;
|
||||||
|
|
||||||
|
char* text = new char[7];
|
||||||
|
|
||||||
|
|
||||||
void setup()
|
void setup()
|
||||||
{
|
{
|
||||||
|
pinMode(2, INPUT_PULLUP);
|
||||||
pinMode(A3, INPUT);
|
pinMode(A3, INPUT);
|
||||||
|
|
||||||
display = new SegmentDisplay();
|
display = new SegmentDisplay();
|
||||||
//display->setClockSpeed(4000000UL);
|
//display->setClockSpeed(4000000UL);
|
||||||
display->setClockPin(12);
|
display->setClockPin(12);
|
||||||
|
@ -13,6 +20,14 @@ void setup()
|
||||||
display->setLatchPin(10);
|
display->setLatchPin(10);
|
||||||
display->setDigits(6);
|
display->setDigits(6);
|
||||||
display->begin();
|
display->begin();
|
||||||
|
|
||||||
|
text[0] = '\0';
|
||||||
|
text[1] = '\0';
|
||||||
|
text[2] = '\0';
|
||||||
|
text[3] = '\0';
|
||||||
|
text[4] = '\0';
|
||||||
|
text[5] = '\0';
|
||||||
|
text[6] = '\0';
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned long currentTime;
|
unsigned long currentTime;
|
||||||
|
@ -20,21 +35,76 @@ unsigned long lastCounterTime = 0;
|
||||||
uint32_t counter = 0;
|
uint32_t counter = 0;
|
||||||
uint32_t delayValue;
|
uint32_t delayValue;
|
||||||
|
|
||||||
|
bool showChars = true;
|
||||||
|
byte character = ASCIIUppercaseA - 1;
|
||||||
|
|
||||||
|
int buttonValue;
|
||||||
|
bool buttonDown = false;
|
||||||
|
unsigned long lastButtonChange = 0;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void loop()
|
void loop()
|
||||||
{
|
{
|
||||||
currentTime = millis();
|
currentTime = millis();
|
||||||
|
|
||||||
if (currentTime - lastCounterTime > 100UL)
|
buttonValue = digitalRead(2);
|
||||||
|
if (buttonValue == LOW)
|
||||||
{
|
{
|
||||||
counter++;
|
if (!buttonDown && (currentTime - lastButtonChange) > 50)
|
||||||
if (counter > 999999)
|
{
|
||||||
counter = 0;
|
buttonDown = true;
|
||||||
|
showChars = !showChars;
|
||||||
lastCounterTime = currentTime;
|
lastButtonChange = currentTime;
|
||||||
|
}
|
||||||
delayValue = ((uint32_t)analogRead(A3) * 100);
|
}
|
||||||
display->setDigitDelayMicroseconds(delayValue);
|
else
|
||||||
|
{
|
||||||
|
if (buttonDown && (currentTime - lastButtonChange) > 50)
|
||||||
|
{
|
||||||
|
buttonDown = false;
|
||||||
|
lastButtonChange = currentTime;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
display->writeNumber(counter);
|
if (showChars)
|
||||||
|
{
|
||||||
|
if (lastCounterTime == 0 || currentTime - lastCounterTime > 250UL)
|
||||||
|
{
|
||||||
|
character++;
|
||||||
|
if (character > ASCIIUppercaseZ)
|
||||||
|
character = ASCIIUppercaseA;
|
||||||
|
|
||||||
|
lastCounterTime = currentTime;
|
||||||
|
|
||||||
|
delayValue = ((uint32_t)analogRead(A3) * 100);
|
||||||
|
display->setDigitDelayMicroseconds(delayValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (byte c = 0; c < 6; c++)
|
||||||
|
{
|
||||||
|
if (character + c > ASCIIUppercaseZ)
|
||||||
|
text[c] = ' ';
|
||||||
|
else
|
||||||
|
text[c] = character + c;
|
||||||
|
}
|
||||||
|
|
||||||
|
display->writeTextLeft(text);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (currentTime - lastCounterTime > 100UL)
|
||||||
|
{
|
||||||
|
counter++;
|
||||||
|
if (counter > 999999)
|
||||||
|
counter = 0;
|
||||||
|
|
||||||
|
lastCounterTime = currentTime;
|
||||||
|
|
||||||
|
delayValue = ((uint32_t)analogRead(A3) * 100);
|
||||||
|
display->setDigitDelayMicroseconds(delayValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
display->writeNumber(counter);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,6 +23,11 @@ void SegmentDisplay::begin()
|
||||||
#if defined(SDUseSPI)
|
#if defined(SDUseSPI)
|
||||||
SPI.begin();
|
SPI.begin();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if defined(SDSerialDebug)
|
||||||
|
Serial.begin(9600);
|
||||||
|
Serial.print("SegmentDisplay::begin\n");
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -36,6 +41,11 @@ void SegmentDisplay::end()
|
||||||
|
|
||||||
void SegmentDisplay::writeNumber(uint32_t value)
|
void SegmentDisplay::writeNumber(uint32_t value)
|
||||||
{
|
{
|
||||||
|
#if defined(SDSerialDebug)
|
||||||
|
String textValue = String(value);
|
||||||
|
Serial.print("SegmentDisplay::writeNumber: " + textValue + "\n");
|
||||||
|
#endif
|
||||||
|
|
||||||
byte digitMask = 1;
|
byte digitMask = 1;
|
||||||
|
|
||||||
for (byte digit = digits; digit > 0; digit--)
|
for (byte digit = digits; digit > 0; digit--)
|
||||||
|
@ -48,96 +58,113 @@ void SegmentDisplay::writeNumber(uint32_t value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#define ASCIIZero 48
|
void SegmentDisplay::writeTextLeft(char* value)
|
||||||
#define ASCIINine 57
|
|
||||||
#define ASCIIUppercaseA 65
|
|
||||||
#define ASCIIUppercaseZ 90
|
|
||||||
#define ASCIILowercaseA 97
|
|
||||||
#define ASCIILowercaseZ 122
|
|
||||||
|
|
||||||
|
|
||||||
void SegmentDisplay::writeText(char* value)
|
|
||||||
{
|
{
|
||||||
byte digitMask = 1;
|
#if defined(SDSerialDebug)
|
||||||
byte digit = digits;
|
Serial.print("SegmentDisplay::writeTextLeft: " + value + "\n");
|
||||||
byte charValue;
|
#endif
|
||||||
|
|
||||||
while (digit > 0 && value != '\0')
|
byte digitMask = 1 << (digits - 1);
|
||||||
|
byte charIndex = 0;
|
||||||
|
|
||||||
|
while (charIndex < digits && value[charIndex] != '\0')
|
||||||
{
|
{
|
||||||
charValue = *value;
|
writeChar(value[charIndex], digitMask);
|
||||||
|
|
||||||
// Lowercase
|
digitMask >>= 1;
|
||||||
if (charValue >= ASCIILowercaseA && charValue <= ASCIILowercaseZ)
|
charIndex++;
|
||||||
writeDisplay(pgm_read_byte_near(SDCharacterSegments + (charValue - ASCIILowercaseA)), digitMask);
|
|
||||||
|
|
||||||
// Uppercase
|
|
||||||
else if (charValue >= ASCIIUppercaseA && charValue <= ASCIIUppercaseZ)
|
|
||||||
writeDisplay(pgm_read_byte_near(SDCharacterSegments + (charValue - ASCIIUppercaseA)), digitMask);
|
|
||||||
|
|
||||||
// Numbers
|
|
||||||
else if (charValue >= ASCIIZero && charValue <= ASCIINine)
|
|
||||||
writeDisplay(pgm_read_byte_near(SDNumberSegments + (charValue - ASCIIZero)), digitMask);
|
|
||||||
|
|
||||||
// Space / unknown
|
|
||||||
else
|
|
||||||
writeDisplay(0, digitMask);
|
|
||||||
|
|
||||||
digit--;
|
|
||||||
digitMask <<= 1;
|
|
||||||
value++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
while (digit > 0)
|
while (charIndex < digits)
|
||||||
{
|
{
|
||||||
writeDisplay(0, digitMask);
|
writeDisplay(0, digitMask);
|
||||||
|
digitMask >>= 1;
|
||||||
digit--;
|
charIndex++;
|
||||||
digitMask <<= 1;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void SegmentDisplay::writeTextCenter(char* value)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void SegmentDisplay::writeTextRight(char* value)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
inline void SegmentDisplay::writeDigit(byte value, byte digitMask)
|
inline void SegmentDisplay::writeDigit(byte value, byte digitMask)
|
||||||
{
|
{
|
||||||
writeDisplay(pgm_read_byte_near(SDNumberSegments + value), digitMask);
|
writeDisplay(pgm_read_byte_near(SDNumberSegments + value), digitMask);
|
||||||
|
}
|
||||||
|
|
||||||
if (digitDelayMicroseconds > 1000)
|
|
||||||
|
inline void SegmentDisplay::writeChar(char value, byte digitMask)
|
||||||
|
{
|
||||||
|
// Lowercase
|
||||||
|
if (value >= ASCIILowercaseA && value <= ASCIILowercaseZ)
|
||||||
|
writeDisplay(pgm_read_byte_near(SDCharacterSegments + (value - ASCIILowercaseA)), digitMask);
|
||||||
|
|
||||||
|
// Uppercase
|
||||||
|
else if (value >= ASCIIUppercaseA && value <= ASCIIUppercaseZ)
|
||||||
|
writeDisplay(pgm_read_byte_near(SDCharacterSegments + (value - ASCIIUppercaseA)), digitMask);
|
||||||
|
|
||||||
|
// Numbers
|
||||||
|
else if (value >= ASCIIZero && value <= ASCIINine)
|
||||||
|
writeDisplay(pgm_read_byte_near(SDNumberSegments + (value - ASCIIZero)), digitMask);
|
||||||
|
|
||||||
|
// Space / unknown
|
||||||
|
else
|
||||||
|
writeDisplay(0, digitMask);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline void SegmentDisplay::writeDisplay(byte segmentMask, byte digitMask)
|
||||||
|
{
|
||||||
|
// If no segments should be lit, clear the digit mask as well to prevent
|
||||||
|
// power leaking through (it's probably an issue in my circuit or with the
|
||||||
|
// specific displays I used, but it still makes sense to close both sides).
|
||||||
|
//
|
||||||
|
// Still push out the zeros though, if we don't the display will vary
|
||||||
|
// in brightness depending on what's on it.
|
||||||
|
if (segmentMask == 0)
|
||||||
|
digitMask = 0;
|
||||||
|
|
||||||
|
#if defined(SDSerialDebug)
|
||||||
|
String segmentValue = String(segmentMask);
|
||||||
|
String digitValue = String(digitMask);
|
||||||
|
|
||||||
|
Serial.print("SegmentDisplay::writeDisplay: " + segmentValue + " " + digitValue + "\n");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(SDUseSPI)
|
||||||
|
SPI.beginTransaction(SPISettings(clockSpeed, MSBFIRST, SPI_MODE0));
|
||||||
|
#if defined(SDPushSegmentsFirst)
|
||||||
|
SPI.transfer(segmentMask);
|
||||||
|
SPI.transfer(digitMask);
|
||||||
|
#else
|
||||||
|
SPI.transfer(digitMask);
|
||||||
|
SPI.transfer(segmentMask);
|
||||||
|
#endif
|
||||||
|
SPI.endTransaction();
|
||||||
|
#else
|
||||||
|
#if defined(SDPushSegmentsFirst)
|
||||||
|
shiftOut(dataPin, clockPin, MSBFIRST, segmentMask);
|
||||||
|
shiftOut(dataPin, clockPin, MSBFIRST, digitMask);
|
||||||
|
#else
|
||||||
|
shiftOut(dataPin, clockPin, MSBFIRST, digitMask);
|
||||||
|
shiftOut(dataPin, clockPin, MSBFIRST, segmentMask);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
digitalWrite(latchPin, HIGH);
|
||||||
|
digitalWrite(latchPin, LOW);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(SPHandleLargeDelays)
|
||||||
|
if (digitDelayMicroseconds > 15000)
|
||||||
delay(digitDelayMicroseconds / 1000);
|
delay(digitDelayMicroseconds / 1000);
|
||||||
else
|
else
|
||||||
|
#endif
|
||||||
delayMicroseconds(digitDelayMicroseconds);
|
delayMicroseconds(digitDelayMicroseconds);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#if defined(SDUseSPI)
|
|
||||||
|
|
||||||
inline void SegmentDisplay::writeDisplay(byte segmentMask, byte digitMask)
|
|
||||||
{
|
|
||||||
SPI.beginTransaction(SPISettings(clockSpeed, MSBFIRST, SPI_MODE0));
|
|
||||||
#if defined(SDPushSegmentsFirst)
|
|
||||||
SPI.transfer(segmentMask);
|
|
||||||
SPI.transfer(digitMask);
|
|
||||||
#else
|
|
||||||
SPI.transfer(digitMask);
|
|
||||||
SPI.transfer(segmentMask);
|
|
||||||
#endif
|
|
||||||
SPI.endTransaction();
|
|
||||||
}
|
|
||||||
|
|
||||||
#else
|
|
||||||
|
|
||||||
inline void SegmentDisplay::writeDisplay(byte segmentMask, byte digitMask)
|
|
||||||
{
|
|
||||||
digitalWrite(latchPin, LOW);
|
|
||||||
|
|
||||||
#if defined(SDPushSegmentsFirst)
|
|
||||||
shiftOut(dataPin, clockPin, MSBFIRST, segmentMask);
|
|
||||||
shiftOut(dataPin, clockPin, MSBFIRST, digitMask);
|
|
||||||
#else
|
|
||||||
shiftOut(dataPin, clockPin, MSBFIRST, digitMask);
|
|
||||||
shiftOut(dataPin, clockPin, MSBFIRST, segmentMask);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
digitalWrite(latchPin, HIGH);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
|
@ -29,7 +29,9 @@ class SegmentDisplay
|
||||||
void end();
|
void end();
|
||||||
|
|
||||||
void writeNumber(uint32_t value);
|
void writeNumber(uint32_t value);
|
||||||
void writeText(char* value);
|
void writeTextLeft(char* value);
|
||||||
|
void writeTextCenter(char* value);
|
||||||
|
void writeTextRight(char* value);
|
||||||
|
|
||||||
byte getDigits() { return digits; }
|
byte getDigits() { return digits; }
|
||||||
void setDigits(byte value) { digits = value; }
|
void setDigits(byte value) { digits = value; }
|
||||||
|
@ -55,6 +57,8 @@ class SegmentDisplay
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void writeDigit(byte value, byte digitMask);
|
void writeDigit(byte value, byte digitMask);
|
||||||
|
void writeChar(char value, byte digitMask);
|
||||||
|
public:
|
||||||
void writeDisplay(byte characterMask, byte digitMask);
|
void writeDisplay(byte characterMask, byte digitMask);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -13,6 +13,14 @@
|
||||||
#define SegmentG 64 // Middle
|
#define SegmentG 64 // Middle
|
||||||
|
|
||||||
|
|
||||||
|
#define ASCIIZero 48
|
||||||
|
#define ASCIINine 57
|
||||||
|
#define ASCIIUppercaseA 65
|
||||||
|
#define ASCIIUppercaseZ 90
|
||||||
|
#define ASCIILowercaseA 97
|
||||||
|
#define ASCIILowercaseZ 122
|
||||||
|
|
||||||
|
|
||||||
const byte SDNumberSegments[10] PROGMEM =
|
const byte SDNumberSegments[10] PROGMEM =
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
|
@ -162,7 +170,7 @@ const byte SDCharacterSegments[26] PROGMEM =
|
||||||
* | |
|
* | |
|
||||||
*
|
*
|
||||||
**/
|
**/
|
||||||
SegmentB | SegmentC | SegmentD | SegmentF | SegmentG,
|
SegmentB | SegmentC | SegmentE | SegmentF | SegmentG,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
|
|
|
@ -23,4 +23,28 @@
|
||||||
**/
|
**/
|
||||||
//#define SDPushSegmentsFirst
|
//#define SDPushSegmentsFirst
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Support large digit delays (> 15000 microseconds)
|
||||||
|
*
|
||||||
|
* If not defined, delayMicroseconds() will always be used,
|
||||||
|
* which is currently only accurate up to 16383, but it saves
|
||||||
|
* the cost of checking the value.
|
||||||
|
*
|
||||||
|
* If you want to delay the digits further, most likely
|
||||||
|
* for multiplexing demonstration purposes only, enable this
|
||||||
|
* to automatically fall back to delay().
|
||||||
|
**/
|
||||||
|
#define SPHandleLargeDelays
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Debug output
|
||||||
|
*
|
||||||
|
* If defined, outputs a trace of every call using Serial.print.
|
||||||
|
* The performance cost is of course massive, you probably
|
||||||
|
* only want to enable this while debugging the library.
|
||||||
|
**/
|
||||||
|
//#define SDSerialDebug
|
||||||
|
|
||||||
#endif
|
#endif
|
Binary file not shown.
After Width: | Height: | Size: 588 KiB |
Loading…
Reference in New Issue