Compare commits

...

16 Commits

Author SHA1 Message Date
211740d51a Fixed #2 Persist counters
Added initialisation sketch and reset state
2016-12-10 12:01:43 +01:00
e79cbc265a Fixed issue #1 Power saving 2016-12-10 00:00:42 +01:00
40b6b68933 Fixed issue #4 Rename to "StatTrak" 2016-12-09 21:28:11 +01:00
a4d7396ed9 Fixed writeRaw checking for null characters
Changed O to lower-case
2016-12-09 21:06:18 +01:00
2e8007d510 Support for gun armed detection
First attempt at implementing animation
2016-12-05 23:42:20 +01:00
ba58eb93c0 Moved away from proof of concepts, started prototyping for the final software
- Button library
- State handling and transitions
- Default state: dual counter display
- User unknown state: static for now
- Lost the game state: static for now
2016-12-04 19:53:43 +01:00
b4e971cc4a Fixed character output
Added placeholders for centered/right-aligned text
Added text mode toggle for testing purposes
Added serial debug option
2016-11-29 20:00:47 +01:00
8cc217b168 Added Eagle schema and board 2016-11-27 23:15:40 +01:00
4c16260e55 Fixed data corruption issue due to incorrect PROGMEM usage
Added switchable shift register order
Added potentiometer-controlled delay for demonstration purposes
2016-11-27 23:14:17 +01:00
2e1cb6e054 Corrected pin assignment for ULN2803 2016-10-07 20:03:01 +02:00
c7ede4c61f Added some ASCII art to the references 2016-10-04 22:38:12 +02:00
3d23a7bec2 Added build photos for embedding the displays 2016-10-02 19:19:23 +02:00
8bb9959f67 Moved lib files to project root to be compatible with the standard Arduino IDE
Implemented 2-digit counter as a test
2016-09-30 23:14:29 +02:00
15dc4ee679 Back to bytes 2016-09-30 21:03:16 +02:00
0d85edbb42 Fixed inconsistent file naming (yes. it matters ;-)) 2016-09-30 20:07:17 +02:00
a2128677f9 Added reference files for SN74HC595 and ULN2803 2016-09-29 22:28:52 +02:00
38 changed files with 4571 additions and 576 deletions

48
Button.cpp Normal file
View File

@ -0,0 +1,48 @@
#include "Button.h"
void Button::init(uint8_t pin, int offState, bool usePullUp)
{
this->pin = pin;
this->offState = offState;
this->lastState = offState;
if (usePullUp)
pinMode(pin, INPUT_PULLUP);
else
pinMode(pin, INPUT);
}
void Button::update(unsigned long referenceTime)
{
unsigned long currentTime = getTime(referenceTime);
int currentState = digitalRead(pin);
if (lastChangedTime != 0)
{
if (currentState != lastState && (currentTime - lastChangedTime) > debounceMillis)
{
lastChanged = true;
if (currentState != offState)
lastPressedTime = currentTime;
else if (blocked)
{
blocked = false;
lastChanged = false;
}
lastChangedTime = currentTime;
lastState = currentState;
return;
}
}
else
{
lastChangedTime = currentTime;
lastState = currentState;
}
lastChanged = false;
}

37
Button.h Normal file
View File

@ -0,0 +1,37 @@
#ifndef Button_h
#define Button_h
#include "Arduino.h"
class Button
{
public:
void init(uint8_t pin, int offState = HIGH, bool usePullUp = true);
void update(unsigned long referenceTime = 0);
void block() { if (lastState != offState) blocked = true; }
bool changed() { return !blocked && lastChanged; }
bool pressed() { return !blocked && lastState != offState; }
unsigned long pressedMillis(unsigned long referenceTime = 0) { return getTime(referenceTime) - lastPressedTime; }
unsigned long getDebounceMillis() { return debounceMillis; }
void setDebounceMillis(unsigned long value) { debounceMillis = value; }
protected:
inline unsigned long getTime(unsigned long referenceTime) { return referenceTime == 0 ? millis() : referenceTime; };
private:
uint8_t pin = 1;
int offState = HIGH;
unsigned long debounceMillis = 50;
unsigned long lastChangedTime = 0;
unsigned long lastPressedTime = 0;
int lastState;
bool lastChanged;
bool blocked = false;
};
#endif

168
Globals.cpp Normal file
View File

@ -0,0 +1,168 @@
#include "NerfStatTrakConfig.h"
#include "Globals.h"
#include "StateHandler.h"
#include "LowPower.h"
#include "EEPROM.h"
SegmentDisplay* display;
Button* buttonA;
Button* buttonB;
Button* buttonArmed;
uint32_t shots = 0;
uint32_t hits = 0;
unsigned long currentTime;
AbstractStateHandler* currentState;
byte shotCounterOffset;
byte hitCounterOffset;
#define counterTreshold (uint32_t)10000
uint32_t lastShotCounterIteration;
uint32_t lastHitCounterIteration;
void setCurrentState(AbstractStateHandler* value)
{
buttonA->block();
buttonB->block();
currentState = value;
currentState->setup();
}
void update()
{
currentTime = millis();
buttonA->update(currentTime);
buttonB->update(currentTime);
buttonArmed->update(currentTime);
// Count the shot no matter which state we're in
if (buttonArmed->changed() && !buttonArmed->pressed())
addShot();
}
void wakeUp()
{
}
void sleep()
{
display->clear();
// Uses RocketScream's Low-Power library
// https://github.com/rocketscream/Low-Power
uint32_t interrupt = digitalPinToInterrupt(NerfButtonWakeUp);
attachInterrupt(interrupt, wakeUp, NerfButtonWakeUpState);
LowPower.powerDown(SLEEP_FOREVER, ADC_OFF, BOD_OFF);
detachInterrupt(interrupt);
currentTime = millis();
// The button triggers the wake-up, so block the first release after
if (NerfButtonWakeUp == NerfButtonA)
{
buttonA->update(currentTime);
buttonA->block();
}
if (NerfButtonWakeUp == NerfButtonB)
{
buttonB->update(currentTime);
buttonB->block();
}
}
#define counterLocation(offset) 2 + (offset * sizeof(uint32_t))
void readCounters()
{
shotCounterOffset = EEPROM.read(0);
hitCounterOffset = EEPROM.read(1);
EEPROM.get(counterLocation(shotCounterOffset), shots);
EEPROM.get(counterLocation(hitCounterOffset), hits);
lastShotCounterIteration = shots / counterTreshold;
lastHitCounterIteration = hits / counterTreshold;
}
void setShots(uint32_t value)
{
shots = value;
uint32_t newShotCounterIteration = shots / counterTreshold;
if (newShotCounterIteration != lastShotCounterIteration || value == 0)
{
shotCounterOffset++;
if (counterLocation(shotCounterOffset) > EEPROM.length() - sizeof(uint32_t))
{
shotCounterOffset = 0;
if (shotCounterOffset == hitCounterOffset)
shotCounterOffset++;
}
EEPROM.write(0, shotCounterOffset);
lastShotCounterIteration = newShotCounterIteration;
}
EEPROM.write(counterLocation(shotCounterOffset), shots);
}
void addShot()
{
setShots(shots + 1);
}
void setHits(uint32_t value)
{
hits = value;
uint32_t newHitCounterIteration = hits / counterTreshold;
if (newHitCounterIteration != lastHitCounterIteration || value == 0)
{
hitCounterOffset++;
if (counterLocation(hitCounterOffset) > EEPROM.length() - sizeof(uint32_t))
{
hitCounterOffset = 0;
if (hitCounterOffset == shotCounterOffset)
hitCounterOffset++;
}
EEPROM.write(1, hitCounterOffset);
lastHitCounterIteration = newHitCounterIteration;
}
EEPROM.write(counterLocation(hitCounterOffset), hits);
}
void addHit()
{
setHits(hits + 1);
}
void resetShots()
{
setShots(0);
}
void resetHits()
{
setHits(0);
}

30
Globals.h Normal file
View File

@ -0,0 +1,30 @@
#ifndef Globals_h
#define Globals_h
#include "SegmentDisplay.h"
#include "SegmentDisplayConfig.h"
#include "Button.h"
#include "StateHandler.h"
extern SegmentDisplay* display;
extern Button* buttonA;
extern Button* buttonB;
extern Button* buttonArmed;
extern uint32_t shots;
extern uint32_t hits;
extern unsigned long currentTime;
extern AbstractStateHandler* currentState;
void setCurrentState(AbstractStateHandler* value);
void update();
void sleep();
void readCounters();
void addShot();
void addHit();
void resetShots();
void resetHits();
#endif

1062
LowPower.cpp Normal file

File diff suppressed because it is too large Load Diff

169
LowPower.h Normal file
View File

@ -0,0 +1,169 @@
#ifndef LowPower_h
#define LowPower_h
#include "Arduino.h"
enum period_t
{
SLEEP_15MS,
SLEEP_30MS,
SLEEP_60MS,
SLEEP_120MS,
SLEEP_250MS,
SLEEP_500MS,
SLEEP_1S,
SLEEP_2S,
SLEEP_4S,
SLEEP_8S,
SLEEP_FOREVER
};
enum bod_t
{
BOD_OFF,
BOD_ON
};
enum adc_t
{
ADC_OFF,
ADC_ON
};
enum timer5_t
{
TIMER5_OFF,
TIMER5_ON
};
enum timer4_t
{
TIMER4_OFF,
TIMER4_ON
};
enum timer3_t
{
TIMER3_OFF,
TIMER3_ON
};
enum timer2_t
{
TIMER2_OFF,
TIMER2_ON
};
enum timer1_t
{
TIMER1_OFF,
TIMER1_ON
};
enum timer0_t
{
TIMER0_OFF,
TIMER0_ON
};
enum spi_t
{
SPI_OFF,
SPI_ON
};
enum usart0_t
{
USART0_OFF,
USART0_ON
};
enum usart1_t
{
USART1_OFF,
USART1_ON
};
enum usart2_t
{
USART2_OFF,
USART2_ON
};
enum usart3_t
{
USART3_OFF,
USART3_ON
};
enum twi_t
{
TWI_OFF,
TWI_ON
};
enum usb_t
{
USB_OFF,
USB_ON
};
enum idle_t
{
IDLE_0,
IDLE_1,
IDLE_2
};
class LowPowerClass
{
public:
#if defined (__AVR__)
#if defined (__AVR_ATmega328P__) || defined (__AVR_ATmega168__)
void idle(period_t period, adc_t adc, timer2_t timer2,
timer1_t timer1, timer0_t timer0, spi_t spi,
usart0_t usart0, twi_t twi);
#elif defined __AVR_ATmega2560__
void idle(period_t period, adc_t adc, timer5_t timer5,
timer4_t timer4, timer3_t timer3, timer2_t timer2,
timer1_t timer1, timer0_t timer0, spi_t spi,
usart3_t usart3, usart2_t usart2, usart1_t usart1,
usart0_t usart0, twi_t twi);
#elif defined __AVR_ATmega256RFR2__
void idle(period_t period, adc_t adc, timer5_t timer5,
timer4_t timer4, timer3_t timer3, timer2_t timer2,
timer1_t timer1, timer0_t timer0, spi_t spi,
usart1_t usart1,
usart0_t usart0, twi_t twi);
#elif defined __AVR_ATmega32U4__
void idle(period_t period, adc_t adc, timer4_t timer4,
timer3_t timer3, timer1_t timer1, timer0_t timer0,
spi_t spi, usart1_t usart1, twi_t twi, usb_t usb);
#else
#error "Please ensure chosen MCU is either 168, 328P, 32U4, 2560 or 256RFR2."
#endif
void adcNoiseReduction(period_t period, adc_t adc, timer2_t timer2) __attribute__((optimize("-O1")));
void powerDown(period_t period, adc_t adc, bod_t bod) __attribute__((optimize("-O1")));
void powerSave(period_t period, adc_t adc, bod_t bod, timer2_t timer2) __attribute__((optimize("-O1")));
void powerStandby(period_t period, adc_t adc, bod_t bod) __attribute__((optimize("-O1")));
void powerExtStandby(period_t period, adc_t adc, bod_t bod, timer2_t timer2) __attribute__((optimize("-O1")));
#elif defined (__arm__)
#if defined (__SAMD21G18A__)
void idle(idle_t idleMode);
void standby();
#else
#error "Please ensure chosen MCU is ATSAMD21G18A."
#endif
#else
#error "Processor architecture is not supported."
#endif
};
extern LowPowerClass LowPower;
#endif

