MSTimer Interrupt Code

Hi guys. I’m trying to build some camera control gear to move a focus puller in intervals between exposures with a small gear motor. Starting with the code from OpenMoco.org, here is what I’ve got, modified in that the variables are input via Serial and can thus change (and this code has been removed to simplify my question here). I want to use MSTimer to engage the motor during the interval time and generally organize the order of what happens in my program and thus with my gear. I need the sequence of events to be:

  1. Focus
  2. Exposure
  3. Delay
  4. Interval
  5. Focus
  6. Exposure
  7. Delay
  8. Interval
    …etc.

So a complete cycle is <focus, exposure, delay, interval>. Typical values would be focus=500ms, exposure=5000ms, delay = 800ms, and interval=2000ms. And again, I want the motor to be on during the Interval time, but the motor cannot be on during Exposure. Once started it should loop cycle after cycle. I’dd eventually like to add physical start and stop buttons but for now I’ll just disengage the power supply to stop it.

#include <MsTimer2.h>
int CAMERA_PIN = 13;
int MotorPin = 9;
int FocusPin = 8;

//last time our camera fired
unsigned long last_tm = 0;
// whether or not we're currently exposing
bool exposing = false;
//variable for Exposure (length of time camera is on)
unsigned int EXP; 
//variable for Focus (signal sent to camera to focus)
unsigned int FT;
//variable for Interval (time between shots)
unsigned int INT; 
//variable for Exposure Delay (time placed before exposure)
unsigned int EXPDLY; 
//variable for Motor Speed given in % from 0 to 100%
unsigned int MTR; 

void setup() {
  
  pinMode(CAMERA_PIN, OUTPUT);
  pinMode(MotorPin, OUTPUT);
  pinMode(FocusPin, OUTPUT);
  Serial.begin(115200);
}

void loop() {

if( exposing == false && millis() - last_tm > INT ) { 
    
      // if the camera is not currently exposing, and our timer has elapsed, fire camera...
      // set timer interrupt to call our function to disengage the camera
    MsTimer2::set( EXP, camera_off );
      // enable timer
    MsTimer2::start();
    
      // set flag to indicate that we're currently exposing
    exposing = true;
      // enable optocoupler and fire camera
    digitalWrite(CAMERA_PIN, HIGH);
      } // end if not exposing and timer has elapsed
    
      }

void camera_off() {
  
     // disable optocoupler, stop exposing
  digitalWrite(CAMERA_PIN, LOW);

     // disable timer
  MsTimer2::stop();
  
     // we set this now to ensure that our interval time is measured from the
     // time an image is completed until the time the next one is triggered
     // if you want the interval time to be measured between the time the image
     // is triggered and the next image is triggered, move this to before
     // bringing the camera pin high
      
  last_tm = millis(); 
    
     // reset exposing flag
  exposing = false;
}

