From 4c16260e55e9d2cd3502f67354fa54b93c38cc93 Mon Sep 17 00:00:00 2001 From: Mark van Renswoude Date: Sun, 27 Nov 2016 23:14:17 +0100 Subject: [PATCH] Fixed data corruption issue due to incorrect PROGMEM usage Added switchable shift register order Added potentiometer-controlled delay for demonstration purposes --- NerfStatTrek.ino | 18 ++++++-- SegmentDisplay.cpp | 44 +++++++++++++------ SegmentDisplay.h | 29 ++++++------ SegmentDisplayConfig.h | 26 +++++++++++ .../SMA410363 - 3-digit 7-segment display.txt | 18 ++++++++ .../UDN2981A - 8-Channel Source Driver.txt | 33 ++++++++++++++ 6 files changed, 136 insertions(+), 32 deletions(-) create mode 100644 SegmentDisplayConfig.h create mode 100644 reference/UDN2981A - 8-Channel Source Driver.txt diff --git a/NerfStatTrek.ino b/NerfStatTrek.ino index 24d908a..00fbe5e 100644 --- a/NerfStatTrek.ino +++ b/NerfStatTrek.ino @@ -4,26 +4,36 @@ SegmentDisplay* display; void setup() { + pinMode(A3, INPUT); + display = new SegmentDisplay(); //display->setClockSpeed(4000000UL); - display->setDigits(2); + display->setClockPin(12); + display->setDataPin(11); + display->setLatchPin(10); + display->setDigits(6); display->begin(); } +unsigned long currentTime; unsigned long lastCounterTime = 0; uint32_t counter = 0; +uint32_t delayValue; void loop() { - unsigned long currentTime = millis(); + currentTime = millis(); - if (currentTime - lastCounterTime > 1000UL) + if (currentTime - lastCounterTime > 100UL) { counter++; - if (counter > 99) + 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 15bec1a..ab8f556 100644 --- a/SegmentDisplay.cpp +++ b/SegmentDisplay.cpp @@ -1,10 +1,12 @@ +#include "SegmentDisplayConfig.h" #include "SegmentDisplay.h" void SegmentDisplay::begin() { - #if !defined(SDSupportSPI) pinMode(latchPin, OUTPUT); + + #if !defined(SDUseSPI) pinMode(clockPin, OUTPUT); pinMode(dataPin, OUTPUT); @@ -12,11 +14,13 @@ void SegmentDisplay::begin() digitalWrite(dataPin, LOW); #endif + writeDisplay(0, 0); + digitalWrite(latchPin, HIGH); digitalWrite(latchPin, LOW); digitalWrite(latchPin, HIGH); - #if defined(SDSupportSPI) + #if defined(SDUseSPI) SPI.begin(); #endif } @@ -24,7 +28,7 @@ void SegmentDisplay::begin() void SegmentDisplay::end() { - #if defined(SDSupportSPI) + #if defined(SDUseSPI) SPI.end(); #endif } @@ -64,15 +68,15 @@ void SegmentDisplay::writeText(char* value) // Lowercase if (charValue >= ASCIILowercaseA && charValue <= ASCIILowercaseZ) - writeDisplay(SDCharacterSegments[charValue - ASCIILowercaseA], digitMask); + writeDisplay(pgm_read_byte_near(SDCharacterSegments + (charValue - ASCIILowercaseA)), digitMask); // Uppercase else if (charValue >= ASCIIUppercaseA && charValue <= ASCIIUppercaseZ) - writeDisplay(SDCharacterSegments[charValue - ASCIIUppercaseA], digitMask); + writeDisplay(pgm_read_byte_near(SDCharacterSegments + (charValue - ASCIIUppercaseA)), digitMask); // Numbers else if (charValue >= ASCIIZero && charValue <= ASCIINine) - writeDisplay(SDNumberSegments[charValue - ASCIIZero], digitMask); + writeDisplay(pgm_read_byte_near(SDNumberSegments + (charValue - ASCIIZero)), digitMask); // Space / unknown else @@ -95,29 +99,43 @@ void SegmentDisplay::writeText(char* value) inline void SegmentDisplay::writeDigit(byte value, byte digitMask) { - writeDisplay(SDNumberSegments[value], digitMask); - delayMicroseconds(digitDelayMicroseconds); + writeDisplay(pgm_read_byte_near(SDNumberSegments + value), digitMask); + + if (digitDelayMicroseconds > 1000) + delay(digitDelayMicroseconds / 1000); + else + delayMicroseconds(digitDelayMicroseconds); } -#if defined(SDSupportSPI) +#if defined(SDUseSPI) -inline void SegmentDisplay::writeDisplay(byte characterMask, byte digitMask) +inline void SegmentDisplay::writeDisplay(byte segmentMask, byte digitMask) { SPI.beginTransaction(SPISettings(clockSpeed, MSBFIRST, SPI_MODE0)); - SPI.transfer(characterMask); + #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 characterMask, byte digitMask) +inline void SegmentDisplay::writeDisplay(byte segmentMask, byte digitMask) { digitalWrite(latchPin, LOW); - shiftOut(dataPin, clockPin, MSBFIRST, characterMask); + #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); } diff --git a/SegmentDisplay.h b/SegmentDisplay.h index 1237798..4f1d00e 100644 --- a/SegmentDisplay.h +++ b/SegmentDisplay.h @@ -1,28 +1,27 @@ #ifndef SegmentDisplay_h #define SegmentDisplay_h +#include "SegmentDisplayConfig.h" #include "Arduino.h" + +#if defined(SDUseSPI) #include "SPI.h" +#endif #include "SegmentDisplayChars.h" /** * Drives up to 8 digits using two 8-bit shift registers. * - * Pushes out the segment bits first and the display selection - * second: connect the display select register first and chain the - * segment register to it's output. + * Least significant bit ends up at output pin 0 of the shift register, + * which correlates to Segment A (as defined in SegmentDisplayChars.h). + * The last digit is also assumed to be at output pin 0 of the chained + * shift register. * - * Least significant bit ends up at pin 0, which correlates to - * (as defined in SegmentDisplayChars.h): - * - Last digit - * - Segment A + * The order in which the shift registers are chained is determined by + * (un)defining SDPushSegmentsFirst. **/ -// Comment to use shiftOut. Set clockPin and dataPin instead. -//#define SDSupportSPI - - class SegmentDisplay { public: @@ -41,12 +40,12 @@ class SegmentDisplay uint32_t getDigitDelayMicroseconds() { return digitDelayMicroseconds; } void setDigitDelayMicroseconds(uint32_t value) { digitDelayMicroseconds = value; } - #if defined(SDSupportSPI) + #if defined(SDUseSPI) uint32_t getClockSpeed() { return clockSpeed; } void setClockSpeed(uint32_t value) { clockSpeed = value; } #endif - #if !defined(SDSupportSPI) + #if !defined(SDUseSPI) uint32_t getClockPin() { return clockPin; } void setClockPin(uint32_t value) { clockPin = value; } @@ -63,11 +62,11 @@ class SegmentDisplay uint32_t digitDelayMicroseconds = 1000; uint32_t latchPin = SS; - #if defined(SDSupportSPI) + #if defined(SDUseSPI) uint32_t clockSpeed = 20000000; #endif - #if !defined(SDSupportSPI) + #if !defined(SDUseSPI) uint32_t clockPin = SCK; uint32_t dataPin = MOSI; #endif diff --git a/SegmentDisplayConfig.h b/SegmentDisplayConfig.h new file mode 100644 index 0000000..4ed415f --- /dev/null +++ b/SegmentDisplayConfig.h @@ -0,0 +1,26 @@ +#ifndef SegmentDisplayConfig_h +#define SegmentDisplayConfig_h + +/** + * Enable SPI support + * + * If not defined, shiftOut will be used. Use setClockPin and + * setDataPin instead to change the defaults. + * + * When using SPI, use setClockSpeed to match your target. +**/ +//#define SDUseSPI + + +/** + * Shift register chaining order + * + * If defined, the segment mask is pushed out first followed + * by the digit mask. In other words, connect D1, D2, etc to + * the first shift register and A, B, etc to the second. + * + * If not defined, the order is reversed. +**/ +//#define SDPushSegmentsFirst + +#endif \ No newline at end of file diff --git a/reference/SMA410363 - 3-digit 7-segment display.txt b/reference/SMA410363 - 3-digit 7-segment display.txt index b7f8bb7..eb2dd86 100644 --- a/reference/SMA410363 - 3-digit 7-segment display.txt +++ b/reference/SMA410363 - 3-digit 7-segment display.txt @@ -1,4 +1,6 @@ + Top view + D1 A F D2 D3 B __|__|__|__|__|__|__ | | @@ -11,6 +13,22 @@ E D DP C G + + Bottom view + + B D3 D2 F A D1 + __|__|__|__|__|__|__ +| | +| | +| | +| | +| | +|_____ __ __ __ __ __| + | | | | | + G C DP D E + + + Pin Assignment 1 E Bottom Left diff --git a/reference/UDN2981A - 8-Channel Source Driver.txt b/reference/UDN2981A - 8-Channel Source Driver.txt new file mode 100644 index 0000000..0e11e2d --- /dev/null +++ b/reference/UDN2981A - 8-Channel Source Driver.txt @@ -0,0 +1,33 @@ + + O1 O2 O3 O4 O5 O6 O7 O8 GND + __|____|____|____|____|____|____|____|____|__ +| | +| | +|\ | +|/ | +| | +|__ ____ ____ ____ ____ ____ ____ ____ ____ __| + | | | | | | | | | + I1 I2 I3 I4 I5 I6 I7 I8 VCC + + +Pin Assignment + +1 I1 +2 I2 +3 I3 +4 I4 +5 I5 +6 I6 +7 I7 +8 I8 +9 VCC +10 GND Ground +11 O8 +12 O7 +13 O6 +14 O5 +15 O4 +16 O3 +17 O2 +18 O1 \ No newline at end of file