46
NerfStatTrak.ino Normal file
View File

@ -0,0 +1,46 @@
#include "NerfStatTrakConfig.h"
#include "Globals.h"
#include "StateHandler.h"
#include "StateDefault.h"
void setup()
{
// Configure display
display = new SegmentDisplay();
#ifdef SDUseSPI
display->setClockSpeed(NerfClockSpeed);
#else
display->setClockPin(NerfClockPin);
display->setDataPin(NerfDataPin);
#endif
display->setLatchPin(NerfLatchPin);
display->setDigits(NerfDigits);
display->begin();
display->clear();
// Configure buttons
buttonA = new Button();
buttonA->init(NerfButtonA);
buttonB = new Button();
buttonB->init(NerfButtonB);
buttonArmed = new Button();
buttonArmed->init(NerfButtonArmed, LOW);
readCounters();
setCurrentState(new DefaultState());
}
void loop()
{
update();
currentState->loop();
}

56
NerfStatTrakConfig.h Normal file
View File

@ -0,0 +1,56 @@
#ifndef NerfStatTrakConfig_h
#define NerfStatTrakConfig_h
/**
* Display configuration
**/
#define NerfDigits 6
/**
* Display pin configuration
*
* Clock and data are used only when not using SPI,
* clock speed is only for SPI
**/
#define NerfLatchPin 10
#define NerfDataPin 11
#define NerfClockPin 12
#define NerfClockSpeed 1600000UL
/**
* Button configuration
**/
#define NerfButtonLongPressThreshold 1000
/**
* Button pin configuration
**/
#define NerfButtonA 3
#define NerfButtonB 2
#define NerfButtonArmed 4
// Must be usable for interrupts
#define NerfButtonWakeUp 2
#define NerfButtonWakeUpState LOW
/**
* Default state configuration
**/
#define NerfDefaultIntroTime 1000
#define NerfDefaultSleepTime 10000
/**
* Reset state configuration
**/
#define NerfResetIntroTime 1000
#define NerfResetOutroTime 2000
#endif

View File

@ -1,57 +0,0 @@
#include "lib/SegmentDisplay.h"
const int PinBottom = 2;
const int PinTop = 5;
const int PinDigit3 = 3;
const int PinDigit2 = 4;
void setup()
{
pinMode(PinTop, OUTPUT);
pinMode(PinBottom, OUTPUT);
pinMode(PinDigit3, OUTPUT);
pinMode(PinDigit2, OUTPUT);
digitalWrite(PinTop, LOW);
digitalWrite(PinBottom, LOW);
}
int lastTime = 0;
bool top = true;
void loop()
{
int currentTime = millis();
if (currentTime - lastTime > 1000)
{
top = !top;
lastTime = currentTime;
}
// Digit 3 (right) - switch between top and bottom
digitalWrite(PinDigit3, HIGH);
if (top)
{
digitalWrite(PinTop, HIGH);
delay(1);
digitalWrite(PinTop, LOW);
}
else
{
digitalWrite(PinBottom, HIGH);
delay(1);
digitalWrite(PinBottom, LOW);
}
digitalWrite(PinDigit3, LOW);
// Digit 2 (middle) - always bottom
digitalWrite(PinDigit2, HIGH);
digitalWrite(PinBottom, HIGH);
delay(1);
digitalWrite(PinBottom, LOW);
digitalWrite(PinDigit2, LOW);
}

192
SegmentDisplay.cpp Normal file
View File

@ -0,0 +1,192 @@
#include "SegmentDisplayConfig.h"
#include "SegmentDisplay.h"
void SegmentDisplay::begin()
{
pinMode(latchPin, OUTPUT);
#if !defined(SDUseSPI)
pinMode(clockPin, OUTPUT);
pinMode(dataPin, OUTPUT);
digitalWrite(clockPin, LOW);
digitalWrite(dataPin, LOW);
#endif
writeDisplay(0, 0);
digitalWrite(latchPin, HIGH);
digitalWrite(latchPin, LOW);
digitalWrite(latchPin, HIGH);
#if defined(SDUseSPI)
SPI.begin();
#endif
#if defined(SDSerialDebug)
Serial.begin(9600);
Serial.print("SegmentDisplay::begin\n");
#endif
}
void SegmentDisplay::end()
{
#if defined(SDUseSPI)
SPI.end();
#endif
}
void SegmentDisplay::clear()
{
writeDisplay(0, 0);
}
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--)
{
writeDigit((byte)(value % 10), digitMask);
value /= 10;
digitMask <<= 1;
}
}
void SegmentDisplay::writeTextLeft(char const* value)
{
#if defined(SDSerialDebug)
Serial.print("SegmentDisplay::writeTextLeft: " + value + "\n");
#endif
byte digitMask = 1 << (digits - 1);
byte charIndex = 0;
while (charIndex < digits && value[charIndex] != '\0')
{
writeChar(value[charIndex], digitMask);
digitMask >>= 1;
charIndex++;
}
while (charIndex < digits)
{
writeDisplay(0, digitMask);
digitMask >>= 1;
charIndex++;
}
}
void SegmentDisplay::writeRaw(char const* value)
{
#if defined(SDSerialDebug)
Serial.print("SegmentDisplay::writeRaw: " + value + "\n");
#endif
byte digitMask = 1 << (digits - 1);
byte charIndex = 0;
while (charIndex < digits)
{
writeDisplay(value[charIndex], digitMask);
digitMask >>= 1;
charIndex++;
}
while (charIndex < digits)
{
writeDisplay(0, digitMask);
digitMask >>= 1;
charIndex++;
}
}
inline void SegmentDisplay::writeDigit(byte value, byte digitMask)
{
writeDisplay(pgm_read_byte_near(SDNumberSegments + value), digitMask);
}
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);
}
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);
}

78
SegmentDisplay.h Normal file
View File

@ -0,0 +1,78 @@
#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.
*
* 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.
*
* The order in which the shift registers are chained is determined by
* (un)defining SDPushSegmentsFirst.
**/
class SegmentDisplay
{
public:
void begin();
void end();
void clear();
void writeNumber(uint32_t value);
void writeTextLeft(char const* value);
void writeRaw(char const* value);
byte getDigits() { return digits; }
void setDigits(byte value) { digits = value; }
uint32_t getLatchPin() { return latchPin; }
void setLatchPin(uint32_t value) { latchPin = value; }
uint32_t getDigitDelayMicroseconds() { return digitDelayMicroseconds; }
void setDigitDelayMicroseconds(uint32_t value) { digitDelayMicroseconds = value; }
#if defined(SDUseSPI)
uint32_t getClockSpeed() { return clockSpeed; }
void setClockSpeed(uint32_t value) { clockSpeed = value; }
#endif
#if !defined(SDUseSPI)
uint32_t getClockPin() { return clockPin; }
void setClockPin(uint32_t value) { clockPin = value; }
uint32_t getDataPin() { return dataPin; }
void setDataPin(uint32_t value) { dataPin = value; }
#endif
protected:
void writeDigit(byte value, byte digitMask);
void writeChar(char value, byte digitMask);
void writeDisplay(byte characterMask, byte digitMask);
private:
byte digits = 6;
uint32_t digitDelayMicroseconds = 1000;
uint32_t latchPin = SS;
#if defined(SDUseSPI)
uint32_t clockSpeed = 20000000;
#endif
#if !defined(SDUseSPI)
uint32_t clockPin = SCK;
uint32_t dataPin = MOSI;
#endif
};
#endif

326
SegmentDisplayChars.h Normal file
View File

@ -0,0 +1,326 @@
#ifndef SegmentDisplayChars_h
#define SegmentDisplayChars_h
#include "avr/pgmspace.h"
#define SegmentA 1 // Top
#define SegmentB 2 // Top right
#define SegmentC 4 // Bottom right
#define SegmentD 8 // Bottom
#define SegmentE 16 // Bottom left
#define SegmentF 32 // Top left
#define SegmentG 64 // Middle
#define SegmentDP (char)128 // Dot point
#define ASCIIZero 48
#define ASCIINine 57
#define ASCIIUppercaseA 65
#define ASCIIUppercaseZ 90
#define ASCIILowercaseA 97
#define ASCIILowercaseZ 122
/**
* _
* | |
* |_|
*
**/
#define Char0 SegmentA | SegmentB | SegmentC | SegmentD | SegmentE | SegmentF
/**
*
* |
* |
*
**/
#define Char1 SegmentB | SegmentC
/**
* _
* _|
* |_
*
**/
#define Char2 SegmentA | SegmentB | SegmentD | SegmentE | SegmentG
/**
* _
* _|
* _|
*
**/
#define Char3 SegmentA | SegmentB | SegmentC | SegmentD | SegmentG
/**
*
* |_|
* |
*
**/
#define Char4 SegmentB | SegmentC | SegmentF | SegmentG
/**
* _
* |_
* _|
*
**/
#define Char5 SegmentA | SegmentC | SegmentD | SegmentF | SegmentG
/**
* _
* |_
* |_|
*
**/
#define Char6 SegmentA | SegmentC | SegmentD | SegmentE | SegmentF | SegmentG
/**
* _
* |
* |
*
**/
#define Char7 SegmentA | SegmentB | SegmentC
/**
* _
* |_|
* |_|
*
**/
#define Char8 SegmentA | SegmentB | SegmentC | SegmentD | SegmentE | SegmentF | SegmentG
/**
* _
* |_|
* _|
*
**/
#define Char9 SegmentA | SegmentB | SegmentC | SegmentD | SegmentF | SegmentG
/**
* _
* |_|
* | |
*
**/
#define CharA SegmentA | SegmentB | SegmentC | SegmentE | SegmentF | SegmentG
/**
*
* |_
* |_|
*
**/
#define CharB SegmentC | SegmentD | SegmentE | SegmentF | SegmentG
/**
* _
* |
* |_
*
**/
#define CharC SegmentA | SegmentD | SegmentE | SegmentF
/**
*
* _|
* |_|
*
**/
#define CharD SegmentB | SegmentC | SegmentD | SegmentE | SegmentG
/**
* _
* |_
* |_
*
**/
#define CharE SegmentA | SegmentD | SegmentE | SegmentF | SegmentG
/**
* _
* |_
* |
*
**/
#define CharF SegmentA | SegmentE | SegmentF | SegmentG
/**
* _
* |_|
* _|
*
**/
#define CharG SegmentA | SegmentB | SegmentC | SegmentD | SegmentF | SegmentG
/**
*
* |_|
* | |
*
**/
#define CharH SegmentB | SegmentC | SegmentE | SegmentF | SegmentG
/**
*
* |
* |
*
**/
#define CharI SegmentE | SegmentF
/**
*
* |
* |_|
*
**/
#define CharJ SegmentB | SegmentC | SegmentD | SegmentE
/**
*
* |_
* |
*
**/
#define CharK SegmentE | SegmentF | SegmentG
/**
*
* |
* |_
*
**/
#define CharL SegmentD | SegmentE | SegmentF
/**
* _
*
* | |
*
**/
#define CharM SegmentA | SegmentC | SegmentE
/**
*
* _
* | |
*
**/
#define CharN SegmentC | SegmentE | SegmentG
/**
*
* _
* |_|
*
**/
#define CharO SegmentC | SegmentD | SegmentE | SegmentG
/**
* _
* |_|
* |
*
**/
#define CharP SegmentA | SegmentB | SegmentE | SegmentF | SegmentG
/**
* _
* |_|
* |
*
**/
#define CharQ SegmentA | SegmentB | SegmentC | SegmentF | SegmentG
/**
*
* _
* |
*
**/
#define CharR SegmentE | SegmentG
/**
* _
* |_
* _|
*
**/
#define CharS SegmentA | SegmentC | SegmentD | SegmentF | SegmentG
/**
*
* |_
* |_
*
**/
#define CharT SegmentD | SegmentE | SegmentF | SegmentG
/**
*
* | |
* |_|
*
**/
#define CharU SegmentB | SegmentC | SegmentD | SegmentE | SegmentF
/**
*
*
* |_|
*
**/
#define CharV SegmentC | SegmentD | SegmentE
/**
*
* | |
* _
*
**/
#define CharW SegmentB | SegmentD | SegmentF
/**
*
* _|
* |
*
**/
#define CharX SegmentB | SegmentC | SegmentG
/**
*
* |_|
* _|
*
**/
#define CharY SegmentB | SegmentC | SegmentD | SegmentF | SegmentG
/**
* _
* _|
* |_
*
**/
#define CharZ SegmentA | SegmentB | SegmentD | SegmentE | SegmentG
const byte SDNumberSegments[10] PROGMEM =
{
Char0, Char1, Char2, Char3, Char4, Char5, Char6, Char7, Char8, Char9
};
const byte SDCharacterSegments[26] PROGMEM =
{
CharA, CharB, CharC, CharD, CharE, CharF, CharG, CharH, CharI, CharJ, CharK, CharL, CharM,
CharN, CharO, CharP, CharQ, CharR, CharS, CharT, CharU, CharV, CharW, CharX, CharY, CharZ
};
#endif

