Modbus é um dos protocolos de comunicação mais amplamente utilizados na automação industrial. Desenvolvido na década de 1970 pela Modicon, agora parte da Schneider Electric, o Modbus oferece uma estrutura simples e robusta para a troca de dados entre dispositivos em um ambiente industrial. Uma de suas variantes mais comuns é o Modbus RTU (Remote Terminal Unit), uma implementação serial do protocolo que utiliza a transmissão de dados em formato binário. Essa versão é especialmente popular em sistemas que exigem comunicação confiável e eficiente entre dispositivos em distâncias moderadas. Nesta introdução, exploraremos os princípios básicos do Modbus e suas características-chave, com foco específico no Modbus RTU e seu papel essencial na automação industrial.
Diagrama de classe básico, contendo apenas os métodos públicos acessiveis ao usuário. As classes se encontram no diretório includes/ e seus métodos no diretório src/.
O fluxo da comunicação entre cliente e servidor via modbus rtu é bastante simples. Basicamente o cliente, ao executar uma das seguintes funções modbus: read_coils, read_input_coils, read_holding_registers, read_input_registers, write_single_coil, write_single_register, write_multiple_coils e write_multiple_registers, ira enviar uma requisição para os servidores. Todos os servidores irão receber a mensagem através da função task(), está ira processar e responder somente se a requisição for destinada a ela.
O Cliente gera uma configuração aleatória dos leds e envia uma requisição write_multiple_registers com as configurações dos leds para o servidor. O servidor ira receber a requisição e atualizar as configurações dos seus leds conforme a requisição do cliente e enviar uma resposta.
#include <Arduino.h>
#include <HardwareSerial.h>
#include "industrialli_hubInit.h"
#include "industrialli_ledsHub.h"
#include "modbus/industrialli_modbus_rtu_server.h"
#define RS485_USART2_RX PD6
#define RS485_USART2_TX PD5
#define RS485_USART2_RE_DE PD4
industrialli_hubInit startHub;
industrialli_ledsHubCtrl ledsCtrl;
HardwareSerial rs485_usart2_serial(RS485_USART2_RX, RS485_USART2_TX);
Industrialli_Modbus_RTU_Server modbus;
void setup(){
startHub.begin();
rs485_usart2_serial.begin(9600);
SerialUSB.begin(9600);
modbus.begin(&rs485_usart2_serial, 9600, RS485_USART2_RE_DE);
modbus.set_server_address(10);
for (int i = 0; i < 32; i++){
modbus.create_status_coil(i, LOW);
}
ledsCtrl.begin();
}
void loop() {
modbus.task();
for (int i = 0; i < 32; i++){
ledsCtrl._shiftRegisterLed[i] = modbus.get_status_coil(i);
}
ledsCtrl.ledsUpdate();
}
#include <Arduino.h>
#include <HardwareSerial.h>
#include "industrialli_hubInit.h"
#include "industrialli_ledsHub.h"
#include "modbus/industrialli_modbus_rtu_client.h"
#define RS485_USART2_RX PD6
#define RS485_USART2_TX PD5
#define RS485_USART2_RE_DE PD4
industrialli_hubInit startHub;
industrialli_ledsHubCtrl ledsCtrl;
HardwareSerial rs485_usart2_serial(RS485_USART2_RX, RS485_USART2_TX);
Industrialli_Modbus_RTU_Client modbus;
void setup(){
startHub.begin();
rs485_usart2_serial.begin(9600);
modbus.begin(&rs485_usart2_serial, 9600, RS485_USART2_RE_DE);
pinMode(RS485_USART2_RE_DE, OUTPUT);
ledsCtrl.begin();
}
void loop() {
for (int i = 0; i < 32; i++){
ledsCtrl._shiftRegisterLed[i] = rand() % 2;
}
modbus.write_multiple_coils(10, 0, ledsCtrl._shiftRegisterLed, 32);
ledsCtrl.ledsUpdate();
delay(300);
}
Segue abaixo as funções genéricas do protocolo Modbus para gerenciamento de registradores, referentes a classe Industrialli_Modbus.
create_status_coil
Inicializa um registrador do tipo coil.
Parâmetros:
- uint16_t _address: endereço do coil.
- bool: _value: valor do coil.
Retorno: void
Exemplo
modbus.create_status_coil(11, 1);
create_input_coil
Inicializa um registrador do tipo discrete input coil.
Parâmetros:
- uint16_t _address: endereço do coil.
- bool: _value: valor do coil.
Retorno: void
Exemplo
modbus.create_input_coil(11, 1);
create_input_register
Inicializa um registrador do tipo input.
Parâmetros:
- uint16_t _address: endereço do registrador.
- uint16_t: _value: valor do registrador.
Retorno: void
Exemplo
modbus.create_input_register(15, 1332);
create_holding_register
Inicializa um registrador do tipo holding.
Parâmetros:
- uint16_t _address: endereço do registrador.
- uint16_t: _value: valor do registrador.
Retorno: void
Exemplo
modbus.create_holding_register(12, 5543);
set_status_coil
Atualiza um registrador do tipo coil.
Parâmetros:
- uint16_t _address: endereço do coil.
- bool: _value: valor do coil.
Retorno: void
Exemplo
modbus.set_status_coil(11, 1);
set_input_coil
Atualiza um registrador do tipo discrete input coil.
Parâmetros:
- uint16_t _address: endereço do coil.
- bool: _value: valor do coil.
Retorno: void
Exemplo
modbus.set_input_coil(11, 1);
set_input_register
Atualiza um registrador do tipo input.
Parâmetros:
- uint16_t _address: endereço do registrador.
- uint16_t: _value: valor do registrador.
Retorno: void
Exemplo
modbus.set_input_register(15, 1332);
set_holding_register
Atualiza um registrador do tipo holding.
Parâmetros:
- uint16_t _address: endereço do registrador.
- uint16_t: _value: valor do registrador.
Retorno: void
Exemplo
modbus.set_holding_register(12, 5543);
get_status_coil
Retorna o valor de um registrador do tipo coil.
Parâmetros:
- uint16_t _address: endereço do coil.
Retorno: bool: valor do coil.
Exemplo
bool value = modbus.get_status_coil(11);
get_input_coil
Retorna o valor de um registrador do tipo discrete input coil.
Parâmetros:
- uint16_t _address: endereço do coil.
Retorno: bool: valor do coil.
Exemplo
bool value = modbus.get_input_coil(11);
get_input_register
Retorna o valor de um registrador do tipo input.
Parâmetros:
- uint16_t _address: endereço do registrador.
Retorno: uint16_t: valor do registrador.
Exemplo
uint16_t value = modbus.set_input_register(15);
get_holding_register
Retorna o valor de um registrador do tipo holding.
Parâmetros:
- uint16_t _address: endereço do registrador.
Retorno: uint16_t: valor do registrador.
Exemplo
uint16_t value = modbus.get_holding_register(12);
Segue abaixo as funções específicas do servidor Modbus RTU, referentes a classe Industrialli_Modbus_RTU_Server.
begin
Inicializa um servidor Modbus RTU.Parâmetros:
- HardwareSerial *_serial: endereço de memória referente a conexão serial.
- long _baud: frequência da comunicação serial.
- int _de_pin: pino re/de.
Retorno: void
Exemplo
rs485_usart2_serial.begin(9600);
modbus.begin(&rs485_usart2_serial, 9600, RS485_USART2_RE_DE);
set_server_address
Define o endereço do servidor Modbus RTU.Parâmetros:
- uint8_t _server_address: endereço do servidor.
Retorno: void
Exemplo
modbus.set_server_address(10);
get_server_address
Retorna o endereço do servidor Modbus RTU.Parâmetros: void
Retorno: uint8_t _server_address: endereço do servidor.
task
Recebe, processa e responde um frame de requisição do cliente.Parâmetros: void
Retorno: void
Exemplo
void loop(){
modbus.task();
}
Segue abaixo as funções específicas do cliente Modbus RTU, referentes a classe Industrialli_Modbus_RTU_Client.
begin
Inicializa um cliente Modbus RTU.Parâmetros:
- HardwareSerial *_serial: endereço de memória referente a conexão serial.
- long _baud: frequência da comunicação serial.
- int _de_pin: pino re/de.
Retorno: void
Exemplo
rs485_usart2_serial.begin(9600);
modbus.begin(&rs485_usart2_serial, 9600, RS485_USART2_RE_DE);
read_coils
Envia uma requisição Modbus RTU do tipo read coils para um servidor.Parâmetros:
- uint8_t _address: endereço do servidor.
- uint16_t _starting_address: endereço de inicio da leitura dos registradores do tipo status coil.
- uint16_t _quantity_of_coils: quantidade de registradores do tipo status coil que serão lidos a partir do endereço de início.
Retorno: void
Exemplo
modbus.read_coils(10, 0, 32);
read_input_coils
Envia uma requisição Modbus RTU do tipo read input coils para um servidor.Parâmetros:
- uint8_t _address: endereço do servidor.
- uint16_t _starting_address: endereço de inicio da leitura dos registradores do tipo input coil.
- uint16_t _quantity_of_coils: quantidade de registradores do tipo input coil que serão lidos a partir do endereço de início.
Retorno: void
Exemplo
modbus.read_input_coils(10, 0, 32);
read_holding_registers
Envia uma requisição Modbus RTU do tipo read holding registers para um servidor.Parâmetros:
- uint8_t _address: endereço do servidor.
- uint16_t _starting_address: endereço de inicio da leitura dos registradores do tipo holding.
- uint16_t _quantity_of_registers: quantidade de registradores do holding que serão lidos a partir do endereço de início.
Retorno: void
Exemplo
modbus.read_holding_registers(10, 0, 32);
read_input_registers
Envia uma requisição Modbus RTU do tipo read input registers para um servidor.Parâmetros:
- uint8_t _address: endereço do servidor.
- uint16_t _starting_address: endereço de inicio da leitura dos registradores do tipo input.
- uint16_t _quantity_of_registers: quantidade de registradores do input que serão lidos a partir do endereço de início.
Retorno: void
Exemplo
modbus.read_input_registers(10, 0, 32);
write_single_coil
Envia uma requisição Modbus RTU do tipo write single coil para um servidor.Parâmetros:
- uint8_t _address: Endereço do servidor.
- uint16_t _coil_address: endereço do coil.
- uint16_t _value: valor do coil.
Retorno: void
Exemplo
modbus.write_single_coil(10, 5, 0xFF00);
write_single_register
Envia uma requisição Modbus RTU do tipo write single register para um servidor.Parâmetros:
- uint8_t _address: Endereço do servidor.
- uint16_t _register_address: endereço do registrador do tipo holding.
- uint16_t _value: valor do registrador.
Retorno: void
Exemplo
modbus.write_single_register(10, 5, 6454);
write_multiple_coils
Envia uma requisição Modbus RTU do tipo write nultiple coils para um servidor.Parâmetros:
- uint8_t _address: endereço do servidor.
- uint16_t _starting_address: endereço de inicio dos registradores do tipo coil que serão alterados os valores.
- uint8_t* _values: vetor boleano que contem os novos valores dos registradores do tipo coil.
- uint16_t _quantity_of_coils: quantidade de registradores do tipo coil que terão seus valores atualizados.
Retorno: void
Exemplo
uint8_t values[5] = {0,1,1,0,1};
modbus.write_multiple_coils(10, 0, values, 5);
write_multiple_registers
Envia uma requisição Modbus RTU do tipo write nultiple registers para um servidor.Parâmetros:
- uint8_t _address: endereço do servidor.
- uint16_t _starting_address: endereço de inicio dos registradores do tipo holding que serão alterados os valores.
- uint16_t* _values: vetor que contem os novos valores dos registradores do tipo holding.
- uint16_t _quantity_of_coils: quantidade de registradores do tipo holding que terão seus valores atualizados.
Retorno: void
Exemplo
uint8_t values[5] = {423,22,324,2,1};
modbus.write_multiple_registers(10, 0, values, 5);