Pages: [1]   Go Down
Author Topic: Serial Interrupt from RX pin  (Read 1926 times)
0 Members and 1 Guest are viewing this topic.
0
Offline Offline
Jr. Member
**
Karma: 0
Posts: 55
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi,

I am currently doing some software interfacing with arduino.
As there are no physical buttons/switches involved, how can I produce an interrupt to the program?

My program is big, and it has lots of loops and, yes. delays. So interrupt is really needed. (but without pressing any physical switches)
Here's the code for the interrupt

Code:
#include <avr/interrupt.h>

//volatile int bumper;          // have we hit something

void setup(){
 Serial.begin(9600); 
  pinMode(2, INPUT);      // Make digital 2 an input
   
    // attach our interrupt pin to it's ISR
    attachInterrupt(0, bumperISR, CHANGE);
    // we need to call this to enable interrupts
    interrupts();
}

// The interrupt hardware calls this when we hit our left bumper
void bumperISR(){

  //  bumper = 1;
     Serial.println("interrupt!");
 

}

void loop(){
    // if bumper triggered
    /*if(bumper > 0){
       Serial.println("tadaaa");   
       delay(5000);           
       bumper = 0;
    }*/
      Serial.println(millis());
      delay(10997);
   
    // we could do lots of other stuff here.
}

