SparkFun Forums 

Where electronics enthusiasts find answers.

Have questions about a SparkFun product or board? This is the place to be.
By Mee_n_Mac
#140257
OK, I looked that your code and what was gnawing at me wasn't important (a redundant IF condition). For getting the gun to fire 1 cycle ... it should work. After all right now you're still shaking out the hardware side. I'd do a test where I held the trigger firmly pressed and see if it triples and then release the trigger and see if you get any ADs. Then I'd increase the DebounceDelay to something wild, perhaps 200 msec and see if that stops your tripling.

I've commented up your code (just the main loop) and got rid of the FP calcs (you'd need to redo the threshold number). See if you agree with the comments, as that'll tell me I've understood your thinking.
Code: Select all
void loop() 
{
  buttonState = digitalRead(buttonPin);
  if (buttonState == HIGH)		//trigger is pressed
  {
    analogWrite(MotorPin, MotorSpeed);	//turn on motor
    digitalWrite(ledPin, HIGH);		//light LED, indicate trigger pressed
    do
    {
       IRead = analogRead(CurrentSensor); //read current sensor
       //IRead = (IMain-511.5)*0.66;	//delete
    }
    while (IRead > LowAmpTrigger);	//need to set threshold in A/D counts
                                     //stay in loop until current is low (after spring release)
    
    if (IRead < LowAmpTrigger)		//redundant, only way to get here is if current below threshold
    {
      do
      {
        buttonState = digitalRead(buttonPin); //read trigger state
        //delay(50);
        analogWrite(MotorPin, 0);		//turn motor off as soon as amps low since 1 cycle only
      }
      while (buttonState == HIGH);		//stay in loop until trigger is released
    }
    delay(DebounceDelay);		//exit loop after trigger released, wait to read trigger again
    digitalWrite(ledPin, LOW);	//write LED indicator to trigger off state
    }
  else                              //trigger not pressed
  {
    digitalWrite(ledPin, LOW);		//if trigger not pressed, LED = off
    analogWrite(MotorPin, 0);		//turn motor off whenever trigger not pressed, prior to next cycle
  }
}
Last edited by Mee_n_Mac on Fri Feb 24, 2012 3:02 am, edited 2 times in total.
By dkulinski
#140260
Hardware diagnostics have always interested me. Very interesting use of a timer for watchdogging the board during operation. Thanks for the explanation of what items may be using timers. I do debounce with a timer, the same 38KHz timer the IR LED uses actually (button must be on for X amount of cycles, X is run-time tunable).
By Mee_n_Mac
#140262
I believe the millis(), micros() and delay() library functions all use some hardware timer. The PWM function does as well. So once all the desired timer functions/usages get defined and a possible implementation planned, which function uses what ATmega timer will need to be determined to make sure that one function doesn't step all over some other function, trying to use a timer already in use. That the hardware timer usage is hidden behind some software call won't make that easy.

My thinking on various watch dog timers would be to detect if the motor has stalled or a fuse has blown or the trigger gets stuck or ... In each case I think you could define a "state" of the AEG based upon where it is in a firing cycle. If the transition to the next state takes too long (ie - stuck in an infinite loop waiting for the current to be more or less than some threshold) due to some HW malfunction, then the WD timer does not get reset and it subsequently times out and triggers an ISR, which in turn puts the AEG back to some good (off) state and let's the operator know something went AFU. Perhaps even prohibits any more firing until the fault is cleared ????

My thinking to date would be to do the state to state processing in the background, using the main loop and reading the digi and analog inputs in tight loops as/when those inputs are needed to go from one state to the next. ISRs are then used for the error functions and chrony and shot counter. The display gets updated in the background as well, on a "when it can be done" basis.

Whether the OP has any interest in doing any of the above is a whole 'nuther question. :twisted:

