I'll apologize now because it is both horribly commented and way more than you need for what you want to do.
This project had an LCD display that showed ammo for both stampedes, had configurable burst fire, semi, and fully automatic fire modes, and maintained preferences when powering on and off.
here is the bit that managed the relay and stampede fire cycle switch.
void pullTrigger(int barrel)
{//0 neither, 1 upper, 2 lower
if(barrel == 1)
{
while(digitalRead(UpperSensor) == HIGH)
{//check and see if the firing cycle has taken over
Serial.println("firing interval");
digitalWrite(RelayUpper, LOW);//turn the relay on
delay(FIRING_INTERVAL);//wait a little bit
digitalWrite(RelayUpper, HIGH);//turn the relay off
}
}
else if(barrel == 2)
{
while(digitalRead(LowerSensor) == HIGH)
{//check and see if the firing cycle has taken over
Serial.println("firing interval");
digitalWrite(RelayLower, LOW);//turn the relay on
delay(FIRING_INTERVAL);//wait a little bit
digitalWrite(RelayLower, HIGH);//turn the relay off
}
}
}
Like i said, i had two stampedes, but there you can see how it handled firing via relay.
the full code is below
/*
*/
#include <LiquidCrystal.h>
#include <DFR_Key.h>
#include <stdio.h>
#include <avr/pgmspace.h>
#include <phi_big_font.h>
#include <EEPROM.h>
//storing preferences between power cycles
#define EEPCOUNTUPPER 0
#define EEPCOUNTLOWER 1
#define EEPBARREL 2
#define EEPROUNDS 3
#define EEPMODE 5
#define CAPACITY 18
#define DISPLAYCOUNT 19
char* capacityDisplay[] = {"00", "01", "02", "03", "04", "05", "06", "07", "08", "09", "10", "11", "12", "13", "14", "15", "16", "17", "18", "XX"};
static unsigned char CountUpper;
static unsigned char CountLower;
#define BARRELS 3
static boolean Shooting = true;
static boolean menuBarrel = true;
static int Mode; //0: Both, 3 Empty uppersecond; 4 Lower emptysecond; 5 Both empty; 6 menuRounds; 7 menuBarrel
//0 > 5 > 0
// 1 > 3 > 2 > 4 > 5
// 2 > 4 > 1 > 3 > 5
static char Rounds; //0: semi-auto, 1: Full auto, 2+ bursts
static unsigned char Barrel; //0 both, 1 upper, 2 lower
const static int RelayUpper = 11;
static const int RelayLower = 12;
static const int Trigger = 13;
#define UpperSensor A2
#define LowerSensor A3
#define FIRING_INTERVAL 10
//A1 unused
#define UPPERMAGSENSOR A4
#define LOWERMAGSENSOR A5
#define UPPEROVERRIDE 2
#define LOWEROVERRIDE 3
#define BLINKRATE 500
#define DISPLAYRATE 3000
//Pin assignments for SainSmart LCD Keypad Shield
LiquidCrystal lcd(8, 9, 4, 5, 6, 7);
//---------------------------------------------
DFR_Key keypad;
int localKey = 0;
String keyString = "";
unsigned long time;
unsigned long lastDisplay;
unsigned long lastBlink;
void setup()
{
Serial.begin(9600);
digitalWrite(RelayUpper, HIGH);
digitalWrite(RelayLower, HIGH);
pinMode(RelayUpper,OUTPUT);
pinMode(RelayLower,OUTPUT);
pinMode(Trigger,INPUT_PULLUP);
pinMode(UpperSensor,INPUT_PULLUP);
pinMode(LowerSensor,INPUT_PULLUP);
pinMode(UPPERMAGSENSOR, INPUT_PULLUP);
pinMode(LOWERMAGSENSOR, INPUT_PULLUP);
pinMode(UPPEROVERRIDE, INPUT_PULLUP);
pinMode(LOWEROVERRIDE, INPUT_PULLUP);
init_big_font(&lcd);
lcd.begin(16, 2);
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("SPARKYBFG ONLINE");
lcd.setCursor(0,1);
lcd.print("INITIALIZING NOW");
waitTrig(2000);
lcd.clear();
Mode = 1;
keypad.setRate(2500);
char check = EEPROM.read(0);
if(check == 255)
{//no preferences saved
CountUpper = CAPACITY;
CountLower = CAPACITY;
Rounds = 1;
Barrel = 0;
}
else
{
CountUpper = EEPROM.read(EEPCOUNTUPPER);
CountLower = EEPROM.read(EEPCOUNTLOWER);
Rounds = EEPROM.read(EEPROUNDS);
Barrel = EEPROM.read(EEPBARREL);
}
displayCount();
}
void loop()
{
waitTrig(100);
Serial.print("Barrel: ");
Serial.println( Barrel);
Serial.print("Rounds: ");
Serial.println(Rounds, DEC);
HandleKeys();
//reload detection
if(digitalRead(UPPERMAGSENSOR) == HIGH)
{
Serial.println("Upper Reloaded");
CountUpper = CAPACITY;
}
if(digitalRead(LOWERMAGSENSOR) == HIGH)
{
Serial.println("Lower Reloaded");
CountLower = CAPACITY;
}
// Serial.println(analogRead(UPPEROVERRIDE));
// Serial.println(analogRead(LOWEROVERRIDE));
if(digitalRead(UPPEROVERRIDE) == LOW)
{
Serial.println("Upper Disabled");
Barrel = 1;
CountUpper = 0;
}
if(digitalRead(LOWEROVERRIDE) == LOW)
{
Serial.println("Lower Disabled");
Barrel = 2;
CountLower = 0;
}
//firing control -- Blocking
while(digitalRead(Trigger) == LOW)
{
Serial.println("shooting");
Shooting = true;
switch(Barrel){
case 0://fire both barrels
{
FireBoth(Rounds);
}
break;
case 1://fire upper
{
FireUpper(Rounds);
}
break;
case 2://fire lower
{
FireLower(Rounds);
}
break;
default://not a valid firing mode
{
}
break;
}
}
time = millis();
if(Shooting == false)
{
Serial.println("Not Shooting. Display menu");
if(time > lastDisplay + DISPLAYRATE)
{
selectCount();
lastDisplay = millis();
}
if(lastBlink + BLINKRATE < time)
{
if(((time/BLINKRATE)%2) == 0)
{
blinkMenuCursor();
}
else
{
blankMenuCursor();
}
}
}
else
{
if(time > lastDisplay + DISPLAYRATE)
{
displayCount();
lastDisplay = millis();
}
}
switch(Mode){
break;
case 3:
{
if(CountLower == 0)
{
Mode = 5;
}
else
{
Mode = 2;
Barrel = 2;
}
}
break;
case 4:
{
if(CountUpper == 0)
{
Mode = 5;
}
else
{
Mode = 1;
Barrel = 1;
}
}
break;
case 5:
{
reload();
}
break;
default:
{
}
//don't need to do nothin
}
savePrefs();
}
void FireBoth(int rounds)//0 makes no sense in this mode, but is valid.
{
if(rounds == 0)
{
FireUpper(rounds);
Barrel = 1;
}
else
{
short ready;
while(rounds > 0)
{
ready = readyToFire();
if(ready)
{
pullTrigger(ready);
rounds--;
shotFired(ready);
}
}
}
}
void shotFired(short barrel)
{
if(barrel == 1)
{
CountUpper--;
displayCount();
}
else
{
CountLower--;
displayCount();
}
}
short readyToFire()//checks upper first
{
if(digitalRead(UpperSensor) == HIGH)
{
return 1;
}
else if(digitalRead(LowerSensor) == HIGH)
{
return 2;
}
else
{
return 0;
}
}
void pullTrigger(int barrel)
{//0 neither, 1 upper, 2 lower
if(barrel == 1)
{
while(digitalRead(UpperSensor) == HIGH)
{//check and see if the firing cycle has taken over
Serial.println("firing interval");
digitalWrite(RelayUpper, LOW);//turn the relay on
delay(FIRING_INTERVAL);//wait a little bit
digitalWrite(RelayUpper, HIGH);//turn the relay off
}
}
else if(barrel == 2)
{
while(digitalRead(LowerSensor) == HIGH)
{//check and see if the firing cycle has taken over
Serial.println("firing interval");
digitalWrite(RelayLower, LOW);//turn the relay on
delay(FIRING_INTERVAL);//wait a little bit
digitalWrite(RelayLower, HIGH);//turn the relay off
}
}
}
void FireUpper(int rounds)
{
if(CountUpper != 0)
{
if(rounds == 0)
{
while(digitalRead(UpperSensor) == HIGH)
{//check and see if the firing cycle has taken over
Serial.println("firing interval");
digitalWrite(RelayUpper, LOW);//turn the relay on
delay(FIRING_INTERVAL);//wait a little bit
digitalWrite(RelayUpper, HIGH);//turn the relay off
}
while(digitalRead(UpperSensor) == LOW)
{
//firing in progress
}//and finished
shotFired(Barrel);
if(CountUpper == 0)
{
Mode = 3;
}
while(digitalRead(Trigger) == LOW)
{
//wait because semi-auto means 1 shot per pull
}
}
for(int i = rounds; i> 0; i--)
{
if(CountUpper == 0)
{
FireLower(i);
i = 0;
}
while(digitalRead(UpperSensor) == HIGH){//check and see if the firing cycle has taken over
Serial.println("firing interval");
digitalWrite(RelayUpper, LOW);//turn the relay on
delay(FIRING_INTERVAL);//wait a little bit
digitalWrite(RelayUpper, HIGH);//turn the relay off
}
while(digitalRead(UpperSensor) == LOW)
{
//firing in progress
}//and finished
shotFired(Barrel);
}
}
}
void FireLower(int rounds)
{
if(CountLower != 0)
{
if(rounds == 0)
{
while(digitalRead(LowerSensor) == HIGH)
{//check and see if the firing cycle has taken over
Serial.println("firing interval");
digitalWrite(RelayLower, LOW);//turn the relay on
delay(FIRING_INTERVAL);//wait a little bit
digitalWrite(RelayLower, HIGH);//turn the relay off
}
while(digitalRead(LowerSensor) == LOW)
{
//firing in progress
}//and finished
shotFired(Barrel);
if(CountLower == 0)
{
Mode = 3;
}
while(digitalRead(Trigger) == LOW)
{
//wait because semi-auto means 1 shot per pull
}
}
for(int i = rounds; i> 0; i--)
{
if(CountLower == 0)
{
FireUpper(i);
i = 0;
Mode = 3;
}
else
{
while(digitalRead(LowerSensor) == HIGH){//check and see if the firing cycle has taken over
Serial.println("firing interval");
digitalWrite(RelayLower, LOW);//turn the relay on
delay(FIRING_INTERVAL);//wait a little bit
digitalWrite(RelayLower, HIGH);//turn the relay off
}
while(digitalRead(LowerSensor) == LOW)
{
//firing in progress
}//and finished
shotFired(Barrel);
}
}
}
}
void Select_Button()
{
Serial.println("Select Pressed");
Shooting = !Shooting;
Serial.print("Shooting value : ");
Serial.println(Shooting);
if(Shooting)
{
displayCount();
}
else
{
lastDisplay = 0;
}
}
void Left_Button()
{
Serial.println("leftbutton pressed");
if(Shooting)
{
reload();
}
else if(menuBarrel)
{
Barrel = (Barrel +(BARRELS-1))%BARRELS;
lastDisplay = 0;
}
else
{
if(Rounds == 0)
{
Rounds = 1;
}
else
{
Rounds--;
}
lastDisplay = 0;
}
}
void Right_Button()
{
Serial.println("Right Pressed");
if(Shooting)
{
reload();
}
else if(menuBarrel)
{
Barrel = (Barrel + 1)%BARRELS;
lastDisplay = 0;
}
else
{
Rounds++;
lastDisplay = 0;
}
}
void Up_Button()
{
Serial.println("Up Pressed");
if(Shooting)
{
reload();
}
else
{
menuBarrel = !menuBarrel;
lastDisplay = 0;
lastBlink = 0;
}
}
void Down_Button()
{
Serial.println("Down Pressed");
if(Shooting)
{
reload();
}
else
{
menuBarrel = !menuBarrel;
lastDisplay = 0;
lastBlink = 0;
}
}
void HandleKeys()
{
localKey = keypad.getKey();
if (localKey != -1)//TODO confirm that -1 is correct and not 0
{
//Serial.println(localKey);
//Key Codes (in left-to-right order):
//None - 0
//Select - 1
//Left - 2
//Up - 3
//Down - 4
//Right - 5
switch(localKey){
case 1:
{
Select_Button();
}
break;
case 2:
{
Left_Button();
}
break;
case 3:
{
Up_Button();
}
break;
case 4:
{
Down_Button();
}
break;
case 5:
{
Right_Button();
}
break;
default: //should never happen
break;
}
}
}
void blinkMenuCursor()
{
if(menuBarrel)
{
lcd.setCursor(5,1);
lcd.print("::");
}
else
{
lcd.setCursor(5,0);
lcd.print("::");
}
}
void blankMenuCursor()
{
if(menuBarrel)
{
lcd.setCursor(5,1);
lcd.print(" ");
}
else
{
lcd.setCursor(5,0);
lcd.print(" ");
}
}
void selectCount(){
// ________________
// BURST: SEMI-AUTO
// BURST: FULL-AUTO
// BURST: XX ROUNDS
// ________________
// FIRE : UPPER
// FIRE : LOWER
// FIRE : DOUBLE
lcd.clear();
lcd.setCursor(0, 1);
lcd.print("FIRE ");
switch(Barrel)
{
case 0:
lcd.print(" DOUBLE");
break;
case 1:
lcd.print(" UPPER");
break;
case 2:
lcd.print(" LOWER");
break;
default:
lcd.print(" ERROR");
}
lcd.setCursor(0,0);
lcd.print("BURST ");
switch(Rounds)
{
case 0:
lcd.print("SEMI-AUTO");
break;
case 1:
lcd.print("FULL-AUTO");
break;
default:
lcd.print(Rounds, DEC);
lcd.print(" ROUNDS");
}
}
void displayCount()
{
lcd.clear();
render_big_msg(capacityDisplay[CountLower],0,0);
render_big_msg(capacityDisplay[CountUpper],8,0);
}
void reload()
{
CountUpper = CAPACITY;
CountLower = CAPACITY;
displayCount();
}
void waitTrig( int mseconds)
{
unsigned long endTime = millis() + mseconds;
while(endTime > time)
{
time = millis();
if(digitalRead(Trigger) == LOW)
{
endTime = 0;
}
}
}
void savePrefs()
{
char check;
check = EEPROM.read(EEPCOUNTUPPER);
if(check != CountUpper)
{
EEPROM.write(EEPCOUNTUPPER, CountUpper);
}
check = EEPROM.read(EEPCOUNTLOWER);
if(check != CountLower)
{
EEPROM.write(EEPCOUNTLOWER, CountLower);
}
check = EEPROM.read(EEPBARREL);
if(check != Barrel)
{
EEPROM.write(EEPBARREL, Barrel);
}
check = EEPROM.read(EEPROUNDS);
if(check != Rounds)
{
EEPROM.write(EEPROUNDS, Rounds);
}
}








