# Transfer float into holding regsiters

Hi, I’m trying to write a method for transferring a floating point number into 2 holding registers. I convert the float into a long (while scaling up by 400K) then I used This thread to convert the long into two ints which go into holding registers.

``````float Aval = 3.5634;
long y = lround(Aval*scale);
int16_t high = y >> 16;
int16_t low = (int16_t)y;
holdingRegs[Aa] = low;
holdingRegs[Ab] = high;
``````

It works great - but I need to do it for many different values in my code, and I can’t get the general method below to work - could someone please point out what I’m missing? Many thanks,

``````void floatconv (float input, int16_t Aa, int16_t Ab){
long lconv = lround(input*scale);
Aa = lconv >> 16;
Ab = (int16_t)lconv;
}

float Bval = 3.5634;
floatconv(Bval, holdingRegs[Ba], holdingRegs[Bb]);
``````

The fuller version of the above code is here:

``````#include <ModbusRtu.h>

#define ID          1
#define TXEN        2

long scale = 400000000;

enum
{
Aa,      //CHANNEL 0
Ab,      //CHANNEL 1
Ba,      //CHANNEL 2
Bb,      //CHANNEL 3
HOLDING_REGS_SIZE
};

unsigned int holdingRegs[HOLDING_REGS_SIZE];
//*/
//Modbus slave(1, 0, TXEN); // this is slave @1 and RS-485

void setup() {
//////////////////////////////////////////////////////////////////////////////////////////////
// start modbus communication
//slave.begin( 115200 );

Serial.begin(115200);
}

float Aval = 3.5634;
float Bval = 3.5634;

void floatconv (float input, int16_t hAa, int16_t hAb){
long lconv = lround(input*scale);
hAa = lconv >> 16;
hAb = (int16_t)lconv;
}

void loop() {
long y = lround(Aval*scale);
int16_t high = y >> 16;
int16_t low = (int16_t)y;
holdingRegs[Aa] = low;
holdingRegs[Ab] = high;

floatconv(Bval, holdingRegs[Ba], holdingRegs[Bb]);

//modbus communication
//slave.poll( holdingRegs, HOLDING_REGS_SIZE );

Serial.print("Aa: "), Serial.println(holdingRegs[Aa]);
Serial.print("Ab: "), Serial.println(holdingRegs[Ab]);
Serial.print("Ba: "), Serial.println(holdingRegs[Ba]);
Serial.print("Bb: "), Serial.println(holdingRegs[Bb]);
Serial.println("");

delay(50000);
}
``````

Pass the parameters to your function either by pointers or by reference.

Assuming you're working on a processor where floats are 32 bits, this works:

``````void setup() {
float Aval;
uint16_t aReg, bReg;
void *ptr;

Serial.begin(115200);
delay(2000);

Aval = 3.5634;
floatconv(Aval, &aReg, &bReg);
ptr = &Aval;
Serial.println(*(uint32_t *)(ptr), HEX);
Serial.print(aReg, HEX);
Serial.print(", ");
Serial.println(bReg, HEX);

}

void loop() {}

void floatconv(float input, uint16_t *hAa, uint16_t *hAb) {
memcpy((uint8_t *)hAa, (uint8_t *)&input, 2);
memcpy((uint8_t *)hAb, (uint8_t *)&input + 2, 2);
}
``````

Going through a void * to print the hex bytes of the float stops the compiler from whining about "dereferencing type-punned pointer will break strict-aliasing rules"

Easily done with a union.

``````union
{
long y;
struct
{
int Aa;
int Ab;
};
}some_name_here;
``````

Now, if you assign some_name_here.y = lround(input*scale);, some_name_here.Aa contains the low order int and some_name_here.Ab contains the high order int.

Hi, thanks darrob, DKwatson and gfvalvo. GF I used your code. It works great now. I had a look at the page darrob, and its very useful/essential though I think I still don’t understand them lol.

I converted them to a long instead as it seems to function better with my receiving modbus program (DAQFactory) - (set four channels to read S32s on channels 0, 2, 4 and 6).

Many thanks all,

Please find the code below if anyone finds it useful:

``````#include <ModbusRtu.h>

#define ID          1
#define TXEN        2

long scale = 400000;
long lconv = 0;

float Aval = 3.563543;
float Bval = 5.46233;
float Cval = -1.55065;
float Dval = -2.34223;

enum
{
Aa,      //CHANNEL 0
Ab,      //CHANNEL 1
Ba,      //CHANNEL 2
Bb,      //CHANNEL 3
Ca,      //CHANNEL 0
Cb,      //CHANNEL 1
Da,      //CHANNEL 2
Db,      //CHANNEL 3
HOLDING_REGS_SIZE
};

unsigned int holdingRegs[HOLDING_REGS_SIZE];

/**
Modbus object declaration
u8id : node id = 0 for master, = 1..247 for slave
u8serno : serial port (use 0 for Serial)
u8txenpin : 0 for RS-232 and USB-FTDI
or any pin number > 1 for RS-485
*/
Modbus slave(1, 0, TXEN); // this is slave @1 and RS-485

void setup() {
//////////////////////////////////////////////////////////////////////////////////////////////
// start modbus communication
slave.begin( 115200 );

//Serial.begin(115200);
}

void loop() {
//long time1 = millis();

floatconv(Aval, &holdingRegs[Aa], &holdingRegs[Ab]);
floatconv(Bval, &holdingRegs[Ba], &holdingRegs[Bb]);
floatconv(Cval, &holdingRegs[Ca], &holdingRegs[Cb]);
floatconv(Dval, &holdingRegs[Da], &holdingRegs[Db]);
//modbus communication
slave.poll( holdingRegs, HOLDING_REGS_SIZE );

//Serial.print("Aa: "), Serial.println(holdingRegs[Aa]);
//Serial.print("Ab: "), Serial.println(holdingRegs[Ab]);
//Serial.print("Ba: "), Serial.println(holdingRegs[Ba]);
//Serial.print("Bb: "), Serial.println(holdingRegs[Bb]);
//Serial.print("Ca: "), Serial.println(holdingRegs[Ca]);
//Serial.print("Cb: "), Serial.println(holdingRegs[Cb]);
//Serial.print("Da: "), Serial.println(holdingRegs[Da]);
//Serial.print("Db: "), Serial.println(holdingRegs[Db]);
//Serial.println("");

delay(1000);
}

void floatconv(float input, uint16_t *ha, uint16_t *hb) {
long lconv = lround(input*scale);
memcpy((uint8_t *)ha, (uint8_t *)&lconv, 2);
memcpy((uint8_t *)hb, (uint8_t *)&lconv + 2, 2);
}
``````