2

I'll start telling that the reference on the function serialEvent is not very well documented for Arduino. https://www.arduino.cc/en/Reference/SerialEvent

Due to the lack of information I've misunderstood how this function works. As I have the Arduino Mega 2560 it comes with 4 Serial inputs/outputs, and they have their own serialEventX function (where X = {'',1,2,3}).

I've successfully communicated with a ESP8266 module, which sends and receives information once a client is connected to it.

Using the serialEvent1 (1 because it's connected to RX1 and TX1) I want serialEvent1 to be called only when data is incoming, but actually is called also whenever I use Serial1.write(msg), so this means when a message is being sent.

#define DEBUG_ESP8622 1
#include <esp8622.h>
#include <string.h>
#include "common.h"
#include <stdlib.h>
Wifi esp = Wifi(); //Here Serial1.begin(115200) happens
void setup() {
  Serial.begin(9600); //First of all SERIAL for debugging
  Serial.println("Starting");

  while(!esp.sReachable());   //Works
  Serial.println("ESP found");

  while(!esp.sSetMode(1));    //Works
  Serial.println("Mode set to Client");

  while(!esp.sConnect(WIFISSID,WIFIPASSWORD));  //Works
  Serial.println("Connected");
  Serial.print("IP:");
  Serial.println(esp.getIP());

  while(!esp.sStartServer(80));  //Works
  Serial.println("Server started");
}
void loop() {
    if(Serial.available()>0){
            int inByte=Serial.read();
            /*HERE whenever I call Serial1.write(inByte)
              serialEvent1 will be called at the end of the loop
              but actually I don't want it to
            */
            Serial1.write(inByte);
    }

}
void serialEvent(){
    return;
}
void serialEvent1(){
   Serial.println("Write or Read event?");
   while(Serial1.available()>0){
      int inByte=Serial1.read();
      //Serial.write(inByte);
   }
   //esp.onSerialEvent(); //Stores message and parses it, not relevant
   return;
}

So now, knowing that the Arduino libraries are based on the AVR libc libraries, I suppose that the RX1 and TX1 interrupts inside the microcontroller are binded both to serialEvent1 through Arduino libraries.

Is it possible to unbind only TX1 from serialEvent1 using the library and still be using Arduino libraries (Serial1.write()/read())?

I use the easiest way to upload code to the Mega using a Makefile. Opted to use arduino from command line because it suited my needs so far, I know avrdude and avr-gcc is a more complete or better way to compile/upload from command line, correct me if I'm wrong.

CC=arduino
upload: terminal.ino
    $(CC) terminal.ino --upload

verify: terminal.ino
    $(CC) terminal.ino --verify

Should I start learning how to use avrdude and avr-gcc instead if I start using ? (or maybe it has nothing to do with the fact of using AVR libraries)

And last, I'm using the above Makefile with an USB cable, If i use avrdude and avr-gcc is it through ICSP or can be still used through USB cable? will this erese the bootloader?

Many thanks

5
  • When serialEvent1() is called, is there data Serial1.available()? - You may want to change serialEvent1() to do while(Serial1.available()>0){ instead of if(.... Commented Jan 27, 2016 at 14:02
  • 1
    Plus, you also may want to check if the ESP8266 is configured to echo back your commands to you (ATE0/ATE1). Commented Jan 27, 2016 at 14:04
  • @HannoBinder, thanks for the pointing that out, changed it. About the ESP8266 echoing back, it doesn't, already checked it with the code mentioned here: arduino.cc/en/Tutorial/MultiSerialMega Commented Jan 27, 2016 at 15:08
  • @HannoBinder actually you are right, I was reading the NeoHWSerial code posted below and actually TX pin doesn't call serialEvent, my bad for not double checking about the ESP8266 echoing back, did it right this time and ATE0 solved the problem. Please post a reference to the AT commands, I was using this set link Commented Jan 30, 2016 at 10:53
  • @HannoBinder, please post the set of AT commands reference you use for the ESP8266, Commented Feb 1, 2016 at 14:01

1 Answer 1

0

Yes, the SerialEvent functions are silly. They are no different from polling them in loop. You can still lose data if you do something time-consuming and don't return to loop quickly enough. The solution is to attach to the RX interrupt, but that isn't supported by the built-in class, HardwareSerial.

I have posted modified versions of HardwareSerial that allow you to attach to the RX interrupt. It is called NeoHWSerial.

Because it is a replacement, you must use only the NeoSerial[#] variables. You can't use Serial and NeoSerial1 in the same sketch. Just use NeoSerial instead of Serial, even though you don't call NeoSerial.attachInterrupt:

void setup()
{
  NeoSerial.begin( 9600 );            // replaces `Serial.begin(9600)`
  NeoSerial.println( F("Started.") ); // ... and all your prints, too

  NeoSerial1.attachInterrupt( myRxFunction );
  NeoSerial1.begin( 9600 );

Remember that myRxFunction is called during the interrupt. You must be quick about handling each character, and don't call things that depend on not being in an interrupt, like print or even millis(). Bad juju!

And be sure the files in the matching IDE version subdirectory (e.g., 1.6.5r2) are copied to your libraries/NeoHWSerial subdirectory. Do not put them in libraries/1.0.5 or libraries/1.6.5r2

Sign up to request clarification or add additional context in comments.

3 Comments

In fact, the standard HW serial is interrupt-driven too. Received data is put into an RX buffer by the ISR to be retrieved in SerialEvent later. This buffering gives you more time to react because you won't lose data even if your loop takes e.g. 5 RX byte times before SerialEvent can run. Hence, if you don't need to react fast/asynchronously on an incoming byte, you're probably better off using the Arduino version.
I didn't say the standard HardwareSerial isn't interrupt driven. I said that SerialEvent is a polled function. SerialEvent is not called from the interrupt; it is called after you return from loop, and does not provide any benefit over just polling Serial from inside loop. Its name and usage implies that it is called asynchronously, but it really isn't. This is a source of confusion for many, as he stated. BTW, reaction time isn't the only criterion: other libraries' blocking time can cause the input buffer to overflow, losing data. Handling chars in the ISR might be the answer.
OTOH, in SerialEvent you can do more complex tasks, like parsing longer received messages, which may become awkward in an ISR. Depends on personal preference, I guess, but I favor the asynchronous approach, where processing of the data is not synchronous to reception. - I did however misunderstand your statement re polling, thinking you meant polling the serial port for single bytes instead of polling the rx buffer.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.