Transferring FLOAT data via HC12

I want to transfer numerical data from on arduino to another using the HC12. The HC12 uses the arduino Library SoftwareSerial.
I want to transfer FLOAT data in the numerical format from max. 999.99. I have tried int and left off the decimal parts but i only number up to 255 which I understand. I have also read a lot about Serial transfer using parse float but this does not work with the HC12, at least I cannot get it to work.
I have attached my code that works with INT, please advise how I can get it to work with FLOAT if possible.
On the TX and RX side.

/*
  HC12_BME280_altitude_TX_paul_V2_18_03_2018

  Receives from the hardware serial, sends to software serial.
  Receives from software serial, sends to hardware serial.

  The circuit:
   RX is digital pin 10 (connect to TX of other device)
   TX is digital pin 11 (connect to RX of other device)


*/
#include <SoftwareSerial.h>

SoftwareSerial mySerial(10, 11); // RX, TX
int ref = 0;

void setup() {
  // Open serial communications and wait for port to open:
  Serial.begin(9600);
  mySerial.begin (9600);
}
void loop() {
  if (ref > 9) {
    ref = 0;
  }
  else {
    ref ++;

  }
  // if (mySerial.available()) {  (this does not work when I remove the //)
  mySerial.write(ref);
  Serial.print("ref =      ");
  Serial.println(ref);
  delay(100);
  // }
}
/*
  HC12_BME280_altitude_RX_paul_V2_18_03_2018

  Receives from the hardware serial, sends to software serial.
  Receives from software serial, sends to hardware serial.

  The circuit:
   RX is digital pin 10 (connect to TX of other device)
   TX is digital pin 11 (connect to RX of other device)
*/
#include <SoftwareSerial.h>
int ref;
SoftwareSerial mySerial(10, 11); // RX, TX

void setup() {
  // Open serial communications and wait for port to open:
  Serial.begin(9600);
  mySerial.begin (9600);
}
void loop() { // run over and over
  if (mySerial.available() > 1) {
    ref = (mySerial.read());
    Serial.println(ref);

  }
}

This page has some information on using a union to send data types larger than a byte. There are other ways like using dtosrf() and sending a string (NULL terminated character array). Use atof() on the receiving end to get the float back.

Also the serial input basics tutorial will help you improve the sending and receiving of the data.

Thank you for the information. I have no problem with the normal serial transmission, this works. It is specifically using HC12 and SoftwareSerial library I have the problem.

You can use the following trick assuming that your fractional decimal number is 999.99.

1. Declare as flaot x = 999.99; //x holds binary32 formatted value = 0x4479FF5C
2. Now, read the content of x as separate 4-byte data and store them into an array.

void setup() 
{
  Serial.begin(9600);
  float x = 999.99;
  byte *ptr; 
  ptr = (byte*) &x;
  byte dataArray[4];

  for (int i = 0; i<4; i++)
  {
    dataArray[i]= *ptr;
    Serial.println(dataArray[i], HEX);
    ptr++;
  }
  
}

void loop() 
{
  
}

3. Convert the digits of the dataArray[] of Step-2 into ASCII codes and write them into HC-12 Module. Please take care of the endianess. (dataArray[0] contains the LS-byte of the 32-bit data.)

4. At the receiver end, perform the reverse process and obtain 999.99.

Sorry I think I have been misunderstood. I have to transmit the data with mySerial.write() and on the receiver side with mySerial.read(). I need to know have to use these for float. Please see my code I attached. Thank you. The library is SoftwareSerial.h

I want to transfer FLOAT data in the numerical format from max. 999.99.

Let me paraphrase the above expression quoted from your post.

1. The data type is float. Correct?
2. Example of sample data = 999.99. Correct?
3. You want to transfer it via HC-12 Module. Correct?

HC-12 is a UART Port driven Bluetooth Module. Correct?

Serial.write() only sends 1 byte so you have to either use multiple Serial.write() calls to get bigger numbers, or use Serial.print() which will turn to number into a string and then transmit it.

On the receiving end, you will either have to perform multiple Serial.read()'s to gather all the data, or Serial.parseFloat()

to be able to decode the float correctly on the receiving side, the receiver need to know when to start interperting the receiving data as a float ie I would suggest you to implement a start byte

for example you start byte could describe how many data byte the receiver will be receiving

maybe something like this on your TX side:

union{
  float num;
  uint8_t bytes[sizeof(float)];
} f_tx;

