/*
Copyright 2015 Dustin L. Westaby
----------------------------------------------------------------------
Decrement Counter for Arduino Trinket Pro (also works for other arduinos)
----------------------------------------------------------------------
Author: Dustin Westaby
Date Created: 11/15/09
Last Modified: 12/23/15
Purpose: Counter down program for two digit display. Firing modes
make for an ideal ammo counter.
Compiled with cloud based Clang Compiler on codebender.cc
Revisions List:
11/15/09 Initial program, Display pins configured, Count loops added
11/16/09 Firing modes added, Low Power loops added
11/17/09 SHOT1 & SHOT3 are now combined in BURST mode
12/01/09 Header comments added
12/09/09 Added device select for different Board Revisions
12/10/09 Split project folders, VMUSIC revision is now a seperate project
07/25/13 Re-wrote display subroutines to be more efficient - http://pastebin.com/7wjmQj6H
08/12/13 Converted to Arduino Compiler - http://pastebin.com/nezr1ZxJ
09/01/13 Added FX extended timing code. - http://pastebin.com/0TdL6d6q
12/22/15 Reworked for Trinket Pro - http://pastebin.com/NgGU4qCe
Trinket Pro Pinouts [Arduino]
USB
+------+-vv-+------+
2C D9 |o ~9 | | BAT o| 3.3 - 5 volt battery pack
| | | |
2B D10 |o ~10 ------ GND o| Ground (CC)
| |
2A D11 |o ~11 BUS o|
| |
Fire D12 |o 12 3.3V o|
| |
LED D13 |o 13 8 o| D8 2D
| |
|o Ar ~6 o| D6 2E
| |
2F D14 |o A0 ~5 o| D5 1C
| |
2G D15 |o A1 4 o| D4 1D
| |
1B D16 |o A2 ~3 o| D3 1E
| |
1A D17 |o A3 TX o|
| |
1F D18 |o A4 RX o|
| |
1G D19 |o A5 RST o| Reload
| |
| o o o o o |
+------------------+
Dual Digit Display (7-Segment, common cathode)
1 1 1 1 C C 2 2 2
F G A B C C F A B
+---------------------------+
| o o o o o o o o o |
| 1A 2A |
| ------ ------ |
| | | | | |
|1F| |1B 2F| |2B |
| | 1G | | 2G | |
| ------ ------ |
| | | | | |
|1E| |1C 2E| |2C |
| | 1D | | 2D | |
| ------ . ------ . |
| o o o o o o o o o |
+---------------------------+
1 1 1 D 2 2 2 2 D
E D C P E D G C P
Two Single Digit Displays (7-Segment, common cathode)
1 1 C 1 1 2 2 C 2 2
G F C A B G F C A B
+--------------+ +--------------+
| o o o o o | | o o o o o |
| 1A | | 2A |
| ------ | | ------ |
| | | | | | | |
| 1F| |1B | | 2F| |2B |
| | 1G | | | | 2G | |
| ------ | | ------ |
| | | | | | | |
| 1E| |1C | | 2E| |2C |
| | 1D | | | | 2D | |
| ------ . | | ------ . |
| o o o o o | | o o o o o |
+--------------+ +--------------+
1 1 C 1 D 2 2 C 2 D
E D C C P E D C C P
Pinout Mapping
Arduino Trinket I/O Signal Type Name
-------------------------------------------------
3 ~3 O Display Output Digit 1, Segment E
4 4 O Display Output Digit 1, Segment D
5 ~5 O Display Output Digit 1, Segment C
6 ~6 O Display Output Digit 2, Segment E
8 8 O Display Output Digit 2, Segment D
9 ~9 O Display Output Digit 2, Segment C
10 ~10 O Display Output Digit 2, Segment B
11 ~11 O Display Output Digit 2, Segment A
12 12 I Switch Input Fire Switch
13 13 I LED Output LED
14 A0 O Display Output Digit 2, Segment F
15 A1 O Display Output Digit 2, Segment G
16 A2 O Display Output Digit 1, Segment B
17 A3 O Display Output Digit 1, Segment A
18 A4 O Display Output Digit 1, Segment F
19 A5 O Display Output Digit 1, Segment G
RST RST I Switch Input Reload Switch
----------------------------------------------------------------------
*/
//--------------------------------------
// Includes |
//--------------------------------------
#include <EEPROM.h>
//--------------------------------------
// Globals & Constants |
//--------------------------------------
#define COUNT_DELAY_MS 60 /* Time between shots */
#define FX_DELAY_MS 500 /* Time FX output */
/* Common Ground Display, HIGH is ON */
#define ON (HIGH)
#define OFF (LOW)
#define CONT (0)
#define BURST (1)
#define NUMBER (2)
#define TEXT (3)
#define MODE1 (1)
#define MODE2 (2)
#define MODE3 (3)
#define MODE4 (4)
#define MODE5 (5)
#define MODE_ADDRESS 46
#define MIN_MODE (MODE1)
#define MAX_MODE (MODE5)
volatile int current_mode = MODE1;
//--------------------------------------
// Pinouts |
//--------------------------------------
int Fire_Signal_Pin = 12;
int LED_Bottom_Pin = 13;
//Reload is wired to the CPU Reset pin
//Digit 1
byte pinMap_digit1[7] =
{
17, // 1A
16, // 1B
5, // 1C
4, // 1D
3, // 1E
18, // 1F
19, // 1G
};
//Digit 2
byte pinMap_digit2[7] =
{
11, // 2A
12, // 2B
9, // 2C
8, // 2D
6, // 2E
14, // 2F
15 // 2G
};
//--------------------------------------
// Init Function |
//--------------------------------------
void setup()
{
int segment;
/* Set Pin Directions */
for (segment = 0; segment < 7; segment++)
{
pinMode( pinMap_digit1[segment], OUTPUT);
pinMode( pinMap_digit2[segment], OUTPUT);
}
pinMode(Fire_Signal_Pin, INPUT);
pinMode(LED_Bottom_Pin, OUTPUT);
/* Verify read EEPROM value is within mode range
Check for fire button held down (enter mode selection) */
eeprom_verify();
}
//--------------------------------------
// Main Application |
//--------------------------------------
void loop()
{
/* Variables */
int shotmode = CONT;
int burst_value = 1;
int continuous_bust = OFF;
int counter_value = 32;
/* ====================================
Starting Values
==================================== */
if (current_mode == MODE1)
{
shotmode = CONT;
burst_value = 1;
counter_value = 5;
}
else if (current_mode == MODE2)
{
shotmode = BURST;
burst_value = 3;
counter_value = 36;
}
else if (current_mode == MODE3)
{
shotmode = BURST;
burst_value = 3;
counter_value = 36;
continuous_bust = ON;
}
else if (current_mode == MODE4)
{
shotmode = BURST;
burst_value = 1;
counter_value = 12;
}
else /* MODE5 */
{
shotmode = BURST;
burst_value = 1;
counter_value = 15;
}
/* ====================================
Startup Animation
==================================== */
/* Display Animation */
for( int i = 0; i < counter_value; i++)
{
display_num( NUMBER, i, OFF );
delay(500 / counter_value);
}
display_num( NUMBER, counter_value, ON );
/* ====================================
Program Run
==================================== */
while(counter_value > 0)
{
/* Wait for Button Press */
while (fire_button_is_pressed())
{
display_num( NUMBER, counter_value, ON );
}
/* Decrement hit count */
if (burst_value > 1)
{
for( int i = 1; i <= burst_value; i++)
{
display_num( NUMBER, --counter_value, ON );
delay(COUNT_DELAY_MS);
}
}
else
{
/* Update display and send flash to FX */
counter_value--;
display_num( NUMBER, counter_value, ON );
}
/* Delay before next shot allowed */
if( shotmode == CONT )
{
/* Delay between full auto shots */
delay(COUNT_DELAY_MS);
}
else if (continuous_bust == OFF)
{
/* Wait for Button Release */
while ( !fire_button_is_pressed() )
{
display_num( NUMBER, counter_value, ON );
}
}
} /* end main program */
/* ====================================
Program End
==================================== */
/* One last display update, ensure zeros */
display_num( NUMBER, 0x00, OFF );
delay(2000);
while(1);
}
//--------------------------------------
// EEPROM Subroutine |
//--------------------------------------
void eeprom_verify()
{
/* Variables */
int eeprom_byte_read = EEPROM.read(MODE_ADDRESS);
/* Reset mode in EEPROM if unknown */
if ( !( ( eeprom_byte_read >= MIN_MODE ) && ( eeprom_byte_read <= MAX_MODE ) ) )
{
EEPROM.write ( MODE_ADDRESS, MIN_MODE );
}
/* Read last mode saved */
current_mode = EEPROM.read(MODE_ADDRESS); //mode stays the same unless modified by user input
/* Check for fire button held during reset */
if (!fire_button_is_pressed())
{
/* User wants to change modes */
current_mode++;
if (current_mode > MAX_MODE) //MAX Mode Check
{
/* Wrap back to MODE 1 */
current_mode = MIN_MODE;
}
/* Save mode setting for next reset */
EEPROM.write (MODE_ADDRESS, current_mode);
/* Output to user for new mode ACCEPTED, example:F1 = Fire Mode 1 */
display_num( TEXT, 0xF0 + (current_mode & 0x0F), OFF );
/* Wait for fire button to be released */
while (!fire_button_is_pressed());
}
}
//--------------------------------------
// Button Subroutine |
//--------------------------------------
int fire_button_is_pressed()
{
/* Check if Button was Pressed for at least 1ms (debounce) */
if (digitalRead(Fire_Signal_Pin))
{
delay(1);
if (digitalRead(Fire_Signal_Pin))
{
return true;
}
}
return false;
}
//--------------------------------------
// Math Subroutine |
//--------------------------------------
/* Author: robtillaart */
int dec2bcd(int dec)
{
return (dec / 10) * 16 + (dec % 10);
}
//--------------------------------------
// Display Subroutine |
//--------------------------------------
void display_num(int type, int disp_output, int bottom_led)
{
/* Look Up Table */
byte seg_array[16] =
{
// Segments Hex Number
// GFEDCBA
0b00111111, // 0 126
0b00000110, // 1 6
0b01011011, // 2 91
0b01001111, // 3 79
0b01100110, // 4 102
0b01101101, // 5 109
0b01111101, // 6 125
0b00000111, // 7 7
0b01111111, // 8 127
0b01100111, // 9 103
0b01110111, // A 119
0b01111100, // B 124
0b00111001, // C 57
0b01011110, // D 94
0b01111001, // E 121
0b01110110 // F 113
//0b01000000 // - (This entry is impossible for BCD)
};
/* Variables */
int segment;
int digit1;
int digit2;
/* ====================================
BCD Conversion
==================================== */
/* Decimal Numbers need to be in BCD form */
if( type == NUMBER )
{
disp_output = dec2bcd(disp_output);
}
digit1 = (disp_output >> 4 ) & 0x0F;;
digit2 = disp_output & 0x0F;
/* ====================================
Assemble Ouput Digits
==================================== */
for (int i = 0; i < 7; i = i + 1)
{
digitalWrite( pinMap_digit1[i], (seg_array[digit1] >> i) & 1);
digitalWrite( pinMap_digit2[i], (seg_array[digit2] >> i) & 1);
}
digitalWrite( LED_Bottom_Pin, bottom_led); // Bottom LED output [13]
} /* End Display Num Function */