Sending and receiving int value to/from serial port - c++

I am developing a window's application that sends and receives data to an Arduino via the serial port.
The problem I have is when I try to send an int value to the serial port and pick it up in the Arduino program. I am using WriteFile() in the window's program to send the int and pick it up in the Arduino using Serial.parseInt(). When I send char values I can pick them up with no problems.
If I want to send int values the only time I receive an integer in the arduino is if I send integers 48 to 57 which give me an int value of 0 to 9 which are the ASCII characters for decimal 48 to 57, weird. e.g. 57, The Arduino seems to pick this up as 9 which is the char value for ASCII 57.
below is the code in the windows program and the Arduino
C++ code:
DWORD ComPort::WriteAnalogData(int *buffer)
{
if (!connected)
return 0;
DWORD bytesSent;
DWORD errors;
if (!WriteFile(hCom, (void *)buffer, sizeof(buffer), &bytesSent, 0))
ClearCommError(hCom, &errors, NULL); // If it fails, clear com errors
else return bytesSent; // Return the number of bytes sent
return 0; // Or return 0 on failure
}
the return value(bytesSent) after the int is written is 4 so I think this function is working. I have a similar function for sending single bytes of data which works and the Arduino picks the data up ok
Arduino Code:
int scadaAnalogVal;
scadaAnalogVal = Serial.parseInt();
digitalWrite(scadaAnalogVal,HIGH);
can anyone tell me what's going on. Probably something simple but i can't see what the issue is, thanks.

The Arduino parseInt() method has a long return type (32-bits) in the Arduino architecture. I think you should change your Arduino code to:
long scadaAnalogVal;
ParseInt documentation

Related

Serial communication - I'm having trouble turning an incoming char array into an int

I'm trying to receive a number from an Arduino as an integer in C++. The full code is below:
#define STRICT
#include <tchar.h>
#include <windows.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "Serial.h"
#include <boost\lexical_cast.hpp>
enum { EOF_Char = 27 };
int __cdecl _tmain(int /*argc*/, char** /*argv*/)
{
CSerial serial;
LONG lLastError = ERROR_SUCCESS;
// Attempt to open the serial port (COM4)
lLastError = serial.Open(_T("COM4"), 0, 0, false);
// Setup the serial port (9600,8N1, which is the default setting)
lLastError = serial.Setup(CSerial::EBaud9600, CSerial::EData8, CSerial::EParNone, CSerial::EStop1);
// Register only for the receive event
lLastError = serial.SetMask(CSerial::EEventBreak |
CSerial::EEventCTS |
CSerial::EEventDSR |
CSerial::EEventError |
CSerial::EEventRing |
CSerial::EEventRLSD |
CSerial::EEventRecv);
// Use 'non-blocking' reads, because we don't know how many bytes
// will be received. This is normally the most convenient mode
// (and also the default mode for reading data).
lLastError = serial.SetupReadTimeouts(CSerial::EReadTimeoutNonblocking);
// Keep reading data, until an EOF (CTRL-Z) has been received
bool fContinue = true;
do
{
// Wait for an event
lLastError = serial.WaitEvent();
// Save event
const CSerial::EEvent eEvent = serial.GetEventType();
// Handle data receive event
if (eEvent & CSerial::EEventRecv)
{
// Read data, until there is nothing left
DWORD dwBytesRead = 0;
char szBuffer[101];
do
{
// Read data from the COM-port
lLastError = serial.Read(szBuffer, sizeof(szBuffer) - 1, &dwBytesRead);
if (dwBytesRead > 0)
{
// Finalize the data, so it is a valid string
szBuffer[dwBytesRead] = '\0';
// Display the data
printf("%s", szBuffer);
// Check if EOF (CTRL+'[') has been specified
if (strchr(szBuffer, EOF_Char))
fContinue = false;
}
} while (dwBytesRead == sizeof(szBuffer) - 1);
}
} while (fContinue);
// Close the port again
serial.Close();
return 0;
}
I have my Arduino constantly sending out the number 51. This code works fine and consistently displays "51". However, I want an int to manipulate in C++.
First I added
std::stringstream str(szBuffer);
int tester;
str >> tester;
printf("My number is: %d\n", tester+1);
right after
printf("%s", szBuffer);
A typical result looks like:
51My number is: 52
51My number is: 52
51My number is: 52
51My number is: 52
51My number is: 52
5My number is: 6
1My number is: 2
After doing it perfectly 5 or 6 times, the output always separates the incoming digits once or twice in a row (I haven't been able to find a specific pattern yet, but it's always 5-6 and 1-2).
My other attempt was to use the boost library:
int tester = boost::lexical_cast<int>(szBuffer);
printf("My number is: %d\n", tester);
right after
printf("%s", szBuffer);
and I get the same result (1-2 errors after 5-6 correct ones). I don't think the Arduino is sending bad data, since just a
printf("%s", szBuffer);
will never deviate from the number it's supposed to be. Could the conversion be messing up the receiving of data? Thanks.
EDIT: The Arduino code is:
void setup() {
Serial.begin(9600); // same as in your c++ script
}
void loop() {
Serial.print(51);
delay(1000);
}
With serial ports, there is no mechanism where a transmitter can inform a receiver how many bytes were transmitted as a block. I.e. there's no "hidden" marker where Serial.print(51); tells the receiver that it sent two characters as one number. You have to add some kind of indication (spaces, commas, line ends, initial byte counts, whatever) to your serial protocol.
Because of this, the number of characters you get from serial.Read depends on the number of characters you asked it to read (the second parameter) and how many characters are in the serial port's receive buffer, whichever is smaller. Most of the time, it seems the Arduino sends both digits before you call serial.Read, but sometimes it only gets one out in time... and the second is read the next time through the loop.
So let's assume you decided to use line ends to separate your numbers. All you have to do on the Arduino end is change to Serial.println(51);. The receive end is a little more complex.
I don't know what your serial library has in it. Most have some kind of "read line" function, and you would just replace the serial.Read call with something like:
serial.Readline(szBuffer, sizeof(szBuffer) - 1);
and it will take care of null-terminating the output. If it doesn't take care of null-termination, you'll need to find the line end and change it to a \0 yourself. From this point on, your code will work fine, because the serial.Readline function will block until it gets the whole line.
If you don't have a "read line" or at least a "read until this character" function, it's a bit harder. You have to repeatedly call serial.Read, moving through your buffer, until you see the line end character. Further, you run the risk of reading part or all of the next line, so you can't just discard all the data you read when you're done reading the number; you have to move teh data in the buffer so the next line's data (and further) is at the start of the buffer.
If you're using Boost (are you? it has no CSerial that I see), it looks like it has a read_until function. This takes three parameters: the stream you're reading from, a stream buffer to store the data in, and something to stop on. In this case, the stream buffer for storage is the one in your std::stringstream:
std::stringstream buffer;
size_t chars = boost::asio::read_until(serial, buffer.rdbuf(), '\n');
if(chars == 0) return;
int tester;
buffer >> tester;
printf("My number is: %d\n", tester+1);