50
SegmentDisplayConfig.h Normal file
View File

@ -0,0 +1,50 @@
#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
/**
* 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

107
StateDefault.cpp Normal file
View File

@ -0,0 +1,107 @@
#include "StateDefault.h"
#include "NerfStatTrakConfig.h"
#include "Globals.h"
#include "StateLoseTheGame.h"
#include "StateUserUnknown.h"
#include "StateReset.h"
bool DefaultState::ShowHits = true;
void DefaultState::setup()
{
introStart = currentTime;
lastAction = currentTime;
}
void DefaultState::loop()
{
if (buttonA->pressed() && buttonB->pressed())
{
// A + B
setCurrentState(new UserUnknownState());
return;
}
// A short (triggered on release)
if (buttonA->changed() && !buttonA->pressed() && buttonA->pressedMillis(currentTime) <= NerfButtonLongPressThreshold)
{
addHit();
if (!DefaultState::ShowHits)
setShowHits(true);
lastAction = currentTime;
}
// A long
if (buttonA->pressed() && buttonA->pressedMillis(currentTime) > NerfButtonLongPressThreshold)
{
setCurrentState(new ResetState());
}
// B short (triggered on release)
if (buttonB->changed() && !buttonB->pressed() && buttonB->pressedMillis(currentTime) <= NerfButtonLongPressThreshold)
{
setShowHits(!DefaultState::ShowHits);
lastAction = currentTime;
}
// B long
if (buttonB->pressed() && buttonB->pressedMillis(currentTime) > NerfButtonLongPressThreshold)
{
setCurrentState(new LoseTheGameState());
return;
}
// Shot
if (buttonArmed->changed() && !buttonArmed->pressed())
{
// The shot has already been counted in Globals.cpp
lastAction = currentTime;
}
if (showIntro)
{
if (currentTime - introStart >= NerfDefaultIntroTime)
showIntro = false;
if (DefaultState::ShowHits)
{
// Prevents warning: deprecated conversion from string constant to 'char*'
char text[] = "Hits";
display->writeTextLeft(text);
}
else
{
char text[] = "Shots";
display->writeTextLeft(text);
}
}
else
{
if (currentTime - lastAction >= NerfDefaultSleepTime)
{
sleep();
lastAction = currentTime;
}
if (DefaultState::ShowHits)
display->writeNumber(hits);
else
display->writeNumber(shots);
}
}
void DefaultState::setShowHits(bool value)
{
showIntro = true;
introStart = currentTime;
DefaultState::ShowHits = value;
}

35
StateDefault.h Normal file
View File

@ -0,0 +1,35 @@
#ifndef StateDefault_h
#define StateDefault_h
#include "StateHandler.h"
/**
* Default state
*
* Start by showing the current counter mode (hits or shots),
* then display the value.
*
* A short: Add hit
* A long: Go to reset state
* B short: Toggle between hits and shots and restart state
* A + B: Display "Error user unknwn"
* B long: Display "You lost the game" animation (losethegame.com - you're welcome!)
**/
class DefaultState : public AbstractStateHandler
{
private:
bool showIntro = true;
unsigned long introStart;
unsigned long lastAction;
void setShowHits(bool value);
public:
static bool ShowHits;
void setup();
void loop();
};
#endif

11
StateHandler.h Normal file
View File

@ -0,0 +1,11 @@
#ifndef StateHandler_h
#define StateHandler_h
class AbstractStateHandler
{
public:
virtual void setup() = 0;
virtual void loop() = 0;
};
#endif

87
StateLoseTheGame.cpp Normal file
View File

@ -0,0 +1,87 @@
#include "StateLoseTheGame.h"
#include "Globals.h"
#include "StateDefault.h"
#include "SegmentDisplayChars.h"
#define CharPipeLeft SegmentE | SegmentF
#define CharPipeRight SegmentB | SegmentC
struct Frame
{
uint32_t time;
char frame[6];
};
Frame const animation[] = {
// Snake towards the middle
{ 100, { SegmentF, 0, 0, 0, 0, SegmentB } },
{ 100, { SegmentF | SegmentE, 0, 0, 0, 0, SegmentB | SegmentC } },
{ 100, { SegmentE | SegmentD, 0, 0, 0, 0, SegmentC | SegmentD } },
{ 100, { SegmentD | SegmentC, 0, 0, 0, 0, SegmentD | SegmentE } },
{ 100, { SegmentC | SegmentB, 0, 0, 0, 0, SegmentE | SegmentF } },
{ 100, { SegmentB, SegmentF, 0, 0, SegmentB, SegmentF } },
{ 100, { 0, SegmentF | SegmentE, 0, 0, SegmentB | SegmentC, 0 } },
{ 100, { 0, SegmentE | SegmentD, 0, 0, SegmentC | SegmentD, 0 } },
{ 100, { 0, SegmentD | SegmentC, 0, 0, SegmentD | SegmentE, 0 } },
{ 100, { 0, SegmentC | SegmentB, 0, 0, SegmentE | SegmentF, 0 } },
{ 100, { 0, SegmentB, SegmentF, SegmentB, SegmentF, 0 } },
{ 100, { 0, 0, SegmentF | SegmentE, SegmentB | SegmentC, 0, 0 } },
{ 100, { 0, 0, SegmentE | SegmentD, SegmentC | SegmentD, 0, 0 } },
{ 100, { 0, 0, SegmentD | SegmentC, SegmentD | SegmentE, 0, 0 } },
{ 500, { 0, 0, SegmentC | SegmentB, SegmentE | SegmentF, 0, 0 } },
// Slide open to reveal 'you'
{ 100, { 0, 0, CharPipeLeft | CharO, CharU | CharPipeRight, 0, 0 } },
{ 100, { 0, CharPipeRight, CharO, CharU, CharPipeLeft, 0 } },
{ 100, { 0, CharPipeLeft | CharY, CharO, CharU, CharPipeRight, 0 } },
{ 100, { CharPipeRight, CharY, CharO, CharU, 0, CharPipeLeft } },
{ 100, { CharPipeLeft, CharY, CharO, CharU, 0, CharPipeRight } },
{ 500, { 0, CharY, CharO, CharU, 0, 0 } },
// The rest of the text
{ 750, { 0, CharL, CharO, CharS, CharT, 0 } },
{ 750, { 0, 0, CharT, CharH, CharE, 0 } },
{ 500, { SegmentDP, CharG, CharA | SegmentDP, CharM, CharE | SegmentDP, 0 } },
{ 500, { 0, CharG | SegmentDP, CharA, CharM | SegmentDP, CharE, SegmentDP } },
{ 500, { SegmentDP, CharG, CharA | SegmentDP, CharM, CharE | SegmentDP, 0 } },
{ 500, { 0, CharG | SegmentDP, CharA, CharM | SegmentDP, CharE, SegmentDP } },
{ 500, { SegmentDP, CharG, CharA | SegmentDP, CharM, CharE | SegmentDP, 0 } },
{ 500, { 0, CharG | SegmentDP, CharA, CharM | SegmentDP, CharE, SegmentDP } },
{ 500, { SegmentDP, CharG, CharA | SegmentDP, CharM, CharE | SegmentDP, 0 } },
{ 500, { 0, CharG | SegmentDP, CharA, CharM | SegmentDP, CharE, SegmentDP } },
{ 0, { 0, 0, 0, 0, 0, 0 } }
};
void LoseTheGameState::setup()
{
animationTime = currentTime;
animationStep = 0;
}
void LoseTheGameState::loop()
{
if (buttonA->pressed() || buttonB->pressed())
{
setCurrentState(new DefaultState());
}
if (currentTime - animationTime > animation[animationStep].time)
{
animationStep++;
animationTime = currentTime;
if (animation[animationStep].time == 0)
setCurrentState(new DefaultState());
}
display->writeRaw(animation[animationStep].frame);
}

25
StateLoseTheGame.h Normal file
View File

@ -0,0 +1,25 @@
#ifndef StateLoseTheGame_h
#define StateLoseTheGame_h
#include "Arduino.h"
#include "StateHandler.h"
/**
* Lose the game state
*
* Note that the animation in this state is hardcoded
* to 6 digits.
**/
class LoseTheGameState : public AbstractStateHandler
{
public:
void setup();
void loop();
private:
unsigned long animationTime;
byte animationStep;
};
#endif

114
StateReset.cpp Normal file
View File

@ -0,0 +1,114 @@
#include "StateReset.h"
#include "Globals.h"
#include "NerfStatTrakConfig.h"
#include "StateDefault.h"
void ResetState::setup()
{
intro = true;
introStart = currentTime;
outro = false;
selected = 0;
}
void ResetState::loop()
{
if (intro)
{
if (currentTime - introStart >= NerfResetIntroTime)
intro = false;
char text[] = "Reset";
display->writeTextLeft(text);
return;
}
if (outro)
{
loopOutro();
return;
}
if (buttonA->changed() && !buttonA->pressed())
{
switch (selected)
{
case 0:
setCurrentState(new DefaultState());
return;
case 1:
resetHits();
break;
case 2:
resetShots();
break;
case 3:
resetHits();
resetShots();
break;
}
outroStart = currentTime;
outro = true;
return;
}
if (buttonB->changed() && !buttonB->pressed())
{
selected++;
if (selected > 3)
selected = 0;
}
switch (selected)
{
case 0:
{
char text[] = "Cancel";
display->writeTextLeft(text);
break;
}
case 1:
{
char text[] = "Hits";
display->writeTextLeft(text);
break;
}
case 2:
{
char text[] = "Shots";
display->writeTextLeft(text);
break;
}
case 3:
{
char text[] = "Both";
display->writeTextLeft(text);
break;
}
}
}
void ResetState::loopOutro()
{
if (currentTime - outroStart >= NerfResetOutroTime)
{
setCurrentState(new DefaultState());
return;
}
char text[] = "Done";
display->writeTextLeft(text);
}

31
StateReset.h Normal file
View File

@ -0,0 +1,31 @@
#ifndef StateReset_h
#define StateReset_h
#include "StateHandler.h"
#include "Arduino.h"
/**
* Reset state
*
* Shows a menu providing reset options. A confirms the
* selection, B switches to the next.
**/
class ResetState : public AbstractStateHandler
{
private:
bool intro;
unsigned long introStart;
bool outro;
unsigned long outroStart;
byte selected;
protected:
void loopOutro();
public:
void setup();
void loop();
};
#endif

65
StateUserUnknown.cpp Normal file
View File

