Sscanf ruins my code :(

Ok a little update for people who don't want to read trough the entire thread:

Goal: Send a 6-digit code via 433Mhz to an Arduino, the code should be split up in three pieces (123456 would be split up in 12, 34 and 56) these pieces each represent a color in my RGB setup.

Problem:
the code i must use is an long integer, in order to slice it up i want to convert it to an Char array, i tried doing this by using:

-sscanf
-.toCharArray
-sprintf

all of these codes prevent the code from running multiple times (they can do it once successfully but won't run a second time)

Question:

So the question is:

  1. Why do these functions mess up my sketch, they work perfectly besides the fact they can only be used one time.
  2. Is there an alternative? or a way to split an integer like this?

Thank you for reading this and my apologies for my lack of knowledge as i'm completely new to this :blush:

Here is my current code:

#include <RCSwitch.h>
#include <sstream.h> // std::istringstream
#include <iostream.h>
#include <string.h>

RCSwitch mySwitch = RCSwitch();

int ledPinR = 9;
int ledPinG = 10;
int ledPinB = 11;
int Fblue;
char red [3] = {0,0,0};
char blue [3] = {0,0,0};
char green [3] = {0,0,0};
char Pred [3] = {0,0,0};
char Pblue [3] = {0,0,0};
char Pgreen [3] = {0,0,0};
String str;


void setup() {
  pinMode(ledPinR, OUTPUT);
  pinMode(ledPinG, OUTPUT);
  pinMode(ledPinB, OUTPUT);
  
  Serial.begin(9600);
  mySwitch.enableReceive(0);  // Receiver on inerrupt 0 => that is pin #2
  Serial.println("Setup was succesfull");
}

void loop() {
  if (mySwitch.available()) {
    Serial.println("mySwitch is available");
    long value = mySwitch.getReceivedValue();
    int length = floor(log10(value)+1);
    if (length == 6){
      Serial.print("This is mySwitch.getReceivedValue, it should contain 6 numbers:");
      Serial.println( mySwitch.getReceivedValue() );
      Serial.print("This is value, it should contain 6 numbers:");
      Serial.println(value);
      char data [7];

      ----------Here should the value of value be copied to data ----------------
     
      Serial.print("This is data, it should contain 6 numbers:");
      Serial.println(data);
      memcpy(red,data+0,2); //copy 2 bytes starting from data[0]
      memcpy(blue,data+2,2); //copy 2 bytes starting from data[2]
      memcpy(green,data+4,2); //copy 2 bytes starting from data[4]
        Serial.print("This is blue, it is an char and should contain 2 numbers:");
        Serial.println(blue);
        Fblue = atoi(blue); 
        Serial.print("This is Fblue, it is an int and should contain 2 numbers:");
        Serial.println(Fblue);
       analogWrite(ledPinB, Fblue);
       // Pblue = Fblue incompatible types in assignment of 'int' to 'char [3]
       strcpy (Pblue,blue);
       Serial.println(Pblue);
      
      
      }
      mySwitch.resetAvailable();
      Serial.println("Available is reseted");
      }
    

}

If i include one of the functions listed above this is the result, no matter how many codes i keep sending: (first code i send was 222222 in this case)

Setup was succesfull
mySwitch is available
This is mySwitch.getReceivedValue, it should contain 6 numbers:222222
This is value, it should contain 6 numbers:222222
This is data, it should contain 6 numbers:222222
This is blue, it is an char and should contain 2 numbers:22
This is Fblue, it is an int and should contain 2 numbers:22
22
Available is reseted

-----------------------------Outdated-Info--------------------------------------
Ok so i have a piece of code right here:

void loop() {
  if (mySwitch.available()) {
    Serial.println("Test1");
    int value = mySwitch.getReceivedValue();
    String code = String(value);
    String Sblue = code.substring(0,3);
    sscanf(Sblue.c_str(), "%d", &blue);
    Serial.print(blue);
    if (blue != Cblue) {
    analogWrite(ledPinR, blue);
    Cblue = blue;
    Serial.println("blauw");
    }
    
    mySwitch.resetAvailable();
    Serial.println("reset");
    }

}

Serial monitor with sscanf:

Test1
100blauw
reset
(only works 1 time)

Serial monitor without sscanf:

Test1
0blauw
reset
(works for ever)

I can send a code once and it wil work perfectly, but when i send a second one the first if statement wil not act as if it is TRUE, while it is! When i remove: sscanf(Sblue.c_str(), "%d", &blue); it does repeat the proces correctly but obviously renders my code useless. If somebody could help me over here i would be most grateful, i already asked a friend with a lot of experience but as he specialises in Java he couldn't solve it.

Thanks in advance!

p.s. This is an Example that came with the library.

/*
  Simple example for receiving
  
  http://code.google.com/p/rc-switch/
  
  Need help? http://forum.ardumote.com
*/

#include <RCSwitch.h>

RCSwitch mySwitch = RCSwitch();

void setup() {
  Serial.begin(9600);
  mySwitch.enableReceive(0);  // Receiver on inerrupt 0 => that is pin #2
}

void loop() {
  if (mySwitch.available()) {
    
    int value = mySwitch.getReceivedValue();
    
    if (value == 0) {
      Serial.print("Unknown encoding");
    } else {
      Serial.print("Received ");
      Serial.print( mySwitch.getReceivedValue() );
      Serial.print(" / ");
      Serial.print( mySwitch.getReceivedBitlength() );
      Serial.print("bit ");
      Serial.print("Protocol: ");
      Serial.println( mySwitch.getReceivedProtocol() );
    }

    mySwitch.resetAvailable();
  }
}
sscanf(Sblue.c_str(), "%d", &blue);

What is a "blue"?
Why are you bothering with String?

Wow thanks for the fast response!

this is everything:

#include <RCSwitch.h>
#include <sstream.h> // std::istringstream

RCSwitch mySwitch = RCSwitch();

int ledPinR = 9;
int ledPinG = 10;
int ledPinB = 11;
int red = 0;
int green = 0;
int blue = 0;
int Cred = 0;
int Cgreen = 0;
int Cblue = 0;

void setup() {
  pinMode(ledPinR, OUTPUT);
  pinMode(ledPinG, OUTPUT);
  pinMode(ledPinB, OUTPUT);
  
  Serial.begin(9600);
  mySwitch.enableReceive(0);  // Receiver on inerrupt 0 => that is pin #2
}

void loop() {
  if (mySwitch.available()) {
    Serial.println("Test1");
    int value = mySwitch.getReceivedValue();
    String code = String(value);
    String Sblue = code.substring(0,3);
    sscanf(Sblue.c_str(), "%d", &blue); // dit verpest de code
    Serial.print(blue);
    if (blue != Cblue) {
    analogWrite(ledPinR, blue);
    Cblue = blue;
    Serial.println("blauw");
    }
    
    mySwitch.resetAvailable();
    Serial.println("reset");
    }

}

i use the string so i can take parts from the decimal code the Arduino receives

value is an int. what kind of string are you expecting from it? What happens if it is not 4 characters long?

I'm not very familiar with the String, this is the first time i've used it and you're right, when i use more digits, for example 1500000 it gives this:

Test1
-73blauw
reset

while i want it to be 150, apparently a String is not suited for this, but what should i use then?

edit:
Maybe it's more useful when i explain what i want to archive, i want the arduino to be able to receive a code trough RC with 9 decimals (three times a value between 0 and 255) to drive an RGB LED. So the arduino has to split up the code in three pieces and write the values to the pins.

Just use a char array and pick it apart.

I have very little experience, i certainly won't ask you to write down the code but can you point me in the right direction, how would i do such a thing?

And by the way thanks for the fast responses and the enormous help you guys give to someone who has a post count of 5, and in all of them i'm asking for help :sweat_smile:

Google "char array c++". You will instantly (first result) find an explanation of what a char array is.
Then google sscanf. The first result is an explanation and sample code of how to use the function.

Ditch the "String" class and use char arrays.

Okay, i googled it and searched a bit, also found other options like "std::string", "std::string::copy" and maybe "scanf"?? but how would i split a char array of 9 characters into three pieces? (1,3-4,6-7,9) i can't find any info on that subject.

It depends how you want them split. If it just in thirds, you can do something simple like:

char data [9] = {1,2,3,4,5,6,7,8,9};
char left [3];
char mid [3];
char right [3];
memcpy( left,data+0,3); //copy 3 bytes starting from data[0]
memcpy(  mid,data+3,3); //copy 3 bytes starting from data[3]
memcpy(right,data+6,3); //copy 3 bytes starting from data[6]

Ok, i have put the piece of code in my sketch, sometimes it works and sometimes it doesn't but my main problem is:

When i send a code with 4 digits it works (80% of the time)

Setup was successful
mySwitch is available
This is data, it should contain 6 numbers:1231
31This is blue, it is an char and should contain 2 numbers:31
This is Fblue, it is an int and should contain 2 numbers:31
31
Available is reseted

But when i send a code with 6 digits (in this case: 123123) it fails.

Setup was successful
mySwitch is available
This is data, it should contain 6 numbers:-7949
9439This is blue, it is an char and should contain 2 numbers:9439
This is Fblue, it is an int and should contain 2 numbers:9439
9439
Available is reseted

here is my entire sketch :

#include <RCSwitch.h>
#include <sstream.h> // std::istringstream
#include <iostream.h>
#include <string.h>

RCSwitch mySwitch = RCSwitch();

int ledPinR = 9;
int ledPinG = 10;
int ledPinB = 11;
int Fblue;
char red [3] = {0,0,0};
char blue [3] = {0,0,0};
char green [3] = {0,0,0};
char Pred [3] = {0,0,0};
char Pblue [3] = {0,0,0};
char Pgreen [3] = {0,0,0};
String str;


void setup() {
  pinMode(ledPinR, OUTPUT);
  pinMode(ledPinG, OUTPUT);
  pinMode(ledPinB, OUTPUT);
  
  Serial.begin(9600);
  mySwitch.enableReceive(0);  // Receiver on inerrupt 0 => that is pin #2
  Serial.println("Setup was succesfull");
}

void loop() {
  if (mySwitch.available()) {
    Serial.println("mySwitch is available");
    int value = mySwitch.getReceivedValue();
    //char data [7] = {value}; does not work
    char data [6];
    //value++;
    str = String(value);
    str.toCharArray(data,6); // from: "https://sites.google.com/site/kingauswebpage/my-projects/arduino-how-to-convert-int-to-char-array"
    Serial.print("This is data, it should contain 6 numbers:");
    Serial.println(data);
    char red [3];
    char blue [3];
    char green [3];
    memcpy(red,data+0,2); //copy 2 bytes starting from data[0]
    memcpy(blue,data+2,2); //copy 2 bytes starting from data[2]
    memcpy(green,data+4,2); //copy 2 bytes starting from data[4]
Serial.print(blue);
    if (blue != Pblue) {
      Serial.print("This is blue, it is an char and should contain 2 numbers:");
      Serial.println(blue);
      //Fblue = int(blue); alternative
      Fblue = atoi(blue); 
      //Fblue++;
      Serial.print("This is Fblue, it is an int and should contain 2 numbers:");
      Serial.println(Fblue);
     analogWrite(ledPinB, Fblue);
     // Pblue = Fblue incompatible types in assignment of 'int' to 'char [3]
     strcpy (Pblue,blue);
     Serial.println(Pblue);
    }
    
    mySwitch.resetAvailable();
    Serial.println("Available is reseted");
    }
    

}

The issues I see:
(1) you are still using the String class, which won't guarantee that you get 6 characters.
(2) you are not adding a null termination to the 'red', 'blue', and 'green' strings because you have made an uninitialized local copy which shadows the global one which has a null.
(3) you cannot compare c-strings by using the == operator. You have to use strcmp().

Try this:

RCSwitch mySwitch = RCSwitch();

int ledPinR = 9;
int ledPinG = 10;
int ledPinB = 11;
int Fblue;
char red [3] = {0,0,0};
char blue [3] = {0,0,0};
char green [3] = {0,0,0};
char Pred [3] = {0,0,0};
char Pblue [3] = {0,0,0};
char Pgreen [3] = {0,0,0};
String str;


void setup() {
  pinMode(ledPinR, OUTPUT);
  pinMode(ledPinG, OUTPUT);
  pinMode(ledPinB, OUTPUT);
  
  Serial.begin(9600);
  mySwitch.enableReceive(0);  // Receiver on inerrupt 0 => that is pin #2
  Serial.println("Setup was succesfull");
}

void loop() {
  if (mySwitch.available()) {
    Serial.println("mySwitch is available");
    unsigned int value = mySwitch.getReceivedValue();
    char data [7];
    sprintf(data,"%06d",value); //convert 'value' to a string which is padded with 0's to 6 characters.
    Serial.print("This is data, it should contain 6 numbers:");
    Serial.println(data);
    memcpy(red,data+0,2); //copy 2 bytes starting from data[0]
    memcpy(blue,data+2,2); //copy 2 bytes starting from data[2]
    memcpy(green,data+4,2); //copy 2 bytes starting from data[4]
    Serial.print(blue);
    if (strcmp(blue,Pblue)) {
      Serial.print("This is blue, it is an char and should contain 2 numbers:");
      Serial.println(blue);
      Fblue = atoi(blue); 
      Serial.print("This is Fblue, it is an int and should contain 2 numbers:");
      Serial.println(Fblue);
     analogWrite(ledPinB, Fblue);
     // Pblue = Fblue incompatible types in assignment of 'int' to 'char [3]
     strcpy (Pblue,blue);
     Serial.println(Pblue);
    }
    
    mySwitch.resetAvailable();
    Serial.println("Available is reseted");
    }
    

}

OK first of all thank you because this solved several problems, first the value of data is now always 6 digits and slicing the value works as expected. But unfortunately some errors are stil present. For example the Arduino still refuses to see the if statement as true the second time, sometimes i get to the 3d but that's rare. And i stil get weird numbers when i send a code with more digit's than six :

The fist time it was 1212 witch is processed perfectly and the second time it was 121212...

This is data, it should contain 6 numbers:001212
12Available is reseted
mySwitch is available
This is data, it should contain 6 numbers:-09860
98Available is reseted

Oh and btw i replaced "!strcmp(blue,Pblue)" with "strcmp (blue,Pblue) != 0"
and "sprint(data,"%06d",value);" to "sprintf(data,"%06d",value); "

the Arduino still refuses to see the if statement as true the second time

Almost certainly because it isn't true.
But you haven't posted your code, so on the balance of probability, I'm going to exhonorate the Arduino..

rutierut:
and "sprint(data,"%06d",value);" to "sprintf(data,"%06d",value); "

Sorry about the 'sprint' rather than 'sprintf', IE keeps automatically correcting it as I type.

I believe it is because %d is seeing it as a signed number, try this instead:

sprintf(data,"%06u",value); //convert 'value' to a string which is padded with 0's to 6 characters.

haha doesn't matter i'm already very happy with you help, but it is still not working,

I'm sending these codes

pi@Willems ~ $ sudo ./codesend 101010
sending code[101010]
pi@Willems ~ $ sudo ./codesend 101210
sending code[101210]
pi@Willems ~ $ sudo ./codesend 111111
sending code[111111]
pi@Willems ~ $ sudo ./codesend 222222
sending code[222222]
pi@Willems ~ $

and this is the arduino sketch

#include <RCSwitch.h>
#include <sstream.h> // std::istringstream
#include <iostream.h>
#include <string.h>

RCSwitch mySwitch = RCSwitch();

int ledPinR = 9;
int ledPinG = 10;
int ledPinB = 11;
int Fblue;
char red [3] = {0,0,0};
char blue [3] = {0,0,0};
char green [3] = {0,0,0};
char Pred [3] = {0,0,0};
char Pblue [3] = {0,0,0};
char Pgreen [3] = {0,0,0};
String str;


void setup() {
  pinMode(ledPinR, OUTPUT);
  pinMode(ledPinG, OUTPUT);
  pinMode(ledPinB, OUTPUT);
  
  Serial.begin(9600);
  mySwitch.enableReceive(0);  // Receiver on inerrupt 0 => that is pin #2
  Serial.println("Setup was succesfull");
}

void loop() {
  if (mySwitch.available()) {
    Serial.println("mySwitch is available");
    unsigned int value = mySwitch.getReceivedValue();
    char data [7];
    sprintf(data,"%06u",value); //convert 'value' to a string which is padded with 0's to 6 characters.
    Serial.print("This is data, it should contain 6 numbers:");
    Serial.println(data);
    memcpy(red,data+0,2); //copy 2 bytes starting from data[0]
    memcpy(blue,data+2,2); //copy 2 bytes starting from data[2]
    memcpy(green,data+4,2); //copy 2 bytes starting from data[4]
    Serial.print(blue);
    if (strcmp (blue,Pblue) != 0) {
      Serial.print("This is blue, it is an char and should contain 2 numbers:");
      Serial.println(blue);
      Fblue = atoi(blue); 
      Serial.print("This is Fblue, it is an int and should contain 2 numbers:");
      Serial.println(Fblue);
     analogWrite(ledPinB, Fblue);
     // Pblue = Fblue incompatible types in assignment of 'int' to 'char [3]
     strcpy (Pblue,blue);
     Serial.println(Pblue);
    }
    
    mySwitch.resetAvailable();
    Serial.println("Available is reseted");
    }
    

}

and this is the Serial output: (just one time as you see and a entire different code)

Setcesfull
Setup was succesfull
mySwitch is available
This is data, it should contain 6 numbers:035474
54This is blue, it is an char and should contain 2 numbers:54
This is Fblue, it is an int and should contain 2 numbers:54
54
Available is reseted

when sending 4 digit codes this happens:

433 Mhz transmitter

pi@Willems ~ $ sudo ./codesend 2222
sending code[2222]
pi@Willems ~ $ sudo ./codesend 1111
sending code[1111]

Serial output from arduino:

Setup was succesfull
mySwitch is available
This is data, it should contain 6 numbers:002222
22This is blue, it is an char and should contain 2 numbers:22
This is Fblue, it is an int and should contain 2 numbers:22
22
Available is reseted

That appears to be doing what it should.

Could you elaborate as to what you are expecting to see?

Check the return value from getReceivedValue, it's supposed to be an unsigned long.

That's why 6 digits doesn't work (you're overflowing your unsigned int).

Hope this helps,

Brad
KF7FER

EDIT: Minor typo/grammar correction/ugh!

Ah, see what you mean now.

Yes, as Brad said, you will need your 'value' variable declared as an unsigned long, and also make sure that the getRecievedValue() function has a return type of unsigned long as well.

Tom-

That was supposed to be the point of my poorly edited post (done via tablet at McDonalds on break).

In the library being used the getReceivedValue() function does indeed have a return value of unsigned long, which is what I was trying to indicate.

Thanks for making a much clearer post than I did.

Regards,

Brad
KF7FER