Aliens pulse rifle assistance

Working on aliens pulse rifle for the wife for halloween, and need some assistance.
i have 3 buttons:
rifle trigger
grenade launcher trigger
reload

right now only rifle trigger and reload are displayed in the code, as I am unsure how to implement the grenade button to do what i want it to do.

lets assume the pulse rifle is turned on, and the rifle and grenade launcher have full ammo.

rifle ammo starts at 95
grenade starts at 4
push rifle button - rifle round count displays (95) - we are now in rifle mode
next push fires rifle. (lets say trigger is released at a count of 90 displayed on 7 segment)
push grenade button. - grenade round count displays (4) - we are now in grenade launcher mode
push grenade button - grenade round count drops to 3
push rifle button - displays last value (90) - back to rifle mode
push and hold rifle button - count drops again, and is remembered.
push grenade button once again - grenade value shows - you guessed it, back to grenade launcher mode.

so on and so forth, until a reload button reloads either the rifle or grenade launcher (while theyre in their respective modes):
in rifle mode, reload button reloads the rifle ONLY (ammo count 5).
when in grenade launcher mode, it reloads the grenade launcher ONLY (ammo count 4).

so far i have everything setup for the rifle and reload button only. I have yet to implement the grenade button, because i am unsure how to go about doing this. Basically, i dont know what i dont know and not sure where to begin.

#include "SevSeg.h"
SevSeg sevseg; 
unsigned int ammo = 0; //full mag
unsigned long previousMillis = 0;
long interval = 60;
int triggerState = 0; //current state of trigger.  will be assigned to digital read starting at 0 for off
int reloadState = 0;
unsigned int lastReloadState = 95;


#define triggerPin 5
#define reloadPin 4

void setup(){
    byte numDigits = 2;
    byte digitPins[] = {3,2};
    byte segmentPins[] = {6, 7, 8, 9, 10, 11, 12};
    bool resistorsOnSegments = true;
    byte hardwareConfig = COMMON_CATHODE; 
    sevseg.begin(hardwareConfig, numDigits, digitPins, segmentPins, resistorsOnSegments);
    sevseg.setBrightness(90);
    pinMode(triggerPin, INPUT_PULLUP);
    pinMode(reloadPin, INPUT_PULLUP);
    int triggerState = digitalRead(triggerPin);
    sevseg.refreshDisplay();
    sevseg.setNumber(00,2);
   
    
 
}

void loop()
{
  
   int triggerState = digitalRead(triggerPin);
   int reloadState = digitalRead(reloadPin);
   


       if (reloadState == LOW && triggerState == HIGH  && ammo>=0)
     {
       ammo = lastReloadState;
       sevseg.setNumber(ammo,1);
       
     }

      if (triggerState == LOW  && reloadState == HIGH  &&  ammo<=95)
   
   {
     unsigned long currentMillis = millis();
     if (currentMillis - previousMillis >= interval)
     {
       previousMillis = currentMillis;
       sevseg.setNumber(ammo,1);
       ammo--;
     
     

     }
     
   }
     
     sevseg.refreshDisplay();
   }

Did you test your code?
Does it work as expected? If not, what is the problem?
Why are you not able to add the rest of your functionality? What is witholding you from trying? It seems you are on the right track...

I would structure this:

       if (reloadState == LOW && triggerState == HIGH  && ammo>=0)
     {
       ammo = lastReloadState;
       sevseg.setNumber(ammo,1);
       
     }

      if (triggerState == LOW  && reloadState == HIGH  &&  ammo<=95) {
                   blabla;
      }

like this:

       if (reloadState == LOW && triggerState == HIGH) {
             if  (ammo>=0) {      
                   ammo = lastReloadState;
                   sevseg.setNumber(ammo,1);
             }
             if  (ammo<=95) {
                   blabla;
             }
       }

But that is a matter of taste...

The code I posted works, but it doesnt have grenades yet.

Also, grenades are single shot whereas rifle is full auto.
Id like one trigger pull of grenade = 1 round fired, unlike the rifle. This also means one blink from the LEDs - not sure how to interrupt a button push......if i were to accidentally hold the grenade trigger down, it would go full auto grenades (which is rad, but not for this application. Who doesnt love some MK19 action).

I am just not sure how to structure that portion of the code. and havent stumbled across a good example or reference point yet.

Can your gun be in 2 states at the same time?
If not: have one status variable (instead of 2).
Add the third status.
Use a switch case statement to run code depending on state.

It may also be helpful to make a block diagram with all your states and how you can go from one state to another state.

No. Only one state at a time. It cannot fire both grenade launcher and rifle at the same time.

I am not the best with switch statements, so Im not sure what it would look like.

Study...
Geeks to geeks has good tutorials.

If not: write an endless series of if else stuff.

Definitely working on it.
One day ill be a code guru. Until then......................practice practice practice.

