Background
I've written an Arduino function which receives strings in the format "a,b,c,d,e" over a serial connection, where a,b,c,d,e are integers, and I'm trying to update an array with these integers every time a new string is received. The data is received and parsed into individual integers fine, but the array won't update properly.
Attempt
Below is the code, I've left the getData() function out as all it does is receive the string from the serial connection and store it in an array of characters input (that part is working fine).
void setup() {
Serial.begin(9600);
}
void loop() {
getData();
if(parsed == false){
parseData(readings);
}
}
void parseData(int readings[]) {
x = 0;
char * split;
split = strtok(input,",");
while (split != NULL)
{
readings[x] = split;
split = strtok (NULL, ",");
x++;
}
parsed = true;
}
Problem
If I send a string like "6,7,8,9,0", the array readings[] is updated to [289,291,293,295,297] no matter what values I send, I have checked what values split takes inside the function and they are correct, however the line readings[x] = split; fails to update the array elements to anything other than those 5 numbers in that order. This is the case when the value of readings[n] is checked inside or outside the parseData function.
Also, if I send fewer than 5 integers in the string, e.g. a,b,c, only the first array elements will change and the others will remain at 0, e.g. [289,291,293,0,0]
Before I found out about passing array pointers to functions, the exact same thing was happening with slightly different code - when I called the function in the loop, I just used parseData();, and when I defined the function I just used void parseData(){
Question
Why isn't the array updating properly and how can I fix it?
Your readings is an array of integers.
And split is a pointer-to-char.
The statement
readings[x] = split
stores split, which is the address of a character, as an integer value.
If I write
const char *pointer = "42";
int address = pointer;
I am not storing the integer value 42 in address - I'm storing the number identifying the memory location of the first character in my string.
If you want to convert a string into an integer, you need to parse it with a function like strtol.
Related
The characters I got for Arduino BLE characteristics reading are always tailed with some random characters. For example, the printing should ends with "test string" but it actually print out "test string !" The tailing string is randomized based on different string being sent.
Any suggestions for resolving this issue?
The code for reading character is the following:
void incomingCharacteristicWritten(BLEDevice central, BLECharacteristic characteristic) {
byte value[characteristic.valueLength()];
incomingDataCharacteristic.readValue(value, characteristic.valueLength());
Serial.print("Characteristic event, written: ");
Serial.print((char *) value);
}
The problem is that readValue() writes to a buffer of bytes, which is NOT the same as a null-terminated C string. So by simply casting the buffer to a char * and printing it, the print() function will stop when it encounters the first null character. This may be soon or late, depending on what arbitrary contents you have in memory. This explains the random characters you've observed.
To fix this, either print the bytes one at a time in a loop, convert it to a C++ string, or make sure to null-terminate it.
For example, the following should work:
void incomingCharacteristicWritten(BLEDevice central, BLECharacteristic characteristic) {
int length = characteristic.valueLength();
byte value[length + 1]; // one byte more, to save the '\0' character!
incomingDataCharacteristic.readValue(value, length);
value[length] = '\0'; // make sure to null-terminate!
Serial.print("Characteristic event, written: ");
Serial.print((char *) value);
}
I am doing this IoT based project on displaying data to connected display( I've used the MAX7219 module, in this case) with the help of nodeMCU. The idea here is that the string which is stored in my firebase database is to be display on the led display.
I've had no trouble in getting the value from the database to my nodeMCU but there is this little problem with converting that string to char array since the code i am using( Max72xx_Message_serial, which was available as an example with the max72xx library) has used char array but i can only fetch the stored data in string format. I've modified that code so as to connect with firebase but the main issue is to convert the string fetched from the database to char array.
I tried toCharArray() but it still shows conversion error.
void readfromfirebase(void)
{
static uint8_t putIndex = 0;
int n=1;
while (Firebase.available())
{
newMessage[putIndex] = (char)Firebase.getString("Submit Message"); // this line produces the error
if ((newMessage[putIndex] == '\n') || (putIndex >= BUF_SIZE-3)) // end of message character or full buffer
{
// put in a message separator and end the string
newMessage[putIndex++] = ' ';
newMessage[putIndex] = '\0';
// restart the index for next filling spree and flag we have a message waiting
putIndex = 0;
newMessageAvailable = true;
}
else if (newMessage[putIndex] != '\r')
// Just save the next char in next location
{putIndex++;}
n++;
}
}
I think you are confusing the types
getString returns a String object wich can be converted to a char[] using the methods of the String class.
I assume your newMessage is of type char[] or char*.
Then I would advise you to go for the String.c_str() method, because it returns a C style null-terminated string, meaning a char*.
See https://www.arduino.cc/reference/en/language/variables/data-types/string/functions/c_str/ for reference.
It also sets the last character of the string to 0. So methods like strlen, strcmp etc will work.
! be carefull not to modify the array returned by c_str(), if you want to modify it you chould copy the char[] or use string.toCharArray(buf, len).
Your Code might then look like the following.
String msg = Firebase.getString("Submit Message");
newMessage = msg.c_str();
// rest of your code
If newMessage is a buffer storing multiple messages, meaning char* newMessage[3].
String msg = Firebase.getString("Submit Message");
newMessage[putIndex] = msg.c_str();
// rest of your code
Be careful, because you are storing multiple characters in an array, so use strcmp to compare these arrays!
If you are new to C I would recommend reading.
https://www.cprogramming.com/tutorial/c/lesson9.html
https://www.arduino.cc/reference/en/language/variables/data-types/stringobject/ (as pointed out by #gre_gor)
I'm trying to collect data from a simple multimeter circuit, but instead of returning numbers my serial port is just outputting random Unicode symbols.
Here's my code:
void setup() {
pinMode(2, INPUT);
Serial.begin(1200);
int prevVal = 0;
int timeVar = 0;
}
void loop() {
int digisensorVal = digitalRead(2);
int anasensorVal = analogRead(2) * 100;
Serial.print("D" + digisensorVal);
Serial.print(",");
Serial.println("A" + anasensorVal);
delay(250);
}
And here's a sample of the output:
⸮L/⸮U⸮⸮⸮⸮⸮?⸮⸮⸮w⸮e⸮⸮⸮⸮1⸮⸮⸮⸮}⸮J⸮⸮⸮⸮⸮oޝ⸮Y⸮⸮⸮|s⸮⸮}⸮⸮⸮⸮⸮⸮⸮є6x⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮y[⸮⸮⸮⸮⸮?⸮v⸮=⸮⸮⸮-⸮^⸮Y_z⸮⸮d⸮⸮⸮%ܿjV⸮~O⸮⸮G⸮⸮⸮⸮e⸮⸮U⸮⸮~+0⸮⸮⸮hh⸮s⸮
⸮c⸮⸮⸮+⸮⸮io3:⸮5kλϣ
,⸮g⸮⸮⸮⸮⸮>⸮⸮
⸮yꨛ⸮v⸮N⸮⸮⸮=⸮⸮=⸮⸮⸮l⸮⸮g⸮g⸮⸮⸮⸮⸮s⸮U⸮⸮⸮⸮⸮⸮=⸮ܳt⸮⸮⸮}⸮⸮'⸮˾⸮k⸮⸮⸮⸮⸮⸮⸮{⸮ᦒ⸮⸮⸮⸮ϓ߿gVp⸮⸮⸮⸮Y⸮⸮O⸮/F⸮~⸮⸮⸮⸮q4⸮⸮_f⸮⸮⸮⸮⸮I|P⸮⸮⸮NE⸮~u⸮7⸮⸮⸮⸮g⸮⸮G~⸮⸮⸮⸮__#⸮⸮⸮⸮⸮⸮⸮C⸮⸮⸮k⸮T⸮o/⸮t^⸮~⸮{}⸮w⸮⸮⸮⸮'h=⸮ϸ~⸮⸮⸮⸮⸮⸮⸮?⸮s⸮s⸮l⸮o5⸮^⸮⸮⸮w9{]⸮⸮q~⸮⸮⸮,⸮⸮⸮c⸮2_⸮⸮⸮⸮o6k)ޏ⸮k⸮ׇ⸮i⸮⸮m⸮⸮:⸮⸮⸮⸮|⸮⸮??⸮⸮⸮⸮3⸮⸮⸮⸮⸮⸮⸮⸮⸮^⸮⸮ڏ⸮⸮⸮⸮l⸮⸮⸮⸮⸮⸮H⸮~⸮>⸮⸮z⸮⸮⸮⸮⸮OwM;⸮⸮l⸮⸮
⸮sr⸮S⸮⸮}⸮⸮⸮⸮ׂٶ⸮⸮~⸮{⸮⸮]⸮⸮⸮⸮⸮⸮⸮⸮i⸮⸮⸮⸮⸮[⸮⸮⸮⸮⸮Nz⸮⸮⸮⸮⸮k⸮⸮⸮⸮⸮g⸮k⸮⸮⸮i3ɵ⸮⸮~⸮⸮⸮⸮⸮]⸮2ϪWކ⸮i>⸮gu⸮⸮ӵ⸮?⸮̥⸮⸮m⸮⸮|⸮⸮⸮⸮Wɓ⸮⸮⸮[⸮⸮O㠑_⸮⸮⸮⸮⸮⸮⸮⸮⸮/⸮M⸮⸮_⸮⸮gwF⥷⸮⸮yn⸮P⸮⸮-⸮⸮⸮N⸮⸮⸮=⸮⸮⸮⸮⸮⸮⸮>J⸮}⸮⸮&⸮⸮⸮C⸮HG翎⸮/⸮⸮⸮⸮}⸮⸮⸮^⸮⸮,⸮)[⸮⸮⸮⸮⸮⸮У⸮⸮}⸮ޯ⸮⸮⸮⸮7⸮⸮⸮⸮ó⸮U:~⸮⸮ns⸮⸮z⸮⸮n⸮⸮G|ӳ⸮⸮}⸮⸮L⸮~⸮⸮KI⸮⸮G⸮⸮⸮⸮⸮⸮ӏ⸮⸮⸮⸮u6⸮W⸮⸮⸮⸮Ӊ۾⸮⸮9⸮zVΆ럿⸮⸮⸮ۘ⸮⸮T⸮<⸮⸮⸮⸮⸮⸮⸮/⸮⸮⸮⸮xG~⸮V⸮⸮u+N⸮⸮ݫ⸮⸮⸮cv~⸮⸮⸮W⸮
Serial.println("A" + anasensorVal);
This needs to be done in two lines. You're adding the sensor value to a pointer value and sending whatever garbage is pointed to at the memory location that adds up to. And it definitely isn't what you want. This isn't Java. You can't just add strings with a + like that.
With
Serial.println("A" + anasensorVal);
you are not actually printing number, but a string from some place in the memory starting at the address of "A" + value of "anasensorVal" and thus you will get some garbage.
You are trying to add an integer to a pointer to char(and likely move beyond the end of the string "A"), that's not what you want.
The usual way of formating output on arduino:
Serial.print("A");
Serial.println(anasensorVal);
Alternatively, you can define a stream operator for the Serial object, see https://playground.arduino.cc/Main/StreamingOutput how to do that and then format output like this:
Serial << "A" << anasensorVal;
Adding an int type and character type in Serial.print is messing up the format of the data you are trying to print to the monitor.
With reference to the code below: After calling the function CheckSMS and passing the struct * DB1, the fields are updated according the the strtok call. This function reads and parses a text message, storing its contents into char* fields of the DB struct.
In the main loop, I have called Serial.println(DB1.last_order) before and after calling the CheckSMS function. If I have received a text, the order is printed appropriately in the main loop, however on the next call to CheckSMS, DB1.last_order is cleared, replaced with a \n or a NULL or something. I cannot figure out why DB1.last_order does not retain its value, and rather, it is overwritten with every call to CheckSMS. Thanks for any help.
Note - All text messages contain "CMT+", therefore writing to DB1 only happens when a text is received. Calling CheckSMS when no text is received should simply skip through.
int CheckSMS(Robot *DB1) {
int j = 0;
char response[100];
char *pch;
unsigned long previous;
memset(response, '\0', 100);
while(Serial2.available()>0){
response[j] = Serial2.read();
j++;
Serial.println("inc");
}
delay(100);
if (strstr(response, "CMT:") != NULL){
DB1->new_message = strtok(response, " ,");
DB1->last_phone = strtok(NULL, " ,");
pch = strtok(NULL, " ,");
DB1->last_date = strtok(NULL, " ,");
DB1->last_time = strtok(NULL, " ,\n");
DB1->last_order = strtok(NULL," ,\n");
new_message = 1;
}
else{
}
return 0;
}
The strtok function returns pointers to the string you're tokenizing, the local array response in your case. When the function returns the response array goes out of scope and disappears, leaving your structure with pointers to a string that no longer exists, and giving you undefined behavior.
You have a couple of solutions:
Allocate the string dynamically using malloc, but then you must save it in the structure so you can free it when you're done with the structure
Make the response array static, but then the next call to the function will have the same array leading the old data to be updated
Pass in a string to store the response and use that string, the string must have a lifetime at least as long as the structure and don't change contents. The string can of course be a member of the structure itself
The answer Joachim gave is correct, I just want to add that you could also change the Robot structure to contain char arrays (like this: char new_message[MAX_BUF_CHARS]; and so on). Be sure to have enough space in them. Then instead of assigning the pointers returned from strtok, copy the strings in there.
I'm trying to create a binary representation of a string of characters but could only print them using serial.print(arr,BIN);
Is there a way to save the binary values of each char of the string to an array or even a long number?
* Working on Arduino sketch (C++) if it makes any difference.
I used this code trying to create an array but couldn't make it work:
void loop() {
String Message = "Hello World";
int l = Message.length();
int BinMessage[l];
for (int j=0; Message[j] != NULL; j++){
BinMessage[j] = String(Message[j], BIN);
Serial.println(BinMessage);
}
One option might be to use bitRead function to read the bits of each character one by one, then store those values as characters in a new string.