Need help on understanding Writefile - arduino

I would like your assistance to understand a bit of code that would hugely help me in my project. Without going into too much details, here is what is causing me so much problems :
bool Serial::WriteData(char *buffer, unsigned int nbChar)
{
DWORD bytesSend;
//Try to write the buffer on the Serial port
if(!WriteFile(this->hSerial, (void *)buffer, nbChar, &bytesSend, 0))
{
//In case it don't work get comm error and return false
ClearCommError(this->hSerial, &this->errors, &this->status);
return false;
}
else
return true;
}
I use this function to send a variable to my Arduino Uno over Serial port like this :
snprintf(Data, sizeof(Data) - 1, "%3.1f", (int)(pf->speedKmh)*1.0);
SP->WriteData(Data, sizeof(Data) - 1); printf("\nData\n");
Some helpful info :
speedkmh is a float
char Data[8] = "";
So my question is : I would like to know exactly what is being sent to the Arduino. At the moment I don't really know if it is sending an array, bits one at a time, if it sends a float etc... Could you help me understand this?
Thanks!

The following line:
snprintf(Data, sizeof(Data) - 1, "%3.1f", (int)(pf->speedKmh)*1.0);
converts your floating point number to a string (an array of characters). Then
SP->WriteData(Data, sizeof(Data) - 1); printf("\nData\n");
sends these characters, one at a time, over the serial port.
BTW, it is not very clear why you convert your float to an integer, then back to a float (by multiplying it by 1.0), then to a string. As I see it, this would have the result of truncating the fractional part of the float, then appending a misleading ".0" to the string (from the ".1f" part of the control string). That is, both 1.0 and 1.4 will be converted to "1.0".

Related

Serial communication printing issue

I am working on serial communication between two MCU's particularly teensy(similar to Arduino) for generating fake GPS data. I have been able to write GPS data and read from the other MCU fine but if u look closely, the data that is printed has some ambiguity. The last values are changed somehow and I don't understand why is this because of sprintf command or conversion of float to string or what?
Some help will be appreciated.
Below are the working code and snippet of the serial terminal.
Thank you
float lat = 37.4980608;
char str1[21];
void setup()
{
Serial3.begin(115200);
Serial.begin(115200); // Config serial port (USB)
while(!Serial);
while(!Serial3);
Serial.println("Sending gps data");
}
void loop()
{
sprintf(str1, "%.7f%.7f", lon, lat);
Serial.println(str1);
Serial3.write(str1);
Serial3.flush();
delay(500);
}
What you are seeing is the compiler's approximation of your floats because their values are exceeding the precision possible with a float (4-bytes). Using a double won't help unless your MCU supports 8-byte doubles; I've not used a teensy but I highly doubt it supports 8-byte doubles.
This is not a clever solution but it should get you pointed in the right direction.
Define a struct that can represent large real number values
typedef struct {
int whole;
unsigned long fraction;
} BigNumber;
The you may declare/initialize latitude and longitude l
BigNumber latitude { 126, 9653503 };
BigNumber longitude { 37, 4980608 };
Then printing is easy:
sprintf(strbuf, "%i.%lu %i.%lu",
latitude.whole, latitude.fraction,
longitude.whole, longitude.fraction
);
However if mathematical operations are necessary - add, subtract, etc. - this won't cut it; find an arbitrary big number library like Nick Gammon's
Lastly, have a care: in your code str1 is too small - there is no accounting for the null terminator appended by sprintf, so you're getting plain lucky your program is not crashing.

C functions returning an array

Sorry for the post. I have researched this but..... still no joy in getting this to work. There are two parts to the question too. Please ignore the code TWI Reg code as its application specific I need help on nuts and bolts C problem.
So... to reduce memory usage for a project I have started to write my own TWI (wire.h lib) for ATMEL328p. Its not been put into a lib yet as '1' I have no idea how to do that yet... will get to that later and '2'its a work in progress which keeps getting added to.
The problem I'm having is with reading multiple bytes.
Problem 1
I have a function that I need to return an Array
byte *i2cBuff1[16];
void setup () {
i2cBuff1 = i2cReadBytes(mpuAdd, 0x6F, 16);
}
/////////////////////READ BYTES////////////////////
byte* i2cReadBytes(byte i2cAdd, byte i2cReg, byte i2cNumBytes) {
static byte result[i2cNumBytes];
for (byte i = 0; i < i2cNumBytes; i ++) {
result[i] += i2cAdd + i2cReg;
}
return result;
}
What I understand :o ) is I have declared a Static byte array in the function which I point to as the return argument of the function.
The function call requests the return of a pointer value for a byte array which is supplied.
Well .... it doesn't work .... I have checked multiple sites and I think this should work. The error message I get is:
MPU6050_I2C_rev1:232: error: incompatible types in assignment of 'byte* {aka unsigned char*}' to 'byte* [16] {aka unsigned char* [16]}'
i2cBuff1 = i2cReadBytes(mpuAdd, 0x6F, 16);
Problem 2
Ok say IF the code sample above worked. I am trying to reduce the amount of memory that I use in my sketch. By using any memory in the function even though the memory (need) is released after the function call, the function must need to reserve an amount of 'space' in some way, for when the function is called. Ideally I would like to avoid the use of static variables within the function that are duplicated within the main program.
Does anyone know the trade off with repeated function call.... i.e looping a function call with a bit shift operator, as apposed to calling a function once to complete a process and return ... an Array? Or was this this the whole point that C does not really support Array return in the first place.
Hope this made sense, just want to get the best from the little I got.
BR
Danny
This line:
byte *i2cBuff1[16];
declares i2cBuff1 as an array of 16 byte* pointers. But i2cReadBytes doesn't return an array of pointers, it returns an array of bytes. The declaration should be:
byte *i2cBuff1;
Another problem is that a static array can't have a dynamic size. A variable-length array has to be an automatic array, so that its size can change each time the function is called. You should use dynamic allocation with malloc() (I used calloc() instead because it automatically zeroes the memory).
byte* i2cReadBytes(byte i2cAdd, byte i2cReg, byte i2cNumBytes) {
byte *result = calloc(i2cNumBytes, sizeof(byte));
for (byte i = 0; i < i2cNumBytes; i ++) {
result[i] += i2cAdd + i2cReg;
}
return result;
}

Arduino sketch with Serial.available() passes twice

When I test Serial.available() or Serial.available() > 0 in my loop() function, it appears to return true twice each time I enter serial data. The second time, it sets the throttle value in my code to 0. Here is the code:
#include <Servo.h>
Servo rc_rotor;
int throttle = 0; // servo position indicates throttle position.
String s_throttle_set = "Throttle set to: ";
String s_throttle_read = "Reading throttle value: ";
String s_action_error = "No action known for input value: ";
void setup()
{
rc_rotor.attach(9);
Serial.begin(9600);
while(! Serial);
Serial.println("Throttle value: 0 through 255, or 999 to read current value.");
}
void loop()
{
rc_rotor.write(throttle);
delay(20);
if (Serial.available())
{
int temp_throttle = Serial.parseInt();
if (temp_throttle >= 0 && temp_throttle <= 180)
{
throttle = temp_throttle;
Serial.println(s_throttle_set + throttle);
}
else if (temp_throttle == 999)
{
Serial.println(s_throttle_read + throttle);
}
else
{
Serial.println(s_action_error + temp_throttle);
}
}
}
Please note this code is not my final masterpiece. Much of it is from publicly available examples. Anyway, the statement if (Serial.available()) succeeds twice. By that I mean, it is true when I type in a value such as 125, and a moment later it will be 'true' again when I have typed in nothing additional. I only expect one value to go through this way. The result is that my throttle is being set to the value I enter, and then almost immediately re-set to 0. Why would something like this happen?
It turns out there is no mysterious problem with the hardware or the code, as I first suspected there was. Actually, the solution is simply to select "no line ending" in the Arduino Serial Monitor's dropdown option (by default, I guess mine was set to "New Line"). Without the additional character being inserted by the Serial Monitor, everything behaves as expected.
One thing I did not expect is how the Arduino software interprets the newline. I debugged by printing the ascii values that were making it through my if-statement. First of all, the Serial Monitor sent the number I typed in, followed moments later by ascii 10, which is the line feed character. Fine, no problem. But then Serial.parseInt() chewed on that line feed for a moment (there was a slight but noticeable delay), then fed the numeral 0 to my function. It took me a little while to figure out why. Here is an explanation from the Serial part of the Arduino Language Reference:
parseInt()
Description
Looks for the next valid integer in the incoming serial stream.
parseInt() inherits from the Stream utility class.
In particular:
Initial characters that are not digits or a minus sign, are skipped;
Parsing stops when no characters have been read for a configurable
time-out value, or a non-digit is read;
If no valid digits were read
when the time-out (see Serial.setTimeout()) occurs, 0 is returned;
So Serial.available() is true after the line feed character enters the buffer, but there is no "valid digit" according to Serial.parseInt(). Understandably... we are looking at an empty buffer that finally times out. Therefore Serial.parseInt() returns 0 and the code that follows proceeds with that value.
The code in the question assumed that the only input would be integers coming over the serial connection, which is actually a pretty fragile assumption. If you need to use Serial.parseInt in a situation where empty buffers (null), line feeds or other unexpected characters might come through, it should just be a matter of filtering the input better than I did in the example code.

Communication issue printing from Arduino to Qt using QSerialPort

I am having problems communicating FROM the arduino to my Qt application through QSerialPort. I have a listening signal that tells me when there is data ready to be read from the arduino. I expect a value for the number of steps that a stepper motor has undertaken before hitting a limit switch, so only a simple int such as "2005". When the data is available for reading, sometimes I get two separate reads with "200" and "5". Obviously this messes things up when I am parsing the data because it records it as two numbers, both much smaller than the intended number.
How can I fix this without me putting in a Sleep or QTimer to allow for a bit more time for the data to come in from the arduino? Note: my program is not multithreaded.
Example Qt code:
//Get the data from serial, and let MainWindow know it's ready to be collected.
QByteArray direct = arduino->readAll();
data = QString(direct);
emit dataReady();
return 0;
Arduino:
int count = 2005;
Serial.print(count);
You can add line break to synchronize.
Example Qt code:
//Get the data from serial, and let MainWindow know it's ready to be collected.
QByteArray direct = arduino->readLine();
data = QString(direct);
emit dataReady();
return 0;
Arduino:
int count = 2005;
Serial.print(count);
Serial.println();
If you are going to use QSerialPort::readyRead signal, you need to also use the QSerialPort::canReadLine function, see this.
Thank you for your help Arpegius. The println() function was definitely a good choice to use for the newline delimiter. And following that link, I was able to get a listening function that got everything the arduino sent as seperate strings. The extra if statements in the loop handle any cases where the incoming string does not contain the newline character (I am paranoid :D)
My code for anyone that has the same problem in the future.
int control::read()
{
QString characters;
//Get the data from serial, and let MainWindow know it's ready to be collected.
while(arduino->canReadLine())
{
//String for data to go.
bool parsedCorrectly = 0;
//characters = "";
//Loop until we find the newline delimiter.
do
{
//Get the line.
QByteArray direct = arduino->readLine();//Line();
//If we have found a new line character in any line, complete the parse.
if(QString(direct).contains('\n'))
{
if(QString(direct) != "\n")
{
characters += QString(direct);
characters.remove(QRegExp("[\\n\\t\\r]"));
parsedCorrectly = 1;
}
}
//If we don't find the newline straight away, add the string we got to the characters QString and keep going.
else
characters += QString(direct);
}while(!parsedCorrectly);
//Save characters to data and emit signal to collect it.
data = characters;
emit dataReady();
//Reset characters!
characters = "";
}
return 0;
}

