Go Down

Topic: serialEvent function, Interrupt driven or not? (Read 25540 times) previous topic - next topic

StanK

Hello,

I am trying to figure out if serialEvent is interrupt driven. It doesn't say in the reference if it is or not. There is no initializing in setup. I am not sure how to use it. I would like to interrupt when serial data is available rather than sitting in a loop waiting with Serial.Available. I have tried it and it doesn't seem to do anything.

StanK

majenko

In main.cpp in the arduino core:

Code: [Select]

int main(void)
{
    init();

#if defined(USBCON)
    USBDevice.attach();
#endif

    setup();

    for (;;) {
        loop();
        if (serialEventRun) serialEventRun();
    }

    return 0;
}

As you can see from that, any serial events are processed at the termination of each iteration of the loop() function.  It's not interrupt driven.

You can only reliably use the serial events if your loop() function doesn't run for too long (and certainly not if loop() never returns), so never ever use delay() unless you have modified your system to give the serial system a huuuuuge buffer.

StanK


aarondc


In main.cpp in the arduino core:

Code: [Select]

int main(void)
{
    init();

#if defined(USBCON)
    USBDevice.attach();
#endif

    setup();

    for (;;) {
        loop();
        if (serialEventRun) serialEventRun();
    }

    return 0;
}

As you can see from that, any serial events are processed at the termination of each iteration of the loop() function.  It's not interrupt driven.

You can only reliably use the serial events if your loop() function doesn't run for too long (and certainly not if loop() never returns), so never ever use delay() unless you have modified your system to give the serial system a huuuuuge buffer.


Interesting. The documentation I read somewhere just says it gets called after loop(). (!!) I have been using it to check for and process serial data, and did not realise it only gets called if there is serial data available.

Interesting.

Thanks for the question, OP.

AWOL

Quote
and did not realise it only gets called if there is serial data available.

It doesn't - it is always called after "loop"

majenko

serialEventRun() is called after every loop, but it then checks the availability of serial data and calls the serialEvent() function only if needed:

Code: [Select]

void serialEventRun(void)
{
#ifdef serialEvent_implemented
  if (Serial.available()) serialEvent();
#endif
#ifdef serialEvent1_implemented
  if (Serial1.available()) serialEvent1();
#endif
#ifdef serialEvent2_implemented
  if (Serial2.available()) serialEvent2();
#endif
#ifdef serialEvent3_implemented
  if (Serial3.available()) serialEvent3();
#endif
}

PaulS

Quote
It doesn't - it is always called after "loop"

Code: [Select]
void serialEventRun(void)
{
#ifdef serialEvent_implemented
  if (Serial.available()) serialEvent();
#endif
#ifdef serialEvent1_implemented
  if (Serial1.available()) serialEvent1();
#endif
#ifdef serialEvent2_implemented
  if (Serial2.available()) serialEvent2();
#endif
#ifdef serialEvent3_implemented
  if (Serial3.available()) serialEvent3();
#endif
}

The serialEventRun() method is always called. The user-supplied serialEvent() method is only called if there is some serial; data to process.
The art of getting good answers lies in asking good questions.

majenko


aarondc


Quote
and did not realise it only gets called if there is serial data available.

It doesn't - it is always called after "loop"


I'm talking about SerialEvent - the topic of the thread. It isn't always called after "loop".

OldRick

It would be interesting to learn more how this feature works. My ambitions with the AVR micros are to create a slave terminal device on linux that purely runs in command mode. And the ArduinoUno with the VirtualSerialPort interface is a perfect fit. I wrote an assembler program a few years ago using the Atmel stk500 listed here; http://www.sytekcom.com/eng/eAVR_Command_Interpreter.asm.html
I can understand why standalone robots want parallel tasking, and scheduling, but old fashioned linear command/return script programming is solid.
I saw the headers and main.cpp, and really can't figure out what the uploaded assembler code might be doing.
Glad others are confused too.

flodis

The /Tutorial/SerialEvent documentation makes explicit calls to serialEvent from loop. Looks like that call is not needed.

westfw

Quote
It's not interrupt driven.
The Serial port itself continues to be interrupt driven, but SerialEvent() is not called from interrupt level.
(which is a really good thing.)

The current Tutorial example is really stupid, IMO.

SerialEvent gives you "baby multitasking."  You have the "loop" task, and you have the "serialEvent" task(s) that only gets called when there has been Serial data received.   If you are reading sensors and controlling stuff in loop(), you could put a command/response function in SerialEvent so that you could "check" on things in the event code without interfering with the logic of loop()   As long as "commands" are infrequent and short (fit in the serial ISR buffer: usually 64 bytes), you can even do significant delay() calls in your loop.

Here's a slighly less silly example.  "Blink with Serial Event."   A typical "Blink" program, with a serialEvent handler added to modify or report on the state of blinking...

Code: [Select]
/*
  Blink with SerialEvent
  by WestfW: released to the public domain
  This demonstrates the use of serialEvent to implement a command "add-on"
  to a simple "Blink" sketch.
*/

byte ledstate = 0;
static const byte LED = 13;

void setup() {
  pinMode(LED, OUTPUT);
  Serial.begin(9600);
}

/*
 * loop() blinks the LED by complementing the current state and writing the result, and then
 * delaying for a second.  A trivial process, and not at all encumbered by having to deal with
 * the serial port.
 */
void loop() {
  ledstate = ! ledstate;  // Complement the LED state
  digitalWrite(LED, ledstate);  // write the new value.
  delay(1000);
}

/*
 * seralEvent will be called whenever there is traffic on the serial port.  We read what is
 * expected to be a command, and can report on and/or modify the program state used in loop
 */
void serialEvent()
{
  switch (Serial.read()) {  // read a character
    case '0':  //  0 means turn the LED off
      Serial.println("turning off LED");
      ledstate = 1;  // gets complemented in loop()
      break;
    case '1':  // 1 means turn it on
      Serial.println("Turning on LED");
      ledstate = 0;
      break;
    case 's':  // S means report the current/next status
    case 'S':
      Serial.print("Current LED state: "),
                   Serial.print(ledstate);
      if (ledstate)
        Serial.println(".  LED will be OFF next");
      else
        Serial.println(".  LED will be ON next");
      break;
    default:  // all other commands are ignored.
      Serial.println("Bad Command");
  }
  while (Serial.read() >= 0)
     ; // flush any extra characters
}

Robin2

serialEvent() is the exact equivalent of this
Code: [Select]
void loop() {

    // other code

    if (Serial.available() > 0) {
         mySerialFunction();
    }
}


You may be interested in Serial Input Basics

...R
Two or three hours spent thinking and reading documentation solves most programming problems.

-dev

Quote
You may be interested in Serial Input Basics
...or the truly interrupt-driven NeoHWSerial, NeoICSerial and NeoSWSerial.  They're just slightly-modified versions of our favorites, HardwareSerial, AltSoftSerial and jboyton's efficient version of SoftwareSerial.

Cheers,
/dev
Really, I used to be /dev.  :(

Robin2

...or the truly interrupt-driven
Are they alternatives to the code in Serial Input Basics?

Or are they alternatives to SoftwareSerial and could/should be used in conjunction with my code?

...R
Two or three hours spent thinking and reading documentation solves most programming problems.

Go Up