Go Down

Topic: Button triggered Macro, problems with interrupt and delay (Read 1 time) previous topic - next topic

twistedsymphony

Dec 28, 2012, 04:45 pm Last Edit: Dec 28, 2012, 05:14 pm by twistedsymphony Reason: 1
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.

Here is my sketch:

Code: [Select]
/*
SNES Controller Test
presses each of the buttons on the controller when the go button is pushed
should also stop the sequence if the go button is pushed a second time
*/

//set names for the output pins
int A = 4;
int B = 0;
int X = 1;
int Y = 2;

int R = 12;
int L = 7;

int Select = 13;

int Up = 11;
int Down = 10;
int Left = 9;
int Right = 8;

int Go = 1; //interrupt 1 pin #3

volatile int state = HIGH; // The go button state toggle
unsigned long lastInterruptTime = 0; //set the interrupt counter

// the setup routine runs once when you press reset:
void setup() {
 // initialize the digital pins as an output.
 pinMode(A, OUTPUT);
 pinMode(B, OUTPUT);
 pinMode(X, OUTPUT);
 pinMode(Y, OUTPUT);
 pinMode(L, OUTPUT);
 pinMode(R, OUTPUT);
 pinMode(Select, OUTPUT);
 pinMode(Up, OUTPUT);
 pinMode(Down, OUTPUT);
 pinMode(Left, OUTPUT);
 pinMode(Right, OUTPUT);
 
 //setup interrupt    
 attachInterrupt(Go, buttonPushed, LOW);
 
 //make sure everything is in the starting state that we want
 allClear();
}

//sets all outputs to off (high)
void allClear(){
 digitalWrite(Up, HIGH);
 digitalWrite(Down, HIGH);
 digitalWrite(Left, HIGH);
 digitalWrite(Right, HIGH);
 digitalWrite(A, HIGH);
 digitalWrite(B, HIGH);
 digitalWrite(X, HIGH);
 digitalWrite(Y, HIGH);
 digitalWrite(L, HIGH);
 digitalWrite(R, HIGH);
 digitalWrite(Select, HIGH);
}

// the loop routine runs over and over again forever:
void loop() {
wait();
}

// the interrupt routine run with the go button is pushed
void buttonPushed(){
 unsigned long interruptTime = millis(); //check the interrupt time
 
 // If interrupts come faster than 50ms, assume it's a bounce and ignore
 if (interruptTime - lastInterruptTime > 50){
   state = !state; //change state
   if (state){
     doStuff(); //run the sequence
   } else {
     allClear(); //clear the outputs
   }
   lastInterruptTime = interruptTime; //set the last interrupt time
 }
}

// my non "delay" delay routine
void myDelay(int interval){
 unsigned long previousMillis = millis(); //get the start time
 unsigned long currentMillis = millis(); //get the current time
 while (previousMillis + interval < currentMillis){ //loop until the start time plus the desired delay is reached
   currentMillis = millis(); //get the current time
 }
}

void wait(){
 myDelay(1000); // wait for 1 second
}

// the output sequence routine
void doStuff(){
 digitalWrite(Up, LOW);
 myDelay(1000);
 digitalWrite(Up, HIGH);
 digitalWrite(Down, LOW);
 myDelay(1000);
 digitalWrite(Down, HIGH);
 digitalWrite(Left, LOW);
 myDelay(1000);
 digitalWrite(Left, HIGH);
 digitalWrite(Right, LOW);
 myDelay(1000);
 digitalWrite(Right, HIGH);
 digitalWrite(A, LOW);
 myDelay(1000);
 digitalWrite(A, HIGH);
 digitalWrite(B, LOW);
 myDelay(1000);
 digitalWrite(B, HIGH);
 digitalWrite(X, LOW);
 myDelay(1000);
 digitalWrite(X, HIGH);
 digitalWrite(Y, LOW);
 myDelay(1000);
 digitalWrite(Y, HIGH);
 digitalWrite(L, LOW);
 myDelay(1000);
 digitalWrite(L, HIGH);
 digitalWrite(R, LOW);
 myDelay(1000);
 digitalWrite(R, HIGH);
 digitalWrite(Select, LOW);
 myDelay(1000);
 digitalWrite(Select, HIGH);
}

PeterH

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.

twistedsymphony

#2
Dec 28, 2012, 05:39 pm Last Edit: Dec 28, 2012, 05:42 pm by twistedsymphony Reason: 1
thanks! I'll give the restructuring a shot.

Though the "myDelay" function in my code above is modeled after the "blink without delay" program.

it doesn't seem to actually work though, I'm not sure why.

PeterH


thanks! I'll give the restructuring a shot.

Though the "myDelay" function in my code above is modeled after the "blink without delay" program.

it doesn't seem to actually work though, I'm not sure why.


Yeah, but it's not designed to be used inside an interrupt.
I only provide help via the forum - please do not contact me for private consultancy.

twistedsymphony

If I comment out the interrupt code and put my dostuff function in the main loop  it still doesn't work.

Go Up