Hi, I am trying to control Arduino Mega 2560 through C++. To recognize my device I have made the setup():
void setup() {
Serial.begin(115200);
Serial.print("handshake"); // handshake signal to estable authenticity
Serial.flush();
}
When I upload this and open the Arduino Serial Monitor 'handshake' is immediately printed in the output. Then if I close the Arduino Serial Monitor but keep the Arduino Mega 2560 plugged into the computer then my C++ program in Visual Studio also recognizes that and each time I reset the Arduino port the 'handshake' is received in my C++ program. But if I unplug the Arduino Mega 2560 and re-plug it into the computer the 'handshake' signal is not sent until I open Arduino Serial Monitor again, the rest of the code inside setup() and loop() works perfectly all the time. Why is this happening?
If the rest of the code does not require the serial monitor then it will run.
If you require the serial monitor, then once you disconnect your Arduino and reconnect it, you have to re-open the serial monitor because it is essentially establishing a new connection.
That you don't know for sure. What does the TX LED on the Mega tell you?
Do you re-open the serial port in your PC's application after unplugging/plugging the Mega. If not, your PC application uses a file handle that is no longer valid after you unplugged the Mega.
Does restarting the PC application solve the problem?
Yes, because you specifically pointed out the Serial Monitor in Arduino IDE. Of course, I am using the Serial.print() function a lot but that communicates with a serial port on my PC and that works outside of Arduino Serial Monitor. My problem is the Serial.print("handshake"); in the setup() function only works once I have started the Arduino Serial Monitor, after that as long as I do not un-plug the Arduino board the Serial.print("handshake"); in setup() function works everywhere else but once I un-plug the Arduino board it doesn't work unless I start the Arduino Serial Monitor again.
That you don't know for sure. What does the TX LED on the Mega tell you?
I know what it is.
Do you re-open the serial port in your PC's application after unplugging/plugging the Mega. If not, your PC application uses a file handle that is no longer valid after you unplugged the Mega.
Yes, I close the port and re-open a port. The idea here is to establish that the connected Arduino is mine and not someone else's that's why I have put Serial.print("handshake"); in setup() just after Serial.begin(115200);
Does restarting the PC application solve the problem?
No, only restarting the Arduino Serial Monitor fixes the problem.
The "handshake" will have been sent even without the monitor activated.
The opening of the IDE monitor causes the controller to RESET again, just like a powerup.
So you get the "handshake" again.
Exactly! That's what I am expecting that as soon as I reset my port to the Arduino the setup() function will run again and will send "handshake" to my port in my application. But this only happens once the Serial Monitor has had connection with the Arduino board. Why? What is so special about the Serial Monitor is that it needs to have a connection once and then as long as I do not unplug the Arduino board the "handshake" signal is sent every time I reset the port in my application, but if I do not run the Arduino Serial Monitor then this "handshake" signal is never received on my application?
Any code within void setup() will only run once when you connect the Arduino, therefore Serial.print("handshake"); will only run once.
Not true, each time I open a Serial Connection Port through my application to the Arduino this function runs. I do not have to un-plug the Arduino for this to run again, all I have to do is reset the Serial Port that I am connected with to the Arduino and the setup() runs again.
Are you connected to a network, why do you need to establish that a serial communication is coming from your computer?
I am making software for hardware that uses Arduino to control multiple things, e.g. Digital Lines, SPI, etc. When my application starts it needs to go through all the devices connected through COM port to see if the Arduino that is in my hardware is connected or not. Since all Arduino Mega 2560 has the same VID, PID, etc. I need to provide my own method to verify if it's the Arduino in my hardware or someone else's hardware that's why I have the Serial.print("handshake"); in setup().
I think a bit more detail is necessary. I have an Arduino hardware that I have to detect through my C++ application. I can search through all the COM ports available in my system through my application. I look for Arduino Mega 2560 through it's VID (9025) and PID (66). I always find it if it is connected through the USB port. If the Arduino IDE Serial Monitor is open then of course I am unable to open a COM port to this Arduino Mega 2560 which makes sense since only one COM port can communicate at a time with the Arduino. So I close the Serial Monitor in my Arduino IDE and I am able to open my COM port in the C++ application.
The problem: Each time I open (or reset) the COM port using my C++ application the setup() function in Arduino Mega 2560 runs again and the line Serial.print("handshake"); is executed every time but only if I have had open the Arduino Serial Monitor at least once before trying to connect with my C++ application. If I directly plug in my Arduino Mega 2560 in my PC and do not open the Arduino Serial Monitor then I never receive Serial.print("handshake");. The question is why?
Can you share your C++ application? Although I don't use C++ on the PC, a second pair of eyes (and trying to run it) might help you. You can strip it down to the bare minimum that exhibits the behaviour.
Here is the function that connects with the Arduino
void MainWindow::findDevices()
{
if(port.isOpen()) // port is a QSerialPort object
port.close();
auto portList = QSerialPortInfo::availablePorts(); // looks for all available serial ports
if(!portList.isEmpty()) {
for(auto ii = 0; ii < portList.length(); ++ii) {
if((portList[ii].productIdentifier() == 66) && (portList[ii].vendorIdentifier() == 9025)) { // Arduino Mega's PID and VID
port.setPort(portList[ii]);
bool portOpen = port.open(QIODevice::ReadWrite); // opens the port for read and write, unable to open if Arduino Serial Monitor is open
if(portOpen) {
bool baudSuccess = port.setBaudRate(QSerialPort::Baud115200, QSerialPort::AllDirections); // setting the baud rate
if(baudSuccess) {
bool readAvailable = port.waitForReadyRead(30000); // waiting (for 30 seconds) for reply from Arduino telling me that the Serial.print() is ready to send data
while(readAvailable) {
qDebug() << "Port Open, Read All:" << QString::fromUtf8(port.readAll()); // reading the Serial data from Arduino, this is where the "handshake" is printed in the debug output
readAvailable = port.waitForReadyRead(30000); // waiting again for 30 seconds, sometimes only half of Serial output arrives and if anything is still coming in next 30 seconds this becomes true again
}
}
else {
port.close(); // if unable to set the baud rate then I close the port
}
}
break;
}
}
}
}
I am aware that the setup() runs again once you reset the Serial Port but you stated your issue is when you unplug the Arduino board that's why I mentioned that.
Oh ok. Yes, the issue arises when I unplugged the Arduino and re-plug it again but do not run the Arduino Serial Monitor and directly try to communicate to the Arduino using my C++ application.
Found the solution, it had nothing to do with Arduino but with Qt library that I am using to communicate with the Arduino over the Serial Port. After opening the port and setting the baud rate I had to enable port.setDataTerminalReady(true); in my C++ application and then it works perfectly. The correct code for the C++ application would be:
void MainWindow::findDevices()
{
if(port.isOpen()) // port is a QSerialPort object
port.close();
auto portList = QSerialPortInfo::availablePorts(); // looks for all available serial ports
if(!portList.isEmpty()) {
for(auto ii = 0; ii < portList.length(); ++ii) {
if((portList[ii].productIdentifier() == 66) && (portList[ii].vendorIdentifier() == 9025)) { // Arduino Mega's PID and VID
port.setPort(portList[ii]);
bool portOpen = port.open(QIODevice::ReadWrite); // opens the port for read and write, unable to open if Arduino Serial Monitor is open
if(portOpen) {
bool baudSuccess = port.setBaudRate(QSerialPort::Baud115200, QSerialPort::AllDirections); // setting the baud rate
if(baudSuccess) {
port.setDataTerminalReady(true); // V.Imp: If not set then the below waitForReadyRead(3000) does not work unless Arduino already had communication with Arduino IDE's Serial monitor after being plugged in
bool readAvailable = port.waitForReadyRead(30000); // waiting (for 30 seconds) for reply from Arduino telling me that the Serial.print() is ready to send data
while(readAvailable) {
qDebug() << "Port Open, Read All:" << QString::fromUtf8(port.readAll()); // reading the Serial data from Arduino, this is where the "handshake" is printed in the debug output
readAvailable = port.waitForReadyRead(30000); // waiting again for 30 seconds, sometimes only half of Serial output arrives and if anything is still coming in next 30 seconds this becomes true again
}
}
else {
port.close(); // if unable to set the baud rate then I close the port
}
}
break;
}
}
}
}
Thank you everyone for helping me solve this problem. I also posted this on Qt Forum link where I was able to find the answer quite quickly.