@ -0,0 +1,65 @@
#include "StateUserUnknown.h"
#include "Globals.h"
#include "StateDefault.h"
void UserUnknownState::setup()
{
animationTime = currentTime;
animationStep = 0;
}
void UserUnknownState::loop()
{
if (buttonA->pressed() || buttonB->pressed())
{
setCurrentState(new DefaultState());
}
if (currentTime - animationTime > 500)
{
animationStep++;
animationTime = currentTime;
if (animationStep == 12)
animationStep = 0;
}
switch (animationStep)
{
case 0:
case 2:
case 4:
{
char text[] = "ERROR";
display->writeTextLeft(text);
break;
}
case 1:
case 3:
case 5:
{
display->clear();
break;
}
case 6:
case 7:
case 8:
{
char text[] = "user";
display->writeTextLeft(text);
break;
}
case 9:
case 10:
case 11:
{
char text[] = "unknwn";
display->writeTextLeft(text);
break;
}
}
}

24
StateUserUnknown.h Normal file
View File

@ -0,0 +1,24 @@
#ifndef StateUserUnknown_h
#define StateUserUnknown_h
#include "Arduino.h"
#include "StateHandler.h"
/**
* "User unknown" state
*
* Displays "Error user unknwn" until a button is pressed.
**/
class UserUnknownState : public AbstractStateHandler
{
public:
void setup();
void loop();
private:
unsigned long animationTime;
byte animationStep;
};
#endif

618
eagle/Driver board.brd Normal file
View File