I'm not sure how to go about implementing a select fire functionality w/o a separate switch to choose single/burst/auto. I guess you could slow the initial shots down to a single shot rate to allow enough time to distinguish between trigger held and trigger released. I don't know if that would be desireable ? When the cyclic rate is high enough, there's no way a human can react quickly enough, even with a perfect no-bounce trigger, to squeeze off just a single shot. If the AEG runs slow enough to allow a human to press/release the trigger, then I don't see how a burst mode really does anything. Now the OP was going to use a pot as a variable squeeze trigger, to differentiate the modes. That might work but you still have an issue of how long it takes to squeeze the trigger to get into burst or auto modes. I dunno, maybe it's something that needs experimentation to figure out.
By StaticDet5
#140266
I keep forgetting to ask: What's an ISR?

I'm going to wind up having a shot selector system. On the P90, it already has a selection joystick mounted in front of the trigger. The G36 build that I'm working on.... well, I'm going to have to fake that for now. There's going to be a selector switch. I just haven't gotten up to needing it yet.

I'll do better about getting "concept docs" up. I have a couple of flowcharts lying around. I know one got destroyed by a very excited puppy.

I had a strange dream last night that I need to check out, code wise. I'm going to poke at that first because it's burning a hole in my head. Then I'm going to try the suggestions above.

I spent a fair amount of time yesterday afternoon just looking at the project. For the first time I can say I'm pretty confident that there isn't a weird wiring thing going on. Also, I'm stunned at how thermally stable the MOSFET is. Yeah, as AEG's go, this build probably isn't pulling insane current to drive a massive spring, but the heatsink is really cool even during sustained fire.

I'll have more posted today, after I play with it.
By dkulinski
#140269
ISR is an interrupt plain and simple. It is something that can interrupt the current flow of code, do what it needs and then return.

It is great that the target AEG has the selector switch built in already. Hopefully on the G36 you have enough room to add it. One idea may be to tie into the safety switch so that when the gun is safed you can change modes with the trigger.

I suspect the MOSFET is thermally stable due to having correctly sized wires and connections. What would be interesting is to use the Arduino as a cheap o-scope and chart the amperage draw of the firing cycle. Then you can visualize the curve and know just how full the duty cycle is for the high current usage. Arduinos are great little tools and offers so much to explore on something that was originally powered by a simple trigger.
By StaticDet5
#140279
I'm embarrassed that my code isn't properly commented. I've always said to myself "If I ever do a project, I'm going to comment my code".
Good teaching point.

I pulled the floating point calculations. I knew that FP calcs took longer, I just didn't "see" it here. Good pick up. They're gone.

OK, I just inserted a debounce delay after the "buttonState = digitalRead(buttonPin);" line (Trigger Read), just to be thorough. I also experimented with delays from 25 to 200. No change to the behavior (Pushing the button and releasing, once the motor starts cranking, fires three shots, sometimes four. Holding the button down has the exact same result).
The good news is that the behavior is what we want, I just need to get the gearbox to fire a single shot.

I tried cranking the "LowAmpTrigger" sensitivity up from 10amps. I went pretty high and got the same behavior until I went through the "cycle floor".

I reset the code back to what I posted last night, and tried something (I had to run an errand, so this came to me on the drive): I changed the analogWrites to the MotorPin to DigitalWrites. No change.

On to interrupts and timers. I haven't used interrupts before, but for this project it was inevitable. No time like the present.
The same thing is mostly true with functions. I tried to play with them before, and failed miserably. I believe I found my problem. No time like the present to "put up or shut up". Time to get learnin'

