Change between modes for airsoft gun

Hello!

Im working on a micro controlled mosfet for my airsoft gun, the idea is to have different shooting modes like.. Single, burst and full auto.

My problem is i can't figure out what code i should use to switch between this modes... i have tried if-statements but doesnt work that good..
when im changing to burst mode and presses the trigger button the motor start spins like hell.. but single works just fine :confused:
so if any one could give me and example of working code to change between different modes i would appreciate it very much!

const int TriggerPin = 7; //Trigger switch attached to digital pin 7
const int ButtonPin = 4; // Change Modes     
const int ledPin = 13; //onboard LED on pin 13
const int MotorPin = 3; //Motor drive pin (on MOSFET) connected to PWM pin at pin 3
const int MotorSpeed = 255; //PWM value for motor, max 255
const int SelectorPin = 8;  //Selector Pin
const float CurveThresh = -4;  //negative slope detection threshold
const int IRD = 110;  //In Rush Delay in milliseconds to deal with in-rush motor startup current
const int Debounce = 50;  //Standard Debounce delay
const float SpringSense = 4; //spring compression slope detection threshold


int switchPin = 2;              // switch is connected to pin 2
int led1 = 12;
int led2 = 11;
int led3 = 10;
int val;                        // variable for reading the pin status
int val2;                       // variable for reading the delayed status
int buttonState;                // variable to hold the button state

int PowerCurve[7];  //initialize the power curve array size 8
float CurvePoint;  //CurvePoint will be compared to CurveThresh to determine if the spring is in free-fall
int fireTime = 0;
int TriggerState = 0; // Trigger button state
int ModeState = 0;
int FireMode = 0; //Firing mode of the gearbox.  0 is always safe, 1 is always singleshot
volatile int IMain = 0; // Direct ADC reading from current sensor

int BurstSetting = 3;  //The number of rounds in a burst

void setup()
{
  Serial.begin(115200);  //High output serial for testing
  pinMode(MotorPin, OUTPUT);
  analogWrite(MotorPin, 0);   //make sure the motorpin is off

  pinMode(TriggerPin, INPUT);
  pinMode(ButtonPin, INPUT);
  digitalWrite(2, HIGH);  //Turn on the internal pull-up on digital 2
  
  
  pinMode(switchPin, INPUT);    // Set the switch pin as input
  pinMode(led1, OUTPUT);
  pinMode(led2, OUTPUT);
  pinMode(led3, OUTPUT);
  buttonState = digitalRead(switchPin);   // read the initial state
  
}


void loop(){
  val = digitalRead(switchPin);      
  delay(10);                         
  val2 = digitalRead(switchPin);     
  if (val == val2) {                 
    if (val != buttonState) {          
      if (val == LOW) {                
        if (FireMode == 0) {          
          FireMode = 1;               
        } else {
          if (FireMode == 1) {       
            FireMode = 2;            
          } else {
            if (FireMode == 2) {      
              FireMode = 3;           
            } else {
			  if (FireMode == 3) 
              {  
                FireMode = 0;           
              }
			}
          }
        }
      }
    }
    buttonState = val;                 // save the new state in our variable
  }

  // Now do whatever the FireMode indicates
  if (FireMode == 0) 
  { // all-off
    digitalWrite(led1, LOW);
    digitalWrite(led2, LOW);
    digitalWrite(led3, LOW);
    analogWrite(MotorPin, 0);
  }

  if (FireMode == 1) 
  { // Single
    digitalWrite(led1, HIGH);
      delay(100);
      digitalWrite(led1, LOW);
      delay(100);
      
      TriggerState = digitalRead(TriggerPin);
      if (TriggerState == HIGH)
      {
        SINGLESHOT();
      }
      else
  {
    analogWrite(MotorPin, 0);
  }
      
  }

  if (FireMode == 2) 
  { // Burst
     digitalWrite(led1, HIGH);
     digitalWrite(led2, HIGH);
      delay(100);
      digitalWrite(led1, LOW);
      digitalWrite(led2, LOW);
      delay(100);
      
      TriggerState = digitalRead(TriggerPin);
      if (TriggerState == HIGH)
      {
        BURST(BurstSetting);
      }
      else
  {
    analogWrite(MotorPin, 0);
  }
      
  }
  
  if (FireMode == 3)  
  { // full auto
    digitalWrite(led1, HIGH);
    digitalWrite(led2, HIGH);
    digitalWrite(led3, HIGH);
      delay(100);
      digitalWrite(led1, LOW);
      digitalWrite(led2, LOW);
      digitalWrite(led3, LOW);
      delay(100);
      TriggerState = digitalRead(TriggerPin);
      if (TriggerState == HIGH)
      {
        FULLAUTO();
      }
      else
  {
    analogWrite(MotorPin, 0);
  }
      
  }  

  
}
int PowerCurve[7];  //initialize the power curve array size 8