Openframeworks, reading serial data from Arduino

I'm trying to read serial data from an Arduino UNO using an ofSerialobject and assign it as an int.
I am able to read in individual bytes, however, the values I'm receiving in the openframeworks console are not the same as the values I'm reading in the Arduino serial monitor.
I have provided screenshots of the respective consoles:
My Arduino code is simply the basic "AnalogReadSerial" example available with the Arduino IDE.
// the setup routine runs once when you press reset:
void setup() {
// initialize serial communication at 9600 bits per second:
Serial.begin(9600);
}
// the loop routine runs over and over again forever:
void loop() {
// read the input on analog pin 0:
int sensorValue = analogRead(A0);
// print out the value you read:
Serial.println(sensorValue);
delay(1); // delay in between reads for stability
}
Whereas my C++ code is mostly copied from the documentation for the ofSerial readByte function.
void serialReader::setup()
{
serial.listDevices();
vector <ofSerialDeviceInfo> deviceList = serial.getDeviceList();
serial.setup("COM4", 9600); //open the first device and talk to it at 9600 baud
}
void serialReader::printByteToConsole()
{
int myByte = 0;
myByte = serial.readByte();
if ( myByte == OF_SERIAL_NO_DATA )
printf("\nno data was read");
else if ( myByte == OF_SERIAL_ERROR )
printf("\nan error occurred");
else
printf("\nmyByte is %d ", myByte);
}
Any insight into what may be causing this disparity between the readings would be greatly appreciated. Thank you.
Arduino's Serial.println translates the raw bytes into their ASCII equivalent and then sends those bytes followed by linefeed (10) and carriage return (13) bytes. So, the raw byte 12 is sent as 4 total bytes -- two bytes representing the ASCII 1 (49), 2 (50) and then (10) and (13) for the new line characters. So, since openFrameworks does not automatically translate the ASCII values back into raw bytes, you are seeing the ASCII version. The Arduino console shows you the ASCII version as readable text.
You can see the translation between ASCII and raw bytes (Decimal / aka DEC) here:
http://www.asciitable.com/
If you want the two numbers to match on both sides, consider using Serial.write in Arduino to write the raw bytes without ASCII translation and new line characters.