#include <SoftwareSerial.h>

SoftwareSerial mySerial(10, 11); // RX, TX
int ref = 0;

void setup() {
  // Open serial communications and wait for port to open:
  Serial.begin(9600);
  mySerial.begin (9600);
}
void loop() {
  if (ref > 9) {
    ref = 0;
  }
  else {
    ref ++;

  }
  
  f_tx.num = ref/10;
  
  
  // if (mySerial.available()) {  (this does not work when I remove the //)
  mySerial.write(sizeof(float)); //start byte
  for(uint8_t i=0; i<sizeof(float);++i){
  mySerial.write(f_tx.bytes[i]);
  delay(100);
  }
  
  Serial.print("f_tx.num =      ");
  Serial.println(f_tx.num,DEC);
  delay(100);
  // }
}

and on you RX side:

union {
  float num;
  uint8_t bytes[sizeof(float)];
} f_rx;

#include <SoftwareSerial.h>

SoftwareSerial mySerial(10, 11); // RX, TX
uint8_t i, r_float;

void setup() {
  // Open serial communications and wait for port to open:
  Serial.begin(9600);
  mySerial.begin (9600);
}
void loop() {
byte data;
  if (mySerial.available()) {
    data = mySerial.read();
    if (data == sizeof(float) && r_float == 0) {
      f_rx.num = 0.0;
      r_float = 1;
      i = 0;
    }
    else if (r_float == 1) {
      if (i < sizeof(float)) {
        f_rx.bytes[i] = data;
        ++i;
      }
      else {
        Serial.print("f_rx.num =      ");
        Serial.println(f_rx.num, DEC);
        r_float = 0;
      }
    }
  }
  else {
    Serial.println(data, DEC);
  }
}

GolamMostafa:
Let me paraphrase the above expression quoted from your post.

1. The data type is float. Correct?
2. Example of sample data = 999.99. Correct?
3. You want to transfer it via HC-12 Module. Correct?

HC-12 is a UART Port driven Bluetooth Module. Correct?

No the HC12 is not a bluetooth module. The rest is correct. It is a UART Port but does not have the same instructions as far as I can see. Does not respond to parse. See the other coments from forum members. Thank you very much for trying to help, but I am not up to your standard of programming that is why I am asking in the Forum.

@GolamMostafa had the right idea, but the solution was too long

void setup() 
{
  Serial.begin(9600);
  float x = 999.99;
  byte* ptr = (byte*) &x;

  for (int i = 0; i<4; i++)
  { 
    Serial.println((int)ptr[i], HEX);
  }
}
void loop(){}