It's always great when the comments match the code. Unlike here... 8)

  digitalWrite(2, HIGH);  //Turn on the internal pull-up on digital 2

You need to set the pinMode() first. Why are you not using the name you created?

  if (val == val2) {                 
    if (val != buttonState) {

buttonState makes sense. val does not. Why should val and buttonState contain the same values? Now, names like currState and prevState would make more sense.

        if (FireMode == 0) {          
          FireMode = 1;               
        } else {
          if (FireMode == 1) {       
            FireMode = 2;            
          } else {
            if (FireMode == 2) {      
              FireMode = 3;           
            } else {
			  if (FireMode == 3) 
              {  
                FireMode = 0;           
              }

That's an awful lot of code to do this:

FireMode++;
if(FireMode == 3)
  FireMode = 0;
  if (FireMode == 0) 
  { // all-off
  }

  if (FireMode == 1) 
  { // Single
  }

  if (FireMode == 2) 
  { // Burst
  }
  
  if (FireMode == 3)  
  { // full auto
  }

Is there some value of FireMode that will cause more than one block to be executed? If not, and I don't see any, then either if/else if/else is more appropriate, or a switch statement.

Tools + Auto Format will make that code easier to read.

The work these folks are doing may help...

Thanks for replys guys! :slight_smile:

i still got the same problem with burst mode, when i enter mode 2 and press the trigger the motor start runs like crazy and the arduino stops working, cant change anything then.. so its some kind of bug or fail programming by me, note that im not an expert on programming... :frowning:

The whole code is insterted now..

Thanks!

const int TriggerPin = 7; //Trigger switch attached to digital pin 7
const int ButtonPin = 4; // Change Modes     
const int ledPin = 13; //onboard LED on pin 13
const int MotorPin = 3; //Motor drive pin (on MOSFET) connected to PWM pin at pin 3
const int MotorSpeed = 255; //PWM value for motor, max 255
const int SelectorPin = 8;  //Selector Pin
const float CurveThresh = -4;  //negative slope detection threshold
const int IRD = 110;  //In Rush Delay in milliseconds to deal with in-rush motor startup current
const int Debounce = 50;  //Standard Debounce delay
const float SpringSense = 4; //spring compression slope detection threshold


int switchPin = 2;              // switch is connected to pin 2
int led1 = 12;
int led2 = 11;
int led3 = 10;
int currState;                        // variable for reading the pin status
int prevState;                       // variable for reading the delayed status
int buttonState;                // variable to hold the button state

int PowerCurve[7];  //initialize the power curve array size 8
float CurvePoint;  //CurvePoint will be compared to CurveThresh to determine if the spring is in free-fall
int fireTime = 0;
int TriggerState = 0; // Trigger button state
int ModeState = 0;
int FireMode = 0; //Firing mode of the gearbox.  0 is always safe, 1 is always singleshot
volatile int IMain = 0; // Direct ADC reading from current sensor

int BurstSetting = 3;  //The number of rounds in a burst

void setup()
{
  Serial.begin(115200);  //High output serial for testing
  pinMode(MotorPin, OUTPUT);
  analogWrite(MotorPin, 0);   //make sure the motorpin is off

  pinMode(TriggerPin, INPUT);
  pinMode(ButtonPin, INPUT);
  pinMode(switchPin, HIGH);  //Turn on the internal pull-up on digital 2


  pinMode(switchPin, INPUT);    // Set the switch pin as input
  pinMode(led1, OUTPUT);
  pinMode(led2, OUTPUT);
  pinMode(led3, OUTPUT);
  buttonState = digitalRead(switchPin);   // read the initial state

}


void loop(){
  currState = digitalRead(switchPin);      
  delay(10);                         
  prevState = digitalRead(switchPin);     
  if (currState == prevState) {                 
    if (currState != buttonState) {          
      if (currState == LOW) {
        FireMode++;
        if(FireMode == 4)
          FireMode = 0;        


      }
    }
  }


  buttonState = currState;                 // save the new state in our variable


    // Now do whatever the FireMode indicates
  if (FireMode == 0) 
  { // all-off
    digitalWrite(led1, LOW);
    digitalWrite(led2, LOW);
    digitalWrite(led3, LOW);
    analogWrite(MotorPin, 0);
  }

  if (FireMode == 1) 
  { // Single
    digitalWrite(led1, HIGH);
    delay(100);
    digitalWrite(led1, LOW);
    delay(100);

    TriggerState = digitalRead(TriggerPin);
    if (TriggerState == HIGH)
    {
      SINGLESHOT();
    }
    else
    {
      analogWrite(MotorPin, 0);
    }

  }

  if (FireMode == 2) 
  { // Burst
    digitalWrite(led1, HIGH);
    digitalWrite(led2, HIGH);
    delay(100);
    digitalWrite(led1, LOW);
    digitalWrite(led2, LOW);
    delay(100);

    TriggerState = digitalRead(TriggerPin);
    if (TriggerState == HIGH)
    {
      BURST(BurstSetting);
    }
    else
    {
      analogWrite(MotorPin, 0);
    }

  }

  if (FireMode == 3)  
  { // full auto
    digitalWrite(led1, HIGH);
    digitalWrite(led2, HIGH);
    digitalWrite(led3, HIGH);
    delay(100);
    digitalWrite(led1, LOW);
    digitalWrite(led2, LOW);
    digitalWrite(led3, LOW);
    delay(100);
    TriggerState = digitalRead(TriggerPin);
    if (TriggerState == HIGH)
    {
      FULLAUTO();
    }
    else
    {
      analogWrite(MotorPin, 0);
    }

  }  


}




// Single fire                  
void SINGLESHOT()
{
  int PowerCurve[7];  //Initialize the PowerCurve Array
  analogWrite(MotorPin, MotorSpeed);  //turn on Motor at MotorSpeed
  digitalWrite(ledPin,HIGH);  //turn on indicator LED
  delay(IRD);  //Allow the motor to run for IRD milliseconds before examining current
  for (int i = 0; i < 7; i++)  //Get 7 of the 8 PowerCurve readings
  {
    IMain = digitalRead(TriggerPin);
    PowerCurve[i] = IMain;
  }
  do                          //shuffle the array readings down one step and add a new reading at the top of the array stack
  {
    PowerCurve[0] = PowerCurve[1];
    PowerCurve[1] = PowerCurve[2];
    PowerCurve[2] = PowerCurve[3];
    PowerCurve[3] = PowerCurve[4];
    PowerCurve[4] = PowerCurve[5];
    PowerCurve[5] = PowerCurve[6];
    PowerCurve[6] = PowerCurve[7];
    CurvePoint = ((float)(PowerCurve[4]+PowerCurve[5]+PowerCurve[6]+PowerCurve[7])/4)-((float)(PowerCurve[0]+PowerCurve[1]+PowerCurve[2]+PowerCurve[3]+PowerCurve[4])/4);
  }  
  while (CurvePoint > CurveThresh);   //keep running until the CurvePoint is below the Curve Threshold
  analogWrite(MotorPin, 0);  // Turn off Motor after a single shot
  digitalWrite(ledPin, HIGH);
  do
  {
    delay(1);
    TriggerState = digitalRead(TriggerPin);  //trigger latch
  }  
  while (TriggerState == HIGH);   //the program will not continue until the trigger is released
  delay(Debounce);  //this debounce is critical.  The SINGLESHOT function exits here.  If the trigger is still bouncing, it will trigger another shot
}





//Burst
void BURST(int BurstCount)
{
  int PowerCurve[7];  //Initialize the PowerCurve Array
  analogWrite(MotorPin, MotorSpeed);  //turn on Motor at MotorSpeed
  digitalWrite(ledPin,HIGH);  //turn on indicator LED
  delay(IRD);  //Allow the motor to run for IRD milliseconds before examining current
  for (int i = 0; i < 7; i++)  //Get 7 of the 8 PowerCurve readings
  {
    IMain = digitalRead(TriggerPin);
    PowerCurve[i] = IMain;
  }
  for (int j = 0; j < BurstCount; j++)  //run the loop enough times to fire the burst
  {
    do                          //shuffle the array readings down one step and add a new reading at the top of the array stack
    {
      PowerCurve[0] = PowerCurve[1];
      PowerCurve[1] = PowerCurve[2];
      PowerCurve[2] = PowerCurve[3];
      PowerCurve[3] = PowerCurve[4];
      PowerCurve[4] = PowerCurve[5];
      PowerCurve[5] = PowerCurve[6];
      PowerCurve[6] = PowerCurve[7];
      CurvePoint = ((float)(PowerCurve[4]+PowerCurve[5]+PowerCurve[6]+PowerCurve[7])/4)-((float)(PowerCurve[0]+PowerCurve[1]+PowerCurve[2]+PowerCurve[3]+PowerCurve[4])/4);
    }  
    while (CurvePoint > CurveThresh);   //keep running until the CurvePoint is below the Curve Threshold
    delay(60);
  }
  analogWrite(MotorPin, 0);  // Turn off Motor after a single shot
  digitalWrite(ledPin, HIGH);
  do
  {
    delay(1);
    TriggerState = digitalRead(TriggerPin);  //trigger latch
  }  
  while (TriggerState == HIGH);   //the program will not continue until the trigger is released
  delay(Debounce);  //this debounce is critical.  The SINGLESHOT function exits here.  If the trigger is still bouncing, it will trigger another shot
}


void FULLAUTO()
{
  int PowerCurve[7];  //Initialize the PowerCurve Array
  analogWrite(MotorPin, MotorSpeed);  //turn on Motor at MotorSpeed
  digitalWrite(ledPin,HIGH);  //turn on indicator LED
  delay(IRD);  //Allow the motor to run for IRD milliseconds before examining current
  for (int i = 0; i < 7; i++)  //Get 7 of the 8 PowerCurve readings
  {
    IMain = analogRead(TriggerPin);
    PowerCurve[i] = IMain;
  }
  do
  {
    do                          //shuffle the array readings down one step and add a new reading at the top of the array stack
    {
      PowerCurve[0] = PowerCurve[1];
      PowerCurve[1] = PowerCurve[2];
      PowerCurve[2] = PowerCurve[3];
      PowerCurve[3] = PowerCurve[4];
      PowerCurve[4] = PowerCurve[5];
      PowerCurve[5] = PowerCurve[6];
      PowerCurve[6] = PowerCurve[7];
      CurvePoint = ((float)(PowerCurve[4]+PowerCurve[5]+PowerCurve[6]+PowerCurve[7])/4)-((float)(PowerCurve[0]+PowerCurve[1]+PowerCurve[2]+PowerCurve[3]+PowerCurve[4])/4);
    }  
    while (CurvePoint > CurveThresh);   //keep running until the CurvePoint is below the Curve Threshold
    delay(60);
    TriggerState = digitalRead(TriggerPin);
  } 
  while (TriggerState == HIGH);
  analogWrite(MotorPin, 0);  // Turn off Motor after a single shot
  digitalWrite(ledPin, HIGH);
  do
  {
    delay(1);
    TriggerState = digitalRead(TriggerPin);  //trigger latch
  }  
  while (TriggerState == HIGH);   //the program will not continue until the trigger is released
  delay(Debounce);  //this debounce is critical.  The SINGLESHOT function exits here.  If the trigger is still bouncing, it will trigger another shot
}
int PowerCurve[7];  //initialize the power curve array size 8

No, it doesn't.

  pinMode(switchPin, HIGH);  //Turn on the internal pull-up on digital 2

No, it doesn't.

    PowerCurve[6] = PowerCurve[7];

PowerCurve[7] does not exist!

  int PowerCurve[7];  //Initialize the PowerCurve Array

Good thing you don't work for me. I'd kick your ass all over the building for having local variables with the same name (and incorrect size) as global variables.

  do
  {
    delay(1);
    TriggerState = digitalRead(TriggerPin);  //trigger latch
  }  
  while (TriggerState == HIGH);   //the program will not continue until the trigger is released

I'd strongly recommend that you get out of the habit of using do/while loops everywhere. They have there place, but a while loop is a lot more common. There is no reason to have a delay() in the loop. It contributes absolutely nothing. Why do you care that the pin is read 8,000,000 times, instead of 800,000?

//Burst
void BURST(int BurstCount)
{
// snipped
  delay(Debounce);  //this debounce is critical.  The SINGLESHOT function exits here.  If the trigger is still bouncing, it will trigger another shot
}

No, it doesn't.

  int PowerCurve[7];  //Initialize the PowerCurve Array

Good thing you don't work for me. I'd kick your ass all over the building for having local variables with the same name (and incorrect size) as global variables.

Hehe, well as i said.. im new at this, learning by my self and tutorials..
i think ill try to rewrite the whole code since its so much misstakes..

Little progress... removed alloooot of unnecessary code..

const int TriggerPin = 7;     //Trigger switch attached to digital pin 7
const int MotorPin = 3;      //Motor drive pin (on MOSFET) connected to PWM pin at pin 3
const int SelectorPin = 2;  //Selector Pin
const int MotorSpeed = 255;//PWM value for motor, max 255
const int RunTime = 110;  //Motor run time

int currState;            // variable for reading the pin status
int prevState;           // variable for reading the delayed status
int buttonState;        // variable to hold the button state
int FireMode = 0;      //Firing mode of the gearbox.  0 is always safe, 1 is always singleshot
int TriggerState = 0; // Trigger button state

int led1 = 12;       //Led number 1
int led2 = 11;      //Led number 2
int led3 = 10;     //Led number 3

void setup()
{
  pinMode(led1, OUTPUT);
  pinMode(led2, OUTPUT);
  pinMode(led3, OUTPUT);
  pinMode(SelectorPin, INPUT);         // Set the switch pin as input

  Serial.begin(115200);              //High output serial for testing
  pinMode(MotorPin, OUTPUT);        //Mosfet 
  pinMode(TriggerPin, INPUT);      //Trigger
}






void loop(){
  currState = digitalRead(SelectorPin);      
  delay(10);                         
  prevState = digitalRead(SelectorPin);     

  if (currState == prevState) 
  {                 
    if (currState != buttonState) 
    {          
      if (currState == LOW) 
      {
        FireMode++;
        if(FireMode == 4)
          FireMode = 0;
      }
    }
  }

  buttonState = currState;  // save the new state in our variable


    // Different fire modes
  if (FireMode == 0) 
  { // all-off
    digitalWrite(led1, LOW);
    digitalWrite(led2, LOW);
    digitalWrite(led3, LOW);
  }

  if (FireMode == 1) 
  { // Single
    digitalWrite(led1, HIGH);
    digitalWrite(led2, LOW);
    digitalWrite(led3, LOW);

    TriggerState = digitalRead(TriggerPin);
    if (TriggerState == HIGH)
    {
      SINGLESHOT();
    }
    else
    {
      analogWrite(MotorPin, 0);
    }


  }

  if (FireMode == 2) 
  { //Burst
    digitalWrite(led1, HIGH);
    digitalWrite(led2, HIGH);
    digitalWrite(led3, LOW);
  }

  if (FireMode == 3)  
  { //Fullauto
    digitalWrite(led1, HIGH);
    digitalWrite(led2, HIGH);
    digitalWrite(led3, HIGH);
  }  
}



void SINGLESHOT()
{
  analogWrite(MotorPin, MotorSpeed);  //turn on Motor at MotorSpeed
  delay(RunTime);                    //For how long time the motor should run

  analogWrite(MotorPin, 0);        // Turn off Motor after a single shot

  do
  {
    delay(1);
    TriggerState = digitalRead(TriggerPin);  //trigger latch
  }  
  while (TriggerState == HIGH);   //the program will not continue until the trigger is released

}

My code is rewriten and much less then the first code, (Copy paste code)
and this time i accually understand what everything is doing :blush: :fearful:

But the code can be smaller then this i think, and i need to test it out on my airsoft gun to get time "timings" right so the motor over run.
and later on ill program so its just 1 LED blinking 1,2 or 3 times for the different modes..

const int TriggerPin = 7;     //Trigger switch attached to digital pin 7
const int MotorPin = 3;      //Motor drive pin (on MOSFET) connected to PWM pin at pin 3
const int SelectorPin = 2;  //Selector Pin
const int MotorSpeed = 255;//PWM value for motor, max 255
const int RunTime = 70;  //Motor run time

int currState;            // variable for reading the pin status
int prevState;           // variable for reading the delayed status
int buttonState;        // variable to hold the button state
int FireMode = 0;      //Firing mode of the gearbox.  0 is always safe, 1 is always singleshot
int TriggerState = 0; // Trigger button state
int BurstSetting = 3;  //The number of rounds in a burst

int led1 = 12;       //Led number 1
int led2 = 11;      //Led number 2
int led3 = 10;     //Led number 3

void setup()
{
  pinMode(led1, OUTPUT);
  pinMode(led2, OUTPUT);
  pinMode(led3, OUTPUT);
  pinMode(SelectorPin, INPUT);         // Set the switch pin as input

  Serial.begin(115200);              //High output serial for testing
  pinMode(MotorPin, OUTPUT);        //Mosfet 
  pinMode(TriggerPin, INPUT);      //Trigger
}


void loop()
{
  currState = digitalRead(SelectorPin);      
  delay(10);                         
  prevState = digitalRead(SelectorPin);     

  if (currState == prevState) 
  {                 
    if (currState != buttonState) 
    {          
      if (currState == LOW) 
      {
        FireMode++;
        if(FireMode == 4)
          FireMode = 0;
      }
    }
  }

  buttonState = currState;  // save the new state in our variable

    // Different fire modes
  if (FireMode == 0) 
  { // all-off
    digitalWrite(led1, LOW);
    digitalWrite(led2, LOW);
    digitalWrite(led3, LOW);
  }

  if (FireMode == 1) 
  { // Single
    digitalWrite(led1, HIGH);
    digitalWrite(led2, LOW);
    digitalWrite(led3, LOW);

    TriggerState = digitalRead(TriggerPin);
    if (TriggerState == HIGH)
    {
      SINGLESHOT();
    }
    else
    {
      analogWrite(MotorPin, 0);
    }
  }

  if (FireMode == 2) 
  { //Burst
    digitalWrite(led1, HIGH);
    digitalWrite(led2, HIGH);
    digitalWrite(led3, LOW);

    TriggerState = digitalRead(TriggerPin);
    if (TriggerState == HIGH)
    {
      BURST(BurstSetting);
    }
    else
    {
      analogWrite(MotorPin, 0);
    }
  }

  if (FireMode == 3)  
  { //Fullauto
    digitalWrite(led1, HIGH);
    digitalWrite(led2, HIGH);
    digitalWrite(led3, HIGH);

    TriggerState = digitalRead(TriggerPin);
    if (TriggerState == HIGH)
    {
      analogWrite(MotorPin, MotorSpeed);  //turn on Motor at MotorSpeed
    }
    else
    {
      analogWrite(MotorPin, 0);
    }

  }  
}

void SINGLESHOT()
{
  analogWrite(MotorPin, MotorSpeed);  //turn on Motor at MotorSpeed
  delay(RunTime);                    //For how long time the motor should run
  analogWrite(MotorPin, 0);         // Turn off Motor after a single shot

  do
  {
    delay(10); //Time between each trigger push
    TriggerState = digitalRead(TriggerPin);  //trigger latch
  }  
  while (TriggerState == HIGH);   //the program will not continue until the trigger is released

}

void BURST(int BurstCount)
{
  analogWrite(MotorPin, MotorSpeed);  //turn on Motor at MotorSpeed
  delay(RunTime);                    //For how long time the motor should run

  for (int j = 0; j < BurstCount; j++)  //run the loop enough times to fire the burst
  {
    delay(33);
  }
  analogWrite(MotorPin, 0);  // Turn off Motor after a single shot
  do
  {
    delay(10);
    TriggerState = digitalRead(TriggerPin);  //trigger latch
  }  
  while (TriggerState == HIGH);   //the program will not continue until the trigger is released

}
  do
  {
    delay(10); //Time between each trigger push
    TriggerState = digitalRead(TriggerPin);  //trigger latch
  }  
  while (TriggerState == HIGH);   //the program will not continue until the trigger is released

I've pointed out the waste of the delay() in this loop once.

  for (int j = 0; j < BurstCount; j++)  //run the loop enough times to fire the burst
  {
    delay(33);
  }

The comment here is plain wrong. This loop does nothing but waste time.