@ -0,0 +1,618 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE eagle SYSTEM "eagle.dtd">
<eagle version="7.7.0">
<drawing>
<settings>
<setting alwaysvectorfont="no"/>
<setting verticaltext="up"/>
</settings>
<grid distance="0.25" unitdist="mm" unit="mm" style="dots" multiple="1" display="yes" altdistance="0.025" altunitdist="inch" altunit="inch"/>
<layers>
<layer number="1" name="Top" color="4" fill="1" visible="yes" active="yes"/>
<layer number="16" name="Bottom" color="1" fill="1" visible="yes" active="yes"/>
<layer number="17" name="Pads" color="2" fill="1" visible="yes" active="yes"/>
<layer number="18" name="Vias" color="2" fill="1" visible="yes" active="yes"/>
<layer number="19" name="Unrouted" color="6" fill="1" visible="yes" active="yes"/>
<layer number="20" name="Dimension" color="15" fill="1" visible="yes" active="yes"/>
<layer number="21" name="tPlace" color="7" fill="1" visible="yes" active="yes"/>
<layer number="22" name="bPlace" color="7" fill="1" visible="yes" active="yes"/>
<layer number="23" name="tOrigins" color="15" fill="1" visible="yes" active="yes"/>
<layer number="24" name="bOrigins" color="15" fill="1" visible="yes" active="yes"/>
<layer number="25" name="tNames" color="7" fill="1" visible="yes" active="yes"/>
<layer number="26" name="bNames" color="7" fill="1" visible="yes" active="yes"/>
<layer number="27" name="tValues" color="7" fill="1" visible="yes" active="yes"/>
<layer number="28" name="bValues" color="7" fill="1" visible="yes" active="yes"/>
<layer number="29" name="tStop" color="7" fill="3" visible="yes" active="yes"/>
<layer number="30" name="bStop" color="7" fill="6" visible="yes" active="yes"/>
<layer number="31" name="tCream" color="7" fill="4" visible="yes" active="yes"/>
<layer number="32" name="bCream" color="7" fill="5" visible="yes" active="yes"/>
<layer number="33" name="tFinish" color="6" fill="3" visible="yes" active="yes"/>
<layer number="34" name="bFinish" color="6" fill="6" visible="yes" active="yes"/>
<layer number="35" name="tGlue" color="7" fill="4" visible="yes" active="yes"/>
<layer number="36" name="bGlue" color="7" fill="5" visible="yes" active="yes"/>
<layer number="37" name="tTest" color="7" fill="1" visible="yes" active="yes"/>
<layer number="38" name="bTest" color="7" fill="1" visible="yes" active="yes"/>
<layer number="39" name="tKeepout" color="4" fill="11" visible="yes" active="yes"/>
<layer number="40" name="bKeepout" color="1" fill="11" visible="yes" active="yes"/>
<layer number="41" name="tRestrict" color="4" fill="10" visible="yes" active="yes"/>
<layer number="42" name="bRestrict" color="1" fill="10" visible="yes" active="yes"/>
<layer number="43" name="vRestrict" color="2" fill="10" visible="yes" active="yes"/>
<layer number="44" name="Drills" color="7" fill="1" visible="yes" active="yes"/>
<layer number="45" name="Holes" color="7" fill="1" visible="yes" active="yes"/>
<layer number="46" name="Milling" color="3" fill="1" visible="yes" active="yes"/>
<layer number="47" name="Measures" color="7" fill="1" visible="yes" active="yes"/>
<layer number="48" name="Document" color="7" fill="1" visible="yes" active="yes"/>
<layer number="49" name="Reference" color="7" fill="1" visible="yes" active="yes"/>
<layer number="51" name="tDocu" color="7" fill="1" visible="yes" active="yes"/>
<layer number="52" name="bDocu" color="7" fill="1" visible="yes" active="yes"/>
<layer number="90" name="Modules" color="5" fill="1" visible="no" active="no"/>
<layer number="91" name="Nets" color="2" fill="1" visible="no" active="no"/>
<layer number="92" name="Busses" color="1" fill="1" visible="no" active="no"/>
<layer number="93" name="Pins" color="2" fill="1" visible="no" active="no"/>
<layer number="94" name="Symbols" color="4" fill="1" visible="no" active="no"/>
<layer number="95" name="Names" color="7" fill="1" visible="no" active="no"/>
<layer number="96" name="Values" color="7" fill="1" visible="no" active="no"/>
<layer number="97" name="Info" color="7" fill="1" visible="no" active="no"/>
<layer number="98" name="Guide" color="6" fill="1" visible="no" active="no"/>
</layers>
<board>
<plain>
<wire x1="23.9" y1="31.71" x2="72.06" y2="31.71" width="0" layer="20"/>
<wire x1="72.06" y1="31.71" x2="72.06" y2="52.695" width="0" layer="20"/>
<wire x1="72.06" y1="52.695" x2="23.805" y2="52.65" width="0" layer="20"/>
<wire x1="23.805" y1="52.65" x2="23.9" y2="31.71" width="0" layer="20"/>
<dimension x1="23.9" y1="52.695" x2="23.9" y2="31.71" x3="18.425390625" y3="42.2025" textsize="1.778" layer="47"/>
<dimension x1="23.9" y1="52.695" x2="72.06" y2="52.695" x3="47.98" y3="59.244996875" textsize="1.778" layer="47"/>
<text x="35.25" y="52.75" size="1.016" layer="49" rot="MR90">Data</text>
<text x="40" y="52.75" size="1.016" layer="49" rot="MR90">Latch</text>
<text x="42.5" y="52.75" size="1.016" layer="49" rot="MR90">Clock</text>
<text x="30" y="52.75" size="1.016" layer="49" rot="MR90">+5V</text>
<text x="37.75" y="52.75" size="1.016" layer="49" rot="MR90">Ground</text>
<text x="51.75" y="31" size="1.016" layer="49" rot="MR270">A</text>
<text x="54.25" y="31" size="1.016" layer="49" rot="MR270">B</text>
<text x="56.75" y="31" size="1.016" layer="49" rot="MR270">C</text>
<text x="59.25" y="31" size="1.016" layer="49" rot="MR270">D</text>
<text x="61.75" y="31" size="1.016" layer="49" rot="MR270">E</text>
<text x="64.25" y="31" size="1.016" layer="49" rot="MR270">F</text>
<text x="66.75" y="31" size="1.016" layer="49" rot="MR270">G</text>
<text x="69.5" y="31" size="1.016" layer="49" rot="MR270">DP</text>
<text x="28.5" y="31" size="1.016" layer="49" rot="MR270">D6</text>
<text x="31" y="31" size="1.016" layer="49" rot="MR270">D5</text>
<text x="33.5" y="31" size="1.016" layer="49" rot="MR270">D4</text>
<text x="36" y="31" size="1.016" layer="49" rot="MR270">D3</text>
<text x="38.75" y="31" size="1.016" layer="49" rot="MR270">D2</text>
<text x="41.25" y="31" size="1.016" layer="49" rot="MR270">D1</text>
</plain>
<libraries>
<library name="74xx-eu">
<description>&lt;b&gt;TTL Devices, 74xx Series with European Symbols&lt;/b&gt;&lt;p&gt;
Based on the following sources:
&lt;ul&gt;
&lt;li&gt;Texas Instruments &lt;i&gt;TTL Data Book&lt;/i&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;Volume 1, 1996.
&lt;li&gt;TTL Data Book, Volume 2 , 1993
&lt;li&gt;National Seminconductor Databook 1990, ALS/LS Logic
&lt;li&gt;ttl 74er digital data dictionary, ECA Electronic + Acustic GmbH, ISBN 3-88109-032-0
&lt;li&gt;http://icmaster.com/ViewCompare.asp
&lt;/ul&gt;
&lt;author&gt;Created by librarian@cadsoft.de&lt;/author&gt;</description>
<packages>
<package name="DIL16">
<description>&lt;b&gt;Dual In Line Package&lt;/b&gt;</description>
<wire x1="10.16" y1="2.921" x2="-10.16" y2="2.921" width="0.1524" layer="21"/>
<wire x1="-10.16" y1="-2.921" x2="10.16" y2="-2.921" width="0.1524" layer="21"/>
<wire x1="10.16" y1="2.921" x2="10.16" y2="-2.921" width="0.1524" layer="21"/>
<wire x1="-10.16" y1="2.921" x2="-10.16" y2="1.016" width="0.1524" layer="21"/>
<wire x1="-10.16" y1="-2.921" x2="-10.16" y2="-1.016" width="0.1524" layer="21"/>
<wire x1="-10.16" y1="1.016" x2="-10.16" y2="-1.016" width="0.1524" layer="21" curve="-180"/>
<pad name="1" x="-8.89" y="-3.81" drill="0.8128" shape="long" rot="R90"/>
<pad name="2" x="-6.35" y="-3.81" drill="0.8128" shape="long" rot="R90"/>
<pad name="7" x="6.35" y="-3.81" drill="0.8128" shape="long" rot="R90"/>
<pad name="8" x="8.89" y="-3.81" drill="0.8128" shape="long" rot="R90"/>
<pad name="3" x="-3.81" y="-3.81" drill="0.8128" shape="long" rot="R90"/>
<pad name="4" x="-1.27" y="-3.81" drill="0.8128" shape="long" rot="R90"/>
<pad name="6" x="3.81" y="-3.81" drill="0.8128" shape="long" rot="R90"/>
<pad name="5" x="1.27" y="-3.81" drill="0.8128" shape="long" rot="R90"/>
<pad name="9" x="8.89" y="3.81" drill="0.8128" shape="long" rot="R90"/>
<pad name="10" x="6.35" y="3.81" drill="0.8128" shape="long" rot="R90"/>
<pad name="11" x="3.81" y="3.81" drill="0.8128" shape="long" rot="R90"/>
<pad name="12" x="1.27" y="3.81" drill="0.8128" shape="long" rot="R90"/>
<pad name="13" x="-1.27" y="3.81" drill="0.8128" shape="long" rot="R90"/>
<pad name="14" x="-3.81" y="3.81" drill="0.8128" shape="long" rot="R90"/>
<pad name="15" x="-6.35" y="3.81" drill="0.8128" shape="long" rot="R90"/>
<pad name="16" x="-8.89" y="3.81" drill="0.8128" shape="long" rot="R90"/>
<text x="-10.541" y="-2.921" size="1.27" layer="25" ratio="10" rot="R90">&gt;NAME</text>
<text x="-7.493" y="-0.635" size="1.27" layer="27" ratio="10">&gt;VALUE</text>
</package>
</packages>
</library>
<library name="uln-udn">
<description>&lt;b&gt;Driver Arrays&lt;/b&gt;&lt;p&gt;
ULN and UDN Series&lt;p&gt;
&lt;author&gt;Created by librarian@cadsoft.de&lt;/author&gt;</description>
<packages>
<package name="DIL18">
<description>&lt;b&gt;Dual In Line Package&lt;/b&gt;</description>
<wire x1="11.43" y1="2.921" x2="-11.43" y2="2.921" width="0.1524" layer="21"/>
<wire x1="-11.43" y1="-2.921" x2="11.43" y2="-2.921" width="0.1524" layer="21"/>
<wire x1="11.43" y1="2.921" x2="11.43" y2="-2.921" width="0.1524" layer="21"/>
<wire x1="-11.43" y1="2.921" x2="-11.43" y2="1.016" width="0.1524" layer="21"/>
<wire x1="-11.43" y1="-2.921" x2="-11.43" y2="-1.016" width="0.1524" layer="21"/>
<wire x1="-11.43" y1="1.016" x2="-11.43" y2="-1.016" width="0.1524" layer="21" curve="-180"/>
<pad name="1" x="-10.16" y="-3.81" drill="0.8128" shape="long" rot="R90"/>
<pad name="2" x="-7.62" y="-3.81" drill="0.8128" shape="long" rot="R90"/>
<pad name="7" x="5.08" y="-3.81" drill="0.8128" shape="long" rot="R90"/>
<pad name="8" x="7.62" y="-3.81" drill="0.8128" shape="long" rot="R90"/>
<pad name="3" x="-5.08" y="-3.81" drill="0.8128" shape="long" rot="R90"/>
<pad name="4" x="-2.54" y="-3.81" drill="0.8128" shape="long" rot="R90"/>
<pad name="6" x="2.54" y="-3.81" drill="0.8128" shape="long" rot="R90"/>
<pad name="5" x="0" y="-3.81" drill="0.8128" shape="long" rot="R90"/>
<pad name="9" x="10.16" y="-3.81" drill="0.8128" shape="long" rot="R90"/>
<pad name="10" x="10.16" y="3.81" drill="0.8128" shape="long" rot="R90"/>
<pad name="11" x="7.62" y="3.81" drill="0.8128" shape="long" rot="R90"/>
<pad name="12" x="5.08" y="3.81" drill="0.8128" shape="long" rot="R90"/>
<pad name="13" x="2.54" y="3.81" drill="0.8128" shape="long" rot="R90"/>
<pad name="14" x="0" y="3.81" drill="0.8128" shape="long" rot="R90"/>
<pad name="15" x="-2.54" y="3.81" drill="0.8128" shape="long" rot="R90"/>
<pad name="16" x="-5.08" y="3.81" drill="0.8128" shape="long" rot="R90"/>
<pad name="17" x="-7.62" y="3.81" drill="0.8128" shape="long" rot="R90"/>
<pad name="18" x="-10.16" y="3.81" drill="0.8128" shape="long" rot="R90"/>
<text x="-11.684" y="-3.048" size="1.27" layer="25" ratio="10" rot="R90">&gt;NAME</text>
<text x="-9.525" y="-0.635" size="1.27" layer="27" ratio="10">&gt;VALUE</text>
</package>
</packages>
</library>
</libraries>
<attributes>
</attributes>
<variantdefs>
</variantdefs>
<classes>
<class number="0" name="default" width="0.508" drill="0">
</class>
</classes>
<designrules name="default *">
<description language="de">&lt;b&gt;EAGLE Design Rules&lt;/b&gt;
&lt;p&gt;
Die Standard-Design-Rules sind so gewählt, dass sie für
die meisten Anwendungen passen. Sollte ihre Platine
besondere Anforderungen haben, treffen Sie die erforderlichen
Einstellungen hier und speichern die Design Rules unter
einem neuen Namen ab.</description>
<description language="en">&lt;b&gt;EAGLE Design Rules&lt;/b&gt;
&lt;p&gt;
The default Design Rules have been set to cover
a wide range of applications. Your particular design
may have different requirements, so please make the
necessary adjustments and save your customized
design rules under a new name.</description>
<param name="layerSetup" value="(1*16)"/>
<param name="mtCopper" value="0.035mm 0.035mm 0.035mm 0.035mm 0.035mm 0.035mm 0.035mm 0.035mm 0.035mm 0.035mm 0.035mm 0.035mm 0.035mm 0.035mm 0.035mm 0.035mm"/>
<param name="mtIsolate" value="1.5mm 0.15mm 0.2mm 0.15mm 0.2mm 0.15mm 0.2mm 0.15mm 0.2mm 0.15mm 0.2mm 0.15mm 0.2mm 0.15mm 0.2mm"/>
<param name="mdWireWire" value="8mil"/>
<param name="mdWirePad" value="8mil"/>
<param name="mdWireVia" value="8mil"/>
<param name="mdPadPad" value="8mil"/>
<param name="mdPadVia" value="8mil"/>
<param name="mdViaVia" value="8mil"/>
<param name="mdSmdPad" value="8mil"/>
<param name="mdSmdVia" value="8mil"/>
<param name="mdSmdSmd" value="8mil"/>
<param name="mdViaViaSameLayer" value="8mil"/>
<param name="mnLayersViaInSmd" value="2"/>
<param name="mdCopperDimension" value="40mil"/>
<param name="mdDrill" value="8mil"/>
<param name="mdSmdStop" value="0mil"/>
<param name="msWidth" value="30mil"/>
<param name="msDrill" value="24mil"/>
<param name="msMicroVia" value="9.99mm"/>
<param name="msBlindViaRatio" value="0.5"/>
<param name="rvPadTop" value="0.25"/>
<param name="rvPadInner" value="0.25"/>
<param name="rvPadBottom" value="0.25"/>
<param name="rvViaOuter" value="0.25"/>
<param name="rvViaInner" value="0.25"/>
<param name="rvMicroViaOuter" value="0.25"/>
<param name="rvMicroViaInner" value="0.25"/>
<param name="rlMinPadTop" value="10mil"/>
<param name="rlMaxPadTop" value="20mil"/>
<param name="rlMinPadInner" value="10mil"/>
<param name="rlMaxPadInner" value="20mil"/>
<param name="rlMinPadBottom" value="10mil"/>
<param name="rlMaxPadBottom" value="20mil"/>
<param name="rlMinViaOuter" value="8mil"/>
<param name="rlMaxViaOuter" value="20mil"/>
<param name="rlMinViaInner" value="8mil"/>
<param name="rlMaxViaInner" value="20mil"/>
<param name="rlMinMicroViaOuter" value="4mil"/>
<param name="rlMaxMicroViaOuter" value="20mil"/>
<param name="rlMinMicroViaInner" value="4mil"/>
<param name="rlMaxMicroViaInner" value="20mil"/>
<param name="psTop" value="-1"/>
<param name="psBottom" value="-1"/>
<param name="psFirst" value="-1"/>
<param name="psElongationLong" value="100"/>
<param name="psElongationOffset" value="100"/>
<param name="mvStopFrame" value="1"/>
<param name="mvCreamFrame" value="0"/>
<param name="mlMinStopFrame" value="4mil"/>
<param name="mlMaxStopFrame" value="4mil"/>
<param name="mlMinCreamFrame" value="0mil"/>
<param name="mlMaxCreamFrame" value="0mil"/>
<param name="mlViaStopLimit" value="0mil"/>
<param name="srRoundness" value="0"/>
<param name="srMinRoundness" value="0mil"/>
<param name="srMaxRoundness" value="0mil"/>
<param name="slThermalIsolate" value="10mil"/>
<param name="slThermalsForVias" value="0"/>
<param name="dpMaxLengthDifference" value="10mm"/>
<param name="dpGapFactor" value="2.5"/>
<param name="checkGrid" value="0"/>
<param name="checkAngle" value="0"/>
<param name="checkFont" value="1"/>
<param name="checkRestrict" value="1"/>
<param name="useDiameter" value="13"/>
<param name="maxErrors" value="50"/>
</designrules>
<autorouter>
<pass name="Default">
<param name="RoutingGrid" value="50mil"/>
<param name="AutoGrid" value="1"/>
<param name="Efforts" value="2"/>
<param name="TopRouterVariant" value="1"/>
<param name="tpViaShape" value="round"/>
<param name="PrefDir.1" value="0"/>
<param name="PrefDir.2" value="0"/>
<param name="PrefDir.3" value="0"/>
<param name="PrefDir.4" value="0"/>
<param name="PrefDir.5" value="0"/>
<param name="PrefDir.6" value="0"/>
<param name="PrefDir.7" value="0"/>
<param name="PrefDir.8" value="0"/>
<param name="PrefDir.9" value="0"/>
<param name="PrefDir.10" value="0"/>
<param name="PrefDir.11" value="0"/>
<param name="PrefDir.12" value="0"/>
<param name="PrefDir.13" value="0"/>
<param name="PrefDir.14" value="0"/>
<param name="PrefDir.15" value="0"/>
<param name="PrefDir.16" value="a"/>
<param name="cfVia" value="8"/>
<param name="cfNonPref" value="5"/>
<param name="cfChangeDir" value="2"/>
<param name="cfOrthStep" value="2"/>
<param name="cfDiagStep" value="3"/>
<param name="cfExtdStep" value="0"/>
<param name="cfBonusStep" value="1"/>
<param name="cfMalusStep" value="1"/>
<param name="cfPadImpact" value="4"/>
<param name="cfSmdImpact" value="4"/>
<param name="cfBusImpact" value="0"/>
<param name="cfHugging" value="3"/>
<param name="cfAvoid" value="4"/>
<param name="cfPolygon" value="10"/>
<param name="cfBase.1" value="0"/>
<param name="cfBase.2" value="1"/>
<param name="cfBase.3" value="1"/>
<param name="cfBase.4" value="1"/>
<param name="cfBase.5" value="1"/>
<param name="cfBase.6" value="1"/>
<param name="cfBase.7" value="1"/>
<param name="cfBase.8" value="1"/>
<param name="cfBase.9" value="1"/>
<param name="cfBase.10" value="1"/>
<param name="cfBase.11" value="1"/>
<param name="cfBase.12" value="1"/>
<param name="cfBase.13" value="1"/>
<param name="cfBase.14" value="1"/>
<param name="cfBase.15" value="1"/>
<param name="cfBase.16" value="0"/>
<param name="mnVias" value="20"/>
<param name="mnSegments" value="9999"/>
<param name="mnExtdSteps" value="9999"/>
<param name="mnRipupLevel" value="10"/>
<param name="mnRipupSteps" value="100"/>
<param name="mnRipupTotal" value="100"/>
</pass>
<pass name="Follow-me" refer="Default" active="yes">
</pass>
<pass name="Busses" refer="Default" active="yes">
<param name="cfNonPref" value="4"/>
<param name="cfBusImpact" value="4"/>
<param name="cfHugging" value="0"/>
<param name="mnVias" value="0"/>
</pass>
<pass name="Route" refer="Default" active="yes">
</pass>
<pass name="Optimize1" refer="Default" active="yes">
<param name="cfVia" value="99"/>
<param name="cfExtdStep" value="10"/>
<param name="cfHugging" value="1"/>
<param name="mnExtdSteps" value="1"/>
<param name="mnRipupLevel" value="0"/>
</pass>
<pass name="Optimize2" refer="Optimize1" active="yes">
<param name="cfNonPref" value="0"/>
<param name="cfChangeDir" value="6"/>
<param name="cfExtdStep" value="0"/>
<param name="cfBonusStep" value="2"/>
<param name="cfMalusStep" value="2"/>
<param name="cfPadImpact" value="2"/>
<param name="cfSmdImpact" value="2"/>
<param name="cfHugging" value="0"/>
</pass>
<pass name="Optimize3" refer="Optimize2" active="yes">
<param name="cfChangeDir" value="8"/>
<param name="cfPadImpact" value="0"/>
<param name="cfSmdImpact" value="0"/>
</pass>
<pass name="Optimize4" refer="Optimize3" active="yes">
<param name="cfChangeDir" value="25"/>
</pass>
</autorouter>
<elements>
<element name="IC1" library="74xx-eu" package="DIL16" value="74HC595N" x="61.71" y="45.72"/>
<element name="IC2" library="74xx-eu" package="DIL16" value="74HC595N" x="39.37" y="45.72"/>
<element name="IC3" library="uln-udn" package="DIL18" value="UDN2981A" x="35.58" y="37.425" rot="R180"/>
<element name="IC4" library="uln-udn" package="DIL18" value="ULN2803A" x="58.69" y="37.425" rot="R180"/>
</elements>
<signals>
<signal name="GND">
<contactref element="IC2" pad="8"/>
<contactref element="IC3" pad="10"/>
<contactref element="IC4" pad="9"/>
<contactref element="IC2" pad="13"/>
<contactref element="IC1" pad="8"/>
<contactref element="IC1" pad="13"/>
<wire x1="48.26" y1="41.91" x2="46.76" y2="44.315" width="0.8128" layer="16"/>
<wire x1="46.76" y1="44.315" x2="38.1" y2="44.315" width="0.8128" layer="16"/>
<wire x1="38.1" y1="44.315" x2="38.1" y2="49.53" width="0.8128" layer="16"/>
<wire x1="60.44" y1="44.315" x2="60.44" y2="49.53" width="0.8128" layer="16"/>
<wire x1="70.6" y1="41.91" x2="69.85" y2="44.315" width="0.8128" layer="16"/>
<wire x1="69.85" y1="44.315" x2="60.44" y2="44.315" width="0.8128" layer="16"/>
<wire x1="48.26" y1="41.91" x2="49.01" y2="38.6" width="0.8128" layer="16"/>
<wire x1="49.01" y1="38.6" x2="48.53" y2="41.235" width="0.8128" layer="16"/>
<wire x1="25.42" y1="33.615" x2="27.67" y2="36.29" width="0.8128" layer="16"/>
<wire x1="27.67" y1="36.29" x2="49.01" y2="36.29" width="0.8128" layer="16"/>
<wire x1="49.01" y1="36.29" x2="49.01" y2="37.695" width="0.8128" layer="16"/>
<wire x1="49.01" y1="37.695" x2="49.01" y2="38.6" width="0.8128" layer="16"/>
<wire x1="69.85" y1="44.315" x2="70.62" y2="41.815" width="0.8128" layer="16"/>
<wire x1="70.62" y1="41.815" x2="70.62" y2="37.695" width="0.8128" layer="16"/>
<wire x1="70.62" y1="37.695" x2="49.01" y2="37.695" width="0.8128" layer="16"/>
</signal>
<signal name="VCC">
<contactref element="IC2" pad="16"/>
<contactref element="IC1" pad="16"/>
<contactref element="IC1" pad="10"/>
<contactref element="IC2" pad="10"/>
<contactref element="IC3" pad="9"/>
<wire x1="30.48" y1="49.53" x2="32.23" y2="51.685" width="0.8128" layer="16"/>
<wire x1="32.23" y1="51.685" x2="45.72" y2="51.685" width="0.8128" layer="16"/>
<wire x1="45.72" y1="49.53" x2="45.72" y2="51.685" width="0.8128" layer="16"/>
<wire x1="45.72" y1="51.685" x2="52.82" y2="51.685" width="0.8128" layer="16"/>
<wire x1="52.82" y1="51.685" x2="52.82" y2="49.53" width="0.8128" layer="16"/>
<wire x1="68.06" y1="49.53" x2="66.06" y2="51.685" width="0.8128" layer="16"/>
<wire x1="66.06" y1="51.685" x2="52.82" y2="51.685" width="0.8128" layer="16"/>
<wire x1="30.48" y1="49.53" x2="30.48" y2="46.105" width="0.8128" layer="16"/>
<wire x1="30.48" y1="46.105" x2="26.92" y2="44.605" width="0.8128" layer="16"/>
<wire x1="26.92" y1="44.605" x2="25.42" y2="41.235" width="0.8128" layer="16"/>
</signal>
<signal name="N$2">
<contactref element="IC1" pad="11"/>
<contactref element="IC2" pad="11"/>
<wire x1="43.18" y1="49.53" x2="43.18" y2="46.355" width="0.8128" layer="16"/>
<wire x1="43.18" y1="46.355" x2="65.52" y2="46.355" width="0.8128" layer="1"/>
<wire x1="65.52" y1="46.355" x2="65.52" y2="49.53" width="0.8128" layer="16"/>
<via x="43.18" y="46.355" extent="1-16" drill="0.8" shape="square"/>
<via x="65.52" y="46.355" extent="1-16" drill="0.8" shape="square"/>
</signal>
<signal name="N$7">
<contactref element="IC1" pad="7"/>
<contactref element="IC4" pad="1"/>
<wire x1="68.06" y1="41.91" x2="68.85" y2="41.235" width="0.8128" layer="16"/>
</signal>
<signal name="N$8">
<contactref element="IC1" pad="6"/>
<contactref element="IC4" pad="2"/>
<wire x1="65.52" y1="41.91" x2="66.31" y2="41.235" width="0.8128" layer="16"/>
</signal>
<signal name="N$9">
<contactref element="IC1" pad="5"/>
<contactref element="IC4" pad="3"/>
<wire x1="62.98" y1="41.91" x2="63.77" y2="41.235" width="0.8128" layer="16"/>
</signal>
<signal name="N$10">
<contactref element="IC1" pad="4"/>
<contactref element="IC4" pad="4"/>
<wire x1="60.44" y1="41.91" x2="61.23" y2="41.235" width="0.8128" layer="16"/>
</signal>
<signal name="N$11">
<contactref element="IC1" pad="3"/>
<contactref element="IC4" pad="5"/>
<wire x1="57.9" y1="41.91" x2="58.69" y2="41.235" width="0.8128" layer="16"/>
</signal>
<signal name="N$12">
<contactref element="IC1" pad="2"/>
<contactref element="IC4" pad="6"/>
<wire x1="55.36" y1="41.91" x2="56.15" y2="41.235" width="0.8128" layer="16"/>
</signal>
<signal name="N$13">
<contactref element="IC1" pad="1"/>
<contactref element="IC4" pad="7"/>
<wire x1="52.82" y1="41.91" x2="53.61" y2="41.235" width="0.8128" layer="16"/>
</signal>
<signal name="N$14">
<contactref element="IC1" pad="15"/>
<contactref element="IC4" pad="8"/>
<wire x1="51.07" y1="41.235" x2="50.915" y2="41.275" width="0.8128" layer="16"/>
<wire x1="50.915" y1="41.275" x2="50.915" y2="45.085" width="0.8128" layer="16"/>
<wire x1="50.915" y1="45.085" x2="55.36" y2="49.53" width="0.8128" layer="16"/>
</signal>
<signal name="N$15">
<contactref element="IC2" pad="15"/>
<contactref element="IC3" pad="8"/>
<wire x1="33.02" y1="49.53" x2="33.02" y2="45.45" width="0.8128" layer="16"/>
<wire x1="33.02" y1="45.45" x2="28.21" y2="43.45" width="0.8128" layer="16"/>
<wire x1="27.96" y1="41.235" x2="28.21" y2="43.45" width="0.8128" layer="16"/>
</signal>
<signal name="N$16">
<contactref element="IC3" pad="7"/>
<contactref element="IC2" pad="1"/>
<wire x1="30.48" y1="41.91" x2="30.5" y2="41.235" width="0.8128" layer="16"/>
</signal>
<signal name="N$17">
<contactref element="IC2" pad="2"/>
<contactref element="IC3" pad="6"/>
<wire x1="33.02" y1="41.91" x2="33.04" y2="41.235" width="0.8128" layer="16"/>
</signal>
<signal name="N$18">
<contactref element="IC2" pad="3"/>
<contactref element="IC3" pad="5"/>
<wire x1="35.56" y1="41.91" x2="35.58" y2="41.235" width="0.8128" layer="16"/>
</signal>
<signal name="N$19">
<contactref element="IC3" pad="4"/>
<contactref element="IC2" pad="4"/>
<wire x1="38.1" y1="41.91" x2="38.12" y2="41.235" width="0.8128" layer="16"/>
</signal>
<signal name="N$20">
<contactref element="IC2" pad="5"/>
<contactref element="IC3" pad="3"/>
<wire x1="40.64" y1="41.91" x2="40.66" y2="41.235" width="0.8128" layer="16"/>
</signal>
<signal name="N$21">
<contactref element="IC3" pad="2"/>
<contactref element="IC2" pad="6"/>
<wire x1="43.18" y1="41.91" x2="43.2" y2="41.235" width="0.8128" layer="16"/>
</signal>
<signal name="N$22">
<contactref element="IC2" pad="7"/>
<contactref element="IC3" pad="1"/>
<wire x1="45.72" y1="41.91" x2="45.74" y2="41.235" width="0.8128" layer="16"/>
</signal>
<signal name="N$1">
<contactref element="IC2" pad="12"/>
<contactref element="IC1" pad="12"/>
<wire x1="40.64" y1="49.53" x2="40.64" y2="47.625" width="0.8128" layer="16"/>
<wire x1="40.64" y1="47.625" x2="62.98" y2="47.625" width="0.8128" layer="1"/>
<wire x1="62.98" y1="47.625" x2="62.98" y2="49.53" width="0.8128" layer="16"/>
<via x="40.64" y="47.625" extent="1-16" drill="0.8" shape="square"/>
<via x="62.98" y="47.625" extent="1-16" drill="0.8" shape="square"/>
</signal>
<signal name="N$3">
<contactref element="IC2" pad="9"/>
<contactref element="IC1" pad="14"/>
<wire x1="48.26" y1="49.53" x2="48.26" y2="45.085" width="0.8128" layer="16"/>
<wire x1="48.26" y1="45.085" x2="57.9" y2="45.085" width="0.8128" layer="1"/>
<wire x1="57.9" y1="45.085" x2="57.9" y2="49.53" width="0.8128" layer="16"/>
<via x="48.26" y="45.085" extent="1-16" drill="0.8" shape="square"/>
<via x="57.9" y="45.085" extent="1-16" drill="0.8" shape="square"/>
</signal>
<signal name="N$4">
<wire x1="27.4829" y1="48.266815625" x2="26.893153125" y2="48.77845" width="0.1" layer="16"/>
<wire x1="26.893153125" y1="48.77845" x2="27.29539375" y2="49.118253125" width="0.1" layer="16"/>
<wire x1="27.29539375" y1="49.118253125" x2="27.428203125" y2="49.29595625" width="0.1" layer="16"/>
<wire x1="27.428203125" y1="49.29595625" x2="27.47511875" y2="49.4502" width="0.1" layer="16"/>
<wire x1="27.47511875" y1="49.4502" x2="27.4829" y2="49.516603125" width="0.1" layer="16"/>
<wire x1="27.4829" y1="49.516603125" x2="27.4829" y2="50.0282375" width="0.1" layer="16"/>
<wire x1="27.4829" y1="50.0282375" x2="26.483053125" y2="49.172909375" width="0.1" layer="16"/>
<wire x1="26.483053125" y1="49.172909375" x2="25.52619375" y2="50.00481875" width="0.1" layer="16"/>
<wire x1="25.52619375" y1="50.00481875" x2="25.52619375" y2="49.4931875" width="0.1" layer="16"/>
<wire x1="25.52619375" y1="49.4931875" x2="25.535959375" y2="49.42678125" width="0.1" layer="16"/>
<wire x1="25.535959375" y1="49.42678125" x2="25.58866875" y2="49.272496875" width="0.1" layer="16"/>
<wire x1="25.58866875" y1="49.272496875" x2="25.72536875" y2="49.09090625" width="0.1" layer="16"/>
<wire x1="25.72536875" y1="49.09090625" x2="26.088590625" y2="48.774559375" width="0.1" layer="16"/>
<wire x1="26.088590625" y1="48.774559375" x2="25.717590625" y2="48.438684375" width="0.1" layer="16"/>
<wire x1="25.717590625" y1="48.438684375" x2="25.58866875" y2="48.258996875" width="0.1" layer="16"/>
<wire x1="25.58866875" y1="48.258996875" x2="25.535959375" y2="48.104753125" width="0.1" layer="16"/>
<wire x1="25.535959375" y1="48.104753125" x2="25.52619375" y2="48.04029375" width="0.1" layer="16"/>
<wire x1="25.52619375" y1="48.04029375" x2="25.52619375" y2="47.5443" width="0.1" layer="16"/>
<wire x1="25.52619375" y1="47.5443" x2="26.498690625" y2="48.3839875" width="0.1" layer="16"/>
<wire x1="26.498690625" y1="48.3839875" x2="27.4829" y2="47.5443" width="0.1" layer="16"/>
<wire x1="27.4829" y1="47.5443" x2="27.4829" y2="48.266815625" width="0.1" layer="16"/>
</signal>
<signal name="N$5">
<wire x1="25.84840625" y1="46.430084375" x2="25.92479375" y2="46.449446875" width="0.1" layer="16"/>
<wire x1="25.92479375" y1="46.449446875" x2="25.9464" y2="46.48975" width="0.1" layer="16"/>
<wire x1="25.9464" y1="46.48975" x2="25.95138125" y2="46.56505625" width="0.1" layer="16"/>
<wire x1="25.95138125" y1="46.56505625" x2="25.951871875" y2="46.665134375" width="0.1" layer="16"/>
<wire x1="25.951871875" y1="46.665134375" x2="26.064340625" y2="47.27970625" width="0.1" layer="16"/>
<wire x1="26.064340625" y1="47.27970625" x2="26.106265625" y2="47.27754375" width="0.1" layer="16"/>
<wire x1="26.106265625" y1="47.27754375" x2="26.216575" y2="46.46901875" width="0.1" layer="16"/>
<wire x1="26.216575" y1="46.46901875" x2="26.241634375" y2="46.488653125" width="0.1" layer="16"/>
<wire x1="26.241634375" y1="46.488653125" x2="26.240984375" y2="46.5174625" width="0.1" layer="16"/>
<wire x1="26.240984375" y1="46.5174625" x2="26.250834375" y2="46.52845625" width="0.1" layer="16"/>
<wire x1="26.250834375" y1="46.52845625" x2="26.240059375" y2="46.56990625" width="0.1" layer="16"/>
<wire x1="26.240059375" y1="46.56990625" x2="26.206421875" y2="47.132121875" width="0.1" layer="16"/>
<wire x1="26.206421875" y1="47.132121875" x2="26.189225" y2="47.306925" width="0.1" layer="16"/>
<wire x1="26.189225" y1="47.306925" x2="26.123125" y2="47.355321875" width="0.1" layer="16"/>
<wire x1="26.123125" y1="47.355321875" x2="26.037453125" y2="47.342340625" width="0.1" layer="16"/>
<wire x1="26.037453125" y1="47.342340625" x2="26.00299375" y2="47.31599375" width="0.1" layer="16"/>
<wire x1="26.00299375" y1="47.31599375" x2="25.967521875" y2="47.25671875" width="0.1" layer="16"/>
<wire x1="25.967521875" y1="47.25671875" x2="25.941440625" y2="47.2003875" width="0.1" layer="16"/>
<wire x1="25.941440625" y1="47.2003875" x2="25.91761875" y2="47.120128125" width="0.1" layer="16"/>
<wire x1="25.91761875" y1="47.120128125" x2="25.8873375" y2="46.487615625" width="0.1" layer="16"/>
<wire x1="25.8873375" y1="46.487615625" x2="25.657196875" y2="46.483290625" width="0.1" layer="16"/>
<wire x1="25.657196875" y1="46.483290625" x2="25.66780625" y2="47.31436875" width="0.1" layer="16"/>
<wire x1="25.66780625" y1="47.31436875" x2="25.583296875" y2="47.244153125" width="0.1" layer="16"/>
<wire x1="25.583296875" y1="47.244153125" x2="25.587259375" y2="47.167171875" width="0.1" layer="16"/>
<wire x1="25.587259375" y1="47.167171875" x2="25.595909375" y2="46.608896875" width="0.1" layer="16"/>
<wire x1="25.595909375" y1="46.608896875" x2="25.59555" y2="46.528284375" width="0.1" layer="16"/>
<wire x1="25.59555" y1="46.528284375" x2="25.598365625" y2="46.47244375" width="0.1" layer="16"/>
<wire x1="25.598365625" y1="46.47244375" x2="25.632675" y2="46.43430625" width="0.1" layer="16"/>
<wire x1="25.632675" y1="46.43430625" x2="25.71225625" y2="46.412778125" width="0.1" layer="16"/>
<wire x1="25.71225625" y1="46.412778125" x2="25.84840625" y2="46.430084375" width="0.1" layer="16"/>
</signal>
<signal name="N$6">
<wire x1="26.363328125" y1="50.79094375" x2="26.177565625" y2="50.781990625" width="0.1" layer="16"/>
<wire x1="26.177565625" y1="50.781990625" x2="25.99690625" y2="50.7556125" width="0.1" layer="16"/>
<wire x1="25.99690625" y1="50.7556125" x2="25.822203125" y2="50.7127875" width="0.1" layer="16"/>
<wire x1="25.822203125" y1="50.7127875" x2="25.654184375" y2="50.65424375" width="0.1" layer="16"/>
<wire x1="25.654184375" y1="50.65424375" x2="25.4937" y2="50.58095" width="0.1" layer="16"/>
<wire x1="25.4937" y1="50.58095" x2="25.341484375" y2="50.4937625" width="0.1" layer="16"/>
<wire x1="25.341484375" y1="50.4937625" x2="25.19838125" y2="50.39344375" width="0.1" layer="16"/>
<wire x1="25.19838125" y1="50.39344375" x2="25.065125" y2="50.280971875" width="0.1" layer="16"/>
<wire x1="25.065125" y1="50.280971875" x2="25.197896875" y2="50.5077375" width="0.1" layer="16"/>
<wire x1="25.197896875" y1="50.5077375" x2="25.35943125" y2="50.713315625" width="0.1" layer="16"/>
<wire x1="25.35943125" y1="50.713315625" x2="25.5469375" y2="50.89490625" width="0.1" layer="16"/>
<wire x1="25.5469375" y1="50.89490625" x2="25.757740625" y2="51.049759375" width="0.1" layer="16"/>
<wire x1="25.757740625" y1="51.049759375" x2="25.9890875" y2="51.175071875" width="0.1" layer="16"/>
<wire x1="25.9890875" y1="51.175071875" x2="26.23825625" y2="51.268015625" width="0.1" layer="16"/>
<wire x1="26.23825625" y1="51.268015625" x2="26.502540625" y2="51.32583125" width="0.1" layer="16"/>
<wire x1="26.502540625" y1="51.32583125" x2="26.779221875" y2="51.345725" width="0.1" layer="16"/>
<wire x1="26.779221875" y1="51.345725" x2="27.16541875" y2="51.306790625" width="0.1" layer="16"/>
<wire x1="27.16541875" y1="51.306790625" x2="27.525034375" y2="51.19516875" width="0.1" layer="16"/>
<wire x1="27.525034375" y1="51.19516875" x2="27.850375" y2="51.0185625" width="0.1" layer="16"/>
<wire x1="27.850375" y1="51.0185625" x2="28.13390625" y2="50.784621875" width="0.1" layer="16"/>
<wire x1="28.13390625" y1="50.784621875" x2="28.36784375" y2="50.50109375" width="0.1" layer="16"/>
<wire x1="28.36784375" y1="50.50109375" x2="28.544409375" y2="50.175671875" width="0.1" layer="16"/>
<wire x1="28.544409375" y1="50.175671875" x2="28.656071875" y2="49.81605625" width="0.1" layer="16"/>
<wire x1="28.656071875" y1="49.81605625" x2="28.694965625" y2="49.429940625" width="0.1" layer="16"/>
<wire x1="28.694965625" y1="49.429940625" x2="28.683946875" y2="49.224203125" width="0.1" layer="16"/>
<wire x1="28.683946875" y1="49.224203125" x2="28.651778125" y2="49.024865625" width="0.1" layer="16"/>
<wire x1="28.651778125" y1="49.024865625" x2="28.5995125" y2="48.833021875" width="0.1" layer="16"/>
<wire x1="28.5995125" y1="48.833021875" x2="28.528365625" y2="48.649771875" width="0.1" layer="16"/>
<wire x1="28.528365625" y1="48.649771875" x2="28.43939375" y2="48.476203125" width="0.1" layer="16"/>
<wire x1="28.43939375" y1="48.476203125" x2="28.333890625" y2="48.31336875" width="0.1" layer="16"/>
<wire x1="28.333890625" y1="48.31336875" x2="28.212990625" y2="48.162365625" width="0.1" layer="16"/>
<wire x1="28.212990625" y1="48.162365625" x2="28.07775" y2="48.02433125" width="0.1" layer="16"/>
<wire x1="28.07775" y1="48.02433125" x2="28.122965625" y2="48.122053125" width="0.1" layer="16"/>
<wire x1="28.122965625" y1="48.122053125" x2="28.16299375" y2="48.222534375" width="0.1" layer="16"/>
<wire x1="28.16299375" y1="48.222534375" x2="28.197434375" y2="48.3256875" width="0.1" layer="16"/>
<wire x1="28.197434375" y1="48.3256875" x2="28.22611875" y2="48.43126875" width="0.1" layer="16"/>
<wire x1="28.22611875" y1="48.43126875" x2="28.2488875" y2="48.53924375" width="0.1" layer="16"/>
<wire x1="28.2488875" y1="48.53924375" x2="28.26541875" y2="48.649325" width="0.1" layer="16"/>
<wire x1="28.26541875" y1="48.649325" x2="28.275546875" y2="48.761390625" width="0.1" layer="16"/>
<wire x1="28.275546875" y1="48.761390625" x2="28.27895" y2="48.875321875" width="0.1" layer="16"/>
<wire x1="28.27895" y1="48.875321875" x2="28.24005625" y2="49.261396875" width="0.1" layer="16"/>
<wire x1="28.24005625" y1="49.261396875" x2="28.12839375" y2="49.620971875" width="0.1" layer="16"/>
<wire x1="28.12839375" y1="49.620971875" x2="27.951828125" y2="49.946353125" width="0.1" layer="16"/>
<wire x1="27.951828125" y1="49.946353125" x2="27.717890625" y2="50.229840625" width="0.1" layer="16"/>
<wire x1="27.717890625" y1="50.229840625" x2="27.4343625" y2="50.46378125" width="0.1" layer="16"/>
<wire x1="27.4343625" y1="50.46378125" x2="27.10901875" y2="50.6403875" width="0.1" layer="16"/>
<wire x1="27.10901875" y1="50.6403875" x2="26.749403125" y2="50.752009375" width="0.1" layer="16"/>
<wire x1="26.749403125" y1="50.752009375" x2="26.363328125" y2="50.79094375" width="0.1" layer="16"/>
</signal>
</signals>
</board>
</drawing>
</eagle>

