Olá @Luiz_Santos!
Por acaso estou trabalhando com algo semelhante com um arduino para ler o valor de um sensor de corrente. Eu não preciso de precisão de 32bits, mas coloquei em um programa de teste para exemplificar.
Tem uma função em C++ que deixa tudo muito simples… é o union! usando union, tu trabalhas internamente com teu inteiro ou float de 32bits e grava em uma variavel union, que está ligada a duas variáveis int16 que vais atualizar no registrador de Holding.
Disponibilizo o código de teste que eu utilizei, para exemplo:
#include <EmonLib.h> // Biblioteca para o calculo de Corrente RMS (dentre outros)
#include <SimpleModbusSlave.h> // Biblioteca Modbus RTU Slave
EnergyMonitor sensor;
// #### Calibração ####
#define RATIO 2000 // Relação do TC (SCT-013) 100A:0.05A
#define SHUNT 509 // Valor do Resistor de Shunt, em OHMS
#define PINO_SENSOR A1 // Pino onde está ligado o Sensor de Corrente
#define TAXA_ATU 5000 // taxa de leitura do sensor de corrente, em milissegundos
double calibrar = RATIO / SHUNT ;
// MODBUS
#define SLAVE_ID 7 // Endereço do escravo na rede modbus
#define TX_PIN 0 // 0 ou 1 significa desabilitado (RS232 e/ou TTL), usar qualquer pino de 2 em diante para o TX enable do MAX485 ou equivalente
#define HOLDING_REGS_SIZE 2 // tamanho do registrador de Holding MODBUS
// 00 - (S) MSB
// 01 - (S) LSB
uint16_t holdingRegs[HOLDING_REGS_SIZE]; // Vetor do Registrador de Holding Modbus
unsigned long tempo_ini = millis(); // Variável para guardar o tempo na rotina de delay
unsigned long tempo_now = millis(); // Variável para guardar o tempo na rotina de delay
typedef union
{
unsigned long int32;
uint16_t int16[2];
} longunion_t;
longunion_t registro_01; // Variavel usando a função Union do C++ para converter automaticamente INT32 em dois INT16
double Irms; // Variável que guarda o valor de corrente lido pelo sensor
int fLed = 500; // Variável da frequencia de piscada do led onboard
void setup() {
modbus_configure(&Serial, 19200, SERIAL_8E2, SLAVE_ID, TX_PIN, HOLDING_REGS_SIZE, holdingRegs); // Inicializando rotina Modbus RTU
sensor.current(PINO_SENSOR, calibrar); // Setup da rotina do calculo da corrente: pino de entrada, fator de calibração.
pinMode(13, OUTPUT); // Pino do LED onboard
}
void loop() {
modbus_update(); // responde solicitacao do Master (se houver)
leitura(); // ler de tempos em tempos o sensor de corrente
atualiza_registradores(); // atualiza o registrador Holding Modbus
pisca_led(); // pisca o led da placa para dizer que esta rodando…
delay(5); // só pra não ficar muito rápido…
}
void leitura() { // Rotina para ler a corrente no sensor de tempos em tempos…
tempo_now = millis();
if ((tempo_now - tempo_ini) > TAXA_ATU) { // IMPORTANTE: Não utilizar delay com a função delay() para não travar o Modbus
Irms = sensor.calcIrms(1480); // Calculo da Corrente RMS (numero de amostras). Quanto maior a amostragem maior o tempo de retorno.
tempo_ini = millis();
}
}
void atualiza_registradores() { // Rotina para atualizar o vetor de Registrador de Holding Modbus, que pode ser lido pelo Master quando ele quiser…
unsigned long temp = Irms * 100;
registro_01.int32 = temp;
holdingRegs[0] = registro_01.int16[1]; // MSB o vetor do union é invertido…
holdingRegs[1] = registro_01.int16[0]; // LSB
}
unsigned long ledblink = millis(); // variavel de contagem do tempo de piscada do LED
boolean ledstate = false; // variavel de estado do LED
void pisca_led() { // Rotina para piscar o led onboard…
if (millis() - ledblink > fLed) { // se o tempo atual menos o tempo inicial é maior que o tempo entre troca de estado…
ledblink = millis(); // reseta o contador de tempo
digitalWrite(13, ledstate); // altera o estado do pino do LED
ledstate = (!ledstate); // inverte flag de estado do pino do LED
}
}
Com este codigo rodando, conectei ao ScadaBR:
Espero ter ajudado!
Abs!