I'm trying to make a serial connection to an Arduino Diecimila board with QextSerialPort. My application hangs though everytime I call port->open(). The reason I think this is happening is because the Arduino board resets itself everytime a serial connection to it is made. There's a way of not making the board reset described here, but I can't figure out how to get QextSerialPort to do that. I can only set the DTR to false after the port has been opened that's not much help since the board has already reset itself by that time.
The code for the connection looks like this:
port = new QextSerialPort("/dev/tty.usbserial-A4001uwj");
port->open(QIODevice::ReadWrite);
port->setBaudRate(BAUD9600);
port->setFlowControl(FLOW_OFF);
port->setParity(PAR_NONE);
port->setDataBits(DATA_8);
port->setStopBits(STOP_1);
port->setDtr(false);
port->setRts(false);
Any ideas on how to get this done. I don't necessarily need to use QextSerialPort should someone know of another library that does the trick.
I'm new to C++ and Qt.
UPDATE:
I noticed that if I run a python script that connects to the same port (using pySerial) before running the above code, everything works just fine.
I had a similar problem.
In my case QExtSerial would open the port, I'd see the RX/TX lights on the board flash, but no data would be received. If I opened the port with another terminal program first QExtSerial would work as expected.
What solved it for me was opening the port, configuring the port settings, and then making DTR and RTS high for a short period of time.
This was on Windows 7 w/ an ATMega32u4 (SFE Pro Micro).
bool serialController::openPort(QString portName) {
QString selectPort = QString("\\\\.\\%1").arg(portName);
this->port = new QextSerialPort(selectPort,QextSerialPort::EventDriven);
if (port->open(QIODevice::ReadWrite | QIODevice::Unbuffered) == true) {
port->setBaudRate(BAUD38400);
port->setFlowControl(FLOW_OFF);
port->setParity(PAR_NONE);
port->setDataBits(DATA_8);
port->setStopBits(STOP_1);
port->setTimeout(500);
port->setDtr(true);
port->setRts(true);
Sleep(100);
port->setDtr(false);
port->setRts(false);
connect(port,SIGNAL(readyRead()), this, SLOT(onReadyRead()));
return true;
} else {
// Device failed to open: port->errorString();
}
return false;
}
libserial is an incredible library I use for stand-alone serial applications for my Arduino Duemilanove.
qserialdevice use!
Example:
http://robocraft.ru/blog/544.html
Can you just use a 3wire serial cable (tx/rx/gnd) with no DTR,RTS lines?
Related
I have an ESP 32 collect data from a moisture sensor, which it then serves on our network. Our WiFi turns off between 1am and 6 am (because no one is using it). The ESP does not automatically try to reconnect, so it gathered data all night which I straight up can not access now.
For obvious reasons I do not want it to halt data collection when it looses connection to our network, so I can not have a loop try to reconnect. I tried this code:
void loop() {
sensor_value = analogRead(sensor_pin);
Serial.println(sensor_value);
push_value(float(sensor_value)/2047.0);
//============
//RELEVANT BIT
//============
if( WiFi.status() != WL_CONNECTED ){
//Try to recconect if connection is lost....
WiFi.disconnect();
WiFi.begin(ssid, pwd);
}
delay(second_delay*1000);
}
I've seen everyone run Wifi.disconnect() before attempting reconnecting. Is that necessary. Also does WiFi.begin() pause execution? I can't test my code right now unfortunately.
I am using the Arduino IDE and Wifi.h
And before you ask: Yes, 2047 is correct. I am running the sensor on the wrong voltage which results in about this max value.
Given that you've tagged esp8266 wifi, I'm assuming you're using that library. If so, then wifi.begin will not block execution. The library sets autoreconnect by default, so it'll automatically reconnect to the last access point when available. Any client functions will simply return an error code while disconnected. I do not know of any reason that wifi.disconnect should be called before begin.
I tried to communicate with my Arduino Uno using the Boost Asio library. Somehow I can't send data to my Arduino, and I have no idea what i'm doing wrong. Reading works fine, but writing only works when i open a terminal and say:
cat /dev/ttyACM0
When this terminal window is open, and I run my C++ application it works otherwise it doesn't work.
Code of the test application (C++):
#include <iostream>
#include <boost/asio.hpp>
char* message;
int main()
{
boost::asio::io_service ioservice;
boost::asio::serial_port serial(ioservice, "/dev/ttyACM0");
serial.set_option(boost::asio::serial_port_base::baud_rate(115200));
serial.set_option(boost::asio::serial_port::flow_control(boost::asio::serial_port::flow_control::none));
serial.set_option(boost::asio::serial_port::parity(boost::asio::serial_port::parity::none));
serial.set_option(boost::asio::serial_port::stop_bits(boost::asio::serial_port::stop_bits::one));
serial.set_option(boost::asio::serial_port::character_size(boost::asio::serial_port::character_size(8)));
std::string s = "u";
boost::asio::streambuf b;
std::ostream os(&b);
os << s;
boost::asio::write(serial, b.data());
if (serial.is_open()) {
serial.close();
}
return 0;
}
Code of my Arduino application:
#include "Servo.h"
Servo servo;
void setup() {
Serial.begin(115200);
servo.attach(9);
servo.write(0);
}
void loop() {
if(Serial.available()) {
char c = Serial.read();
if(c == 'u') {
servo.write(180);
} else if (c == 'v') {
servo.write(0);
}
}
}
I tried this both on my Ubuntu 18.04 and Debian 10 installation to rule out a permission issue, so I think there is something wrong with my code.
Update:
I found the issue, the Arduino is restarting when making a serial connection. When I add a thread sleep for for example 5 seconds and after that resent the data it works (because then it keeps the serial connection alive). I'm still looking for a permanent solution, so that I don't have to do a write before I really want to write something.
Update 2:
Apparently I don't even have to do a write, but where must be a small delay before I can start writing, because when after opening the port the Arduino is still restarting.
I fixed it with adding a small delay before writing to the serial port. As I also wrote in my comment above, the Arduino is restarting when you start a serial communication.
This can be disabled on several ways: https://playground.arduino.cc/Main/DisablingAutoResetOnSerialConnection/
Another option is to send a "ready" signal from the Arduino to know in your application that the Arduino is rebooted. So then start in your application with reading, and when you received that message, you can start writing.
I have the following code:
QSerialPort arduPort("COM5");
arduPort.setBaudRate(QSerialPort::Baud9600);
arduPort.setDataBits(QSerialPort::Data8);
arduPort.setParity(QSerialPort::NoParity);
arduPort.setStopBits(QSerialPort::OneStop);
arduPort.setFlowControl(QSerialPort::NoFlowControl);
arduPort.open(QSerialPort::ReadWrite);
cout<<arduPort.isReadable()<<endl;
cout<<arduPort.isWritable()<<endl;
arduPort.write("a");
QByteArray s=arduPort.readAll();
cout<<QString(s).toStdString()<<endl;
And the next code in Arduino:
int inByte = 0;
void setup()
{
Serial.begin(9600);
while(!Serial){;}
int i=0;
}
void loop()
{
if(Serial.read()=='a')
Serial.write('b');
}
First I send an 'a' to the Arduino, and the ARduino must respond with 'b'. But when I read the port of the Arduino, I recieve '' only.
Anyone knows why I recieve '' instead of 'b'? Thanks for your time.
Update: See bottom of this answer for the answer. TL;DR: You have so set the baud rate (and presumably all the other settings) after you open the port.
I believe this is a bug in the Windows implementation of QSerialPort. I haven't been able to narrow down the cause yet but I have the following symptoms:
Load the Arduino (Uno in my case; Leonardo may behave very differently) with the ASCII demo. Unplug and replug the Arduino. Note that the TX light doesn't come on.
Connect to it with Putty or the Arduino serial port monitor. This resets the Arduino and then prints the ASCII table. The TX light is on continuously as expected.
Unplug/replug the Arduino and this time connect to it with a QSerialPort program. This time despite the port being opened ok the TX light never comes on and readyRead() is never triggered. Also note that the Arduino is not reset because by default QSerialPort does not change DTR. If you do QSerialPort::setDataTerminalReady(false); then pause for 10ms then set it true it will reset the Arduino as expected but it still doesn't transmit.
Note that if you have an Arduino program that transmits data continuously (ASCII example stops), if you open the port with putty so that it starts transmitting and then open it with QSerialPort without unplugging the cable it will work! However as soon as you unplug/plug the cable it stops working again.
This makes me suspect that putty is setting some serial port option that is required by the arduino and reset when you replug the cable. QSerialPort obviously doesn't change this value.
Here are the settings used by Putty as far as I can tell:
dcb.fBinary = TRUE;
dcb.fDtrControl = DTR_CONTROL_ENABLE;
dcb.fDsrSensitivity = FALSE;
dcb.fTXContinueOnXoff = FALSE;
dcb.fOutX = FALSE;
dcb.fInX = FALSE;
dcb.fErrorChar = FALSE;
dcb.fNull = FALSE;
dcb.fRtsControl = RTS_CONTROL_ENABLE;
dcb.fAbortOnError = FALSE;
dcb.fOutxCtsFlow = FALSE;
dcb.fOutxDsrFlow = FALSE;
dcb.Parity = NOPARITY;
dcb.StopBits = ONESTOPBIT;
dcb.BaudRate = ...;
dcb.ByteSize = ...;
And by QSerialPort:
dcb.fBinary = TRUE;
dcb.fDtrControl = unchanged!
dcb.fDsrSensitivity = unchanged!
dcb.fTXContinueOnXoff = unchanged!
dcb.fOutX = FALSE;
dcb.fInX = FALSE;
dcb.fErrorChar = FALSE;
dcb.fNull = FALSE;
dcb.fRtsControl = RTS_CONTROL_DISABLE;
dcb.fAbortOnError = FALSE;
dcb.fOutxCtsFlow = FALSE;
dcb.fOutxDsrFlow = unchanged!
dcb.Parity = NOPARITY;
dcb.StopBits = ONESTOPBIT;
dcb.BaudRate = ...;
dcb.ByteSize = ...;
So I think it must be one of those unchanged values which makes the Arduino think that it isn't connected. From the DCB documentation I suspect fTxContinueOnXoff.
Ok I am going to write a little program to read these settings and see what changes.
Update 1
Ok I wrote my program and made the following discovery. The differences after running putty and just my Qt program were:
BaudRate: THIS WASN'T SET BY QT!!!!!!! It turns out you can only set the baud rate after you open the port.. Otherwise it is left at the previous value which is 0 when you first plug in the cable.
fDtrControl: Set to 1 by Putty, left at 0 by Qt.
fOutX and fInX: Both also set to 1 by Putty and left at 0 by Qt.
After moving all my set...() function calls after the open it worked perfectly. I didn't have to fiddle with DtrControl or Out/InX. (Although I have also set DTR high manually.)
Update 2
While setting all the parameters I thought it would be a good idea to set the error policy to 'skip'. DON'T DO THIS! LEAVE IT ON IGNORE! Otherwise it fucks everything up and adds weird delays to all your communications.
Setting the ports before open is not quite possible before Qt 5.2. The reason is that the original design was a bit too low-level for the class rather properly object oriented. I had been considered for a long-time whether to change it and in the end I actually decided to do so.
I have just submitted a change that is now under code review that will make your original concept work, too.
Here you can find the details:
Make it possible to set the port values before opening
The summary can be read here for the change:
Make it possible to set the port values before opening
This patch also changes the behavior of the open method. We do not use port
detection anymore for good. It has been a broken concept, and it is very
unlikely that anyone has ever relied on it. If anyone had done that, they would
be in trouble anyway, getting noisy warnings needlessly and all that.
The other option was also considered to keep this behavior optionally as the
default, but that would complicate the API too much without not much gain.
The default port settings are now also the sane 9600,8,N,1, and no flow control.
Also please note that the serial port is closed automatically in the open method
if any of the settings fails.
Please update your Qt version (at least to Qt 5.2) or you can backport the change yourself. Then, it is possible to write this code and actually it is even recommended:
QSerialPort arduPort("COM5");
arduPort.setBaudRate(QSerialPort::Baud9600);
arduPort.setDataBits(QSerialPort::Data8);
arduPort.setParity(QSerialPort::NoParity);
arduPort.setStopBits(QSerialPort::OneStop);
arduPort.setFlowControl(QSerialPort::NoFlowControl);
arduPort.open(QSerialPort::ReadWrite);
BaudRate: THIS WASN'T SET BY QT!!!!!!! It turns out you can only set
the baud rate after you open the port.. Otherwise it is left at the
previous value which is 0 when you first plug in the cable.
Yes, it is true. But it has been fixed and will be available in Qt 5.3
fDtrControl: Set to 1 by Putty, left at 0 by Qt.
No. Qt do not touch the DTR signal at opening. This signal will be cleared only when was set to DTR_CONTROL_HANDSHAKE. Because QtSerialPort do not support the DTR/DSR flow control. So, in any case you can control the DTR by means of QSerialPort::setDataTerminalReady(bool).
PS: I mean current Qt 5.3 release
fOutX and fInX: Both also set to 1 by Putty and left at 0 by Qt.
This flag's are used only when you use QSerialPort::Software flow control (Xon/Xoff). But you are use the QSerialPort::NoFlowControl (as I can see from your code snippet), so, all right. So, please check that you use Putty with the "None" flow control too.
While setting all the parameters I thought it would be a good idea to
set the error policy to 'skip'.
Please use only QSerialPort::Ignore policy (by default). Because other policies is deprecated (all policies) and will be removed in future.
UPD:
dcb.fRtsControl = RTS_CONTROL_ENABLE;
Ahh, seems that your Arduino expect that RTS signal should be enabled by default. In this case you should to use QSerialPort::setRequestToSend(bool). But it is possible only in QSerialPort::NoFlowControl mode.
I.e. RTS always will be in RTS_CONTROL_DISABLE or RTS_CONTROL_HANDSHAKE after opening of port (depends on your FlowControl settings, QSerialPort::setFlowControl() ).
I have to read many(8) serial devices on my project. They are Pantilt, Camera, GPS, Compass etc. they all are RS232 devices but they have different command structure and behavior. e.g GPS starts sending data as
soon as I open the port. where as PanTilt and Camera only responds when I send specific commands to them.
I use following environment
OS: Ubuntu 11.10
Language: C++
Framework: Qt 4.7
For PanTilt and Camera I want to develop function like this.
int SendCommand(string& command, string& response)
{
port.write(command, strlen(command));
while(1)
{
if(response contains '\n') break;
port.read(response) // Blocking Read
}
return num_of_bytes_read;
}
I want to implement this way as this function will be used as building block for more complex algorithm
like this...
SendCoammd("GET PAN ANGLE", &angle);
if(angle > 60)
SendCommand("STOP PAN", &stopped?);
if(stopped? == true)
SendCommand("REVERSE PAN DIRECTION", &revesed?);
if(reversed? == true)
SendCommand("START PAN", &ok);
To do something like this I need strict synchronous behavior. Anybody has any idea how to approach this?
I found this tutorial very intresting and helpful.
http://www.webalice.it/fede.tft/serial_port/serial_port.html
It shows how boost::asio can be used to perform both sync and async read/write.
Thank You for the help!
what is the problem of using standard file API?
fd = open("/dev/ttyX");
write(fd, command.cstr(), command.size());
vector v(MAX_SIZE);
read(fd,&v[0], MAX_SIZE);
Low-level communication with serial port in Qt can be established with QExtSerialPort library that partially implements QIODevice interface.
The high level protocols you have to implement yourself.
I am just an Arduino beginner. I bought an Arduino Uno and a Wifly shield yesterday and I am not able to run the Wifly_Test example program come with WiFlySerial library.
When I look at Serial Monitor, I only saw 2 lines are printed out
1.Starting WiFly Tester.
2.Free memory:XXXX
How can I know that the Wifly Sheild that I bought is not faulty?
I soldered the heard ping to Wifly Shield and stacked it to Aurduino Uno and I can see the LEDs blinking on the Wifly Shield.
Do I need to reset the Wifly Sheild? How do I reset it?
Please point me to the most simple example on how to connect to the router.
I have also bought the shield and had trouble to start with.
If you have soldered the pins to the shield that should be fine but make sure you check they all have a connection and that they don't have solder running down the legs of the pins as this causes the shield to be temperamental.
Run the code below which is from the WiFly library (alpha 2 version) that can be found here:
http://forum.sparkfun.com/viewtopic.php?f=32&t=25216&start=30
Once you see that the shield has connected it will ask for an input, type $$$ and press enter... you have now entered the command line and CMD will be displayed.
If you do not know your network settings type scan and this will display them.
Then set your authentication by typing set wlan auth 3 (Mixed WPA1 & WPA2-PSK) or set wlan auth 4 (WPA2-PSK) this depends on the type of authentication you ise so pick the write one for your network.
Then type set wlan phrase YourPharsePhrase (Change YourPharsePhrase to whatever your WPA key is)
Then type join YourSSIDName (Change YourSSIDName to whatever your network name is)
You see something like this:
join YourSSIDName
Auto-Assoc YourSSIDName chan=1 mode=MIXED SCAN OK
Joining YourSSIDName now..
<2.15> Associated!
DHCP: Start
DHCP in 1234ms, lease=86400s
IF=UP
DHCP=ON
IP=10.0.0.116:2000
NM=255.255.255.0
GW=10.0.0.1
Listen on 2000
you are now connected to your network.
Hopefully this will get you up and running.
N.B. REMEMBER TO CAREFULLY CHECK YOUR PINS! I had great trouble with mine because only a small amount of solder is needed but enough to get a good connection, the balance of this was minute but enough that it wouldn't work. I used a magnifying to check mine in the end.
#include "WiFly.h" // We use this for the preinstantiated SpiSerial object.
void setup() {
Serial.begin(9600);
Serial.println("SPI UART on WiFly Shield terminal tool");
Serial.println("--------------------------------------");
Serial.println();
Serial.println("This is a tool to help you troubleshoot problems with the WiFly shield.");
Serial.println("For consistent results unplug & replug power to your Arduino and WiFly shield.");
Serial.println("(Ensure the serial monitor is not open when you remove power.)");
Serial.println();
Serial.println("Attempting to connect to SPI UART...");
SpiSerial.begin();
Serial.println("Connected to SPI UART.");
Serial.println();
Serial.println(" * Use $$$ (with no line ending) to enter WiFly command mode. (\"CMD\")");
Serial.println(" * Then send each command followed by a carriage return.");
Serial.println();
Serial.println("Waiting for input.");
Serial.println();
}
void loop() {
// Terminal routine
// Always display a response uninterrupted by typing
// but note that this makes the terminal unresponsive
// while a response is being received.
while(SpiSerial.available() > 0) {
Serial.write(SpiSerial.read());
}
if(Serial.available()) { // Outgoing data
//SpiSerial.print(Serial.read(), BYTE);
SpiSerial.write(Serial.read());
}
}
Sorry I forgot to mention , you reset the shield by going to the WiFly library and going to: WiFly/tools/HardwareFactoryReset
Then open the serial monitor and type in any character and this will start the reset.
Thanks everyone who tried to answer me. I finally solved my problem by using Arduino 0023 instead of 1.0.