1002
eagle/Driver board.sch Normal file

File diff suppressed because it is too large Load Diff

Binary file not shown.

After

Width:  |  Height:  |  Size: 218 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 177 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 176 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 201 KiB

View File

@ -1,125 +0,0 @@
#include "SegmentDisplay.h"
void SegmentDisplay::begin()
{
#if !defined(SDSupportSPI)
pinMode(latchPin, OUTPUT);
pinMode(clockPin, OUTPUT);
pinMode(dataPin, OUTPUT);
digitalWrite(clockPin, LOW);
digitalWrite(dataPin, LOW);
#endif
digitalWrite(latchPin, HIGH);
digitalWrite(latchPin, LOW);
digitalWrite(latchPin, HIGH);
#if defined(SDSupportSPI)
SPI.begin();
//SPI.setClockDivider(SPI_CLOCK_DIV128);
#endif
}
void SegmentDisplay::end()
{
#if defined(SDSupportSPI)
SPI.end();
#endif
}
void SegmentDisplay::writeNumber(int value)
{
unsigned char digitMask = 1;
for (unsigned char digit = digits; digit > 0; digit--)
{
writeDigit((unsigned char)(value % 10), digitMask);
value /= 10;
digitMask <<= 1;
}
}
#define ASCIIZero 48
#define ASCIINine 57
#define ASCIIUppercaseA 65
#define ASCIIUppercaseZ 90
#define ASCIILowercaseA 97
#define ASCIILowercaseZ 122
void SegmentDisplay::writeText(char* value)
{
unsigned char digitMask = 1;
unsigned char digit = digits;
unsigned char charValue;
while (digit > 0 && value != '\0')
{
charValue = *value;
// Lowercase
if (charValue >= ASCIILowercaseA && charValue <= ASCIILowercaseZ)
writeDisplay(SDCharacterSegments[charValue - ASCIILowercaseA], digitMask);
// Uppercase
else if (charValue >= ASCIIUppercaseA && charValue <= ASCIIUppercaseZ)
writeDisplay(SDCharacterSegments[charValue - ASCIIUppercaseA], digitMask);
// Numbers
else if (charValue >= ASCIIZero && charValue <= ASCIINine)
writeDisplay(SDNumberSegments[charValue - ASCIIZero], digitMask);
// Space / unknown
else
writeDisplay(0, digitMask);
digit--;
digitMask <<= 1;
value++;
}
while (digit > 0)
{
writeDisplay(0, digitMask);
digit--;
digitMask <<= 1;
}
}
inline void SegmentDisplay::writeDigit(unsigned char value, unsigned char digitMask)
{
writeDisplay(SDNumberSegments[value], digitMask);
}
#if defined(SDSupportSPI)
inline void SegmentDisplay::writeDisplay(unsigned char characterMask, unsigned char digitMask)
{
SPI.beginTransaction(SPISettings(clockSpeed, MSBFIRST, SPI_MODE0));
SPI.transfer(characterMask);
SPI.transfer(digitMask);
SPI.endTransaction();
}
#else
inline void SegmentDisplay::writeDisplay(unsigned char characterMask, unsigned char digitMask)
{
digitalWrite(latchPin, LOW);
shiftOut(dataPin, clockPin, MSBFIRST, characterMask);
shiftOut(dataPin, clockPin, MSBFIRST, digitMask);
digitalWrite(latchPin, HIGH);
}
#endif

