diff --git a/NerfStatTrek.ino b/NerfStatTrek.ino index 00fbe5e..352f83e 100644 --- a/NerfStatTrek.ino +++ b/NerfStatTrek.ino @@ -1,11 +1,18 @@ #include "SegmentDisplay.h" +#define ASCIIUppercaseA 65 +#define ASCIIUppercaseZ 90 + SegmentDisplay* display; +char* text = new char[7]; + + void setup() { + pinMode(2, INPUT_PULLUP); pinMode(A3, INPUT); - + display = new SegmentDisplay(); //display->setClockSpeed(4000000UL); display->setClockPin(12); @@ -13,6 +20,14 @@ void setup() display->setLatchPin(10); display->setDigits(6); 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; @@ -20,21 +35,76 @@ unsigned long lastCounterTime = 0; uint32_t counter = 0; uint32_t delayValue; +bool showChars = true; +byte character = ASCIIUppercaseA - 1; + +int buttonValue; +bool buttonDown = false; +unsigned long lastButtonChange = 0; + + + void loop() { currentTime = millis(); - if (currentTime - lastCounterTime > 100UL) + buttonValue = digitalRead(2); + if (buttonValue == LOW) { - counter++; - if (counter > 999999) - counter = 0; - - lastCounterTime = currentTime; - - delayValue = ((uint32_t)analogRead(A3) * 100); - display->setDigitDelayMicroseconds(delayValue); + if (!buttonDown && (currentTime - lastButtonChange) > 50) + { + buttonDown = true; + showChars = !showChars; + lastButtonChange = currentTime; + } + } + 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); + } } diff --git a/SegmentDisplay.cpp b/SegmentDisplay.cpp index ab8f556..1c1e53c 100644 --- a/SegmentDisplay.cpp +++ b/SegmentDisplay.cpp @@ -23,6 +23,11 @@ void SegmentDisplay::begin() #if defined(SDUseSPI) SPI.begin(); #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) { + #if defined(SDSerialDebug) + String textValue = String(value); + Serial.print("SegmentDisplay::writeNumber: " + textValue + "\n"); + #endif + byte digitMask = 1; for (byte digit = digits; digit > 0; digit--) @@ -48,96 +58,113 @@ void SegmentDisplay::writeNumber(uint32_t value) } -#define ASCIIZero 48 -#define ASCIINine 57 -#define ASCIIUppercaseA 65 -#define ASCIIUppercaseZ 90 -#define ASCIILowercaseA 97 -#define ASCIILowercaseZ 122 - - -void SegmentDisplay::writeText(char* value) +void SegmentDisplay::writeTextLeft(char* value) { - byte digitMask = 1; - byte digit = digits; - byte charValue; + #if defined(SDSerialDebug) + Serial.print("SegmentDisplay::writeTextLeft: " + value + "\n"); + #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 - if (charValue >= ASCIILowercaseA && charValue <= ASCIILowercaseZ) - 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++; + digitMask >>= 1; + charIndex++; } - while (digit > 0) + while (charIndex < digits) { writeDisplay(0, digitMask); - - digit--; - digitMask <<= 1; + digitMask >>= 1; + charIndex++; } } +void SegmentDisplay::writeTextCenter(char* value) +{ +} + + +void SegmentDisplay::writeTextRight(char* value) +{ +} + + inline void SegmentDisplay::writeDigit(byte value, byte 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); else + #endif 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 diff --git a/SegmentDisplay.h b/SegmentDisplay.h index 4f1d00e..3d8f1fe 100644 --- a/SegmentDisplay.h +++ b/SegmentDisplay.h @@ -29,7 +29,9 @@ class SegmentDisplay void end(); 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; } void setDigits(byte value) { digits = value; } @@ -55,6 +57,8 @@ class SegmentDisplay protected: void writeDigit(byte value, byte digitMask); + void writeChar(char value, byte digitMask); + public: void writeDisplay(byte characterMask, byte digitMask); private: diff --git a/SegmentDisplayChars.h b/SegmentDisplayChars.h index fbc80cd..1a764a3 100644 --- a/SegmentDisplayChars.h +++ b/SegmentDisplayChars.h @@ -13,6 +13,14 @@ #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 = { /** @@ -162,7 +170,7 @@ const byte SDCharacterSegments[26] PROGMEM = * | | * **/ - SegmentB | SegmentC | SegmentD | SegmentF | SegmentG, + SegmentB | SegmentC | SegmentE | SegmentF | SegmentG, /** * diff --git a/SegmentDisplayConfig.h b/SegmentDisplayConfig.h index 4ed415f..5985d97 100644 --- a/SegmentDisplayConfig.h +++ b/SegmentDisplayConfig.h @@ -23,4 +23,28 @@ **/ //#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 \ No newline at end of file diff --git a/reference/Arduino Nano v3 pinout.jpg b/reference/Arduino Nano v3 pinout.jpg new file mode 100644 index 0000000..2b44daf Binary files /dev/null and b/reference/Arduino Nano v3 pinout.jpg differ