I remembered to restart the Arduino IDE after pulling down the library (If any newbies are following this, don't forget this step. It will save you serious aggravation).

I thought I was going to need to re-write the code, but if I understand this right, I'm actually simplifying the code.
Code: Select all
/*
  BasicAirsoftControlSingleShotInterrupt2-24-2012
 

 
 The circuit:
 * LED on board at pin 13
 * Motor control on pin 3 (PWM pin) 
 * pushbutton attached to pin 7 from +5V
 * 10K resistor attached to pin 7 from ground
 * ADC on analog pin 0
 * ---------------Important-------------------
 * Hall Effect Sensor not used in this sketch!
 * Hall Effect Sensor on pin 8 (Honeywell SS451A)
   Hall Effect Vin (5v) has a 1k resistor to Hall Effect Output
 
 * Note: on most Arduinos there is already an LED on the board
 attached to pin 13.
 * 30amp Current Sensor between battery plug and MOSFET board.
 * Current sensor output wired to Analog 3
 

*/

#include <TimerOne.h>

const int buttonPin = 7;  //Trigger switch attached to digital pin 7
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 VoltageMain = 3;  //Voltage Divider connected to Analog 3
const int Hall = 8;
const int CurrentSensor = 0;  //Current flow sensor attached to Analog 0
const int MotorSpeed = 255;  //PWM value for motor, max 255
const int LowAmpTrigger = 526;  //Amp level direct from ADC signaling end of cycle
int VMain = 0;  
float ADCRead =0;
int buttonState = 0;
int HallState = 0;
int IMain = 0;
float IRead = 0;
int DebounceDelay = 50;
long ReadAmpsInterval = 417;



void setup() {
  pinMode(MotorPin, OUTPUT);  //Set the MotorPin as an output
  analogWrite(MotorPin, 0);  // make sure that the MotorPin is Off
  pinMode(ledPin, OUTPUT);  // Set the LED Pin as an output
  pinMode(buttonPin, INPUT);  // set the trigger pin as an input
  Timer1.initialize(ReadAmpsInterval);  //set up the interrupt timer to read at the ReadAmpsInterval
  Timer1.attachInterrupt(ReadAmps);  //The function to call every interval
}


void loop() {
  buttonState = digitalRead(buttonPin);  //Read the trigger pin state
  delay(DebounceDelay);  // debounce delay
  if (buttonState == HIGH) {                //Trigger Loop
    analogWrite(MotorPin, MotorSpeed);      //Turn the MotorPin on to the MotorSpeed PWM
    digitalWrite(ledPin, HIGH);             //Turn the LED on.  The LED will stay on until the trigger is released
    do
    {
      
      analogWrite(MotorPin, MotorSpeed);  //This loop keeps the motor on until IMain reads an amperage below the LowAmpTrigger
      
    }
    while (IMain > LowAmpTrigger);  //This is the conditional exit
    
    if (IMain < LowAmpTrigger) {  //This loop checks to see that the amperage is less, if so it does not allow the motor to
      do                          // be turned on until the trigger is released (and ultimately depressed again)
    {
      buttonState = digitalRead(buttonPin);  //this continually checks the trigger state
      //delay(50);
      analogWrite(MotorPin, 0);  //this turns the motor off
      
    }
    while (buttonState == HIGH);  //as long as the trigger is depressed, the loop will continue turning off the motor and checking the trigger state
    }
    delay(DebounceDelay);  //debounce in case of trigger bounce issues
    digitalWrite(ledPin, LOW);  //turns off the LED when the trigger is released
  }
  else {
      digitalWrite(ledPin, LOW);  //condition of the main loop.  If the trigger is not depressed, the LED is off
      analogWrite(MotorPin, 0);  //secondary condition of the main loop(possibly unnecessary), no trigger, no motor power

  }
}


void ReadAmps()          //this is the interrupt function
{
  IMain = analogRead(CurrentSensor);   //simply reads the CurrentSensor and stores the value in IMain
}

   
  
    
  
Well crap. That didn't work. The trigger is being read (the LED is coming on), but nothing from the motor.
I think I did that right. I'm not sure.

I'm going to consider this one a bit, and try my array idea. See if I can get a grip on what is happening with the old code.
By StaticDet5
#140284
I'm playing with the array program. I'm getting close. Real close.

I've been thinking in the wrong scale, AGAIN.

First, Arduino's don't like large arrays. There's no "memory protection", keeping you from declaring an array that is too large (Like an array with 4000 entries). When you do it, the code loads with no problem. Mine just sat there.

Next, there's a HUGE difference between a delay(1), and a delay(0), when you're doing a very simple program loop. MASSIVE difference.

Here's the code. I just wanted folks to see it while I spend the rest of my day narrowing this down. I'm starting to get sore, so I'm going to have to take a break soon.
Code: Select all
/*
  BasicAirsoftControlSingleShotArray2-24-2012
 

 
 The circuit:
 * LED on board at pin 13
 * Motor control on pin 3 (PWM pin) 
 * pushbutton attached to pin 7 from +5V
 * 10K resistor attached to pin 7 from ground
 * ADC on analog pin 0
 * ---------------Important-------------------
 * Hall Effect Sensor not used in this sketch!
 * Hall Effect Sensor on pin 8 (Honeywell SS451A)
   Hall Effect Vin (5v) has a 1k resistor to Hall Effect Output
 
 * Note: on most Arduinos there is already an LED on the board
 attached to pin 13.
 * 30amp Current Sensor between battery plug and MOSFET board.
 * Current sensor output wired to Analog 3
 

*/

const int buttonPin = 7;  //Trigger switch attached to digital pin 7
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 VoltageMain = 3;  //Voltage Divider connected to Analog 3
const int Hall = 8;
const int CurrentSensor = 0;  //Current flow sensor attached to Analog 0
const int MotorSpeed = 255;  //PWM value for motor, max 255
const int LowAmpTrigger = 590;  //Amp level direct from ADC signaling end of cycle
int VMain = 0;  
float ADCRead =0;
int buttonState = 0;
int HallState = 0;
int IMain = 0;
float IRead = 0;
int DebounceDelay = 50;
const int ArraySize = 255;  //set the ArraySize for the amperage sensor
int SensorDelay = 400;  // Delay the scanning of the Current Sensor (MICROSECONDS)
int ArrayCounter = 0;  //an iterative counter for the array
int ArrayMax = 0;      //assigned during the firing sequence to represent the final datapoint
int IArray[ArraySize];  //the array to hold the amperage sensor values


void setup() {
  pinMode(MotorPin, OUTPUT);  //Set the MotorPin as an output
  analogWrite(MotorPin, 0);  // make sure that the MotorPin is Off
  pinMode(ledPin, OUTPUT);  // Set the LED Pin as an output
  pinMode(buttonPin, INPUT);  // set the trigger pin as an input
    
  
}

void loop() {
  buttonState = digitalRead(buttonPin);//Read the trigger pin state
  delay(DebounceDelay);  // debounce delay
  if (buttonState == HIGH) {              //Trigger Loop
    analogWrite(MotorPin, MotorSpeed);    //Turn the MotorPin on to the MotorSpeed PWM
    digitalWrite(ledPin, HIGH);           //Turn the LED on.  The LED will stay on until the trigger is released
    do
    {
      
      IMain = analogRead(CurrentSensor);  //simply reads the CurrentSensor and stores the value in IMain
      IArray[ArrayCounter] = IMain;  //assigns the CurrentSensor reading to the array
      ArrayCounter = ArrayCounter + 1;  //increments the ArrayCounter
      delayMicroseconds(SensorDelay);
      if (ArrayCounter > ArraySize)
      {
        IMain = 0;
      }
      
    }
    while (IMain > LowAmpTrigger);  //This is the conditional exit, the motor needs to stay on until the amperage reads low
    
    if (IMain < LowAmpTrigger) {  //This loop checks to see that the amperage is less, if so it does not allow the motor to
      do                          // be turned on until the trigger is released (and ultimately depressed again)                          
    {
      buttonState = digitalRead(buttonPin);  //this continually checks the trigger state
      //delay(50);
      analogWrite(MotorPin, 0);  //this turns the motor off
      
    }
    while (buttonState == HIGH);  //as long as the trigger is depressed, the loop will continue turning off the motor and checking the trigger state
    }
    delay(DebounceDelay);  //debounce in case of trigger bounce issues
    digitalWrite(ledPin, LOW);  //turns off the LED when the trigger is released
    Serial.begin(115200);  //enable the serial port at 115,200 baud
    for(int index = 0; index < (ArrayCounter + 1); index++)  // iterate through each record in the array
    {
      int Spaces = ((IArray[index])/50);
      for (int index2 = 0; index2 < Spaces; index2++)  //pad spaces in front of the serial print
      {
        Serial.print(" ");  //this creates a simple graph layout
      }
      
      Serial.print(IArray[index]);  //print each value of the array to the last record
      Serial.print("   ");
      Serial.println(index);
      
    }
    Serial.end();
  }
  else {
      digitalWrite(ledPin, LOW);  //condition of the main loop.  If the trigger is not depressed, the LED is off
      analogWrite(MotorPin, 0);  //secondary condition of the main loop(possibly unnecessary), no trigger, no motor power

  }
}

   
   
  
    
  
By dkulinski
#140285
Why not just dump the readings to serial to monitor them and get a good idea of what data you are looking at? Dump out the milis() count and the adc reading. No need to store readings locally and then you can make pretty graphs in Excel.
By Mee_n_Mac
#140286
StaticDet5 wrote:OK, I just inserted a debounce delay after the "buttonState = digitalRead(buttonPin);" line (Trigger Read), just to be thorough. I also experimented with delays from 25 to 200. No change to the behavior (Pushing the button and releasing, once the motor starts cranking, fires three shots, sometimes four. Holding the button down has the exact same result).
The good news is that the behavior is what we want, I just need to get the gearbox to fire a single shot.

I tried cranking the "LowAmpTrigger" sensitivity up from 10amps. I went pretty high and got the same behavior until I went through the "cycle floor".

I reset the code back to what I posted last night, and tried something (I had to run an errand, so this came to me on the drive): I changed the analogWrites to the MotorPin to DigitalWrites. No change.
Hmmm ... I'm not sure what to think now. I'd have bet $$s that a bouncing switch would have been the cause of the tripling. I guess the bounce might be longer than 200 msec but not long enough to keep tripling after that delay, My first thought is to add some diagnostics to your code to allow us to "see" what the code "sees". I'm just not sure what that diagnostic code should be. :? Perhaps add a counter to count the times the code sees the trigger pressed and released ... and send that count out via the serial port to the PC for display ? A count of the number of times the motor is turned on ... and off ?

Perhaps knock the debounce delay up to something really wild ... say 1 sec .., or as long as the delay() function will allow. The hardware seems to be working well now, except for the tripling. :?:

FWIW : ISR = Interrupt Service Routine : a piece of code that runs when an interrupt happens. As an example you might have your photodetectors tied to a digital input put which is also setup to be an external interrupt. When the pin changes state, the MCU stops the normal processing and jumps to the ISR. The ISR, in this case, might then increment a "shot" counter and then return ... which re-starts the processing that was interrupted back where it left off. Or another case, to use the idea above, you might set a timer to trigger an interrupt every 1 msec. The ISR might then sample the motor current and send the resulting 2 bytes out over the serial link and then return to the normal background processing. This makes your Arduino into a simple 1 channel O-scope and allows you to see what the motor current looks like during a cycle, msec by msec. Of course this implies the ISR code can do all it's supposed to do in less than 1 msec.
By StaticDet5
#140288
OK, huge apologies for the previous bizarre post. I was a little excited (I'd learned about a dozen different things in the previous 20 minutes. With my stunted mental faculties, this is an exciting moment. :lol: )

I'm going to jump around a bit. (I know, I'm supposed to settle down now)

First, I don't think switch debounce is an issue here (but we/I REALLY need to keep it in mind for later). The code enters into the firing cycle when the trigger pin is triggered "High". After that, the firing cycle doesn't really care if the trigger pin is in an oscillating state, because the only initial exit from the code loop is when the current sensor reads below the pre-set threshold. This threshold isn't reached within a typical "bounce time". It's the current sensor that controls when the motor is turned off.

Next, I tried dumping the sensor values to the serial monitor, but I wasn't getting the "resolution" that I wanted. I (incorrectly) assumed that the serial monitor was slowing the loop down too much for the current sensor to see the drop in the current. That's why I built the array system. It's faster to dump the value into an array, and then check it afterwards. However, I ran into array size issues. The system was filling the array before one motor cycle was even initiated. I put a "delay(1)" command in, and got the opposite problem. The system was never reading a low amp circumstance.

I stopped. I was missing something. Basic. Really basic. I checked the code, and it was spot on, exactly what I wanted.

This is where the time scale issue came in. This thing is running at 16MHz. Faster than I can really comprehend, particularly when you consider how I interact with an Arduino. I look at Serial Prints and LED's. I can't see cycles that fast.
In fact, the Arduino language assumes that you don't need to deal with cycles that fast. The default delay is in milliseconds, 1000 of them to every second.
I changed the sensor delay to "delayMicroseconds". There are 1000 microseconds in each millisecond, and 1,000,000 in every second (This isn't for Mee_n_Mac or dkulinski, but anyone else that, like me, doesn't think that fast).
With a delay of 500 microseconds, all of a sudden the array was picking up low conditions. Not regularly, but occasionally. I kept dropping it down, and fiddling with the maximum number of records in the array. With a delay at 75 microseconds I was consistently getting single shots.

I changed code, and went back to "AirsoftControlSingleShotFail", and put a delayMicroseconds into the sensor loop. I kept dialing it back (This loop is ultra-primitive. No arrays, nothing except checking the current sensor value), until I got to 12 microseconds.

Success. Single shots, every time (tested 25 times at this point).

Looking back, this was definitely a lack of "scale" on my part. I was stuck thinking in a world that I can perceive, or easily contemplate. I know the issue was actually more complex than that, but the root cause was that lack of scale.

Here's the single shot code snippet:
Code: Select all
/*
  BasicAirsoftControlSingleShotSuccess2-24-2012
 

 
 The circuit:
 * LED on board at pin 13
 * Motor control on pin 3 (PWM pin) 
 * pushbutton attached to pin 7 from +5V
 * 10K resistor attached to pin 7 from ground
 * ADC on analog pin 0
 * ---------------Important-------------------
 * Hall Effect Sensor not used in this sketch!
 * Hall Effect Sensor on pin 8 (Honeywell SS451A)
   Hall Effect Vin (5v) has a 1k resistor to Hall Effect Output
 
 * Note: on most Arduinos there is already an LED on the board
 attached to pin 13.
 * 30amp Current Sensor between battery plug and MOSFET board.
 * Current sensor output wired to Analog 3
 

*/

const int buttonPin = 7;  //Trigger switch attached to digital pin 7
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 VoltageMain = 3;  //Voltage Divider connected to Analog 3
const int Hall = 8;
const int CurrentSensor = 0;  //Current flow sensor attached to Analog 0
const int MotorSpeed = 255;  //PWM value for motor, max 255
const int LowAmpTrigger = 680;  //Amp level direct from ADC signaling end of cycle
int VMain = 0;  
float ADCRead =0;
int buttonState = 0;
int HallState = 0;
int IMain = 0;
float IRead = 0;
int DebounceDelay = 50;  //Button debounce delay in milliseconds
int SensorDelay = 12;  //Sensor Read Delay in MICROSECONDS



void setup() {
  pinMode(MotorPin, OUTPUT);  //Set the MotorPin as an output
  analogWrite(MotorPin, 0);  // make sure that the MotorPin is Off
  pinMode(ledPin, OUTPUT);  // Set the LED Pin as an output
  pinMode(buttonPin, INPUT);  // set the trigger pin as an input
  
}

void loop() {
  buttonState = digitalRead(buttonPin);//Read the trigger pin state
  
  if (buttonState == HIGH) {              //Trigger Loop
    analogWrite(MotorPin, MotorSpeed);    //Turn the MotorPin on to the MotorSpeed PWM
    digitalWrite(ledPin, HIGH);           //Turn the LED on.  The LED will stay on until the trigger is released
    delay(DebounceDelay);  // debounce delay
    do
    {
      
      IMain = analogRead(CurrentSensor);  //simply reads the CurrentSensor and stores the value in IMain
      delayMicroseconds(SensorDelay);  //delay between sensor readings
      
    }
    while (IMain > LowAmpTrigger);  //This is the conditional exit, the motor needs to stay on until the amperage reads low
    
    if (IMain < LowAmpTrigger) {  //This loop checks to see that the amperage is less, if so it does not allow the motor to
      do                          // be turned on until the trigger is released (and ultimately depressed again)                          
    {
      buttonState = digitalRead(buttonPin);  //this continually checks the trigger state
      //delay(50);
      analogWrite(MotorPin, 0);  //this turns the motor off
      
    }
    while (buttonState == HIGH);  //as long as the trigger is depressed, the loop will continue turning off the motor and checking the trigger state
    }
    delay(DebounceDelay);  //debounce in case of trigger bounce issues
    digitalWrite(ledPin, LOW);  //turns off the LED when the trigger is released
  }
  else {
      digitalWrite(ledPin, LOW);  //condition of the main loop.  If the trigger is not depressed, the LED is off
      analogWrite(MotorPin, 0);  //secondary condition of the main loop(possibly unnecessary), no trigger, no motor power

  }
}

   
   
  
    
  
By dkulinski
#140289
Congrats! It is interesting that you came to such a delay factor as 12us as that is about 10% of the time for and analogRead to complete.

I guess I don't necessarily think of scale as in what is human perceivable or not. When I am breaking down a problem I try to get to a specific resolution. What is interesting in your solution is that you are merely adding a delay, so rather than an analogRead taking 100us it now takes 112us. So such a small increase seems pretty irrelevant considering it takes 41.7ms (or 41700us) to cycle. So you may have unintentionally migrated to a timed solution to control the readings. I don't have Mee_n_Mac's charting capabilities but your delay adds enough time that the analog reads now fall into the trough due to the small delay you added. As the battery weakens this may become inaccurate.

Also, as I was looking at your timed interrupt code, I forgot to mention you need to make any variables accessed in an interrupt as volatile. That just requires sticking the volatile keyword in front of the variable definition.

Sounds like you are having a good time. It is always exciting when something works.
By StaticDet5
#140291
I see exactly what you're saying (I was going to phrase it in terms of a harmonic, but was worried that would be too obtuse).

Considering it, I keep coming back to the same question:

Why does adding a delay work at all, when doing it without the delay doesn't work?
By StaticDet5
#140293
So it doesn't make sense, so I went back and played a bit. This time with both the G36 and a donated M16.

The M16 was still burst firing.

I played around with the delays again. Desperate. I realized halfway into an experimental series that this wasn't going to fix the problem. I kept going, taking the delay all the way down to 1 microsecond. Burst fire. Two rounds.

I considered other causes. Was I running into a threshold issue? Did I not set my "low amp" value high enough?

Sure enough, as I started gently increasing the low amp threshold, the number of "burst fires" went down.

I switched out the AEG's, and went back to the G36. Even with the increased threshold, it was firing a single shot.

That's the issue. Not timing. I need to have the threshold high enough to catch the troughs of the firing cycle.
That being said, I removed the delay entirely, and everything is functioning just like it should.
By dkulinski
#140299
Great find, I bet that is a relief. Are you going to make that a run time tunable? You could write it to EEPROM so it is non-volatile.

Hopefully your progress continues to be steady. You'll have to get Sparkfun to put it up on the front page!
  • 1
  • 4
  • 5
  • 6
  • 7
  • 8
  • 32