View File

@ -1,71 +0,0 @@
#ifndef SegmentDisplay_h
#define SegmentDisplay_h
#include "Arduino.h"
#include "SPI.h"
#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 as defined in SegmentDisplayChars.h:
* - Last digit
* - Segment A
**/
// Comment to use shiftOut. Set clockPin and dataPin instead.
#define SDSupportSPI
class SegmentDisplay
{
public:
void begin();
void end();
void writeNumber(int value);
void writeText(char* value);
int getDigits() { return digits; }
void setDigits(int value) { digits = value; }
int getLatchPin() { return latchPin; }
void setLatchPin(int value) { latchPin = value; }
#if defined(SDSupportSPI)
long getClockSpeed() { return clockSpeed; }
void setClockSpeed(long value) { clockSpeed = value; }
#endif
#if !defined(SDSupportSPI)
int getClockPin() { return clockPin; }
void setClockPin(int value) { clockPin = value; }
int getDataPin() { return dataPin; }
void setDataPin(int value) { dataPin = value; }
#endif
protected:
void writeDigit(byte value, byte digitMask);
void writeDisplay(byte characterMask, byte digitMask);
private:
int digits = 6;
int latchPin = SS;
#if defined(SDSupportSPI)
long clockSpeed = 20000000;
#endif
#if !defined(SDSupportSPI)
int clockPin = SCK;
int dataPin = MOSI;
#endif
};
#endif