Now, this shows that you can decompose a float into its component bytes. (Don't worry that they look nothing like 999.99!)

If, instead of printing them, you use Serial.write to send all four of them, "Serial.write (ptr,4);", you can transmit them.
A similar serial read at the far end can assign them to another float via a pointer.

No need to parse, no need to lose accuracy, no need to worry if the transmission medium is radio, wire or a length of wet string.

oe8pck:
Sorry I think I have been misunderstood. I have to transmit the data with mySerial.write() and on the receiver side with mySerial.read(). I need to know have to use these for float. Please see my code I attached. Thank you. The library is SoftwareSerial.h

I would always send data in human readable form using mySerial.print() unless that would not be fast enough. Sending data in human readable form makes debugging very much easier.

...R

Robin2:
I would always send data in human readable form using mySerial.print() unless that would not be fast enough. Sending data in human readable form makes debugging very much easier.

...R

But remember the dictum about floats being like mixing sand and dirt . . .
In which case, send the component bytes of the float as ASCII hex, and get accuracy and readability, at the expense of reduced bandwidth.

THANK YOU, I am overwhelmed with the help from all. I will try each suggestion, and need a bit of time.
Although the most simple to understand, for me,was from sherzaad, he used the SoftwareSerial code.
I just want to explain what I am trying to make. I fly model aeroplanes that are radio controlled, gliders to be specific. On the TX side I am using a BMP280 to get the altitude and then send it via the HC12 to another arduino, this then shows me the height and give a piezo sound according to certain height limits. Helps me to keep within the height laws.
Thanks to all once again and I will let you know if it works.

GrooveFlotilla:
But remember the dictum about floats being like mixing sand and dirt . . .

I don't get that?

And, yes, I am suggesting sending the float as text trading bandwith for convenience.

...R

Floating point numbers are like piles of sand; every time you move them around, you lose a little sand and pick up a little dirt. — Brian Kernighan and P.J. Plauger.

@GolamMostafa had the right idea, but the solution was too long

This has been due to Long Mind Set that deals with disciples of varying levels of understandings. Thanks+!

Is there any difference between the following two styles of declarations?
byte ptr; //this was in my code Post#3
byte
ptr; //I see this one in your Post#9

BTW: Your solution is so cute and compact; it will play an excellent role in the task of code reduction among the disciples!

Hi sherzad, I have tried your sketch and it seems to work. If it is not too much trouble could you please add comment to each of your lines, telling me what the code does, so that I can orientate myself and change it for my data. I seem to have trouble with the timing because on the RX side it prints just 0 (zero) until one line comes with data from the TX and then 0(zero) until the next data is received. Hope this all makes sense.

This code works but as you can see with the RX serial output every value is not given.
f_rx.num = 10343.70
f_rx.num = 10346.10
f_rx.num = 10348.50
f_rx.num = 10350.90
f_rx.num = 10353.30
f_rx.num = 10355.70
f_rx.num = 10358.10
f_rx.num = 10360.50
f_rx.num = 10362.90
f_rx.num = 10365.30
f_rx.num = 10367.70
f_rx.num = 10370.10
f_rx.num = 10372.50
f_rx.num = 10374.90
f_rx.num = 10377.30

Iwill now show the CHANGED code.

union{
  float num;
  uint8_t bytes[sizeof(float)];
} f_tx;

#include <SoftwareSerial.h>

SoftwareSerial mySerial(10, 11); // RX, TX
int ref = 0;

void setup() {
  // Open serial communications and wait for port to open:
  Serial.begin(9600);
  mySerial.begin (9600);
}
void loop() {
 /* if (ref > 9) {
    ref = 0;
  }
  else {
    ref ++;

  }
  */
  //f_tx.num = ref/10;
  f_tx.num = f_tx.num + 1.2;
  
  //if (mySerial.available()) {  //(this does not work when I remove the //)
  mySerial.write(sizeof(float)); //start byte
  for(uint8_t i=0; i<sizeof(float);++i){
  mySerial.write(f_tx.bytes[i]);
  delay(100);
  }
  
 /* Serial.print("f_tx.num =      ");

  Serial.println(f_tx.num,2);
*/
 
 // }
}
union {
  float num;
  uint8_t bytes[sizeof(float)];
} f_rx;

#include <SoftwareSerial.h>

SoftwareSerial mySerial(10, 11); // RX, TX
uint8_t i, r_float;

void setup() {
  // Open serial communications and wait for port to open:
  Serial.begin(9600);
  mySerial.begin (9600);
}
void loop() {
  byte data;
  if (mySerial.available() > 1) {
    data = mySerial.read();
    if (data == sizeof(float) && r_float == 0) {
      f_rx.num = 0.0;
      r_float = 1;
      i = 0;
    }
    else if (r_float == 1) {
      if (i < sizeof(float)) {
        f_rx.bytes[i] = data;
        ++i;
      }
      else {
        Serial.print("f_rx.num =      ");
        Serial.println(f_rx.num, 2);
        r_float = 0;
      }
    }
  }
 /* else {
    Serial.println(data, 2);
  }
  */
  //delay (10);
}

I have tried adjusting the delay but as is now gives the best results. I have removed the SerialPrint on the TX side to see if it is taking too much time and hence reducing the TX cycles.

but as you can see with the RX serial output every value is not given.
f_rx.num = 10343.70
f_rx.num = 10346.10
f_rx.num = 10348.50
f_rx.num = 10350.90
f_rx.num = 10353.30
f_rx.num = 10355.70
f_rx.num = 10358.10
f_rx.num = 10360.50
f_rx.num = 10362.90
f_rx.num = 10365.30
f_rx.num = 10367.70
f_rx.num = 10370.10
f_rx.num = 10372.50
f_rx.num = 10374.90
f_rx.num = 10377.30

Please explain .

How do you know that one of the component bytes of your float doesn't contain just a four?

GrooveFlotilla:
Please explain .

How do you know that one of the component bytes of your float doesn't contain just a four?

Sorry but I really have no idea what you mean. I am NOT an expert so everything has to be spelt out for me. :slight_smile:
The TX data just adds 1.2 to the previous number and sends it.