#include <EEPROM.h>
#include <SPI.h>
#include <Wire.h>
#include <digitalWriteFast.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#define trip_count_address 0
#define dwell_address 2
#define mode_index_address 4
#define ROF_address 6
#define eye_sensativity_address 8
#define solenoidPin 2
#define triggerPin 9
#define lockPin 5
#define button1Pin 6
#define button2Pin 7
#define button3Pin 8 // 1.5M ohm resistor to anode of collector, 100 ohm resistor to anode of ir led
#define eyePin 0 // 100k ohm resistor to vcc and 10k ohm resistor to gnd needed on board for voltage divider
#define eye_logic_pin 15
#define ledPin 16
boolean screen_state = 0; //screen states used for keeping the menu screens static while cycling through them (note: the eye screen is dynamic and refreshes
byte screen_number = 1; //constantly so that you may make adjustments to the reflective eye setting.
boolean prevtriggerstate = 0; //trigger states
boolean triggerstate = 0;
boolean prevbutton1state = 0; //button1 states
boolean button1state = 0;
boolean prevbutton2state = 0; //button2 states
boolean button2state = 0;
boolean prevbutton3state = 0; //button3 states
boolean button3state = 0;
byte screen_change_delay = 2;
byte high;
byte low;
int trip_count = 0; //counts how many times the marker has cycled since its last activation
byte eye_delay = 5;
boolean safety_boolean = 1;
boolean oil_flag = 1;
boolean grease_flag = 1;
boolean service_flag = 1;
boolean eye_dip_state = 0; //breakbeam is 0, reflective is 1
boolean eye_adjustment = 1;
int reflective_eye_sensativity = 850; //this is the eye sensativity (higher number = more sensative)
boolean tracker = 0;
int currentTime = 0;
boolean lockState = 0;
boolean eyestate = 0; //eyestate is 1 if a paintball is detected by the eye
boolean eyesOnOff = 0; //this is 0 when the eye is disabled, and 1 when it is enabled
byte rof = 15; //the marker's rate of fire (also used as an index for the float array ROF listed below)
byte dwell = 14; //how many miliseconds the solenoid is receiving a high current from the solenoid pin
float voltage = 0.00;
float ROF[31] = {0, 1000, 500, 333.3, 250, 200, 166.6, 142.8, 125, 111.1, 100, 90.9, 83.3, 76.9, 71.4, 66.6, 62.5, 58.8, 55.5, 52.6, 50, 47.6, 45.4, 43.4, 41.6, 40, 38.4, 37, 35.7, 34.4, 34.3};
float fireROF;
int mode_index = 1; //mode_index is used to cycle through the character array fmode below
char fmode[4] = {'A', 'B', 'C', 'D'}; //these characters are used to indicate different firing modes to the user on different manu screens
char display_eye_status[10] = "Eye: ( )"; //the default message printed at the top of screen 6 (the screen changes dynamically when you move your finger or a paintball over the eye sensor)
char message[10] = "WDP ANGEL"; //Line 1: the default message displayed at the top of the home screen
char safety[10] = "SAFE"; //Line 2: the default safety state of the marker (changes by pressing button 1)
char mode[10] = "MODE: "; //Line 3: the word Mode is printed along with a character from the fmode array to indicate firing mode
char eyes[10] = "EYES: OFF"; //Line 4: the eye status is printed on line 4 (changes by pressing button 3)
//Define OLED Pins
#define OLED_MOSI 11 //dev & JDAM3.1 board change to 11, JDAM V1.0 change to 12
#define OLED_CLK 13
#define OLED_DC 10
#define OLED_CS 12 //dev & JDAM3.1 board change to 12, JDAM V1.0 change to 11
#define OLED_RESET 18
//Create the OLED display
Adafruit_SSD1306 display(OLED_MOSI, OLED_CLK, OLED_DC, OLED_RESET, OLED_CS);
void setup()
{
//Setup the pins
Serial.begin(9600);
pinModeFast(ledPin, OUTPUT);
pinModeFast(solenoidPin, OUTPUT);
pinModeFast(triggerPin, INPUT);
pinModeFast(button1Pin,INPUT);
pinModeFast(button2Pin,INPUT);
pinModeFast(button3Pin,INPUT);
pinModeFast(eye_logic_pin,INPUT);
pinModeFast(lockPin, INPUT);
//We need to seed a meaningful values for the trip_count, mode_index, and eye_sensativity into the EEPROM. You should uncomment
//these next few lines and upload the code, then comment them out and upload the code a second time.
/*
EEPROM.write(0,highByte(trip_count));
EEPROM.write(1,lowByte(trip_count));
EEPROM.write(4,highByte(mode_index));
EEPROM.write(5,lowByte(mode_index));
EEPROM.write(8,highByte(reflective_eye_sensativity));
EEPROM.write(9,lowByte(reflective_eye_sensativity));
*/
//load values from EEPROM
high = EEPROM.read(0);
low = EEPROM.read(1);
trip_count = word(high,low);
high = EEPROM.read(4);
low = EEPROM.read(5);
mode_index = word(high,low);
rof = EEPROM.read(ROF_address);
fireROF = ROF[rof]-dwell;
dwell = EEPROM.read(dwell_address);
high = EEPROM.read(8);
low = EEPROM.read(9);
reflective_eye_sensativity = word(high,low);
//Initial Setup of the OLED Screen (function definition at bottom)
setup_screen();
}
void loop()
{
if(((screen_number == 1)&&(eyesOnOff == 1))||(screen_number == 6))
{
get_eye_reading(&eyestate, &eye_dip_state);
} //detect if there is a paintball in the breech (this is done even if the eyes are turned off)
fire(eyestate, eyesOnOff); //determines the fire mode, and eyestate/eyestatus and fires the marker accordingly
button_1_action(); //reads for button 1 input and performs any button 1 actions
button_2_action(); //reads for button 2 input and performs any button 2 actions
button_3_action(); //reads for button 3 input and performs any button 3 actions
lock_dip_action();
}
void button_1_action() //a list of possible button 1 actions
{
button1state = digitalReadFast(button1Pin);
delay(1);
if(button1state != prevbutton1state)
{
if(button1state == 1)
{
if(screen_number == 1) //if on screen 1, and button 1 pressed: change LIVE to SAFE or SAFE to LIVE
{
//if(safety[0] == 'S') // slow comparison, replaced with faster boolean comparison
if(safety_boolean == 1)
{
memset(safety, '\0', sizeof(safety));
strncpy(safety, "LIVE", 10);
safety_boolean = 0;
readyDisplay();
refresh_home_screen();
}
//else if(safety[0] == 'L')
else if(safety_boolean == 0)
{
memset(safety, '\0', sizeof(safety));
strncpy(safety, "SAFE", 10);
safety_boolean = 1;
readyDisplay();
refresh_home_screen();
}
}
else if(screen_number == 3) //if on screen 3 and button 1 pressed: increase the dwell by 1 (upperbound 40)
{
if(lockState == 0)
{
dwell++;
if(dwell == 49)
{
dwell = 5;
}
}
readyDisplay();
refresh_dwell_screen();
}
else if(screen_number == 4) //if on screen 4 and button 1 pressed: decrease mode index (mode cycles from B -> A -> C )
{
if(lockState == 0)
{
mode_index--;
if(mode_index == -1)
{
mode_index = 3;
}
}
readyDisplay();
refresh_mode_screen();
}
else if(screen_number == 5) //if on screen 5 and button 1 pressed: increase rate of fire by 1
{
if(lockState == 0)
{
if(mode_index != 0) //when in Semi mode
{
rof++;
if(rof == 26)
{
rof = 10;
}
}
if(mode_index == 0) //when in Auto mode
{
rof++;
if(rof == 21)
{
rof = 10;
}
}
}
fireROF = ROF[rof]-dwell;
readyDisplay();
refresh_ROF_screen();
}
else if(screen_number == 6) //if on screen 6 and button 1 pressed: increase the eyes sensativity by 1 (upperbound of 1025, lowerbound of 1018)
{
if(eye_dip_state == 1)
{
if(eye_adjustment == 1)
{
reflective_eye_sensativity=reflective_eye_sensativity + 10;
if(reflective_eye_sensativity > 950 )
{
reflective_eye_sensativity = 600;
}
}
else if(eye_adjustment == 0)
{
eye_delay = eye_delay + 1;
if(eye_delay > 15 )
{
eye_delay = 5;
}
}
}
else if(eye_dip_state == 0)
{
eye_delay = eye_delay + 1;
if(eye_delay > 15 )
{
eye_delay = 5;
}
}
}
}
}
prevbutton1state = button1state;
}
void button_2_action() //button 2's primary function is to cycle the screens
{
button2state = digitalReadFast(button2Pin);
delay(1);
//if((button2state != prevbutton2state) && (safety[0] == 'S')) //button 2 can only cycle screens while in safe mode
if((button2state != prevbutton2state) && (safety_boolean == 1)) //button 2 can only cycle screens while in safe mode
{
if(button2state == 1)
{
screen_state = 1; //screen_state must be set to 1 here. the whole menu system breaks if this is changes. (controls static and dynamic screens)
screen_number = (screen_number + 1)%8; //we want the integers modulo 7, but we do not want 0 (personally I didnt want to reference the home screen as screen 0)
if(screen_number == 0)
{
screen_number = 1;
}
}
}
prevbutton2state = button2state;
if(screen_state == 1)
{
readyDisplay();
if(screen_number == 1)
{
//if screen_number is 1 then display screen 1
refresh_home_screen();
//Write any setting changes to EEPROM
EEPROM.write(8,highByte(reflective_eye_sensativity));
EEPROM.write(9,lowByte(reflective_eye_sensativity));
}
else if(screen_number == 2)
{
//if screen_number is 2 then display screen 2
refresh_trip_screen();
}
else if(screen_number == 3)
{
//if screen_number is 3 then display screen 3
refresh_dwell_screen();
//Write any setting changes to EEPROM
EEPROM.write(0,highByte(trip_count));
EEPROM.write(1,lowByte(trip_count));
}
else if(screen_number == 4)
{
//if screen_number is 4 then display screen 4
refresh_mode_screen();
//Write any setting changes to EEPROM
EEPROM.write(dwell_address, dwell);
}
else if(screen_number == 5)
{
//if screen_number is 5 then display screen 5
if(mode_index == 2)
{
rof = 13;
fireROF = ROF[rof]-dwell;
}
refresh_ROF_screen();
//Write any setting changes to EEPROM
if((mode_index == 0)&&(rof > 20))
{
rof = 20;
fireROF = ROF[rof]-dwell;
}
EEPROM.write(4,highByte(mode_index));
EEPROM.write(5,lowByte(mode_index));
}
else if(screen_number == 6)
{
//if screen_number is 6 then display screen 6
refresh_eye_screen();
//Write any setting changes to EEPROM
EEPROM.write(ROF_address, rof);
get_battery_status();
}
else if(screen_number == 7)
{
//if screen_number is 7 then display screen 7
refresh_battery_screen();
}
//once the screen has been displayed reset the screen_state to 0
screen_state = 0;
}
}
void button_3_action() //a listing of button 3 actions
{
button3state = digitalReadFast(button3Pin);
delay(1);
if(button3state != prevbutton3state)
{
if(button3state == 1)
{
if (screen_number == 1) //if on screen 1 and button 3 pressed: change EYES: OFF to EYES: ON or EYES: ON to EYES: OFF
{
if(eyesOnOff == 0)
{
eyesOnOff = 1;
memset(eyes, '\0', sizeof(eyes));
strncpy(eyes, "EYES: ON", 10);
readyDisplay();
refresh_home_screen();
}
else if(eyesOnOff == 1)
{
eyesOnOff = 0;
memset(eyes, '\0', sizeof(eyes));
strncpy(eyes, "EYES: OFF", 10);
readyDisplay();
refresh_home_screen();
}
}
else if(screen_number == 2) //if on screen 2 and button 3 pressed: reset the trip count
{
oil_flag = 1;
grease_flag = 1;
service_flag = 1;
trip_count = 0;
readyDisplay();
refresh_trip_screen();
}
else if(screen_number == 3) //if on screen 3 and button 3 pressed: decrease the dwell by 1 (lowerbound of 1)
{
if(lockState == 0)
{
dwell--;
if(dwell == 4)
{
dwell = 48;
}
}
readyDisplay();
refresh_dwell_screen();
}
else if(screen_number == 4) //if on screen 4 and button 3 pressed: increase the mode index (mode cycles: A -> B -> C)
{
if(lockState == 0)
{
mode_index++;
if(mode_index == 4)
{
mode_index = 0;
}
}
readyDisplay();
refresh_mode_screen();
}
else if(screen_number == 5) //if on screen 5 and button 3 pressed: decrease rate of fire by 1 (upperbound of 25, lowerbour of 1)
{
if(lockState == 0)
{
if(mode_index != 0) //when in Semi mode
{
rof--;
if(rof == 9)
{
rof = 25;
}
}
if(mode_index == 0) //when in Auto mode
{
rof--;
if(rof == 9)
{
rof = 20;
}
}
}
fireROF = ROF[rof]-dwell;
readyDisplay();
refresh_ROF_screen();
}
else if(screen_number == 6) //if on screen 6 and button 3 pressed: decrease eye sensativity by 1 (higher number = more sensative)
{
if(eye_dip_state == 1)
{
if(eye_adjustment == 1)
{
reflective_eye_sensativity=reflective_eye_sensativity - 10;
if(reflective_eye_sensativity < 600 )
{
reflective_eye_sensativity = 950;
}
}
else if(eye_adjustment == 0)
{
eye_delay = eye_delay - 1;
if(eye_delay < 5 )
{
eye_delay = 15;
}
}
}
else if(eye_dip_state == 0)
{
eye_delay = eye_delay - 1;
if(eye_delay < 5 )
{
eye_delay = 15;
}
}
}
}
}
prevbutton3state = button3state;
}
void get_battery_status()
{
float v = 0.00;
float r1 = 100000;
for(int k = 0; k < 5; k++)
{
delay(1);
v = v + ((analogRead(A3) * 5.0) / 1024.0);
}
v = v/5.0;
voltage = v / (10000 / (r1 + 10000));
}
void refresh_home_screen()
{
if((trip_count >= 8000)&&(trip_count < 10100)&&(oil_flag == 1))
{
display.println(F("Oil Gun"));
oil_flag = 0;
}
else if((trip_count >= 19000)&&(trip_count < 21100)&&(grease_flag == 1))
{
display.print(F("Grease Gun"));
grease_flag = 0;
}
else if((trip_count >= 29000)&&(trip_count < 31100)&&(service_flag == 1))
{
display.println(message);
display.println(F("Full"));
display.println(F("Service"));
display.println(F("Required"));
service_flag = 0;
}
else
{
display.println(message);
}
display.println(safety);
display.print(mode);
if(mode_index == 2)
{
display.println(F("PSP"));
}
else if(mode_index == 3)
{
display.println(F("3SH"));
}
else
{
display.println(fmode[mode_index]);
}
display.println(eyes);
display.display();
delay(screen_change_delay);
}
void refresh_trip_screen()
{
display.println(F("Trip: "));
display.println(F(" "));
if(trip_count <= 999)
{
display.print(trip_count);
display.println(F(" cycles"));
}
else if(trip_count > 999)
{
display.println(trip_count);
display.println(F("cycles"));
}
display.display();
delay(screen_change_delay);
}
void refresh_dwell_screen()
{
display.println(F("Dwell:"));
if(lockState == 1)
{
display.println(F("(locked)"));
}
else
{
display.println(F(" "));
}
display.print(dwell);
display.println(F(" ms"));
display.display();
delay(screen_change_delay);
}
void refresh_mode_screen()
{
display.println(F("Mode:"));
if(lockState == 1)
{
display.println(F("(locked)"));
}
else
{
display.println(F(" "));
}
if(mode_index == 2)
{
display.println(F("PSP 13.33"));
display.println();
}
if(mode_index == 3)
{
display.println(F("PSP 3-SHOT"));
}
else
{
display.println(fmode[mode_index]);
}
display.display();
delay(screen_change_delay);
}
void refresh_ROF_screen()
{
display.println(F("ROF:"));
if(lockState == 1)
{
display.println(F("(locked)"));
}
else
{
display.println(F(" "));
}
if(rof == 25)
{
display.println(F("unlimited"));
}
else if(mode_index == 2)
{
rof = 13;
fireROF = 75.02-dwell;
display.println(F("PSP"));
display.println(F("13.33 bps"));
}
else
{
display.print(rof);
display.println(F(" bps"));
}
display.display();
delay(screen_change_delay);
}
void refresh_battery_screen()
{
if(mode_index == 2){fireROF = 75.02-dwell;}
float battery_percentage = (25.0 * voltage) - 125.0;
if(battery_percentage < 0.0)
{
battery_percentage = 0.0;
}
display.println(F("Battery:"));
display.println(F(" "));
display.print(voltage);
if(battery_percentage >= 100.0)
{
display.println(F("V "));
display.print((int)battery_percentage);
display.println("%");
}
else
{
display.print(F("V "));
display.print((int)battery_percentage);
display.println("%");
}
display.display();
delay(screen_change_delay);
}
void refresh_eye_screen()
{
if(eye_dip_state == 1)
{
if(eye_adjustment == 1)
{
float percentage = floor(((float)(reflective_eye_sensativity)/1024.0)*100.0);
display.println(display_eye_status);
display.println(F("Reflective"));
display.print(percentage);
display.println(F(" %"));
}
else if(eye_adjustment == 0)
{
display.println(display_eye_status);
display.println(F("Reflective"));
display.print(eye_delay);
display.println(F(" ms"));
}
}
else if(eye_dip_state == 0)
{
display.println(display_eye_status);
display.println(F("Breakbeam"));
display.println(F(" "));
display.print(eye_delay);
display.println(F(" ms"));
}
display.display();
delay(screen_change_delay);
}
void setup_screen()
{
delay(200);
display.begin(SSD1306_SWITCHCAPVCC);
display.display();
display.dim(true);
delay(2500);
readyDisplay();
refresh_home_screen();
}
void readyDisplay()
{
display.clearDisplay();
display.setTextSize(2);
display.setTextColor(WHITE);
display.setCursor(0,0);
}
void fire(boolean eyestate, boolean eyesOnOff)
{
if(screen_number == 6)
{
triggerstate = digitalReadFast(triggerPin);
if(triggerstate == 1)
{
eye_adjustment = !eye_adjustment; //eye_adjustment = 1 adjusts reflective percentage
delay(500);
}
}
if((mode_index == 3)&&(safety_boolean == 0))
{
triggerstate = digitalReadFast(triggerPin);
if(eyesOnOff == 0) //code for fireing without eyes
{
if((triggerstate != prevtriggerstate) && (triggerstate == 1))
{
int previousTime = currentTime;
currentTime = millis();
if(currentTime - previousTime < 1000){tracker = 1;}
else{tracker = 0;}
if(tracker == 0){fireOnce();}
else if(tracker == 1){fire3Times();}
}
}
else if(eyesOnOff == 1) //code for firing with eyes///////////////////////////////////////////////////////////////////FIX RUNAWAY BURST//////////////////////////////////////////
{
if((triggerstate != prevtriggerstate) && (triggerstate == 1))
{
int previousTime = currentTime;
currentTime = millis();
if(currentTime - previousTime < 1000){tracker = 1;}
else{tracker = 0;}
if(tracker == 0){with_eyes(eyestate);}
else if(tracker == 1){for(int j = 0; j < 3; j++){with_eyes(eyestate);}}
}
}
prevtriggerstate = triggerstate;
}
if((mode_index == 1)||(mode_index == 2)) //semi and PSP 13.33
{
if((screen_number == 1) && (safety_boolean == 0))
{
triggerstate = digitalReadFast(triggerPin);
if(eyesOnOff == 0)
{
without_eyes();
}
else if(eyesOnOff == 1)
{
with_eyes(eyestate);
}
prevtriggerstate = triggerstate;
}
}
else if(mode_index == 0) //fully automatic
{
if((screen_number == 1) && (safety_boolean == 0))
{
do
{
triggerstate = digitalReadFast(triggerPin);
if((eyesOnOff == 0) && (triggerstate == 1))
{
digitalWriteFast(solenoidPin, 1);
delay(dwell);
digitalWriteFast(solenoidPin, 0);
delay(fireROF);
trip_count = trip_count + 1;
}
else if((eyesOnOff == 1) && (triggerstate == 1))
{
get_eye_reading(&eyestate, &eye_dip_state);
if(eyestate == 1)
{
digitalWriteFast(solenoidPin, 1);
delay(dwell);
digitalWriteFast(solenoidPin, 0);
delay(fireROF);
trip_count = trip_count + 1;
}
else if(eyestate == 0)
{
digitalWriteFast(solenoidPin, 1);
delay(dwell);
digitalWriteFast(solenoidPin, 0);
delay(100-dwell);
trip_count = trip_count + 1;
}
}
}while(triggerstate == 1);
}
}
}
void without_eyes()
{
if((triggerstate != prevtriggerstate) && (triggerstate == 1))
{
digitalWriteFast(solenoidPin, 1);
delay(dwell);
digitalWriteFast(solenoidPin, 0);
delay(fireROF);
trip_count = trip_count + 1;
}
}
void with_eyes(boolean eyestate)
{
if((eyestate == 1) && (triggerstate != prevtriggerstate) && (triggerstate == 1))
{
digitalWriteFast(solenoidPin, 1);
delay(dwell);
digitalWriteFast(solenoidPin, 0);
delay(fireROF);
trip_count = trip_count + 1;
}
else if((eyestate == 0) && (triggerstate != prevtriggerstate) && (triggerstate == 1))
{
trip_count = trip_count + 1;
digitalWriteFast(solenoidPin, 1);
delay(dwell);
digitalWriteFast(solenoidPin, 0);
delay(100-dwell); //10bps
}
}
void lock_dip_action()
{
lockState = digitalReadFast(5);
if(screen_number == 3)
{
readyDisplay();
refresh_dwell_screen();
delay(100);
}
else if(screen_number == 4)
{
readyDisplay();
refresh_mode_screen();
delay(100);
}
else if(screen_number == 5)
{
readyDisplay();
refresh_ROF_screen();
delay(100);
}
}
void get_eye_reading(boolean *eyestate, boolean *eye_dip_state)
{
int QRE_Value = analogRead(A0);
//Serial.println(QRE_Value); //debugging eyes
delay(eye_delay);
*eye_dip_state = digitalReadFast(eye_logic_pin);
if(*eye_dip_state == 1)
{
if(QRE_Value <= reflective_eye_sensativity)
{
digitalWriteFast(ledPin, 1);
*eyestate = 1;
if(screen_number == 6)
{
memset(display_eye_status, '\0', sizeof(display_eye_status));
strncpy(display_eye_status, "Eye: (*)", 10);
readyDisplay();
refresh_eye_screen();
}
}
else if(QRE_Value > reflective_eye_sensativity)
{
digitalWriteFast(ledPin, 0);
*eyestate = 0;
if(screen_number == 6)
{
memset(display_eye_status, '\0', sizeof(display_eye_status));
strncpy(display_eye_status, "Eye: ( )", 10);
readyDisplay();
refresh_eye_screen();
}
}
}
else if(*eye_dip_state == 0)
{
if(QRE_Value >= 850)
{
digitalWriteFast(ledPin, 1);
*eyestate = 1;
if(screen_number == 6)
{
//Serial.println("(*)");
memset(display_eye_status, '\0', sizeof(display_eye_status));
strncpy(display_eye_status, "Eye: (*)", 10);
readyDisplay();
refresh_eye_screen();
}
}
else if(QRE_Value < 850)
{
digitalWriteFast(ledPin, 0);
*eyestate = 0;
if(screen_number == 6)
{
//Serial.println("( )");
memset(display_eye_status, '\0', sizeof(display_eye_status));
strncpy(display_eye_status, "Eye: ( )", 10);
readyDisplay();
refresh_eye_screen();
}
}
}
}
void fireOnce()
{
digitalWriteFast(solenoidPin, 1);
delay(dwell);
digitalWriteFast(solenoidPin, 0);
delay(fireROF);
trip_count = trip_count + 1;
}
void fire3Times()
{
for(int i = 0; i < 3; i++)
{
digitalWriteFast(solenoidPin, 1);
delay(dwell);
digitalWriteFast(solenoidPin, 0);
delay(fireROF);
trip_count = trip_count + 1;
}
}
Comments
Post a Comment