Detecting serial port connection on Leonardo

Dear all,

I would like my Arduino Leonardo self-detect whether it is connected to a serial port (its USB) or not - when it is, it should produce output to the serial terminal; when it isn't, it should ignore the serial output and just care about the electronics connected to the pins. I am only communicating from Arduino to serial, so not the other way around. I would like my code to work on other Arduino boards.

Ok so this is my first attempt at this... Leonardo needs the while(!Serial) {} line in the setup function to wait for serial port response. If I put this line in the code, the Leonardo will lock in its setup function. This can be solved adding a timeout detector, as in:

  serialstarttime = millis();
  while (!Serial) {
    if(millis()-serialstarttime > serialtimeout) {
      use_serial = false;
      break;
    }
  }

This is not ideal because the Leonardo is 'weird' about when the serial port is available and when it's not. I did some testing, here is an overview:
(1) If I load the sketch onto the Arduino, without opening the serial monitor, serial is not available;
(2) If I load the sketch onto the Arduino, with the serial monitor open, serial is available;
(3) I cannot open the serial monitor before connecting the Arduino. After connecting, I have 'serialtimeout' milliseconds to re-open the serial monitor. I know that this makes sense given the program, but it complicates things for the user - too much time is not ideal because it puts the leonardo on hold in the cases it is not connected.
(4) If the serial monitor is open, and I press the onboard reset button, serial communication is not available anymore.

I guess that especially (4) is unexpected for me. In any case, is there any other way to have Arduino detect whether it is connected or not without having my user rushing to open the serial monitor after connecting the leonardo to the usb port? I could put the while(!Serial) in the main loop, but it will lock each loop for 'serialtimeout' milliseconds.

Does anyone know of a more elegant solution?

Thanks,

Peter

Write a little sketch with:

void setup()
{
  Serial.begin(115200);
  pinMode(LED_BUILTIN, OUTPUT);
}

void loop()
{
   digitalWrite(LED_BUILTIN, !!Serial);
}

That should show on the built-in LED if the Serial port is available (ON) or not-available (OFF). Then you can experiment with plugging in, resetting, restarting Serial Monitor, etc.

You can use if(Serial) to make printing conditional.

Now the problem comes if the Leonardo was connected and you disconnect it while it's powered with e.g. 9V on the barrel. The Leonardo does not detect this disconnection and, as you observed, slows down when you try to print. The solution is to use Serial.availableForWrite() and check if there is enough space in the buffer for what you want to print.

Thank you! It blinks a few times, then stays on after a fresh reload (only if monitor already open), but reset button, connected, with monitor still open, or closed and re-opened, does not reconnect the serial monitor.
Just wondering: why the double '!' in '!!Serial'? Wouldn't "digitalWrite(LED_BUILTIN, Serial);" work?

Thanks - this is an excellent solution. Maybe there are cases in which serial communication is configured, at the other end, for sending only, so I tested
if(Serial.availableForWrite()+Serial.available()>0) use_serial = true; else use_serial=false;
This check only requires 4-8 microseconds.

You could try it but I think the "true if Serial is connected" only works when Serial is converted to a boolean. Since the argument to digitalWrite() is an 'int', I think you would get a compile error. The first '!' does a conversion to boolean (because it is a boolean operator) and the second '!' inverts the value so 'true' means connected and 'false' means not-connected.

I have some doubts that it is necessary to check Serial.available(). When you disconnect, you will never get data.

Note that Serial.availableForWrite() returns the number of bytes that you can still put in the buffer. If it only has space for 5 bytes and you try to send 6, it might already slow down the Leonardo.

So I would implement something like this (for text)

// serial data for sending
char serialData[32];
// some data to [rint
int x = random(1024);
// copy data
sprintf(serialData, "%d\r\n", x);

// check if there is enough space
if(Serial.availableForWrite() >= strlen(serialData))
{
  Serial.print(serialData);
}

On the Leonardo the usb serial connection is created in software .
When the Leonardo reboots the port “disappears” and is then “recreated “. It will be there but the PC may find it as a different COM port .

This may be part of your issue ?

If you use a NANO/ UNO this won’t happen

That is interesting. In my particular application, speed is less of an issue; I can keep serial communication in an 'outer loop'. The circuit is not much more than a few buttons, a voltage divider circuit to read a sensor, and an LCD screen. The idea is that the Arduino keeps track of the sensor value during the button press, then produces some statistics after the button is released. ADC conversion and button check needs to be in a rather tight loop, but showing the stats only needs to be as fast as a human can press and release a push button, a few times per second. If the Arduino is connected to the serial port, the stats (once per button press, not once ever ADC conversion) need to be shown on the serial port. If it's not connected, it only needs to show on the LCD screen, after an entire sequence of button presses. That is why the Serial.availableForWrite()>0 solution, without bothering about how many bytes exactly are available, is a good enough solution for me.