Hello all.
My first project on an arduino, and it's been about 10 years since i did anything c++ related. Only c++ experience is basic coding without the use of a microcontroller.

My project is to code lights, sound, round counter, for an alien pulse rifle I am making.
The wife is Ellen Ripley from Aliens for halloween, and I have been trying to get this done.

Here is my issue:

I want my 2 digit 7 segment (common cathode, digit pins 7 and 8) to start at 95, and count to zero.
by count, i mean it cycles down to zero as long as the button is held. When I release the button, I want it to display the number it displayed before the button was released.

Initially, I was able to get it to count to zero. HOWEVER, when i release the button, the display only reads one number on the 2 digit 7 segment.
it will remember where it left off, but it only reads 2 digits when the button is pressed. When released, once again, it only displays one number, sometimes the left side of the 2 digits, sometimes on the right.

I fixed that with the following if statement from provided code:

 if (triggerState == HIGH  &&  ammo>=0)
 {
   sevseg.setNumber(ammo,1);
   
   sevseg.refreshDisplay();
   
 }

but I believe this is a half baked solution, and will only provide problems down the line.

Not sure what I am doing wrong.

Basically i want it to count from 95 to 0 when i press/hold the button, and display the current count.
I want it to stop counting when i release the button.

When it gets to zero, I want it to display '00' - one zero for each digit of the 7 segment.
Before I put the aforementioned 'IF' statment, it would display 2 digits as long as the button was pressed. when released it would display only a single digit.
When it got to the bottom of the countdown, the numbers wouldnt display anything.
if statement fixed those issue, except when I get to zero and keep holding the button, it only displays a single zero until i release the button. at that point, both zeros show ( ex: '00').

. I am not worried about resetting the counter back to 95 just yet, as I have another button im going to program to simulate magazine reloads (drop "empty" mag, insert new mag --> hits button --> resets counter).

Provided is my code, and a screenshot of the wiring. Ignore the fact the resistors dont look connected to anything, as they are - just a side effect of zooming in and out of my simulator.

#include "SevSeg.h"
SevSeg sevseg; 
int ammo = 95; //full mag
unsigned long previousMillis = 0;
long interval = 60;
int triggerState = 0; //current state of trigger.  will be assigned to digital read starting at 0 for off
int lasttriggerState = 0; //take last trigger state

#define triggerPin 5


void setup(){
    byte numDigits = 2;
    byte digitPins[] = {3,2};
    byte segmentPins[] = {6, 7, 8, 9, 10, 11, 12};
    bool resistorsOnSegments = true;
    byte hardwareConfig = COMMON_CATHODE; 
    sevseg.begin(hardwareConfig, numDigits, digitPins, segmentPins, resistorsOnSegments);
    sevseg.setBrightness(90);
    pinMode(triggerPin, INPUT_PULLUP);
}

void loop(){
  
   int triggerState = digitalRead(triggerPin);
      if (triggerState == LOW  &&  ammo>0)
   
   {
     unsigned long currentMillis = millis();
     if (currentMillis - previousMillis >= interval)
     {
       previousMillis = currentMillis;
       sevseg.setNumber(ammo,1);
       sevseg.refreshDisplay();
       
       ammo--;
       
     }
   }
     if (triggerState == HIGH  &&  ammo>=0)
     {
       sevseg.setNumber(ammo,1);
       
       sevseg.refreshDisplay();
       
     }
   }

also attached is a picture of my diagram.
2 digit 7 segment: common cathode.
2 1kohm resistors from the digit pins of the cathode to their respective arduino terminals.

i have yet to incorporate sound or lights. Those im not too worried about. Thanks for your help.

Maybe change loop to something like this?

int ammo = 95;

void loop() {
  int triggerState = digitalRead(triggerPin);
  if (triggerState == LOW && ammo >= 0) {
    unsigned long currentMillis = millis();
    if (currentMillis - previousMillis >= interval) {
      previousMillis = currentMillis;
      sevseg.setNumber(ammo, 1);
      ammo--;
    }
  }
  if (triggerState == HIGH && ammo < 95) {
    // Reset ammo count to 95 when button is no longer depressed.
    // 7 segment will still display value from last setNumber() call made above when button was depressed.
    ammo = 95;
  }

  // Always refresh both digits of the display.
  sevseg.refreshDisplay();
}

My version does assume that ammo is a signed integer.

I think you need to keep calling refreshDisplay() all the time or only one digit will be lit up.

I'm not worried about resetting the ammo back to 95 with the button you see in the code - i will be adding another button later to do so. Right now, I am just working on counting down when the button is held ----> keeping the value displayed in the 2 digit 7 segment when the button is released, and showing "00" when it drops down to zero.
Correct my post to clarify that after reading your comment.

Question - what is the reason you would used a signed int vs an int?

Basically the counter simulates an automatic rifle when the trigger is pulled, released, and runs out of ammo.
then button 2, which i will add will simulate reloading the rifle. actually plan on putting it in the magazine well, so when i put the new magazine in, it hits the button, thus resetting the count to 95.