How would I go about adding functionality to the program so that I can also engage the motor (on pin #9 for PWM) during the interval time? Would it be via another void() function placed at the bottom, something like "motor_on()? Or do I need to change the MsTimer2(set) function in the loop with some if or if/else or while statements? If you hadn’t guessed it I’m relatively new to Arduino and still learning a lot of the basic concepts and I know I have dove into the deep end of the pool with this as a project. Thanks.

void motor_on() {
  
if (exposing == false && millis() - last_tm > INT){
 MsTimer2::set(EXP,camera_off);
 MsTimer2::start();
 exposing == true;
 analogWrite(MotorPin, MTR / 2.55); // this # should convert the range of 1-100 (motor %) to 0 to 255 for PWM

To put it another way, basically what I want to do is the same things as this loop, but with MSTimer to make things a bit more reliable:

void loop() {

  /* There needs to be a way to order the loop. The cycle should be:
1. Focus Tap (FT)
2. Exposure (EXP)
3. Exposure Delay (EXPDLY)
4. Interval (INT)

The motor should be on at the % given by the value of MTR during INT. 
*/  


//1. Focus Tap
digitalWrite (FocusPin, HIGH); 
delay(FT); 
digitalWrite (FocusPin, LOW);
//2. Exposure
digitalWrite (CameraPin, HIGH);
delay (EXP);
digitalWrite (CameraPin, LOW);
//3. Exposure Delay
delay (EXPDLY);
//4. Interval
analogWrite (MotorPin, MTR / 2.55);
delay (INT);
// for INT milliseconds, BUT only while the camera is not exposing

}

So a complete cycle is <focus, exposure, delay, interval>.

Why can’t you do this using millis() and a state machine?

@Paul - I'm sure I could, I had not heard of a state machine until you just brought it up and I looked into it. Sounds like just what I would need.

Would you suggest QP or Finite State Machine? How would millis() enter into the code for developing the sequencing?

Take a look at this thread: Arduino Forum. I posted a simple piece of state machine code for a similar problem.

Thanks Wildbill. Great example. If I may ask, can you tell me what the advantages would be of using a state machine instead of interrupts with subtractive timing (like millis() or MSTimer2 to trigger events? Does it have to do with a lower load on the ATMega? I'd like to do gain a better understanding of both as I progress with my program. Thanks again for your help.

If I may ask, can you tell me what the advantages would be of using a state machine instead of interrupts with subtractive timing (like millis() or MSTimer2 to trigger events?

How about the fact that it is much easier to understand? Doesn't that count for something? A lot, in my book.

@Paul - I will accept that! Here is what I have come up with, with A. Brevig’s FSM library.

I do not have a momentary switch with me at the moment but can try to find one later tonight, but can you tell me if this code will work?

Watching the serial monitor, I see my variable “presses” is staying at 0…what I want is for the program to start out and remain in the “init” state, where it idles until I press the button (and digital.Read 6 should become “HIGH” and increment “presses” from 0 to 1). Then it should move into the “run” state and do it’s thing until the user presses the button again which would put it into “reset” state (increment presses from 1 to 2), which quickly returns the state to “init.”

Is the code written correctly?

#include <FiniteStateMachine.h>

  //temporary definitions 
#define FT 500
#define EXP 2500
#define EXPDLY 500
#define INT 4000
#define MTR 100
  // pin definitions
#define CameraPin 13
#define MotorPin 9
#define FocusPin 8

  //how many states are we cycling through?
const byte NUMBER_OF_STATES = 3; 
 
  //initialize states
State Init = State(DSInit); //startup state
State Run = State (DSRun); //shooting the timelapse
State Reset = State(DSReset);  //reset state triggerred by pressing button 3x

FSM DSStateMachine = FSM(Init);     //initialize DSState machine, start in state: Init

bool StartButton = false;       // helps to start program in "Init" state by declaring "StartButton" as false
long firstPress = 0; // starts variable "firstPress" as value = 0
int presses = 0; // variable for # of times button is pressed
int buttonPin = 6; //pin button is connected to

void setup(){ 

  pinMode(CameraPin, OUTPUT);
  pinMode(MotorPin, OUTPUT);
  pinMode(FocusPin, OUTPUT);
  pinMode (StartButton, INPUT);
  Serial.begin(115200);
  Serial.println("Serial communication has started");
}


void loop(){
 if(digitalRead(6) ==HIGH)
{
  ++presses;
}


  if (presses = 0)
    {DSStateMachine.isInState(Init);//stay in state INIT
  }
    else {
     presses = 0;
      switch (presses) { //this should switch states when the button is pressed
      case 0: DSStateMachine.transitionTo(Run); break;
      case 1: DSStateMachine.transitionTo(Reset); break;
    //case 2: DSStateMachine.transitionTo(????); break;
      }
    }
      State& getCurrentState();
  
  DSStateMachine.update();
  Serial.println(presses);
  delay(100);
  
  
}

//utility functions
void DSInit () {
   //digitalWrite (MotorPin, LOW);
  // digitalWrite (CameraPin, LOW);
  // digitalWrite (FocusPin, LOW);
//any init functions go here
}

void DSRun () {
   digitalWrite (FocusPin, HIGH);
   delay (FT);
   digitalWrite (FocusPin, LOW);
   //delay(5);
   digitalWrite (CameraPin, HIGH);
   delay (EXP);
   digitalWrite (CameraPin, LOW);
   delay (EXPDLY);
   digitalWrite (MotorPin, HIGH);
   delay(INT);
   digitalWrite (MotorPin, LOW); 
   
}

void DSReset(){ 
    DSStateMachine.immediateTransitionTo(Init);
    }

//end utility functions
  ++presses;

Unless the post-fix vs. prefix notation matters (sometimes it does), the post-fix notation is generally used. You've perhaps noticed that the language is called C++, not ++C.

  if (presses = 0)

In the parentheses is an assignment statement, not an equality test.

    {DSStateMachine.isInState(Init);//stay in state INIT

Please don't do this. Nothing comes after the {, to make it stand out.

     presses = 0;
      switch (presses) { //this should switch states when the button is pressed
      case 0: DSStateMachine.transitionTo(Run); break;
      case 1: DSStateMachine.transitionTo(Reset); break;
    //case 2: DSStateMachine.transitionTo(????); break;

Now many of these cases will ever be executed?

      State& getCurrentState();

This is a function prototype, not a call to the function. As such, it doesn't belong inside loop. It really isn't clear if you are trying to call a function or do something else. Whichever it is, this isn't correct.

Now that you have a state machine, you can test on each pass through loop what state you are in, and whether it is time to do something else, and get rid of all those delay()s.

The whole reason for the state machine is so that while you are in the Run ("taking a picture") state, you can do other things, if needed. Like checking your watch (millis()) to see if it is time to diddle with a pin (Yes, it's time to activate the focus pin; yes, it's time to open the aperture, yes, it's time to close the aperture, yes, it's time to move the film, hey, that's long enough - stop).

By the way, great job on the code (other than the few minor issues).

Thanks for the pointers and the kind words Paul. A little progress feels good! I took your suggestions into account, and decided to simplify things and to use the “default” function of the Switch/Case to keep things in the “Init” State.

The program loads fine, and “idles” in “Init” until the button is pressed, and then it moves into “Run” state and cycles through what is in that function. I cannot seem to get another press of the button to be read by the program to switch the case to #2 and bring things into the “Reset” state - the program just keeps repeating “Run.” if I hold down the button, it does cycle through Reset" once and then goes back to “Run.”

#include <FiniteStateMachine.h>
#include <Button.h>
 //temporary definitions 
#define FT 500
#define EXP 15000
#define EXPDLY 1500
#define INT 7000
#define MTR 100
  // pin definitions
#define CameraPin 13
#define MotorPin 9
#define FocusPin 8
#define ButtonPin 6

  //how many states are we cycling through?
const byte NUMBER_OF_STATES = 3; 
 
  //initialize states
State Init = State(DSInit); //startup state
State Run = State (DSRun); //shooting the timelapse
State Reset = State(DSReset);  //reset state triggerred by pressing button during "Run" state

FSM DSStateMachine = FSM(Init);     //initialize DollySlider state machine, start in state: Init

int presses = 0; // variable for # of times button is pressed
//int ButtonPin = 6; //pin button is connected to

void setup(){ 

  pinMode(CameraPin, OUTPUT);
  pinMode(MotorPin, OUTPUT);
  pinMode(FocusPin, OUTPUT);
  pinMode (ButtonPin, INPUT);
  Serial.begin(115200);
  Serial.println("Serial communication has started");
}


void loop(){
 if(digitalRead(6) == HIGH)
{
  presses++;
}
    switch (presses) {  //this should switch states when the button is pressed
      case 0: 
        DSStateMachine.transitionTo(Init);
        break;
      case 1: 
        DSStateMachine.transitionTo(Run); 
        Serial.println("Running");
        presses = 1;
        break;
      case 2: 
        DSStateMachine.transitionTo(Reset); 
        Serial.println("Reset");
        delay(100);
        presses = 0;
        break;
      default: DSStateMachine.isInState(Init);//stay in state INIT
       }
    
  DSStateMachine.update(); 
  
  Serial.println(presses);
  
  
}

//utility functions
void DSInit () {
   //digitalWrite (MotorPin, LOW);
  // digitalWrite (CameraPin, LOW);
  // digitalWrite (FocusPin, LOW);
 Serial.println("Armed");
 //any init functions go here
}

void DSRun () {
  digitalWrite (FocusPin, HIGH);
  Serial.println("Focusing");
  delay (FT);
  digitalWrite (FocusPin, LOW);
  Serial.println("Exposing");
  digitalWrite (CameraPin, HIGH);
  delay (EXP);
  Serial.println("Delay");
  digitalWrite (CameraPin, LOW);
  delay (EXPDLY);
  Serial.println("Motor On");
  digitalWrite (MotorPin, HIGH);
  delay(INT);
  digitalWrite (MotorPin, LOW); 
   
}

void DSReset(){ 
    DSStateMachine.immediateTransitionTo(Init);
    }

//end utility functions

So, this tells me that you are right about the fact that I need to get rid of the delays in my “Run” state function, as I have a suspicion that they are impeding the correct reading of the button. I see on the FSM library page (http://arduino.cc/playground/Code/FiniteStateMachine) that I should be able to have the program tell me what state the FSM is in:

State& getCurrentState() // Returns the current state
boolean isInState( State &state ) //Check if state is equal to the current state of the FSMcall

And earlier, you pointed out a bad piece of code that I had in my loop as being prototypical - State& getCurrentState() - but I’m not sure how I need to change this to get it to work properly?

I tried:

Serial.println(State& DSStateMachine.getCurrentState());

but I got error: expected primary-expression before ‘&’ token. So I know I am doing something wrong syntactically, presumably it’s a typical beginner’s coding mistake? What is the proper usage of the functions listed on the FSM library page, in my program? Can you or anyone else out there point me in the right direction for how I would modify my program to get rid of the delays? Thanks.

as I have a suspicion that they are impeding the correct reading of the button.

That is exactly what is happening. Switch press events, and everything else except interrupts, are ignored while delay() is executing it's thumb-twiddling.

I see on the FSM library page (Arduino Playground - HomePage) that I should be able to have the program tell me what state the FSM is in:

Yes. You would declare a variable of type State and then call the function:

State currState;

currState = DSStateMachine.getCurrentState();

but I got error: expected primary-expression before '&' token.

As expected. The Serial.print() function has no idea what a State is, even if you remove the State& bit, so it won't be able to print anything useful.

You would have to do something like:

if(currState == Run)
  Serial.print("Run state active");
else if(currState == Init)
  Serial.print("Init state active");

Thanks yet again for the info Paul.

So if I want to find my way out of the “delay forest,” what are my options? Use the millis() timer or the MSTimer2 library to establish sequential timing based on my initial parameters? Or is there a more “elegant” way to code it?

Is there a direct way to add a time parameter to the digitalWrite function itself?

edit - I spent a few hours tonight giving this a try with MsTimer2 to no avail. To summarize, I want to use the timer to achieve a cycle that looks like this:

void DSRun () {
 //button has been pressed so we are here in Run State from Init State
 //turn on Focus line for FT ms
 //turn on CameraPin for EXP ms
 //wait EXPDLY ms
 //turn on MotorPin for INT ms
 //start cycle over again and repeat until reset state is achieved through another button press

}

So if I want to find my way out of the "delay forest," what are my options? Use the millis() timer

The millis() function isn't a timer. It is a watch. You can time things using a watch, by noting when an event started and when it ended. Or, you can cause an event to happen at the right time, relative to some other event, by noting when the other event occurs, and seeing, periodically, if enough time has elapsed.

It is this second approach that you are interested in. An event occurs (the state changes to run). Do something (start the focus) and record the time that the event occurred.

Periodically, see if it is time for the next event to occur. Fortunately, loop() executes pretty often (as long as there are no delay()s), so "periodically" means "on every pass through loop()".

You'll need to keep track of what should happen next (stop focusing, open the shutter, close the shutter, start the motor, stop the motor, or nothing) and when the last event occurred.

You can think of this (and implement it, if overkill is your desire) as a state machine for the run state.

You mean I have to use math???? Joking. I'm going to give it a try with another FSM in my "run" state with millis() as a timer - are you sure that I can declare and use multiple State Machines in the same program?

One thing that did cross my mind - let's say I want this program to run for 12+ hours, or maybe even a few days. Millis() says it will run for 50 days, but before that, wouldn't the value of it climb so high that I would overflow or cause the math behind the timing to take so long so as to actually interfere with the timing?

geek_tk:
wouldn't the value of it climb so high that I would overflow or cause the math behind the timing to take so long so as to actually interfere with the timing?

Ahh... no. Doing a subtraction on variables of the same type (so as long as they're ints) they'll take the same amount of time. And the timer will wrap around after 50 days, but if you program it right, you just have to make sure you don't have a period longer than that, and it'll "take care" of the wrap around.

WizenedEE is right. Think about how you deal with your watch rolling over every day. When you get up in the morning, you don't have any trouble figuring out how long you slept, do you? Go to bed at 10:00 PM, for instance, and get up at 4:30, and you can easily determine how long you slept. Not near enough, if your math is correct. No, wait, I mean 6 and half hours.

Now, where it gets harder is if you sleep for 30 and a half hours, instead...

Thanks guys. So I gave it a try, and now I'm getting declare errors with two instances of FSM (Finite State Machine). Does that library handle multiple state machines, or do I have to design the entire program with one?

You should be able to create two instances (with different names, of course). Or, expand your current state machine to have Run_Focus, Run_Snap, Run_Wind, etc.

All together now: Post your code!.

OK, Here’s where I am at. The program works, for one cycle through my variables. Then, my LEDs look like a concert light show - my state machine (which itself is running in the DSRun state of the overall FSM) cycles back and forth between states 1,2, and 3. I know this is because the way I have setup the if statements with the relative timer variables only works for one cycle. At this point I am seriously regretting taking the AP Calculus exam in 12th grade and placing myself out of Calc in college, because the math for this should be “easy” but for some reason I can’t see it…

How do I get my machine to keep cycling through the states as the millis () increases through time by FT, EXP, EXPDLY, and INT as the program runs for hours and hours?

#include <FiniteStateMachine.h>

 //temporary definitions 
#define FT 500
#define EXP 15000
#define EXPDLY 1500
#define INT 7000
#define MTR 100

  // pin definitions
#define CameraPin 13
#define MotorPin 9
#define FocusPin 8
#define ButtonPin 6

  // Objects for Timing
float CameraTime = 0;
float Timer1 = CameraTime + FT;
float Timer2 = CameraTime + FT + EXP;
float Timer3 = CameraTime + FT + EXP + EXPDLY;
float Timer4 = CameraTime + FT + EXP + EXPDLY + INT;

//pin states for Timelapse timing
int FocusState = LOW;
int ExposureState = LOW;
int ExposureDelayState = LOW;
int IntervalState = LOW;
int MotorState = LOW;

  //overall state machine states
State Init = State(DSInit); //startup state
State Run = State (DSRun); //shooting the timelapse
State Reset = State(DSReset);  //reset state triggerred by pressing button during "Run" state
State CurrentState = Init;  //
FSM DSStateMachine = FSM(Init);     //initialize DS State Machine, start in state: Init


 //timing State Machine States (these are within the DSRun sketch)
State Focusing = State (DSTiming_Focusing);
State Exposing = State (DSTiming_Exposing);
State ExpDelaying = State (DSTiming_ExpDelaying);
State Interval = State (DSTiming_Interval);
FSM DSTimingMachine = FSM(Focusing);


int presses = 0; // variable for # of times button is pressed
int DSTiming = 0; //variable for Timing State Machine

void setup(){ 
  pinMode(CameraPin, OUTPUT);
  pinMode(MotorPin, OUTPUT);
  pinMode(FocusPin, OUTPUT);
  pinMode (ButtonPin, INPUT);
 // start all pins out as OFF or LOW
  digitalWrite(CameraPin,LOW);
  digitalWrite(FocusPin, LOW);
  digitalWrite(MotorPin,LOW);
 // fire up the serial monitor for debugging, add LCD screen later
  Serial.begin(115200);
  Serial.println("Serial communication has started");
  
}


void loop(){
 if(digitalRead(6) == HIGH)
{
  presses++;
  delay(500); //added half a second delay to make sure the button read isn't bouncy
}
    switch (presses) {  //this should cause the program to switch states when the button is pressed
      case 0: 
        DSStateMachine.transitionTo(Init);
        presses = 0;
        break;
      case 1: 
        DSStateMachine.transitionTo(Run); 
        presses = 1;
        break;
      case 2: 
        DSStateMachine.transitionTo(Reset); 
        //Serial.println("Reset");
        presses = 0;
        break;
      default: DSStateMachine.isInState(Init);//stay in state INIT
       }
    
  DSStateMachine.update(); 
  
  //CurrentState = DSStateMachine.getCurrentState();
}

void DSInit () {
 Serial.println("Armed");
 delay(500);
}

//----------------------MAIN PROGRAM FUNCTION----------------


void DSRun () {
CameraTime = millis(); // CameraTime should = around 3500 ms
Serial.println(DSTiming);
delay(100);

   switch (DSTiming) {  //this should cause the program to switch states when the button is pressed
      case 0: 
        DSTimingMachine.transitionTo(Focusing);
        Serial.println("Focusing");
        break;
      case 1: 
        DSTimingMachine.transitionTo(Exposing);
        Serial.println("Exposing"); 
        break;
      case 2: 
        DSTimingMachine.transitionTo(ExpDelaying); 
        Serial.println("Delay");
        break;
      case 3:
        DSTimingMachine.transitionTo(Interval);
        Serial.println("Motor On");
        break;
       case 4:
        DSTimingMachine.transitionTo(Focusing);
    default: DSTimingMachine.isInState(Focusing);//start in state Focusing
       }
      DSTimingMachine.update(); 
}

//-------------TIMING FUNCTIONS---------------  
       //FOCUSING
 void DSTiming_Focusing(){
   digitalWrite(FocusPin, HIGH);
   if (CameraTime > Timer1){ 
        DSTiming++;  
        }
    }
      //EXPOSING
void DSTiming_Exposing (){
   digitalWrite (FocusPin, LOW);
   digitalWrite (CameraPin, HIGH);
   if (CameraTime > Timer2){
        DSTiming++; 
        }
   }
      //DELAY
 void DSTiming_ExpDelaying (){
   digitalWrite(FocusPin, LOW);
   digitalWrite(CameraPin, LOW);
   digitalWrite(MotorPin, LOW);
   if (CameraTime > Timer3){
        DSTiming++;
   }
 }
   //INTERVAL -MOTOR

void DSTiming_Interval(){
   digitalWrite (MotorPin, HIGH);
   digitalWrite (CameraPin, LOW);
   if (CameraTime > Timer4){
        DSTiming = 1; 
        }
  }


  
//-----------------RESET STATE FUNCTION---------------------

void DSReset(){ 
    DSStateMachine.immediateTransitionTo(Init);
    }
float CameraTime = 0;
float Timer1 = CameraTime + FT;
float Timer2 = CameraTime + FT + EXP;
float Timer3 = CameraTime + FT + EXP + EXPDLY;
float Timer4 = CameraTime + FT + EXP + EXPDLY + INT;

Why are these floats?

 if(digitalRead(6) == HIGH)
{
  presses++;
  delay(500); //added half a second delay to make sure the button read isn't bouncy
}

The value 6 conveys no information.

delay(100);

The whole reason for using state machines was to get rid of delay()s. You still have two of them

CameraTime = millis(); // CameraTime should = around 3500 ms

I have no idea where you got that idea.

I suggest that you get rid of the DSTiming variable. Instead of setting the variable in a bunch of places, make each function that sets it invoke the transitionTo() method for the DSTimingMachine, to transition to the correct state. When the DSTimingMachine reaches the last state, it needs to transition to an idle state AND cause the DSStateMachine to transition to a new state (this is the big problem with your current code).

If, once DSStateMachine transitions to the Run state, the DSTimingMachine should transition through all of it's states over and over, then I have no idea what the heck presses is for, or why loop() allows presses to be incremented except when the DSStateMachine is in the Init state.

If, once DSStateMachine transitions to the Run state, the DSTimingMachine should transition through all of it's states over and over, then DSTiming_Interval (lousy name, by the way) should set DSTiming to 0, shouldn't it, rather than 1?

PaulS:
Why are these floats?

Let's say I run this for 40 days. 40 days in milliseconds = 3,456,000,000 milliseconds. Should I use int instead? I know float uses up more precious memory allocation on the ATMega 328.

delay(100);

I had the delay in because the button input was bouncy.

I suggest that you get rid of the DSTiming variable. Instead of setting the variable in a bunch of places, make each function that sets it invoke the transitionTo() method for the DSTimingMachine, to transition to the correct state. When the DSTimingMachine reaches the last state, it needs to transition to an idle state AND cause the DSStateMachine to transition to a new state (this is the big problem with your current code).

I will give this a try in my next iteration, good suggestion.

If, once DSStateMachine transitions to the Run state, the DSTimingMachine should transition through all of it's states over and over, then I have no idea what the heck presses is for, or why loop() allows presses to be incremented except when the DSStateMachine is in the Init state.

Presses and "listening" for a button press is supposed to allow for a reset in the middle of the shooting sequence. If, for example, I want to change the parameters and start over I wanted to have a way to use one button to start, and stop/reset the program, then start it again. I'm thinking about two buttons now though....one for start and one for stop/reset.

If, once DSStateMachine transitions to the Run state, the DSTimingMachine should transition through all of it's states over and over, then DSTiming_Interval (lousy name, by the way) should set DSTiming to 0, shouldn't it, rather than 1?

Is the name lousy because it's too long? Is it cleaner to use an acronym?

Thanks as always for your helpful suggestions Paul.