So I'm building a macro game controller, my intent is that I push a button and the Arduino will run through a macro sequence, ideally I'd like to be able to push the button a 2nd time to immediately stop the macro even if it hasn't completed. pushing it a 3rd time would start the macro sequence back at the beginning again.

I've got the hardware side complete and confirmed working.I wrote a small program that turns an LED on and off via an interrupt and then I wrote another one that runs through my sequence as part of the main loop, both of those worked great (and confirmed that my hardware is setup properly) but I'm having problems now that I'm trying to combine them.

Initially when I tried running my macro sequence via an interrupt it would just skip over the calls to "delay" so I swapped that out for a manual calculation of delay using millis() but I can't seem to get that working and I don't know why. I would appreciate any help or advice.

You can't use delay() in an interrupt, and you should not be trying to. Interrupts are designed for things that happen very quickly, and your replay sequence does not happen very quickly.

I suggest you restructure your code into two parts:

A function to poll the switch input state, do any debouncing necessary and detect button transitions (up to down). Use this to toggle the state of your sketch between 'replay running' and 'replay not running'. The function should not call delay() or do anything that would prevent it returning promptly. Call this function once in loop().

A function which is called repeatedly while the replay is running. It should use the techniques demonstrated in 'blink without delay' (and also used in your current interrupt handler) to decide whether it is time to perform the next output action, and perform it if so. This function should be called once in loop() if the state is 'replay running'.

I only provide help via the forum - please do not contact me for private consultancy.

My only questions now are: Is there a more elegant way to do what I'm doing between each step in the doStuff function?

I'm interested in loading in the sequence from a separate file and ideally programming the state of all 12 outputs plus the delay time in a single line for ease of reading... I have some ideas but I don't like any of them any suggestions on the best way to go about this?

byte state = HIGH; // The macro state 0=running 1=stoppedbyte lastButtonState = HIGH; // The go button state toggle 0=depressedunsigned long lastPushTime = 0; //the milliseconds since the last time the button was pushedunsigned long currentMillis = 0; //get the delay start time in millisecondsunsigned long previousMillis = 0; //get the current time in milliseconds

// the loop routine runs over and over again forever:void loop() { checkPushed(); //check if the button was pushed if (!state){ //if the state is set to run doStuff(); //run the sequence state = HIGH; //reset the state so we don't run again } allClear(); //set all the outputs to the starting position}

// the interrput routine run with the go button is pushedvoid checkPushed(){ byte buttonState = digitalRead(Go); if (lastButtonState && !buttonState){ unsigned long pushTime = millis(); //check the time

// If pushed again within 60ms, assume it's a bounce and ignore if (pushTime - lastPushTime > 60){ state = !state; //change state lastPushTime = pushTime; //set the last check time } } lastButtonState = buttonState;}

// check for the button pushvoid myDelay(unsigned long interval){ currentMillis = millis(); //get the current time previousMillis = currentMillis; //get the start time while (currentMillis - previousMillis < interval){ //loop until the desired delay is reached currentMillis = millis(); //get the current time checkPushed(); //check if the button has been pushed if (state){ //if the button push triggered a state change return; //exit the delay function } }}

// the output sequence routinevoid doStuff(){ digitalWrite(Up, LOW); //start of first step in the sequence myDelay(1000); //continue running step while checking for a state change if (state){ //if there was a state change return; //quit the sequence } digitalWrite(Up, HIGH); //end of first step in the sequence

Is there a more elegant way to do what I'm doing between each step in the doStuff function?

I don't know about more elegant, but state is not a boolean. It should be, it you are going to use it as such. It should be assigned the values true or false. It should also have a better name, like stuffToDo. It should also be assigned the correct values at the correct times.

so I found another project that used an external file to separate the logic from the macro and it seems to work very well but now I'm having a weird bug....

So when I run my old "doStuff" function everything works great, I get a low signal on each output one at a time each for 1 second.

when I run my new function instead, which loops through an array and should be doing the exact same thing as "doStuff" the pin for pin_B, and pin_X don't work... I also sometimes get pin_X flashing low along at the same time I loop to the next step (just a quick low back to high, rather than staying low for the full 1 second).

I'm sure it's not the hardware since this doesn't happen on doStuff, Also I'm outputting the raw data that I'm processing to serial and everything seem to be correct.... I'm at a loss as to why this is happening

byte state = HIGH; // The macro state 0=running 1=stoppedbyte lastButtonState = HIGH; // The go button state toggle 0=depressedunsigned long lastPushTime = 0; //the millis since the last time the button was pushedunsigned long currentMillis = 0; //get the start timeunsigned long previousMillis = 0; //get the current time

// the loop routine runs over and over again forever:void loop() { checkPushed(); //check if the button was pushed if (state == LOW){ //doStuff(); runSeq(); allClear(); state = HIGH; }}

// the interrput routine run with the go button is pushedvoid checkPushed(){ byte buttonState = digitalRead(pin_Go); if (lastButtonState == HIGH && buttonState == LOW){ unsigned long pushTime = millis(); //check the time

// If pushed again within 60ms, assume it's a bounce and ignore if (pushTime - lastPushTime > 60){ state = !state; //change state lastPushTime = pushTime; //set the last check time } } lastButtonState = buttonState;}

// check for the button pushvoid myDelay(unsigned long interval){ currentMillis = millis(); //get the current time previousMillis = currentMillis; //get the start time while (currentMillis - previousMillis < interval){ //loop until the start time plus the desired delay is reached currentMillis = millis(); //get the current time checkPushed(); if (state){ return; } }}

void runSeq(){ unsigned long seq = 0; Serial.begin(9600); for(int i=0; i<sizeOfSeq; i++){ //loop through each step in the sequence seq = pgm_read_dword(&(steps[i])); //reads the steps from the included file