Hope this clarifys my goal.
Also, thanks for your help on this. Ill update with how it goes.

DUDE, you da man. wrong placement of resetting the display - followed what you did and it worked like a charm. now i can remove the second if statement altogether.

However, there is some chop with the 7segment - everytime it gets to the next ten value lower (ex 40 down to 39), it stops for the smallest fraction of a second, then picks back up again.

Still - thanks brother. this has taken me all day of scratching my head to try to figure out.

sorry for the novel length replies, but def grateful for your help.

1 Like

I switched one of the if statements to check for >= 0 which would always be true for an unsigned int. I did this so that "00" would be shown and not stop at "01" instead. If you move ammo--; before the setNumber() call then maybe you could get rid of that requirement and switch the conditional back to >0.

Excellent. This is good news

Are you saying that it stays at 40 longer than you expect? The code in loop() shouldn't really know anything about decades (it is all happening in binary on the microcontroller). It must be something with the seven segment code itself. Maybe it detects that both digits are changing and it needs to run more code to update its model of which segments should be on and which shouldn't?

every ten digits when it lands on an 8 (88, 78, 68 etc), it stalls for a fraction of a second then keeps going.

granted, im using a simulator (wokwi) to make sure everything works.
didnt wanna attempt on my arduino and blow something by getting the wiring incorrect.
could be that.

Yeah maybe wait and see what happens once you run it on real hardware. If it happens on real hardware as well then add a note here and maybe we can optimize something to work around it :slight_smile:

Best of luck with your Halloween project.

many thanks. ill update as this goes along.

I've seen other posts where people post a problem related to this specific build, and you never hear from them again.
others don't share the final code, even though they asked for help here. they then turn around and sell it. while I'm not against people doing that, id rather people enjoy this without having to drop $100s to purchase an install kit to make it happen.
I don't want anyone else to go through that frustration.

2 Likes

OK. Next question.
At the beginning, i do not want the trigger button to do anything, until i have loaded a magazine (simulated by button B).

I know i can use a boolean value to make this happen, I am just not sure how.

Basically, when the gun turns on, and you load a magazine (thus pushing the reload/load button), it will allow the Trigger button to have the ability to fire.
But until that happens, I want to cancel out the trigger button.

Flow:
1.gun turns on, no magazine inserted/reload button not pushed yet, trigger does nothing.
2. magazine inserted (pushing the reload button), the trigger is now operational.
3. This just needs to happen once, at the beginning when the toy rifle is turned on. Afterwards, it wont matter because when the counter gets to zero, the trigger will be shut off with an if statement.

How can i achieve this will boolean operator. if a better method exists, i am all ears.

New code listed below for the addition of a reload button:

#include "SevSeg.h"
SevSeg sevseg; 
unsigned int ammo = 95; //full mag
unsigned long previousMillis = 0;
long interval = 60;
int triggerState = 0; //current state of trigger.  will be assigned to digital read starting at 0 for off
int reloadState = 0;
unsigned int lastReloadState = 95;


#define triggerPin 5
#define reloadPin 4

void setup(){
    byte numDigits = 2;
    byte digitPins[] = {3,2};
    byte segmentPins[] = {6, 7, 8, 9, 10, 11, 12};
    bool resistorsOnSegments = true;
    byte hardwareConfig = COMMON_CATHODE; 
    sevseg.begin(hardwareConfig, numDigits, digitPins, segmentPins, resistorsOnSegments);
    sevseg.setBrightness(90);
    pinMode(triggerPin, INPUT_PULLUP);
    pinMode(reloadPin, INPUT_PULLUP);
}

void loop(){
  
   int triggerState = digitalRead(triggerPin);
   int reloadState = digitalRead(reloadPin);

       if (reloadState == LOW && triggerState == HIGH  && ammo>=0)
     {
       ammo = lastReloadState;
       sevseg.setNumber(ammo,1);
       
     }

      if (triggerState == LOW  && reloadState == HIGH  &&  ammo<=95)
   
   {
     unsigned long currentMillis = millis();
     if (currentMillis - previousMillis >= interval)
     {
       previousMillis = currentMillis;
       sevseg.setNumber(ammo,1);  
       ammo--;
     
     }
     
   }
      
     sevseg.refreshDisplay();
   }

Thanks again for the help.

Wouldn't it have been easiest to just have kept the code kind of the way that you had it before but:

  • Start the ammo count at 0.
  • When you press reload, it just resets the count to 95.

This is why you make the big bucks in the arduino world.
Your solution is way simpler than what I was thinking.

When i incorporate led's and sounds into this, can i also use the ammo values to trigger specific sounds and make the led's stop blinking?

example for led - ammo goes all the way down to zero. led's stop blinking.
Example for sound - ammo goes all the way down to zero, and you hear a click?