115 lines
3.0 KiB
C
115 lines
3.0 KiB
C
|
|
#ifndef ModbusService
|
||
|
|
#define ModbusService
|
||
|
|
|
||
|
|
HardwareSerial SerialDriver(1);
|
||
|
|
#define RXD1 16
|
||
|
|
#define TXD1 17
|
||
|
|
#define DE_RE_PIN 4 // Pino para DE e RE
|
||
|
|
bool Debug = false;
|
||
|
|
|
||
|
|
class ModbusGetResponse {
|
||
|
|
public:
|
||
|
|
byte _address;
|
||
|
|
byte _command_code;
|
||
|
|
byte _num_registers;
|
||
|
|
double _value;
|
||
|
|
|
||
|
|
ModbusGetResponse() : _address(0), _command_code(0), _num_registers(0), _value(0.0) {}
|
||
|
|
};
|
||
|
|
|
||
|
|
void InicializarModbus(bool _debug = false) {
|
||
|
|
SerialDriver.begin(9600, SERIAL_8N2, RXD1, TXD1);
|
||
|
|
Serial.println("Modbus Inicializado");
|
||
|
|
|
||
|
|
pinMode(DE_RE_PIN, OUTPUT);
|
||
|
|
digitalWrite(DE_RE_PIN, LOW); // Inicialmente em modo de recepção
|
||
|
|
|
||
|
|
Debug = _debug;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Função para calcular CRC16
|
||
|
|
uint16_t calculateCRC(const uint8_t* data, uint8_t length) {
|
||
|
|
uint16_t crc = 0xFFFF;
|
||
|
|
|
||
|
|
for (uint8_t i = 0; i < length; i++) {
|
||
|
|
crc ^= data[i];
|
||
|
|
for (uint8_t j = 0; j < 8; j++) {
|
||
|
|
if (crc & 0x0001) {
|
||
|
|
crc >>= 1;
|
||
|
|
crc ^= 0xA001;
|
||
|
|
} else {
|
||
|
|
crc >>= 1;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return crc;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Função para construir o comando Modbus
|
||
|
|
void sendModbusCommand(uint8_t slaveAddress, uint8_t functionCode, uint16_t registerAddress, int value, uint8_t* response, uint8_t& length) {
|
||
|
|
uint8_t command[8];
|
||
|
|
|
||
|
|
command[0] = slaveAddress;
|
||
|
|
command[1] = functionCode;
|
||
|
|
command[2] = (registerAddress >> 8) & 0xFF; // Big endian
|
||
|
|
command[3] = registerAddress & 0xFF;
|
||
|
|
|
||
|
|
// Converter o valor inteiro para o formato adequado
|
||
|
|
command[4] = (value >> 8) & 0xFF; // Big endian
|
||
|
|
command[5] = value & 0xFF;
|
||
|
|
|
||
|
|
uint16_t crc = calculateCRC(command, 6);
|
||
|
|
command[6] = crc & 0xFF;
|
||
|
|
command[7] = (crc >> 8) & 0xFF;
|
||
|
|
|
||
|
|
// Alternar para modo de transmissão
|
||
|
|
digitalWrite(DE_RE_PIN, HIGH);
|
||
|
|
vTaskDelay(1); // Pequeno atraso para garantir que o modo de transmissão esteja ativo
|
||
|
|
|
||
|
|
SerialDriver.write(command, 8);
|
||
|
|
|
||
|
|
if (Debug) {
|
||
|
|
// Imprimir o comando em formato hexadecimal
|
||
|
|
Serial.print("Comando enviado: ");
|
||
|
|
for (int i = 0; i < 8; i++) {
|
||
|
|
if (command[i] < 0x10) {
|
||
|
|
Serial.print("0"); // Adiciona um zero à esquerda para bytes menores que 0x10
|
||
|
|
}
|
||
|
|
Serial.print(command[i], HEX);
|
||
|
|
Serial.print(" ");
|
||
|
|
}
|
||
|
|
Serial.println();
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
// Alternar para modo de recepção
|
||
|
|
SerialDriver.flush(); // Garantir que todos os dados foram enviados
|
||
|
|
digitalWrite(DE_RE_PIN, LOW);
|
||
|
|
delay(1); // Pequeno atraso para garantir que o modo de recepção esteja ativo
|
||
|
|
|
||
|
|
// Aguardar a resposta
|
||
|
|
delay(100); // Ajuste o tempo de delay conforme necessário
|
||
|
|
|
||
|
|
// Ler a resposta
|
||
|
|
if (SerialDriver.available()) {
|
||
|
|
length = SerialDriver.readBytes(response, SerialDriver.available());
|
||
|
|
|
||
|
|
if (Debug) {
|
||
|
|
// Imprimir a resposta em formato hexadecimal
|
||
|
|
Serial.print("Resposta recebida: ");
|
||
|
|
for (int i = 0; i < length; i++) {
|
||
|
|
if (response[i] < 0x10) {
|
||
|
|
Serial.print("0"); // Adiciona um zero à esquerda para bytes menores que 0x10
|
||
|
|
}
|
||
|
|
Serial.print(response[i], HEX);
|
||
|
|
Serial.print(" ");
|
||
|
|
}
|
||
|
|
Serial.println();
|
||
|
|
}
|
||
|
|
|
||
|
|
} else {
|
||
|
|
length = 0;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
#endif
|