C++ sending an int over serial to arduino that is using Serial.parseInt();

Firstly, the problem:
I cannot find a away to send 2bytes of data via serial to an arduino (that uses Serial.parseInt()) from a windows C++ console app.
The code follows: (it is stripped down for clarity, but the problem still presents itself in a larger version that checks all serial setup function calls are successful and so on)
#include "stdafx.h"
#include <windows.h>
#include <stdio.h>
int main()
{
//setup
HANDLE hSerial;
DCB dcbSerialParams = {0};
COMMTIMEOUTS timeouts = {0};
hSerial = CreateFileA("COM3", GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL );
dcbSerialParams.DCBlength = sizeof(dcbSerialParams);
GetCommState(hSerial, &dcbSerialParams);
dcbSerialParams.BaudRate = CBR_19200;
dcbSerialParams.ByteSize = 8;
dcbSerialParams.StopBits = ONESTOPBIT;
dcbSerialParams.Parity = NOPARITY;
SetCommState(hSerial, &dcbSerialParams);
//the data to send:
//char dataToSend = '5';
//unsigned int dataToSend = 125;
//(LPVOID)
unsigned short dataToSend = 125;
DWORD bytes_written;
//now we send it
WriteFile(hSerial, &dataToSend, sizeof(dataToSend), &bytes_written, NULL);
fprintf(stderr, "%d bytes written\n", bytes_written);
CloseHandle(hSerial);
Sleep(3000);
return 0;
}
The above code will not give the results I'm after, using unsigned int I get all zeros (I'm looking at the data as bits in the arduino), I need 2bytes only so i try unsigned short, same thing, all zeros - however when I try char, I will see the binary representation of 0-9 on the arduino, but not for any other ascii values (I thought I was close to a solution then! i.e. I could just cast the 'int' as it's two bytes in ascii...).
Also tried the '(LPVOID)' cast (no idea what it is but it was mentioned in another thread).
The kicker is that I have an LCD connected on the arduino and using the arduino IDE serial monitor and with that I can send any int value I want and it will work as intended (using 'no line ending').
A little context re. why using parseint>> I'm trying to avoid using anything more than 2bytes as 15bits of data is all I need. Arduino has 2byte ints so I figure I can use that data type to send the info (and code/decode the parts I need using bitwise operations at either end). I have no issue with this (that part at least is working).
The arduino code is as simple as:
if (Serial.available()) {servoData = Serial.parseInt();}
As mentioned, I have no issues with this using the arduino serial monitor.
I've tried flipping endianess, but aren't sure I went about it correctly - the 2byte version was:
dataToSend = (dataToSend << 8) | ((dataToSend >> 8) & 0x00ff);
Something to do with serial, line endings, variable types?
Any hints appreciated :)

What buffer size should be chosen for serial communication of sensor readings?

