Skip to main content


The Sketch: Below is the finalized sketch which runs on all production JDAM boards which were manufactured during 2015. Please use and edit the sketch freely. 

#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

Popular posts from this blog

Original Design: The WDP Angel LCD was, in it's time, one of the most advanced paintball markers on the market. WDP was the primary manufacturer and designers like Ken Rice were probably responsible for many of the design features that I sought to mimic. The Angel was highly popular among professional paintball athletes in the NPPL and PSP as well as weekend warriors, like myself. The above animation is quite old and has been kicking around the web for over a decade, but it does show all the parts in the Angel LCD working in symphony. The trigger is pulled by the user, a signal is sent to a PIC microcontroller, located in the handle/frame, which interprets the input and sends an output signal with the correct voltage and amperage to the SMC solenoid housed in the body of the marker (blue component, upper left of the picture). The solenoid controls the flow of regulated air to the markers pneumatic air ram. The ram moves a spun brass hammer back and forth; when in the forward mo...
PCB Layout software: Originally I began designing parts in Cadsoft Eagle, but a friend of mine who was working on a project for the FAU marine robotics club demonstrated a much easier way of creating part footprints in a program called Copper Connection. It took some getting used to, but once I learned the interface I uninstalled Eagle alltogether. Copper Connection allows for multiple layers and exports designs in the same way Eagle does. Link to Copper Connection Site:  https://www.expresspcb.com/CopperConnection/ Essentially what you are looking at is an Arduino Pro-Mini. The JDAM features an ATMEL ATMEGA328p-au running at 16Mhz and powered by 5 Volts. The main board has the following features: 3 hardware debounced push buttons for accessing the menu and making adjustments 1 hardware debounced OMRON D2F lever switch to act as a trigger input (also used for menu input) 1 2-position dip switch which controls the tournament settings lock, and the eye logic mode. 1 FTDI p...
When I was in college, I was always interested in the relationship between the software I had written and the hardware provided to me in various electronics labs. At FAU our focus was primarily on learning how to program the TI MSP430 family of microprocessors. I remember spending weeks learning the instruction set for the MSP430 so that I would be able to pass my assembly language exams. We covered the normal ABET required algorithms, which were interesting, but I really wanted my microprocessor to do something useful. One night I was finishing an assignment in the FAU electronics lab and one of the TA's for my class handed me an Arduino Micro and explained to me that the language was very similar to C/C++ and that I should be able to pick it up very easily. He was right. At the time I was working on a replica Enigma cipher machine and I needed a way to spin the rotors so that my plain text could be encrypted to cipher text. I remember staying up really late that night learni...