Remontar um Inteiro de 32 bits (Bit shift)

Olá pessoas! Estou dando os primeiros passos no ScadaBR e surgiu uma dúvida ao escrever um script pra recuperar um inteiro de 32 bits de um arduino uno que eu dividi em 2 registros (Estou usando comunicação serial).

Na verdade eu não estou conseguindo visualizar a solução, o que eu tentei foi o seguinte:
-Criei dois Data Points para receber os valores dos dois registros (cada um um inteiro de 16 bits) e ao olhar os valores obtidos nos datapoints da pra perceber que está tudo certo, os valores são coerentes;
-Tentei converter esses dois Data Points pra binário mas o comando Numb.toString(2) retorna um erro;

Sem converter os números de inteiro 16bits pra binário não consigo fazer o bit shift pra juntar os 2 num inteiro de 32bits

Qual o melhor caminho para resolver este problema?

Olá @Luiz_Santos !

Se eu entendi sua duvida, tu tens um registro de 32 bits em um arduino, está enviando via Modbus em 2 registradores de 16 bits (registrador Holding Modbus sempre é 16 bits) e quer que o ScadaBR receba este registro de 32 bits (4 bytes).

Se for isso, a solução me parece simples… basta informar ao ScadaBR na configuração do datapoint que o valor lido é de 32 bits (4 bytes sem ou com sinal, vai depender da origem), e o endereço do primeiro registro modbus, e o ScadaBR automaticamente quando for ler este registro vai carregar os dois registradores Modbus e exibir um unico registro já em 32 bits (4 bytes), sem que tu precises realizar qualquer conversão, e em um único datapoint.

Segue um print de exemplo:

Os campos “bit”, “numero de registradores”, e “Codificacao de caracteres” tu não precisas preencher.

Preencha o campo Offset com o endereço do primeiro registrador Modbus dos dois que guardam o numero. O Resto é por conta do ScadaBR… :wink:

Espero ter ajudado!
Abs!

Bom dia @Gulart, como vai?
Muito interessante, o ScadaBR é uma solução muito completa. Qual a forma de dividir o inteiro para que o ScadaBR possa interpretar o valor?

A forma como eu dividi o inteiro de 32bits foi a seguinte:
Usando como exemplo o número 2000000 ou 0b111101000010010000000

No Holding 0 eu envio 0b1000010010000000
No Holding 1 eu envio 0b0000000000011110

É a forma certa para que seja remontado o inteiro de 32bits pelo ScadaBR?

Agradeço muito a resposta rápida!!!
Grande agraço!

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!

1 curtida