If using this physical interrupt (using switch), it's a success. I've tried to hook the interrupt pin (digital pin 2 of Mega) to the RX pin.
so that, when I print some text, it will blink and trigger the the attachInterrupt(0, bumperISR, CHANGE). (it will repeat the interrupt twice, as the status will be low> high > low.

But as usual, all my serial input to the arduino will be corrupted. (I will be sending some string starting with '<' and end with '>'. e.g  <ms1-1> so that the arduino will recognize this string, and turn on/off something.

Any ideas?

Thank you.
Logged

0
Offline Offline
Sr. Member
****
Karma: 2
Posts: 360
I'm 15. I like making things. I like breaking things better.
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I guess I don't understand what you are asking. What do you want to trigger the interrupt? What does your code do? Can you please post it?

EDIT: Is it that you want to have an interrupt trigger when you receive serial data? Unfortunately, because serial itself is interrupt driven, it is unwise to assign a seperate interrupt to it. I think you are better just checking for serial at various times in your code.
« Last Edit: February 28, 2011, 06:06:05 pm by bilbo » Logged

Alice asked the Chesire Cat, who was sitting in a tree, "What road do I take?"
The cat asked, "Where do you want to go?"
"I don't know," Ali

0
Offline Offline
Jr. Member
**
Karma: 0
Posts: 55
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

My code, usually will listen to the serial line for an action and execute few patterns.
first, it will listen any start string which starts with '<' and end with '>'.

There are few patterns that involved the usage of 'delay', so i really need the interrupt to make sure,
like an example, when I'm running pattern 1, then suddenly when I click pattern2 on my vb application, it will listen and executes directly.

The patterns are situated in 345();  and 123(); subroutines.


here are some details of the code.

Code:

//*********** START LOOP FUNCTION********
//----WILL BE REPEATED THROUGHOUT THE PROCESS
void loop() {
  inByte=0;
  inByte = Serial.read();
  string_len=0;  // clear the array of inByte
  if (inByte == '<'){
    read_serial();  // If Start of line ("<") is found, call read_serial() function
  }
  checkbuttonstate();
}
//*********** END LOOP FUNCTION********


//*********** START CHECK BUTTON STATE SUBROUTINE********
void checkbuttonstate(){

  
  if(buttautostate==0 && buttmanstate==1)  // manual mode
  {  
  if(buttmode1==1 && buttmode2==0  && buttmode3==0){   // check for song mode position
    123();                          //play 123 dialog
    345();
    buttmode1=0;  // clear back status
    }
  
   if(buttmode1==0 && buttmode2==1 && buttmode3==0){  //play mission impossible song
   missionimpossiblesequence();
   buttmode2=0;  //clear back status
   }
  
  if(buttmode1==0 && buttmode2==0 && buttmode3==1){  //play blue danube song
     repeatbluedanube();    `                                                                          
     endbluedanube();
     buttmode3=0; //clear back status
  }
  }
    
  return;
}
.........................................

//*********** END CHECK BUTTON STATE SUBROUTINE********


void read_serial()  // FUNCTION FOR READING THE SERIAL MESSAGE
{
    
   Serial.println("processing");  
   while (inByte!= '>') // As long as end string not found, keep reading until 'break' found. break does not work with 'if'  
   {
    if (Serial.available() > 0) // if new data is available, repeat this loop until Serial.available= 0
        {
          
         if(Serial.available()>1){
          inByte = Serial.read(); // Read new byte
           //Serial.print("READ : "); // Display the new byte
           stringx[string_len] = inByte; // Save the data in a character array
          // Serial.println(string[string_len]); // Print the characters that was recieved. -1 so that we would not read the '>' end string
           string_len++;  //add array  
         }
    
        
         if(Serial.available()==1){   // if serial is on the last bit. receiving '>'
          inByte=Serial.read(); // Read new byte. make it overflow as we dont want to save '>' in string.
            
       }  
      }
  
 
          
    else if (Serial.available() == 0)    // if serial buffer has all been read, and still '>' does not found, execute this line
          {
           //Serial.println("end string not available, data string invalid"); // If end string not in the string
          // Serial.println("$N"); //print FAIL SIGNATURE
           Serial.flush(); // clear the serial buffer before reading new data
           memset(stringx, 0, sizeof(stringx));  // clear the memory array
           break;    // get out of the while loop  
           }
   }

  

 if (inByte == '>')   //only execute the command if the end string '>' found
  {
   //*******  START PUMP STATUS CHECKING
 
   if (strcmp(stringx, "mp-1")  == 0){  // test to see if the two strings are equal
       mainpmpsw_on();
       Serial.println ("main pump is on");   //put a new line
      // blinkLED(ledPin, 2, leddelay);
    }

..............// end checkbuttonstate


void read_serial()  // FUNCTION FOR READING THE SERIAL MESSAGE
{
    
   Serial.println("processing");  
   while (inByte!= '>') // As long as end string not found, keep reading until 'break' found. break does not work with 'if'  
   {
    if (Serial.available() > 0) // if new data is available, repeat this loop until Serial.available= 0
        {
          
         if(Serial.available()>1){
          inByte = Serial.read(); // Read new byte
           //Serial.print("READ : "); // Display the new byte
           stringx[string_len] = inByte; // Save the data in a character array
          // Serial.println(string[string_len]); // Print the characters that was recieved. -1 so that we would not read the '>' end string
           string_len++;  //add array  
         }
    
        
         if(Serial.available()==1){   // if serial is on the last bit. receiving '>'
          inByte=Serial.read(); // Read new byte. make it overflow as we dont want to save '>' in string.
            
       }  
      }
  
 
          
    else if (Serial.available() == 0)    // if serial buffer has all been read, and still '>' does not found, execute this line
          {
           Serial.flush(); // clear the serial buffer before reading new data
           memset(stringx, 0, sizeof(stringx));  // clear the memory array
           break;    // get out of the while loop  
           }
   }

  

 if (inByte == '>')   //only execute the command if the end string '>' found
  {
   //*******  START PUMP STATUS CHECKING
  /*
   if (strcmp(stringx, "ms-1")  == 0){  // test to see if the two strings are equal
       mainsw_on();
       Serial.println ("main switch is on");   //put a new line
      // blinkLED(ledPin, 2, leddelay); // blinkLED(ledPin, times, delay);
    }
  
   if (strcmp(stringx, "ms-0")  == 0){  // test to see if the two strings are equal
       mainsw_off();
       Serial.println ("main switch is off");   //put a new line
       //blinkLED(ledPin, 2, leddelay);
    }
  */
   if (strcmp(stringx, "mp-1")  == 0){  // test to see if the two strings are equal
       mainpmpsw_on();
       Serial.println ("main pump is on");   //put a new line
      // blinkLED(ledPin, 2, leddelay);
    }
................ end void serial read



void 123(){
  
  //print welcome screen first
   printwelcomelcd();
  
   //set delay for starting
   delay(3000);
  
   //play introduction to 123 - signal low  
   digitalWrite(7, LOW);  
  
  // delay for 123 dialog to play
  delay(17000);   //123 dialog finished
  
   //set 123 dialog trigger pin off - signal high
  digitalWrite(7, HIGH);  
  return;
}
//*********** END 123 SUBROUTINES ********





« Last Edit: February 28, 2011, 07:42:45 pm by aminbahar » Logged

Seattle, WA USA
Offline Offline
Brattain Member
*****
Karma: 601
Posts: 48543
Seattle, WA USA
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Code:
   else if (Serial.available() == 0)    // if serial buffer has all been read, and still '>' does not found, execute this line
          {
           //Serial.println("end string not available, data string invalid"); // If end string not in the string
          // Serial.println("$N"); //print FAIL SIGNATURE
           Serial.flush(); // clear the serial buffer before reading new data
           memset(stringx, 0, sizeof(stringx));  // clear the memory array
If there is no serial data to read, there is nothing to flush.

It is not necessary to NULL every element in the char array. Simply put a NULL in the 0 position. Every time you add a character, add a NULL, too.

The code for 345() was not include, but the code in 123() just screams for using millis() and following the lead of the blink without delay example.

Then, the whole idea of needing an interrupt to get the controllers attention goes out the window.  There is even a TimedAction library that you might want to look at.
Logged

Saint Petersburg, Russia
Offline Offline
Full Member
***
Karma: 2
Posts: 105
Amateur
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

But as usual, all my serial input to the arduino will be corrupted. (I will be sending some string starting with '<' and end with '>'. e.g  <ms1-1> so that the arduino will recognize this string, and turn on/off something.

You may use "software" interrupts for this.
http://www.arduino.cc/en/Reference/AttachInterrupt

The HardwareSerial class doesn't use USART_RX_vect interrupt, so if your sketch should receive data from USART while other code is executing, you should add this feature manually instead using Serial class.
Read uC datasheet for USART code examples and HardwareSerial source code to learn how it works, then write your own USART receiver code.
http://www.atmel.com/dyn/resources/prod_documents/doc8161.pdf
Logged

0
Offline Offline
Jr. Member
**
Karma: 0
Posts: 55
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Pauls, the 345 subroutine will look like this. (still there are delay), and I will be looping through all these kind of patterns throughout the program.



Code:
void 345() {
  //start cycle pattern
  for(int pin=nozz1; pin<=nozz5; pin++)
  {
    ledallredon();
    digitalWrite(nozz1, LOW);
    digitalWrite(pin, HIGH);   // set the valve on
    delay(180);    // delay
    digitalWrite(pin, LOW);    // set the LED off
    delay(180);                  // delay
  } 

 
  for(int pin=nozz1; pin<=nozz5; pin++)
  {
    digitalWrite(nozz1, LOW);
    digitalWrite(pin, HIGH);   // set the valve on
    delay(180);    // delay
    digitalWrite(pin, LOW);    // set the LED off
    delay(180);                  // delay
  } 
  ledalloff();
  return;
}


The main reason there is some long delay, is in the subroutine 123, I will be turning on waveshield module.
During this time, it will stay in that loop, and wait until the mp3 finished playing.

TimedAction, will it act similar to delay? but without stopping the program?

Logged

0
Offline Offline
Jr. Member
**
Karma: 0
Posts: 55
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

@Vanyamba,

Is it like this?

Code:
#include <avr/interrupt.h>

//volatile int bumper;          // have we hit something

void setup(){
 Serial.begin(9600); 
  pinMode(2, INPUT);      // Make digital 2 an input
   
    // attach our interrupt pin to it's ISR
    attachInterrupt(0, bumperISR, CHANGE);
    // we need to call this to enable interrupts
    interrupts();
}

// The interrupt hardware calls this when we hit our left bumper
void bumperISR(){

  //  bumper = 1;
     Serial.println("interrupt!");
 

}

void loop(){
    // if bumper triggered
    /*if(bumper > 0){
       Serial.println("tadaaa");   
       delay(5000);           
       bumper = 0;
    }*/
      Serial.println(millis());
      delay(10997);
   
    // we could do lots of other stuff here.
}

How I should connect the RX pin to the interrupt pin?
As I've tried direct connect it, and the interrupt does not read my serial.read properly. (or maybe, nothing).

Any diagram on how I can make this happen?
Logged

0
Offline Offline
Jr. Member
**
Karma: 0
Posts: 55
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

any updates?
Logged

Saint Petersburg, Russia
Offline Offline
Full Member
***
Karma: 2
Posts: 105
Amateur
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

@Vanyamba,

Is it like this?

Slightly more difficult.

How I should connect the RX pin to the interrupt pin?

You sure you need interrupts. But you can't use them. Maybe this task can be resolved without interrupts.

Any diagram on how I can make this happen?

I like diagrams, it's true.
Logged

UK
Offline Offline
Full Member
***
Karma: 2
Posts: 110
Kittens eat Arduinos
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

The HardwareSerial implementation (.cpp) does use the RX interrupt, and puts the received data in a ring buffer for the sketch to read later...

Even if you modified the HardwareSerial implementation to call one of your functions when it copied '>' into the ring buffer (which is not hard to do, but does create a mess that is hard to look after as new versions of the Arduino software are released) there is still the problem that you are using humungous delay()s in your code.

If you delay(10000) in your code, then the sketch can not respond sensibly to the command for 10 seconds!

If you really want to keep the structure of the code relatively unchanged you need to do something like
Code:
static char cmd_i = 0 ;
define CMD_L 10
static char cmd[CMD_L] ;

void
checkSerial(void)
{
    if (Serial.available())
    {
        char ch ;
        if (cmd_i >= CMD_L)
            cmd_i = 0 ;
        cmd[cmd_i++] = ch = Serial.read() ;
        if (ch == '>')
            checkCommand() ;
    }
}

static bool abortDelay = false ;
void
my_delay(int n)
{
   abortDelay = false ;
   long end = millis() + n ;
   while (end > millis())
   {
       checkSerial() ;
       if (abortDelay)
           return ;
   }
}


then call my_delay() rather than the normal one.
Logged

0
Offline Offline
Jr. Member
**
Karma: 0
Posts: 55
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

@dafid,

That looks like a good option.

Meaning, rather than just delay, we will use my_delay()  which will check for the serial every single loop.


By the way,

I would like to ask, how does the delay or milis works?

Does

Code:
delay(1000);

would be same as

Code:
for(int i=0;i<1000;i++){
...}

Does every single line execution resembles '1'?

Any reading details that I can go through to understand this more?

EDIT:  another thing,

what this code does:
Code:
static bool abortDelay = false ;

Thank you.
Logged

Pages: [1]   Go Up
Jump to: