String converted when I send it in a structure with RF24 library - struct

I'm sending a data struct with the RF24 library from one node to another. This structure contains two string and one float.
When I send the structure with the transmitter and I print it to the serial output I get this:
El sensor PIR situat en Menjador te el valor 1.00
I see this in the receiver when I print it to the serial output:
El sensor œ>U situat en Üߧŋ>r te el valor 1.00
Why are the two String changed ("PIR" and "Menjador")?
The structure is this:
struct sensorData {
String sensorType;
String sensorLocation;
float sensorValue;
} PIR1, sensor;
This is how I write it to the radio:
radio.write( &PIR1, sizeof(PIR1) ));
This is how I read it from the radio:
radio.read( &sensor, sizeof(sensor));
And this is how I print it to the serial output in the receiver:
void printOutData(sensorData* data) {
Serial.print("El sensor ");
Serial.print(data->sensorType);
Serial.print(" situat en ");
Serial.print(data->sensorLocation);
Serial.print(" te el valor ");
Serial.println(data->sensorValue);
}
Thank you!!

The String type does not actually contain the bytes of the sensor type and location; it points to the bytes. You are bascially sending the memory address of those bytes, not the bytes themselves.
You need to change your data structure so that it can contain the bytes inside the structure, with "C strings" aka "char arrays":
static const uint8_t SENSOR_TYPE_SIZE = 4;
static const uint8_t SENSOR_LOC_SIZE = 12;
struct sensorData {
char sensorType[ SENSOR_TYPE_SIZE ];
char sensorLocation[ SENSOR_LOC_SIZE ];
float sensorValue;
} PIR1, sensor;
Of course, you will have to change how you set those member values. Without your complete sketch, I can only offer a few possibilities:
void setup()
{
Serial.begin( 9600 );
// Set to a constant value (i.e., a double-quoted string literal)
strncpy( PIR1.sensorType, "TMP", sizeof(PIR.sensorType)-1 );
PIR1.sensorType[ sizeof(PIR.sensorType)-1 ] = '\0'; // NUL-terminate
// Set to characters received over Serial, up to size-1 chars *or* a newline
// (This blocks until the line is entered! Nothing else will happen
// until the line has been completely received.)
size_t count = Serial.readBytesUntil( '\n', PIR1.sensorType, sizeof(PIR.sensorType)-1 );
PIR.sensorType[ count ] = '\0'; // NUL-terminate
}
void loop()
{
// Non-blocking receive of a line. Other things can be performed
// while we're waiting for the newline to arrive.
if (Serial.available()) {
// A char finally came in!
char c = Serial.read();
// end-of-line?
if (c == '\n') {
// Pressed ENTER, send what we have now
PIR.sensorLocation[ count ] = '\0'; // NUL-terminate the C string
radio.write( &PIR1, sizeof(PIR1) ));
// Reset for next time
count = 0;
} else { // not end-of-line, save another char (if there's room)
if (count < sizeof(PIR.sensorLocation)-1) {
PIR.sensorLocation[ count++ ] = c;
}
}
}
// Do some other things here... maybe check some buttons?
}
There are many reasons to avoid String, so switching to char arrays will actually pay off in the long run.

Related

Why does the string output from Arduino look like alien text?

I'm trying to set up a serial communication between Arduino and MATLAB over USB. I have this basic code where I'm sending "hello" from MATLAB to Arduino, and I read it back and print it in MATLAB. However, the "hello" sent from Arduino looks like a strange text.
Arduino:
void setup() {
Serial.begin(57600);
Serial.println("ready");
}
void loop() {
String input;
if (Serial.available()) {
char c = Serial.read();
while (c != '\n') {
input += c;
c = Serial.read();
}
Serial.println("I received: " + String(input));
input = "";
}
}
MATLAB:
s = serial('COM3');
set(s, 'BaudRate', 57600);
fopen(s);
pause(1);
first = strtrim(convertCharsToStrings(fgetl(s)));
if first == "ready"
fprintf(s, '%s', 'hello\n');
for i = 1:10
tline = strtrim(convertCharsToStrings(fgetl(s)));
disp(tline);
if size(tline, 2) > 0
fprintf(s, '%s', 'hello\n');
end
end
end
fclose(s);
The output in MATLAB looks like this:
I received: hÿÿÿÿÿÿeÿÿÿÿÿÿÿlÿÿÿÿÿÿÿÿlÿÿÿÿÿÿoÿÿÿÿÿÿÿ
Also, I would appreciate any constructive criticism on improving my code for serial communication. This is my first time, and I'm trying to get a simple setup in which Arduino and MATLAB take turns writing and reading. Thank you.
Your microcontroller code reads faster than you're physically sending characters, so you're reading from an empty buffer. Serial.available() has one char for you, you read it, then you read more chars even though the receive buffer is already empty. Serial.read() will return -1 when there's nothing to read. -1 cast to char is 0xFF, or in Ascii 'ÿ'.
You could change loop() to something like
void loop() {
String input;
while (Serial.available()) {
char c = Serial.read();
if (c != '\n') {
input += c;
} else {
Serial.println("I received: " + String(input));
input = "";
}
}
}
Or you could go with Arduino's Serial.readString():
void setup() {
Serial.begin(57600);
Serial.setTimeout(20);
Serial.println("ready");
}
void loop() {
String input = Serial.readString();
Serial.println("I received: " + input);
}
Both untested, but you get the idea.

How to print an string array generated in processing to Arduino

I'm trying to send a string generated in processing to Arduino so that it can be printed on an LCD screen. Nothing appears on the LCD using this method. I Have tried various methods and from my research the method I'm trying is this :
#include <LiquidCrystal.h>
char inData[9]; // Allocate some space for the string
char inChar=-1; // Where to store the character read
byte index = 0; // Index into array; where to store the character
const int rs = 12, en = 11, d4 = 5, d5 = 4, d6 = 3, d7 = 2;
LiquidCrystal lcd(rs, en, d4, d5, d6, d7);
void setup() {
lcd.begin(16, 2);
lcd.setCursor(0,1);
Serial.begin(9600); // Start serial communication at 9600 bps
}
char Comp(char* This) {
while (Serial.available() > 0) // Don't read unless
// there you know there is data
{
if(index < 8) // One less than the size of the array
{
inChar = Serial.read(); // Read a character
inData[index] = inChar; // Store it
index++; // Increment where to write next
inData[index] = '\0'; // Null terminate the string
}
}
if (strcmp(inData,This) == 0) {
for (int i=0;i<8;i++) {
inData[i]=0;
}
index=0;
return(0);
}
else {
return(1);
}
}
void loop()
{
if(Serial.available() > 0){
lcd.print(inData[index]);
}
}
I am not sure about my anwser, but it might be because indata is being terminated before its even printed. Although i feel uneasy with my answser but hopefully it helped.
the termination:
inData[index] = '\0'; // Null terminate the string

Arduino ESP8266 read String from EEPROM

I achieve to read a String from the ESP8266 EEPROM - so far so good.
However, trying to append a second string to the just read first one does not work!
I start with having the number 2 at address 0 of the EEPROM. I read from address 0 to 6.
Here is my ESP8266.ino code :
String readM = "";
String appendixStr = "|||";
Serial.print("appendixStr = ");
Serial.println(appendixStr);
String dailyzStr = "";
for (int a = 0; a < 7; ++a) { // addr 0...6
dailyzStr += char(EEPROM.read(a));
}
readM += dailyzStr + appendixStr;
Serial.print("hmmm = ");
Serial.println(readM);
And here is what the log prints:
Clearly, I would expect hmmm = 2||| but I only get hmmm = 2
Why is it not possible to append ??
I would recommend to use this:
#include <EEPROM.h>
// Tell it where to store your config data in EEPROM
#define cfgStart 32
// To check if it is your config data
#define version "abc"
struct storeStruct_t{
char myVersion[3];
char name[32];
};
void saveConfig() {
// Save configuration from RAM into EEPROM
EEPROM.begin(4095);
EEPROM.put( cfgStart, settings );
delay(200);
EEPROM.commit(); // Only needed for ESP8266 to get data written
EEPROM.end(); // Free RAM copy of structure
}
void loadConfig() {
// Loads configuration from EEPROM into RAM
Serial.println("Loading config");
storeStruct_t load;
EEPROM.begin(4095);
EEPROM.get( cfgStart, load);
EEPROM.end();
// Check if it is your real struct
if (test.myVersion[0] != version[0] ||
test.myVersion[1] != version[1] ||
test.myVersion[2] != version[2]) {
saveConfig();
return;
}
settings = load;
}
// Empty settings struct which will be filled from loadConfig()
storeStruct_t settings = {
"",
""
};
Use saveConfig() to save the settings struct
If you want to load from the EEPROM use loadConfig() -> it will be stored in the settings struct

Echo Serial Strings with Arduino

EDIT 2: I got the solution. Anytime someone wants the code I'd be happy to provide. Peace.
Topic:
I'm trying an experiment of echoing strings that I receive in my arduino.
So this is the code so far:
byte byteRead = 0;
bool readable = LOW;
char fullString[50];
int index = 0;
void setup() {
Serial.begin(9600);
}
void loop() {
// State 1
if (Serial.available()) {
readable = HIGH; // flag to enter in the next state when there's nothing else to read
byteRead = Serial.read();
fullString[index] = (char)byteRead;
index++;
}
// State 2
if (readable == HIGH && !Serial.available()){
fullString[index] = '\0'; // '\0' to terminate the string
Serial.println(fullString);
// resets variables
index = 0;
readable = LOW;
}
/**
* Somehow a delay prevents characters of the string from having
* a line printed between them.
* Anyways, when the string is too long, a line is printed between
* the first and second characters
*/
delay(5);
}
Somehow this delay in the end prevents the characters of the string from having a line printed between them, like this:
H
e
l
l
o
Nonetheless, when the string is too long, a line is printed between the first and second characters.
Do you know a better way of doing this?
EDIT: Next time I'd appreciate answers from someone who actually KNOWS programming. Not just condescending idiots.
that's my String Echo
#define MAX_BUFFER_SIZE 0xFF
char buffer[MAX_BUFFER_SIZE];
void setup() {
Serial.begin(115200);
buffer[0] = '\0';
}
void loop() {
while (Serial.available() > 0) {
char incomingByte;
size_t i = 0;
do {
incomingByte = Serial.read();
buffer[i++] = incomingByte;
} while (incomingByte != '\0' && i < MAX_BUFFER_SIZE);
if(i > 0){
delay(1000); /// delay for the echo
Serial.write(buffer, i);
}
}
}
You want to echo the string read, so just echo the input.
void setup() {
Serial.begin(9600);
}
void loop() {
int c = Serial.read();
if (c >= 0) Serial.write(c);
}

Receiving number as string (uart)

I'm trying to receive a number through uart which is packed as a string. I'm sending number 1000, so I get 4 bytes + null character. But when I convert the array to number with atoi() and compare the integer with 1000 I don't always get a correct number. This is my interrupt handler function for receiving the number. What could be wrong?
void USART1_IRQHandler(void)
{
if( USART_GetITStatus(USART1, USART_IT_RXNE) )
{
char t = USART1->RDR;
if( (t != '\n' && t!='\0') && (cnt < 4) )
{
received_string[cnt] = t;
cnt++;
}
else
{
cnt = 0;
}
t = 0;
received_string[4] = 0;
}
if(cnt==4)
{
data = atoi(received_string);
}
}
Try this code instead. Here I check the max number of received bytes to avoid buffer overflow (and possible hardware fault). I created a specific function to clear the reception buffer. You can find also a definition for the string length because the code is more flexible. I suggest also to check the reception errors (after read the incoming byte) because in case of errors the reception is blocked.
//Define the max lenght for the string
#define MAX_LEN 5
//Received byte counter
unsigned char cnt=0;
//Clear reception buffer (you can use also memset)
void clearRXBuffer(void);
//Define the string with the max lenght
char received_string[MAX_LEN];
void USART1_IRQHandler(void)
{
if( USART_GetITStatus(USART1, USART_IT_RXNE) )
{
//Read incoming data. This clear USART_IT_RXNE
char t = USART1->RDR;
//Normally here you should check serial error!
//[...]
//Put the received char in the buffer
received_string[cnt++] = t;
//Check for buffer overflow : this is important to avoid
//possible hardware fault!!!
if(cnt > MAX_LEN)
{
//Clear received buffer and counter
clearRXBuffer();
return;
}
//Check for string length (4 char + '\0')
if(cnt == MAX_LEN)
{
//Check if the received string has the terminator in the correct position
if(received_string[4]== '\0'){
//Do something with your buffer
int data = atoi(received_string);
}
//Clear received buffer and counter
clearRXBuffer();
}
}
}
//Clear reception buffer (you can use also memset)
void clearRXBuffer(void){
int i;
for(i=0;i<MAX_LEN;i++) received_string[i]=0;
cnt=0;
}

Resources