I have an arduino board that is connected to a sensor. From Arduino IDE serial monitor, I see the readings are mostly 160, 150, etc. Arduino has a 10 bit ADC, so I assume the readings range from 0 to 1024.
I want to fetch that readings to my computer so that I can do further processing. It must be done this way up to this point. Now, I wrote a c++ program to read serial port buffer with Windows APIs (DCB). The transfer speed of the serial ports are set to 115200 on both the Arduino IDE and the c++ program.
I will describe my problem first: Since I want to send the readings to my computer, I expect the data looks like the following:
124
154
342
232
...
But now it looks like
321
43
5
2
123
...
As shown, the data are concatenated. I knew it because I tried to display them with [], and the data are truly messed up.
The section of the code that is doing the serial port reading on the computer is as here:
// Read
int n = 10;
char szBuff[10 + 1] = {0};
DWORD dwBytesRead = 0;
int i;
for (i = 0; i < 200; i++){
{
if(!ReadFile(hSerial, szBuff, n, &dwBytesRead, NULL)){
//error occurred. Report to user.
printf("Cannot read.\n");
}
else{
printf("%s\n" , szBuff);
}
}
}
The Arduino code that's doing the serial port sending is:
char buffer [10] = { 0 };
int analogIn = 0;
int A0_val = 0;
void setup() {
Serial.begin(115200);
}
void loop() {
A0_val = analogRead(analogIn);
sprintf(buffer, "%d", A0_val);
Serial.println(buffer);
}
I suspect that the messing up of the data is caused by different size of the buffer used to transmit and receive data in the serial port. What is the good suggestion for the size of the buffer and even better method to guarantee the successful transmission of valid data?
Thanks very much!
Your reciever code cannot assume a single read from the serial port will yield a complete line (i.e. the 2 or 3 digits followed by a '\n' that the arduino continuously sends).
It is up to the receiver to synthetize complete lines of text on reception, and only then try to use them as meaningful numbers.
Since the serial interface is extremely slow compared with your average PC computing power, there is little point in reading more than one character at a time: literally millions of CPU cycles will be spent waiting for the next character, so you really don't need to react fast to the arduino input.
Since in that particular case it will not hinder performances in the slightest, I find it more convenient to read one character at a time. That will save you the hassle of moving bits of strings around. At least it makes writing an educational example easier.
// return the next value received from the arduino as an integer
int read_arduino (HANDLE hserial)
{
char buffer[4]; // any value longer than 3 digits must come
// from a faulty transmission
// the 4th caracter is used for a terminating '\0'
size_t buf_index = 0; // storage position of received characters
for (;;)
{
char c; // read one byte at a time
if (!ReadFile(
hSerial,
&c, // 1 byte buffer
1, // of length 1
NULL, // we will read exactly one byte or die trying,
// so length checking is pointless
NULL)){
/*
* This error means something is wrong with serial port config,
* and I assume your port configuration is hard-coded,
* so the code won't work unless you modify and recompile it.
* No point in keeping the progam running, then.
*/
fprintf (stderr, "Dang! Messed up the serial port config AGAIN!");
exit(-1);
}
else // our read succeded. That's a start.
{
if (c == '\n') // we're done receiving a complete value
{
int result; // the decoded value we might return
// check for buffer overflow
if (buf_index == sizeof (buffer))
{
// warn the user and discard the input
fprintf (stderr,
"Too many characters received, input flushed\n");
}
else // valid number of characters received
{
// add a string terminator to the buffer
buffer[buf_index] = '\0';
// convert to integer
result = atoi (buffer);
if (result == 0)
{
/*
* assuming 0 is not a legit value returned by the arduino, this means the
* string contained something else than digits. It could happen in case
* of electricval problems on the line, typically if you plug/unplug the cable
* while the arduino is sending (or Mr Fluffy is busy gnawing at it).
*/
fprintf (stderr, "Wrong value received: '%s'\n", buffer);
}
else // valid value decoded
{
// at last, return the coveted value
return res; // <-- this is the only exit point
}
}
// reset buffer index to prepare receiving the next line
buf_index = 0;
}
else // character other than '\n' received
{
// store it as long as our buffer does not overflow
if (buf_index < sizeof (buffer))
{
buffer[buf_index++] = c;
/*
* if, for some reason, we receive more than the expected max number of
* characters, the input will be discarded until the next '\n' allow us
* to re-synchronize.
*/
}
}
}
}
}
CAVEAT: this is just code off the top of my head. I might have left a few typos here and there, so don't expect it to run or even compile out of the box.
A couple of basic problems here. First, it is unlikely that the PC can reliably keep up with 115,200 baud data if you only read 10 bytes at a time with ReadFile. Try a slower baud rate and/or change the buffer size and number of bytes per read to something that will get around 20 milliseconds of data, or more.
Second, after you read some data put a nul at the end of it
szBuf[dwBytesRead] = 0;
before you pass it to printf or any other C string code.

QSerialPort reading signed value

I'm trying to use QSerialPort class to reading and writing to serial port.
Right now i'm using virtual comports implemented by eltima driver.
I can successfully send bytes like this:
QSerialPortInfo info = QSerialPortInfo("COM30");
QSerialPort serial;
serial.setPort(info);
serial.setBaudRate(57600);
serial.open(QIODevice::ReadWrite);
char arr[] = {0xAA, 0xBB, 0xCC, 0xDD};
serial.write(arr, 4);
I'm trying reading like this (I want to read just a single byte; this code is called by timer, if data is ready to be read):
virtual uint8_t getByte(void)
{
char arr[2] = {0};
int8_t err = qPort.read(arr, 1);
DEBUG_ASSERT(err != -1);
if(! isNewByte() )
{
onReceiveFinished();
}
return arr[0];
}
If I send to a virtual port (i.e. to my program) any value less then 128, I get it right (as debugger is showing). However, if I try to send 128 or more, I get value-128 o_o (if I send 153 - I get 25. Not -25 or 103).
That seems like something really odd to me.
Can anyone see where is the mistake?
My mistake was really stupid. QSerialPort is set to 7 databits by default (which seems not very practical, actually), so every received byte had its MSB cut off (like substracting 128).
Still, oddly enough, sending worked fine.
Not. You wrong do setBaudRate(). It need to do after the port is opening.