View File

@ -1,312 +0,0 @@
#ifndef SegmentDisplayChars_h
#define SegmentDisplayChars_h
#include "avr/pgmspace.h"
#define SegmentA 1 // Top
#define SegmentB 2 // Top right
#define SegmentC 4 // Bottom right
#define SegmentD 8 // Bottom
#define SegmentE 16 // Bottom left
#define SegmentF 32 // Top left
#define SegmentG 64 // Middle
const byte SDNumberSegments[10] PROGMEM =
{
/**
* _
* | |
* |_|
*
**/
SegmentA | SegmentB | SegmentC | SegmentD | SegmentE | SegmentF,
/**
*
* |
* |
*
**/
SegmentB | SegmentC,
/**
* _
* _|
* |_
*
**/
SegmentA | SegmentB | SegmentD | SegmentE | SegmentG,
/**
* _
* _|
* _|
*
**/
SegmentA | SegmentB | SegmentC | SegmentD | SegmentG,
/**
*
* |_|
* |
*
**/
SegmentB | SegmentC | SegmentF | SegmentG,
/**
* _
* |_
* _|
*
**/
SegmentA | SegmentC | SegmentD | SegmentF | SegmentG,
/**
* _
* |_
* |_|
*
**/
SegmentA | SegmentC | SegmentD | SegmentE | SegmentF | SegmentG,
/**
* _
* |
* |
*
**/
SegmentA | SegmentB | SegmentC,
/**
* _
* |_|
* |_|
*
**/
SegmentA | SegmentB | SegmentC | SegmentD | SegmentE | SegmentF | SegmentG,
/**
* _
* |_|
* _|
*
**/
SegmentA | SegmentB | SegmentC | SegmentD | SegmentF | SegmentG
};
const byte SDCharacterSegments[26] PROGMEM =
{
/**
* _
* |_|
* | |
*
**/
SegmentA | SegmentB | SegmentC | SegmentE | SegmentF | SegmentG,
/**
*
* |_
* |_|
*
**/
SegmentC | SegmentD | SegmentE | SegmentF | SegmentG,
/**
* _
* |
* |_
*
**/
SegmentA | SegmentD | SegmentE | SegmentF,
/**
*
* _|
* |_|
*
**/
SegmentB | SegmentC | SegmentD | SegmentE | SegmentG,
/**
* _
* |_
* |_
*
**/
SegmentA | SegmentD | SegmentE | SegmentF | SegmentG,
/**
* _
* |_
* |
*
**/
SegmentA | SegmentE | SegmentF | SegmentG,
/**
* _
* |_|
* _|
*
**/
SegmentA | SegmentB | SegmentC | SegmentD | SegmentF | SegmentG,
/**
*
* |_|
* | |
*
**/
SegmentB | SegmentC | SegmentD | SegmentF | SegmentG,
/**
*
* |
* |
*
**/
SegmentE | SegmentF,
/**
*
* |
* |_|
*
**/
SegmentB | SegmentC | SegmentD | SegmentE,
/**
*
* |_
* |
*
**/
SegmentE | SegmentF | SegmentG,
/**
*
* |
* |_
*
**/
SegmentD | SegmentE | SegmentF,
/**
* _
*
* | |
*
**/
SegmentA | SegmentC | SegmentE,
/**
*
* _
* | |
*
**/
SegmentC | SegmentE | SegmentG,
/**
* _
* | |
* |_|
*
**/
SegmentA | SegmentB | SegmentC | SegmentD | SegmentE | SegmentF,
/**
* _
* |_|
* |
*
**/
SegmentA | SegmentB | SegmentE | SegmentF | SegmentG,
/**
* _
* |_|
* |
*
**/
SegmentA | SegmentB | SegmentC | SegmentF | SegmentG,
/**
*
* _
* |
*
**/
SegmentE | SegmentG,
/**
* _
* |_
* _|
*
**/
SegmentA | SegmentC | SegmentD | SegmentF | SegmentG,
/**
*
* |_
* |_
*
**/
SegmentD | SegmentE | SegmentF | SegmentG,
/**
*
* | |
* |_|
*
**/
SegmentB | SegmentC | SegmentD | SegmentE | SegmentF,
/**
*
*
* |_|
*
**/
SegmentC | SegmentD | SegmentE,
/**
*
* | |
* _
*
**/
SegmentB | SegmentD | SegmentF,
/**
*
* _|
* |
*
**/
SegmentB | SegmentC | SegmentG,
/**
*
* |_|
* _|
*
**/
SegmentB | SegmentC | SegmentD | SegmentF | SegmentG,
/**
* _
* _|
* |_
*
**/
SegmentA | SegmentB | SegmentD | SegmentE | SegmentG
};
#endif

Binary file not shown.

After

Width:  |  Height:  |  Size: 588 KiB

View File

@ -1,13 +1,44 @@
Top view
D1 A F D2 D3 B
__|__|__|__|__|__|__
| |
| |
| |
| |
| |
|__ __ __ __ __ _____|
| | | | |
E D DP C G
Bottom view
B D3 D2 F A D1
__|__|__|__|__|__|__
| |
| |
| |
| |
| |
|_____ __ __ __ __ __|
| | | | |
G C DP D E
Pin Assignment
1 E (Bottom Left)
2 D (Bottom)
3 Dot
4 C (Bottom Right)
5 G (Middle)
6 B (Top Right)
7 Digit 3 anode (Right)
8 Digit 2 anode (Middle)
9 F (Top Left)
10 A (Top)
11 Digit 1 anode (Left)
1 E Bottom Left
2 D Bottom
3 DP Dot point
4 C Bottom Right
5 G Middle
6 B Top Right
7 D3 Digit 3 anode (Right)
8 D2 Digit 2 anode (Middle)
9 F Top Left
10 A Top
11 D1 Digit 1 anode (Left)

View File

@ -0,0 +1,31 @@
VCC Q0 DS OE STCP SHCP MR Q7S
__|____|____|____|____|____|____|____|__
| |
| |
|\ |
|/ |
| |
|__ ____ ____ ____ ____ ____ ____ ____ __|
| | | | | | | |
Q1 Q2 Q3 Q4 Q5 Q6 Q7 GND
Pin Assignment
1 Q1
2 Q2
3 Q3
4 Q4
5 Q5
6 Q6
7 Q7
8 GND Ground
9 Q7S Serial output
10 MR Memory reset (low = reset)
11 SHCP Clock pulse
12 STCP Latch
13 OE Output enable (low = enabled)
14 DS Serial input
15 Q0
16 VCC

View File

@ -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

View File

@ -0,0 +1,33 @@
C1 C2 C3 C4 C5 C6 C7 C8 COM
__|____|____|____|____|____|____|____|____|__
| |
| |
|\ |
|/ |
| |
|__ ____ ____ ____ ____ ____ ____ ____ ____ __|
| | | | | | | | |
B1 B2 B3 B4 B5 B6 B7 Q8 GND
Pin Assignment
1 B1 Base 1
2 B2 Base 2
3 B3 Base 3
4 B4 Base 4
5 B5 Base 5
6 B6 Base 6
7 B7 Base 7
8 B8 Base 8
9 GND Ground
10 COM Common cathode (for flyback diodes)
11 C8 Collector 8
12 C7 Collector 7
13 C6 Collector 6
14 C5 Collector 5
15 C4 Collector 4
16 C3 Collector 3
17 C2 Collector 2
18 C1 Collector 1

View File

@ -0,0 +1,51 @@
#include "EEPROM.h"
/*
How the EEPROM is used:
First byte: shot counter offset
Second byte: hit counter offset
Each counter is a 32-bit unsigned integer (4 bytes). When it reaches a treshold
which is < 100,000 (the recommended EEPROM cell write limit) a new offset is calculated.
This way we ensure no cell is written over 100,000 times (assuming the EEPROM is
new) and you can click away until you run out of EEPROM.
For initialisation set ShotCounterOffset and HitCounterOffset to
different values. Keep in mind that Offset * 4 must not be greater than
the amount of available EEPROM!
Shot/HitCounterInitial defines the default value to write for
each counters.
*/
#define ShotCounterOffset 0
#define HitCounterOffset 1
#define ShotCounterInitial 0
#define HitCounterInitial 0
#define counterLocation(offset) 2 + (offset * sizeof(uint32_t))
void setup()
{
EEPROM.update(0, ShotCounterOffset);
EEPROM.update(1, HitCounterOffset);
EEPROM.put(counterLocation(ShotCounterOffset), (uint32_t)ShotCounterInitial);
EEPROM.put(counterLocation(HitCounterOffset), (uint32_t)HitCounterInitial);
pinMode(LED_BUILTIN, OUTPUT);
}
void loop()
{
digitalWrite(LED_BUILTIN, HIGH);
delay(1000);
digitalWrite(LED_BUILTIN, LOW);
delay(1000);
}