Go Down

Topic: Implementing a remote controlled "STOP" via an interrupt? (Read 615 times) previous topic - next topic

morecowbell001

Jan 11, 2013, 04:25 am Last Edit: Jan 11, 2013, 09:47 am by Coding Badly Reason: 1
Hello-
I'm fairly new the Arduino and looking for a small amount of code help to get me over this stumbing block- Please!

Here's what I'm trying to make:
1.An RF transmitter circuit with a START and STOP button to remote control a receiver
2.An RF receiver circuit that runs some servos, starting when it receives the RF "start" message and stopping via an interrupt whenever it receives an RF "stop" command.

The part I'm struggling with is the "stop" command. I don't know how to implement it in my code. Right now I've tried a while loop, but realized it only checks for that "stop" message at the beginning of the main routine.

Here is my RECEIVER code:

Code: [Select]
#include <VirtualWire.h>

int startLEDPin = 11;
int stopLEDPin= 12;
int runLEDPin = 4;

void setup()
{
 // initialize input and output remote pins
 pinMode(startLEDPin, OUTPUT);
 pinMode(stopLEDPin, OUTPUT);
 pinMode(runLEDPin, OUTPUT);
 digitalWrite(startLEDPin, LOW);
 digitalWrite(stopLEDPin, LOW);
 digitalWrite(runLEDPin, LOW);

 Serial.begin(9600); // Debugging only
 Serial.println("setup");

 vw_setup(1000); // Bits per sec- can go up to 2400
 vw_set_rx_pin(2);
 vw_rx_start();       // Start the receiver PLL running
}

void MainRoutine()
{
 digitalWrite(runLEDPin, LOW);
 delay(5000);  // this represents the main routine (motor) stuff
}

void ShutDown()
{
 digitalWrite(startLEDPin, LOW);
 digitalWrite(runLEDPin, LOW);
 digitalWrite(stopLEDPin, HIGH);
 delay(2000) // this represents the motor shutdown stuff
   digitalWrite(stopLEDPin, LOW);
}

void loop()
{
 uint8_t buf[VW_MAX_MESSAGE_LEN];
 uint8_t buflen = VW_MAX_MESSAGE_LEN;

 // beginning of RF check
 while (vw_get_message(buf, &buflen) && buf[0] != '1') {
 }
 // while msg is avail (good checksum or not) copy it to buffer and do nothing else

 while (vw_get_message(buf, &buflen) && buf[0] != '2')
 {
   // now that "1" was received (for START) do this stuff...
   digitalWrite(13, true); // Flash a light to show received good message
   // Message with a good checksum received, dump it.
   delay(500);
   digitalWrite(13, false);
   Serial.print("Got: ");  // take this out later
   Serial.print(buf[0]); // print the content of the msg recvd
   Serial.println("");

   MainRoutine();
 }

 // once "2" (for STOP) is received go into shutdown mode
 ShutDown();

 // then start over at the top waiting for another start button press
}



For reference, here is the TRANSMITTER code w/debounce check. It seems to be working o.k.:

Code: [Select]
#include <VirtualWire.h>

int startPin = 5;
int stopPin = 6;
int startLEDPin = 11;
int stopLEDPin= 12;
boolean lastStartButton = LOW;
boolean currentStartButton = LOW;
boolean lastStopButton = LOW;
boolean currentStopButton = LOW;

void setup()
{
 Serial.begin(9600);  // Debugging only
 Serial.println("setup");
 vw_setup(1000); // Bits per sec- can go up to 2400
 vw_set_tx_pin(3);


 // initialize input and output remote pins
 pinMode(startPin, INPUT);
 pinMode(stopPin, INPUT);
 pinMode(startLEDPin, OUTPUT);
 pinMode(stopLEDPin, OUTPUT);

 digitalWrite(startLEDPin, LOW);
 digitalWrite(stopLEDPin, LOW);
}

boolean debounceStart(boolean lastStart)
{
 boolean currentStart = digitalRead(startPin);   // determine the current value of the START switch
 if (lastStart != currentStart)                        // if switch changed states, delay by 5 ms so switch can stop debouncing
 {
   delay(5);
   currentStart = digitalRead(startPin);         // read it again after 5 ms
 }
 return currentStart;                             // return the value of the switch read after the 5 ms delay
}

boolean debounceStop(boolean lastStop)
{
 boolean currentStop = digitalRead(stopPin);   // determine the current value of the STOP switch
 if (lastStop != currentStop)                        // if switch changed states, delay by 5 ms so switch can stop debouncing
 {
   delay(5);
   currentStop = digitalRead(stopPin);         // read it again after 5 ms
 }
 return currentStop;                             // return the value of the switch read after the 5 ms delay
}