Is there a way to receive data as unsigned char over UDP on Qt?

I need to send floating point numbers using a UDP connection to a Qt application. Now in Qt the only function available is
qint64 readDatagram ( char * data, qint64 maxSize, QHostAddress * address = 0, quint16 * port = 0 )
which accepts data in the form of signed character buffer. I can convert my float into a string and send it but it will obviously not be very efficient converting a 4 byte float into a much longer sized character buffer.
I got hold of these 2 functions to convert a 4 byte float into an unsinged 32 bit integer to transfer over network which works fine for a simple C++ UDP program but for Qt I need to receive the data as unsigned char.
Is it possible to avoid converting the floatinf point data into a string and then sending it?
uint32_t htonf(float f)
{
uint32_t p;
uint32_t sign;
if (f < 0) { sign = 1; f = -f; }
else { sign = 0; }
p = ((((uint32_t)f)&0x7fff)<<16) | (sign<<31); // Whole part and sign.
p |= (uint32_t)(((f - (int)f) * 65536.0f))&0xffff; // Fraction.
return p;
}
float ntohf(uint32_t p)
{
float f = ((p>>16)&0x7fff); // Whole part.
f += (p&0xffff) / 65536.0f; // Fraction.
if (((p>>31)&0x1) == 0x1) { f = -f; } // Sign bit set.
return f;
}
Have you tried using readDatagram? Or converting the data to a QByteArray after reading? In many cases a char* is really just a byte array. This is one of those cases. Note that the writeDatagram can take a QByteArray.
Generally every thing sent across sockets is in bytes not strings, layers on either end do the conversions. Take a look here, especially the Broadcaster examples. They show how to create a QByteArray for broadcast and receive.
Not sure why the downvote, since the question is vague in requirements.
A 4-byte float is simply a 4 character buffer, if cast as one. If the systems are homogenous, the float can be sent as a signed char *, and bit for bit it'll be the same read into the signed char * on the receiver directly, no conversion needed. If the systems are heterogenous, then this won't work and you need to convert it to a portable format, anyway. IEEE format is often used, but my question is still, what are the requirements, is the float format the same between systems?
If I read it correctly, your primary question seems to be how to receive data of type unsigned char with QT's readDatagram function which uses a pointer to a buffer of type char.
The short answer is use a cast along these lines:
const size_t MAXSIZE = 1024;
unsigned char* data = malloc(MAXSIZE);
readDatagram ( (unsigned char *)data, MAXSIZE, address, port )
I'm going to assume you have multiple machines which use the same IEEE floating point format but some of which are big endian and some of which are little endian. See this SO post for a good discussion of this issue.
In that case you could do something a bit simpler like this:
const size_t FCOUNT = 256;
float* data = malloc(FCOUNT * sizeof(*data));
readDatagram ( (char *)data, FCOUNT * sizeof(*data), address, port )
for (int i = 0; i != FCOUNT; ++i)
data[i] = ntohf(*((uint32_t*)&data[i]));
The thing to remember is that as far as networking functions like readDatagram are concerned, the data is just a bunch of bits and it doesn't care what type those bits are interpreted as.
If both ends of your UDP connection use Qt, I would suggest looking at QDataStream. You can create this from a QByteArray each time you read a datagram, and then read whatever values you require - floats, maps, lists, QVariants, and of course string.
Similarly, on the sending side, you'd create a data stream, push data into it, then send the resulting QByteArray over writeDatagram.
Obviously this only works if both ends use Qt - the data encoding is well-defined, but non-trivial to generate by hand.
(If you want stream orientated behaviour, you could use the fact that QUDPSocket is a QIODevice with a data-stream, but it sounds as if you want per-datagram behaviour)

Resources