void loop()
{
 char *msg;

 lastStartButton = LOW;   // reseting if this isn't the first loop
 currentStartButton = LOW;   // reseting if this isn't the first loop
 lastStopButton = LOW;   // reseting if this isn't the first loop
 currentStopButton = LOW;   // reseting if this isn't the first loop

 // START of routine for transmitting message
 currentStartButton = debounceStart(lastStartButton); // run debounce function, pass it LastButton
 if(lastStartButton == LOW && currentStartButton == HIGH) // if START button actually changed, do stuff below
 {
   char *msg = "1";    // a message sent of "1" means START
   lastStartButton = currentStartButton;  // resetting the last stop back to the current state
   digitalWrite(startLEDPin, HIGH);
   digitalWrite(13, true); // Flash a light to show transmitting
   vw_send((uint8_t *)msg, strlen(msg));
   vw_wait_tx(); // Wait until the whole message is gone
   digitalWrite(13, false); // Turn off light after transmission
   digitalWrite(startLEDPin, LOW);
 }

 currentStopButton = debounceStop(lastStopButton);  
 if(lastStopButton == LOW && currentStopButton == HIGH)  // if STOP button actually changed, do stuff below
 {
   char *msg = "2";  // a message sent of "2" means STOP
   lastStopButton = currentStopButton;  // resetting the last stop back to the current state
   digitalWrite(stopLEDPin, HIGH);
   digitalWrite(13, true); // Flash a light to show transmitting
   vw_send((uint8_t *)msg, strlen(msg));
   vw_wait_tx(); // Wait until the whole message is gone
   digitalWrite(13, false); // Turn off light after transmission
   digitalWrite(stopLEDPin, LOW);
 }

 // END of routine for transmitting message

}



Moderator edit: [code] [/code] tags added.

Boffin1

Quote
it only checks for that "stop" message at the beginning of the main routine.


it looks like it checks each loop,  main routine is a bit of a confusing name for routine.

As soon as you "start", you have got a half second delay ( delay 500 ) before it can even check for a stop signal,  ( which might be why you are thinking of an interrupt? )

Have a look at blink without delay in the examples, and rather use that for your signalling LEDs.

The loop can carry on all the time, and the interrupt would only work once you have received and identified the "stop"  command from the receiver anyway, so I dont think you need the interrupt if you get rid of the delays.
With my mobile phone I can call people and talk to them -  how smart can you get ?

morecowbell001

Thanks Boffin1- I should clarify that I only want the "loop" to run through once, at which point it is basically done (and wait to be reset.  My code probably doesn't make that at all clear.

The "MainRoutine", as I've poorly called it, will run some servos and will likely last 10-15 seconds. During that time, I'm basically looking for an emergency stop capability via an RF signal from my transmitter.  Since I'm really looking for the ability to stop at any point during a single 10-15 sec run of the "loop", I thought that I needed to use an interrupt function. 

Having clarified that, do you have any additional advice?

Boffin1

#3
Jan 11, 2013, 05:45 am Last Edit: Jan 11, 2013, 05:49 am by Boffin1 Reason: 1
Right I see what you want now, but you are not checking the receiver while you are running your motors.

You have several seconds delay there, but I dont know if that would represent whatever your motor routine does - i.e. not coming back to the main loop ?

I have used the old faithful HT12E and D    encoder / decoder chips for remote controls in the past,  and the decoders VT  ( valid transmission ) output goes high, which I have connected to the inturrupt ( RISING )

You could use the actual stop signal from the decoder chip but I seem to recall it stays high?

The interrupt service routine could check if the stop pin is also high and call shutdown perhaps.

BTW  when you post code, select the code and hit the # button above.
With my mobile phone I can call people and talk to them -  how smart can you get ?

PeterH


stopping via an interrupt whenever it receives an RF "stop" command.


You don't need or want an interrupt for this. You just need to design your sketch so that it continues to handle incoming messages while it is carrying out the action sequence.
I only provide help via the forum - please do not contact me for private consultancy.

morecowbell001

Thanks guys- I have tried the encoder/decoder chips, but I wanted to eliminate them and just use VirtualWire and an Arduino on both ends, which works to send the messages... just not sure how to react to those messages.

PeterH- thank you for the reply. I'm very intrigued into how to do this. Can you tell me what code I would need to continue to handle incoming messages while it is carrying out the action sequence?  Or point me in the direction of any example of this?

Thanks again!


PeterH


PeterH- thank you for the reply. I'm very intrigued into how to do this. Can you tell me what code I would need to continue to handle incoming messages while it is carrying out the action sequence?  Or point me in the direction of any example of this?


Design your sketch so that it does not ever need to stop and wait for time to pass or an event to happen. The 'blink without delay' example sketch shows you how to do this for timed actions. Essentially, instead of your logic being carried out by a chunk of code that does each thing in sequence and stops and waits until it's necessary to do the next thing, you turn the structure inside out so that there is a single piece of code which is executed repeatedly which tests for things it may need to do.

For example, if you need to handle commands from a serial port your code would check whether there were any characters waiting to be read; if there were, it would read and buffer them. If the buffer contains a complete message ready to be processed then it would call the code to process it.

If the code needs to flash an LED it works out whether it is time to turn the LED on or off and if so does it - and if it's not time yet, it does nothing and carries on.

If your code needs to move a servo through a defined path at a specified speed, it tests whether it's time to adjust the servo position yet and if so moves the servo to the next position.

When you structure your code using this non-blocking approach, you can handle events from any source in any order at any time. If you receive a command that tells you to abort some action that was in progress, you just update the state to show that the activity is no longer in progress.
I only provide help via the forum - please do not contact me for private consultancy.

morecowbell001

Ah!  I get it now. Thanks guys for that example!

Ok... that means that I have a lot of reconfiguring of the code to do, but I get it.  I looked over the blinking without delay example and understand the concept. I'll have to look for an example of a similar non-blocking code that has some more inputs and outputs so I can better understand how to translate my code into that.  I'll dig around.  If anyone has any good examples of this type of thing, please let me know.

Go Up