MCU.TEC Modbus,protoclolos Introdução ao ESP-Modbus com ESP-IDF

Introdução ao ESP-Modbus com ESP-IDF

O Modbus é um protocolo de comunicação amplamente utilizado na indústria para conectar dispositivos eletrônicos, como sensores e atuadores. Com o suporte nativo no ESP32 por meio da biblioteca ESP-Modbus, integrá-lo a projetos embarcados torna-se uma tarefa eficiente e confiável.

Este artigo explora como utilizar o ESP-Modbus na plataforma ESP-IDF, explicando conceitos-chave e orientando sobre a configuração de comunicação com dispositivos Modbus em suas variantes mais comuns, como Modbus RTU, Modbus ASCII e Modbus TCP/IP.


Visão Geral do Modbus

O protocolo Modbus define regras de comunicação para troca de mensagens entre dispositivos mestre (master) e escravos (slaves) em uma rede. Ele é amplamente adotado em aplicações industriais devido à sua simplicidade e eficiência.

Tipos de Modbus:

  1. Modbus RTU (Remote Terminal Unit):
    • Comunicação serial com dados representados em formato binário compacto.
    • Utiliza verificação de erros com checksum (CRC).
    • Requer intervalos de silêncio para enquadrar mensagens, sendo o RS-485 a interface mais utilizada.
  2. Modbus ASCII:
    • Dados em formato legível por humanos (ASCII).
    • Inclui checagem de erros com verificação longitudinal (LRC).
    • Mensagens são delimitadas por um caractere : no início e CR/LF no final.
  3. Modbus TCP/IP:
    • Adaptação para redes Ethernet utilizando o protocolo TCP/IP.
    • Transmissão via porta padrão 502, sem necessidade de checksum adicional devido à proteção fornecida pelas camadas inferiores do TCP/IP.

Os dados no Modbus são organizados em registros, que podem ser de quatro tipos principais:

  • Coils (Saídas discretas): Valores binários para controle de atuadores.
  • Discrete Inputs (Entradas discretas): Leituras binárias de sensores.
  • Holding Registers: Valores de 16 bits para leitura e escrita.
  • Input Registers: Valores de 16 bits apenas para leitura.

A biblioteca ESP-Modbus do ESP32 é baseada na FreeModbus, oferecendo suporte para as implementações RTU, ASCII e TCP/IP, tanto para dispositivos mestre quanto escravo.


Modelo de Mensagem e Mapeamento de Dados

Modbus segment diagram
Modbus segment diagram

O Modbus é um protocolo baseado em registros que define um modelo de comunicação estruturado, independente do meio físico utilizado para a transmissão de dados. Este modelo organiza as mensagens como transações entre dispositivos mestre e escravo, onde o mestre controla toda a comunicação.

Comunicação Mestre-Escravo

Em uma rede Modbus:

  • O mestre envia comandos para os dispositivos escravos.
  • Os escravos respondem aos comandos ou permanecem inativos se não forem endereçados.
  • Não há comunicação direta entre escravos.

No caso do Modbus TCP/IP, múltiplos mestres podem coexistir na mesma rede, aproveitando a natureza da comunicação IP.

Tipos de Registros no Modbus
Modbus data mapping

Os dispositivos mapeiam seus dados em quatro tipos de registros que representam características físicas, como leituras de sensores ou estados de atuadores. Abaixo, detalhamos esses tipos:

  1. Coils (Saídas Discretas):
    • Bits de saída que podem ser controlados pelo mestre.
    • Geralmente usados para ligar/desligar dispositivos como relés.
  2. Discrete Inputs (Entradas Discretas):
    • Bits de entrada somente leitura.
    • Utilizados para monitorar estados, como o fechamento de um contato.
  3. Holding Registers:
    • Registros de 16 bits que permitem leitura e escrita.
    • Comumente usados para armazenar valores configuráveis, como setpoints de temperatura.
  4. Input Registers:
    • Registros de 16 bits somente leitura.
    • Geralmente associados a sensores analógicos que enviam valores convertidos.

Mapeamento de Dados no ESP-Modbus

No ESP-Modbus, cada dispositivo na rede é identificado por um endereço escravo único, configurado em seu manual. O mestre deve conhecer o mapa de registros do dispositivo para acessar os dados corretamente. Esse mapa define:

  • O tipo de registro (Coil, Holding, etc.).
  • O endereço inicial.
  • A quantidade de registros disponíveis.

Este mapeamento é essencial para configurar o Modbus no ESP32 e estabelecer uma comunicação eficiente entre dispositivos.


Inicialização da Porta Modbus

Para iniciar a comunicação Modbus em um ESP32 utilizando o ESP-Modbus, é necessário configurar corretamente a porta de comunicação. O ESP-Modbus suporta tanto comunicação serial (via RTU ou ASCII) quanto TCP/IP. A inicialização correta da porta é o primeiro passo para utilizar as APIs disponíveis.

Configuração de Portas no ESP-Modbus

O ESP-Modbus fornece as seguintes funções para inicializar controladores Modbus, tanto para dispositivos mestre quanto escravo, dependendo do tipo de comunicação:

  • Serial (RTU/ASCII):

    • mbc_slave_init(): Inicializa um escravo Modbus em comunicação serial.
    • mbc_master_init(): Inicializa um mestre Modbus em comunicação serial.
  • TCP/IP:

    • mbc_slave_init_tcp(): Inicializa um escravo Modbus em comunicação TCP/IP.
    • mbc_master_init_tcp(): Inicializa um mestre Modbus em comunicação TCP/IP.

A escolha da função depende do tipo de dispositivo (mestre ou escravo) e do meio de transmissão (serial ou TCP/IP).

Exemplo de Inicialização

Para inicializar uma porta serial no modo escravo, o seguinte código pode ser usado:

void* slave_handler = NULL;
// Estrutura de interface 
esp_err_t err = mbc_slave_init(MB_PORT_SERIAL_SLAVE, &slave_handler); 
if (slave_handler == NULL || err != ESP_OK) {
  ESP_LOGE(TAG, "Falha na inicialização do controlador Modbus."); 
}

No caso de comunicação TCP/IP, a inicialização segue um padrão similar, mas com a função mbc_slave_init_tcp:

void* slave_handler = NULL;
esp_err_t err = mbc_slave_init_tcp(&slave_handler);

if (slave_handler == NULL || err != ESP_OK) {
    ESP_LOGE(TAG, "Falha na inicialização do controlador Modbus TCP.");
}


Essas funções configuram a estrutura base para a comunicação Modbus e devem ser chamadas antes de qualquer outra operação relacionada ao protocolo.

API Modbus Mestre – Visão Geral

A API do Modbus para dispositivos mestre no ESP32 oferece uma estrutura completa para configurar, acessar e gerenciar a comunicação com dispositivos escravos. Essa API segue uma sequência lógica de passos para configurar a comunicação e realizar transações.

Etapas Principais da Comunicação Mestre

  1. Inicialização da Porta Modbus:
    • Configura a interface de comunicação (serial ou TCP/IP) e o controlador mestre.
  2. Configuração do Acesso a Dados:
    • Define os parâmetros que o mestre acessará nos dispositivos escravos.
    • Utiliza um mapeamento chamado “Dicionário de Dados”, que associa identificadores únicos (CID) a registros Modbus.
  3. Opções de Comunicação:
    • Configura parâmetros específicos, como baud rate (para serial) ou endereços IP (para TCP/IP).
  4. Início da Comunicação:
    • Ativa o controlador Modbus, permitindo o envio e recebimento de dados entre mestre e escravos.
  5. Finalização:
    • Libera recursos do controlador Modbus ao finalizar a comunicação.

Dicionário de Dados e CID

O ESP-Modbus introduz um nível de abstração acima do protocolo padrão, denominado “Dicionário de Dados”. Cada parâmetro acessível pelo mestre é identificado por:

  • CID (Identificador de Característica): Um número único que identifica um parâmetro no dispositivo escravo.
  • Nome e Unidades: Uma descrição textual do parâmetro e sua unidade física (como °C para temperatura).
  • Tipo de Registro e Endereço: Define o tipo de registro Modbus (Holding, Input, etc.) e seu endereço inicial no dispositivo escravo.

Exemplo de definição de parâmetros no Dicionário de Dados:

mb_parameter_descriptor_t device_parameters[] = {
    { CID_SER_NUM1, "Serial_number_1", "--", MB_DEVICE_ADDR1, MB_PARAM_INPUT, 0, 2, 0, PARAM_TYPE_U32, 4 },
    { CID_TEMP_DATA_1, "Temperature_1", "C", MB_DEVICE_ADDR1, MB_PARAM_HOLDING, 0, 2, 0, PARAM_TYPE_FLOAT, 4 }
};

Neste exemplo:

  • O parâmetro CID_SER_NUM1 refere-se ao número de série do dispositivo.
  • O parâmetro CID_TEMP_DATA_1 mapeia um registro de temperatura em graus Celsius.

Configuração do Mestre

Após definir o Dicionário de Dados, ele deve ser associado ao controlador Modbus utilizando a função mbc_master_set_descriptor():

ESP_ERROR_CHECK(mbc_master_set_descriptor(&device_parameters[0], num_device_parameters));

Isso permite que o mestre acesse os parâmetros do escravo conforme o mapeamento definido.


Configuração de Acesso a Dados no Mestre

Para que um dispositivo mestre possa acessar parâmetros de dispositivos escravos, é necessário configurar o acesso aos dados. Isso é realizado definindo os detalhes de cada parâmetro que será lido ou escrito, utilizando o Dicionário de Dados já apresentado.

Estrutura do Dicionário de Dados

Cada entrada no Dicionário de Dados representa uma característica física ou lógica disponível no dispositivo escravo, como temperatura, pressão ou um número de série. A configuração inclui:

  • CID (Identificador de Característica): Um identificador único que referencia o parâmetro.
  • Endereço do Registro: Define onde os dados estão localizados no mapa de registros do escravo.
  • Tipo de Registro: Especifica se é um registro de entrada, holding, etc.
  • Tamanho: Determina quantos registros Modbus são utilizados para armazenar o valor.

Exemplo Prático de Configuração

Abaixo está um exemplo de definição de parâmetros para dois dispositivos escravos conectados a um mestre:

mb_parameter_descriptor_t device_parameters[] = {
    { CID_TEMP_DATA_1, "Temperature_1", "C", MB_DEVICE_ADDR1, MB_PARAM_HOLDING, 0, 2, 0, PARAM_TYPE_FLOAT, 4 },
    { CID_HUMIDITY_1, "Humidity_1", "%", MB_DEVICE_ADDR1, MB_PARAM_INPUT, 2, 1, 0, PARAM_TYPE_U16, 2 },
    { CID_TEMP_DATA_2, "Temperature_2", "C", MB_DEVICE_ADDR2, MB_PARAM_HOLDING, 0, 2, 0, PARAM_TYPE_FLOAT, 4 },
    { CID_HUMIDITY_2, "Humidity_2", "%", MB_DEVICE_ADDR2, MB_PARAM_INPUT, 2, 1, 0, PARAM_TYPE_U16, 2 }
};

Neste exemplo:

  • CID_TEMP_DATA_1: Mapeia a temperatura do dispositivo 1 (endereço MB_DEVICE_ADDR1) em registros de holding.
  • CID_HUMIDITY_1: Mapeia a umidade do dispositivo 1 como registro de entrada.
  • CID_TEMP_DATA_2 e CID_HUMIDITY_2: Seguem a mesma lógica para o segundo dispositivo.

O número de parâmetros no Dicionário de Dados pode ser calculado automaticamente:

uint16_t num_device_parameters = (sizeof(device_parameters) / sizeof(device_parameters[0]));

Configuração no Controlador Mestre

Após definir o Dicionário de Dados, ele deve ser registrado no controlador Modbus para permitir o acesso aos dispositivos escravos:

ESP_ERROR_CHECK(mbc_master_set_descriptor(&device_parameters[0], num_device_parameters));

Com essa configuração, o mestre está preparado para acessar os parâmetros definidos nos escravos, conforme as especificações do Dicionário de Dados.


Opções de Comunicação do Mestre

Depois de configurar os parâmetros de acesso no Dicionário de Dados, é necessário definir as opções de comunicação do mestre para garantir uma troca de dados eficiente e confiável com os dispositivos escravos. Essas opções incluem parâmetros de comunicação específicos para cada tipo de interface: serial ou TCP/IP.

Configuração de Comunicação Serial

Ao utilizar a comunicação serial (Modbus RTU ou ASCII), os seguintes parâmetros devem ser definidos:

  • Porta Serial: Identifica qual porta UART será utilizada.
  • Modo de Comunicação: Define se será RTU ou ASCII.
  • Taxa de Baud: Determina a velocidade da transmissão em bits por segundo.
  • Paridade: Especifica o tipo de verificação de paridade (nenhuma, ímpar ou par).

Exemplo de configuração para uma porta serial:

mb_communication_info_t comm_info = {
    .port = MB_PORT_NUM,        // Número da porta serial
    .mode = MB_MODE_RTU,        // Modo de comunicação Modbus (RTU ou ASCII)
    .baudrate = 9600,           // Taxa de transmissão em bits por segundo
    .parity = MB_PARITY_NONE    // Tipo de paridade (nenhuma neste caso)
};

// Configura o mestre Modbus com os parâmetros de comunicação
ESP_ERROR_CHECK(mbc_master_setup((void*)&comm_info));

Configuração de Comunicação TCP/IP

Para comunicação via TCP/IP, além dos parâmetros gerais, é necessário configurar os endereços IP dos dispositivos escravos. Esses endereços são utilizados para identificar cada dispositivo na rede.

Exemplo de configuração para uma rede TCP/IP:

char* slave_ip_address_table[MB_SLAVE_COUNT] = {
    "192.168.1.2", // Endereço IP do escravo 1
    "192.168.1.3", // Endereço IP do escravo 2
    NULL           // Término da tabela
};

mb_communication_info_t comm_info = {
    .ip_port = MB_TCP_PORT,                    // Porta Modbus TCP (padrão 502)
    .ip_addr_type = MB_IPV4,                   // Tipo de endereço IP (IPv4)
    .ip_mode = MB_MODE_TCP,                    // Modo de comunicação TCP
    .ip_addr = (void*)slave_ip_address_table,  // Tabela de endereços IP dos escravos
    .ip_netif_ptr = esp_netif_ptr              // Ponteiro para a interface de rede
};

// Configura o mestre Modbus com os parâmetros de comunicação
ESP_ERROR_CHECK(mbc_master_setup((void*)&comm_info));

Considerações Importantes

  1. Para comunicação RS-485, é necessário configurar o modo UART e os pinos apropriados usando as APIs UART do ESP-IDF.
  2. No caso de redes TCP/IP, a descoberta automática de dispositivos pode ser configurada utilizando o serviço mDNS.

Com as opções de comunicação configuradas, o mestre está pronto para iniciar a troca de dados com os escravos.


Comunicação do Mestre

Após configurar o mestre Modbus e suas opções de comunicação, o próximo passo é iniciar a comunicação com os dispositivos escravos. O ESP-Modbus oferece APIs para iniciar, enviar requisições e processar as respostas recebidas.

Inicialização da Comunicação

A comunicação do mestre Modbus é iniciada com a chamada da função mbc_master_start(), que ativa a pilha Modbus e permite a troca de dados.

Exemplo de inicialização:

esp_err_t err = mbc_master_start();
if (err != ESP_OK) {
    ESP_LOGE(TAG, "Falha ao iniciar o controlador Modbus, erro = %x.", err);
}

Envio de Requisições

O mestre envia requisições aos escravos utilizando a função mbc_master_send_request(). Essa função é bloqueante, ou seja, ela aguarda uma resposta do escravo antes de continuar.

Exemplo básico de envio de requisição:

mb_param_request_t request = {
    .slave_addr = 1,          // Endereço do dispositivo escravo
    .command = MB_FUNC_READ,  // Comando Modbus (ex.: leitura de registros)
    .reg_start = 0,           // Endereço inicial do registro
    .reg_size = 2             // Número de registros a serem lidos
};

uint8_t response_data[4]; // Buffer para armazenar a resposta
esp_err_t err = mbc_master_send_request(&request, response_data);
if (err == ESP_OK) {
    ESP_LOGI(TAG, "Requisição bem-sucedida. Dados recebidos.");
} else {
    ESP_LOGE(TAG, "Erro na requisição Modbus, código de erro: %x.", err);
}

Leitura de Dados

O mestre pode acessar os valores de parâmetros definidos no Dicionário de Dados utilizando mbc_master_get_parameter(). Essa função permite recuperar os dados mapeados por um CID específico.

Exemplo de leitura de parâmetro:

const mb_parameter_descriptor_t* param_descriptor = NULL;
uint8_t data_buffer[4]; // Buffer para armazenar os dados
uint8_t data_type;

esp_err_t err = mbc_master_get_cid_info(CID_TEMP_DATA_1,m_descriptor);
if (err == ESP_OK) {
    err = mbc_master_get_parameter(param_descriptor->cid, (char*)param_descriptor->param_key, data_buffer, &data_type);
    if (err == ESP_OK) {
        ESP_LOGI(TAG, "Parâmetro: %s, Valor: 0x%08x", param_descriptor->param_key, *(uint32_t*)data_buffer);
    } else {
        ESP_LOGE(TAG, "Erro ao ler o parâmetro, código de erro: %x.", err);
    }
}

Escrita de Dados

O mestre também pode alterar valores nos registros de um escravo utilizando mbc_master_set_parameter().

Exemplo de escrita:

uint8_t new_value[4] = {0x12, 0x34, 0x56, 0x78};
esp_err_t err = mbc_master_set_parameter(CID_TEMP_DATA_1, "Temperature_1", new_value, NULL);
if (err == ESP_OK) {
    ESP_LOGI(TAG, "Parâmetro atualizado com sucesso.");
} else {
    ESP_LOGE(TAG, "Erro ao atualizar parâmetro, código de erro: %x.", err);
}

Encerramento do Mestre Modbus

Ao finalizar a utilização do mestre Modbus, é essencial encerrar corretamente a pilha de comunicação para liberar os recursos do sistema. O ESP-Modbus oferece APIs específicas para garantir que todo o contexto do controlador seja destruído de forma segura.

Parada da Pilha Modbus

A função mbc_master_stop() deve ser chamada para interromper a pilha de comunicação. Isso encerra todas as operações ativas e desativa o controlador.

Exemplo de parada da pilha:

esp_err_t err = mbc_master_stop();
if (err == ESP_OK) {
    ESP_LOGI(TAG, "Pilha Modbus parada com sucesso.");
} else {
    ESP_LOGE(TAG, "Erro ao parar a pilha Modbus, código de erro: %x.", err);
}

Destruição do Controlador

Após a parada da pilha, o controlador Modbus deve ser destruído utilizando a função mbc_master_destroy(). Isso libera a memória e outros recursos alocados durante a inicialização.

Exemplo de destruição do controlador:

esp_err_t err = mbc_master_destroy();
if (err == ESP_OK) {
    ESP_LOGI(TAG, "Controlador Modbus destruído com sucesso.");
} else {
    ESP_LOGE(TAG, "Erro ao destruir o controlador Modbus, código de erro: %x.", err);
}

Boas Práticas

  • Verificação de Erros: Sempre verifique os códigos de retorno das funções para identificar possíveis falhas e tratar erros de forma adequada.
  • Liberação de Recursos: Certifique-se de que a função mbc_master_destroy() seja chamada antes de finalizar a aplicação para evitar vazamentos de memória.
  • Sincronização: Garanta que todas as operações Modbus tenham sido concluídas antes de encerrar a pilha.

Com esses passos, o ciclo de vida do controlador mestre Modbus é finalizado de forma segura e eficiente.


API Modbus Escravo – Visão Geral

A API Modbus para dispositivos escravos no ESP32 permite configurar e gerenciar a comunicação com mestres Modbus. Assim como a API para mestres, a API para escravos segue uma sequência lógica de configuração e operação.

Etapas Principais da Comunicação Escravo

  1. Inicialização da Porta Modbus:
    • Configura a interface de comunicação (serial ou TCP/IP) e o controlador escravo.
  2. Configuração de Acesso a Dados:
    • Define os registros que estarão disponíveis para acesso pelo mestre, como holding registers ou input registers.
  3. Opções de Comunicação:
    • Configura parâmetros específicos, como taxa de transmissão e endereços de comunicação.
  4. Início da Comunicação:
    • Ativa a pilha Modbus, permitindo a troca de dados entre o escravo e o mestre.
  5. Finalização:
    • Libera os recursos do controlador ao finalizar a comunicação.

Estrutura de Dados no Escravo

Assim como no mestre, o escravo utiliza estruturas de dados para organizar os registros Modbus acessíveis pelo mestre. A configuração de cada área de registro inclui:

  • Tipo de Registro: Define se é um holding register, input register, coil, ou discrete input.
  • Endereço Inicial: Especifica a posição inicial do registro na memória do dispositivo.
  • Tamanho: Determina o número de registros disponíveis para acesso.

Configuração de Acesso a Dados no Escravo

A configuração de acesso a dados no escravo Modbus é uma etapa essencial para disponibilizar registros aos mestres. No ESP-Modbus, isso é feito definindo áreas de memória específicas que armazenarão os dados acessíveis. Essas áreas são mapeadas para tipos de registros Modbus, como Holding Registers e Input Registers.

Definindo Áreas de Registro

Cada tipo de registro Modbus no escravo é configurado utilizando a estrutura mb_register_area_descriptor_t. Essa estrutura especifica:

  • Offset Inicial: A posição relativa do registro dentro do tipo configurado.
  • Tipo de Registro: Indica se a área é de Holding Registers, Input Registers, Coils ou Discrete Inputs.
  • Endereço de Memória: Um ponteiro para a área de memória onde os dados serão armazenados.
  • Tamanho da Área: Define o número de registros disponíveis para leitura/escrita.

Exemplo de configuração de áreas de registro:

#define MB_REG_INPUT_START_AREA0    (0)
#define MB_REG_HOLDING_START_AREA0  (0)
#define MB_REG_HOLD_CNT             (100) // Número de registros de holding
#define MB_REG_INPUT_CNT            (100) // Número de registros de input

mb_register_area_descriptor_t reg_area; // Estrutura de descrição da área de registros

// Área de registros de holding
uint16_t holding_reg_area[MB_REG_HOLD_CNT] = {0};
reg_area.type = MB_PARAM_HOLDING;
reg_area.start_offset = MB_REG_HOLDING_START_AREA0;
reg_area.address = (void*)&holding_reg_area[0];
reg_area.size = sizeof(holding_reg_area);
ESP_ERROR_CHECK(mbc_slave_set_descriptor(reg_area));

// Área de registros de input
uint16_t input_reg_area[MB_REG_INPUT_CNT] = {0};
reg_area.type = MB_PARAM_INPUT;
reg_area.start_offset = MB_REG_INPUT_START_AREA0;
reg_area.address = (void*)&input_reg_area[0];
reg_area.size = sizeof(input_reg_area);
ESP_ERROR_CHECK(mbc_slave_set_descriptor(reg_area));

Proteção e Acesso aos Registros

Para evitar inconsistências durante a escrita/leitura dos registros, é importante proteger as áreas de memória com seções críticas. Exemplo:

portENTER_CRITICALm_lock);
holding_reg_area[2] += 10; // Atualizando um registro
portEXIT_CRITICALm_lock);

Requisitos para a Configuração

  • Pelo menos uma área de cada tipo de registro necessário deve ser configurada.
  • Caso um mestre tente acessar uma área não configurada, será gerada uma exceção Modbus.

Opções de Comunicação do Escravo

Após configurar as áreas de registro, é necessário definir as opções de comunicação para o escravo Modbus. Esses parâmetros garantem que o dispositivo esteja corretamente configurado para se comunicar com o mestre, seja em modo serial (RTU/ASCII) ou TCP/IP.

Configuração de Comunicação Serial

Na comunicação serial, os parâmetros principais são:

  • Porta UART: Define qual porta física será utilizada.
  • Modo de Comunicação: Indica se será RTU ou ASCII.
  • Endereço do Escravo: Identifica unicamente o dispositivo na rede.
  • Taxa de Baud: Determina a velocidade de transmissão.
  • Paridade: Configura o tipo de paridade (nenhuma, ímpar ou par).

Exemplo de configuração serial:

#define MB_SLAVE_DEV_SPEED 9600
#define MB_SLAVE_ADDR 1
#define MB_SLAVE_PORT_NUM 2

mb_communication_info_t comm_info = {
    .mode = MB_MODE_RTU,                    // Modo RTU
    .slave_addr = MB_SLAVE_ADDR,            // Endereço do escravo
    .port = MB_SLAVE_PORT_NUM,              // Porta UART
    .baudrate = MB_SLAVE_DEV_SPEED,         // Taxa de baud
    .parity = MB_PARITY_NONE                // Sem paridade
};

// Configura o escravo Modbus com os parâmetros definidos
ESP_ERROR_CHECK(mbc_slave_setup((void*)&comm_info));

Configuração de Comunicação TCP/IP

Na comunicação via TCP/IP, o escravo precisa estar associado a uma interface de rede válida e configurado para escutar em uma porta específica. A porta padrão para Modbus TCP é a 502.

Exemplo de configuração TCP/IP:

mb_communication_info_t comm_info = {
    .ip_port = MB_TCP_PORT,                    // Porta Modbus TCP (padrão 502)
    .ip_addr_type = MB_IPV4,                   // IPv4
    .ip_mode = MB_MODE_TCP,                    // Modo TCP
    .ip_addr = NULL,                           // Aceita conexões de qualquer cliente
    .ip_netif_ptr = esp_netif_ptr              // Ponteiro para a interface de rede
};

// Configura o escravo Modbus para comunicação TCP/IP
ESP_ERROR_CHECK(mbc_slave_setup((void*)&comm_info));

Considerações para Comunicação Estável

  1. RS-485: Caso a interface serial utilize RS-485, configure os pinos UART e o modo half-duplex utilizando as APIs UART do ESP-IDF.
  2. Descoberta Automática: Para TCP/IP, é possível usar o serviço mDNS para facilitar a descoberta de dispositivos na rede.
  3. Respostas em Tempo Real: Certifique-se de que os registros necessários estejam configurados para evitar erros de timeout no mestre.

Com os parâmetros de comunicação configurados, o escravo está pronto para se comunicar com o mestre.


Comunicação do Escravo

Com as áreas de registro e as opções de comunicação configuradas, o escravo Modbus está pronto para iniciar a troca de dados com o mestre. O ESP-Modbus oferece APIs para gerenciar eventos e processar acessos aos registros configurados.

Início da Comunicação

A comunicação do escravo é iniciada com a função mbc_slave_start(). Isso ativa a pilha Modbus, permitindo que o dispositivo receba e responda às requisições do mestre.

Exemplo de inicialização:

esp_err_t err = mbc_slave_start();
if (err == ESP_OK) {
    ESP_LOGI(TAG, "Escravo Modbus iniciado com sucesso.");
} else {
    ESP_LOGE(TAG, "Erro ao iniciar o escravo Modbus, código: %x.", err);
}

Monitoramento de Eventos

O escravo pode monitorar eventos relacionados ao acesso aos registros utilizando a função mbc_slave_check_event(). Essa função é bloqueante e retorna o tipo de evento ocorrido, como leitura ou escrita em um registro.

Exemplo de monitoramento de eventos:

#define MB_READ_MASK (MB_EVENT_INPUT_REG_RD | MB_EVENT_HOLDING_REG_RD)
#define MB_WRITE_MASK (MB_EVENT_HOLDING_REG_WR)
#define MB_READ_WRITE_MASK (MB_READ_MASK | MB_WRITE_MASK)

mb_event_group_t event = mbc_slave_check_event(MB_READ_WRITE_MASK);

if (event & MB_EVENT_HOLDING_REG_WR) {
    ESP_LOGI(TAG, "Escrita em Holding Register detectada.");
} else if (event & MB_EVENT_INPUT_REG_RD) {
    ESP_LOGI(TAG, "Leitura em Input Register detectada.");
}

Acesso a Parâmetros

A função mbc_slave_get_param_info() permite obter detalhes sobre o registro acessado pelo mestre, como tipo de registro, endereço e tamanho.

Exemplo de acesso:

mb_param_info_t reg_info;
esp_err_t err = mbc_slave_get_param_info_info, MB_PAR_INFO_GET_TOUT);
if (err == ESP_OK) {
    ESP_LOGI(TAG, "Registro acessado: Tipo=%u, Endereço=%u, Tamanho=%u",
             reg_info.type, reg_info.mb_offset, reg_info.size);
} else {
    ESP_LOGE(TAG, "Erro ao obter informações do parâmetro, código: %x.", err);
}

Respostas em Tempo Real

O escravo responde automaticamente às requisições do mestre com base nos registros configurados. Certifique-se de que as áreas de registro estejam atualizadas com os valores corretos para evitar comportamentos inesperados.


Encerramento do Escravo Modbus

Ao finalizar a operação do escravo Modbus, é fundamental encerrar corretamente a pilha de comunicação e liberar os recursos alocados. Isso garante a estabilidade do sistema e evita vazamentos de memória.

Parada da Pilha Modbus

A função mbc_slave_stop() é usada para interromper a pilha Modbus. Essa chamada encerra todas as operações ativas do escravo.

Exemplo de parada:

esp_err_t err = mbc_slave_stop();
if (err == ESP_OK) {
    ESP_LOGI(TAG, "Pilha Modbus do escravo parada com sucesso.");
} else {
    ESP_LOGE(TAG, "Erro ao parar a pilha Modbus, código: %x.", err);
}

Destruição do Controlador

Após parar a pilha, a função mbc_slave_destroy() deve ser chamada para destruir o controlador Modbus e liberar todos os recursos alocados durante a inicialização.

Exemplo de destruição:

esp_err_t err = mbc_slave_destroy();
if (err == ESP_OK) {
    ESP_LOGI(TAG, "Controlador do escravo Modbus destruído com sucesso.");
} else {
    ESP_LOGE(TAG, "Erro ao destruir o controlador Modbus, código: %x.", err);
}

Boas Práticas

  1. Verificação de Operações Ativas: Antes de encerrar a pilha, certifique-se de que todas as operações de leitura/escrita tenham sido concluídas.
  2. Liberação de Recursos: Sempre chame mbc_slave_destroy() para evitar vazamentos de memória ou instabilidades.
  3. Sincronização de Tarefas: Caso múltiplas tarefas acessem os registros Modbus, garanta que todas tenham finalizado antes de destruir o controlador.

Com esses passos, o ciclo de vida do escravo Modbus é encerrado de forma segura e eficiente.


Possíveis Problemas de Comunicação e Soluções

Durante a implementação do protocolo Modbus, podem ocorrer problemas de comunicação entre o mestre e os escravos. A identificação e a solução desses problemas são essenciais para garantir o funcionamento correto do sistema.

Principais Erros e Soluções

  1. Requisição Inválida (ESP_ERR_NOT_SUPPORTED – Código: 0x106)
    • Causa: O mestre enviou uma requisição para um registro ou comando não suportado pelo escravo.
    • Solução: Verifique o mapa de registros do escravo e ajuste a requisição do mestre para corresponder às capacidades do dispositivo.
  2. Timeout na Resposta do Escravo (ESP_ERR_TIMEOUT – Código: 0x107)
    • Causa: O escravo não respondeu dentro do tempo esperado.
    • Solução: Certifique-se de que:
      • O escravo está conectado corretamente.
      • A taxa de baud e os parâmetros de comunicação (como paridade) são compatíveis entre mestre e escravo.
      • O endereço do escravo na requisição está correto.
  3. Resposta Inválida (ESP_ERR_INVALID_RESPONSE – Código: 0x108)
    • Causa: O mestre recebeu uma resposta corrompida ou com erro de validação (checksum inválido).
    • Solução: Verifique a integridade do cabo de comunicação (no caso de RTU/ASCII) ou a estabilidade da conexão de rede (no caso de TCP/IP). Além disso, confirme que os parâmetros Modbus no escravo estão configurados corretamente.
  4. Estado Inválido (ESP_ERR_INVALID_STATE – Código: 0x103)
    • Causa: Erro crítico no controlador Modbus, como sequência de comandos incorreta ou controlador ocupado.
    • Solução: Reinicie o controlador Modbus no mestre ou no escravo. Verifique se múltiplas tarefas estão acessando o controlador simultaneamente e sincronize-as.

Dicas para Diagnóstico

  • Logs Detalhados: Ative logs no ESP-IDF para capturar mensagens de erro detalhadas, como falhas de inicialização ou problemas durante a execução.
  • Testes Isolados: Teste cada dispositivo escravo individualmente antes de integrar vários dispositivos na rede.
  • Osciloscópio ou Analisador de Rede: Use ferramentas de diagnóstico para verificar os sinais na linha de comunicação serial ou monitorar pacotes TCP/IP.

Exemplos de Mensagens de Erro

Um exemplo de mensagem de erro capturada nos logs do mestre:

E (1692332) MB_CONTROLLER_MASTER: mbc_master_get_parameter(111): SERIAL master get parameter failure error=(0x107) (ESP_ERR_TIMEOUT).

Neste caso, o erro indica que o escravo não respondeu no tempo esperado. A solução seria revisar as conexões físicas e os parâmetros de comunicação.


Exemplos de Aplicação

O ESP-Modbus fornece suporte completo para implementar soluções Modbus em dispositivos ESP32, permitindo a integração com uma ampla variedade de dispositivos industriais. Abaixo estão exemplos práticos de aplicações para mestre e escravo, baseados nas APIs discutidas.

Exemplo 1: Mestre Modbus Serial para Monitoramento de Sensores

Um mestre Modbus pode ser utilizado para monitorar parâmetros de sensores conectados via RS-485. O exemplo abaixo ilustra como configurar o mestre para ler a temperatura e umidade de dois dispositivos escravos.

Configuração do Mestre:

#include "mbcontroller.h"

// Configuração do dicionário de dados
mb_parameter_descriptor_t device_parameters[] = {
    { CID_TEMP, "Temperature", "C", MB_DEVICE_ADDR1, MB_PARAM_HOLDING, 0, 2, 0, PARAM_TYPE_FLOAT, 4 },
    { CID_HUMID, "Humidity", "%", MB_DEVICE_ADDR1, MB_PARAM_INPUT, 2, 1, 0, PARAM_TYPE_U16, 2 }
};

void app_main() {
    void* master_handler = NULL;
    ESP_ERROR_CHECK(mbc_master_init(MB_PORT_SERIAL_MASTER, &master_handler));

    mb_communication_info_t comm_info = {
        .port = MB_PORT_NUM,
        .mode = MB_MODE_RTU,
        .baudrate = 9600,
        .parity = MB_PARITY_NONE
    };
    ESP_ERROR_CHECK(mbc_master_setup((void*)&comm_info));

    ESP_ERROR_CHECK(mbc_master_set_descriptor(device_parameters, sizeof(device_parameters) / sizeof(device_parameters[0])));
    ESP_ERROR_CHECK(mbc_master_start());

    uint8_t temp_data[4];
    ESP_ERROR_CHECK(mbc_master_get_parameter(CID_TEMP, "Temperature", temp_data, NULL));
    ESP_LOGI(TAG, "Temperatura lida: %f", *(float*)temp_data);

    ESP_ERROR_CHECK(mbc_master_destroy());
}

Exemplo 2: Escravo Modbus TCP para Controle de Atuadores

Um escravo Modbus pode ser utilizado para controlar dispositivos como relés ou motores conectados via Ethernet. O exemplo abaixo configura o escravo para gerenciar dois relés.

Configuração do Escravo:

#include "mbcontroller.h"

#define RELAY_1_GPIO 25
#define RELAY_2_GPIO 26

void app_main() {
    uint16_t relay_registers[2] = {0}; // Registradores para os relés

    mb_register_area_descriptor_t reg_area = {
        .type = MB_PARAM_COIL,
        .start_offset = 0,
        .address = relay_registers,
        .size = sizeof(relay_registers)
    };
    ESP_ERROR_CHECK(mbc_slave_set_descriptor(reg_area));

    mb_communication_info_t comm_info = {
        .ip_port = MB_TCP_PORT,
        .ip_addr_type = MB_IPV4,
        .ip_mode = MB_MODE_TCP,
        .ip_addr = NULL,
        .ip_netif_ptr = esp_netif_ptr
    };
    ESP_ERROR_CHECK(mbc_slave_setup((void*)&comm_info));
    ESP_ERROR_CHECK(mbc_slave_start());

    while (true) {
        if (relay_registers[0]) {
            gpio_set_level(RELAY_1_GPIO, 1);
        }
        if (relay_registers[1]) {
            gpio_set_level(RELAY_2_GPIO, 1);
        }
        vTaskDelay(pdMS_TO_TICKS(100));
    }

    ESP_ERROR_CHECK(mbc_slave_destroy());
}

Integração com Outras Tecnologias

  • MQTT: Combine Modbus com MQTT para enviar dados lidos pelo mestre para um servidor em nuvem.
  • Automação Industrial: Use o ESP-Modbus para integrar dispositivos como CLPs e inversores de frequência a um sistema de supervisão (SCADA).

Conclusão e Próximos Passos

O suporte ao Modbus no ESP32, através da biblioteca ESP-Modbus, oferece uma solução robusta e flexível para aplicações de automação e integração industrial. Seja na leitura de sensores via Modbus RTU ou no controle remoto de dispositivos com Modbus TCP/IP, o ESP-Modbus simplifica a implementação e gerenciamento dessas comunicações.

Resumo dos Passos

  1. Configuração Inicial: Defina os parâmetros de comunicação e o mapeamento de dados.
  2. Troca de Dados: Utilize as APIs para enviar, receber e processar dados entre mestres e escravos.
  3. Diagnóstico e Resolução de Problemas: Monitore logs e corrija eventuais falhas de comunicação.
  4. Encerramento: Libere recursos corretamente ao finalizar a aplicação.

Próximos Passos

  • Integração com Outras Protocolos: Experimente combinar o Modbus com protocolos como MQTT ou WebSocket para criar sistemas híbridos e conectados.
  • Escalabilidade: Explore o uso de redes maiores com múltiplos dispositivos mestre e escravo.
  • Customização: Adapte os exemplos fornecidos às suas necessidades específicas, otimizando o desempenho e a confiabilidade.

Recursos Adicionais

Para mais informações sobre o ESP-Modbus e o ESP-IDF, acesse:

Com os exemplos e explicações fornecidos neste artigo, você terá uma base sólida para desenvolver aplicações Modbus em dispositivos ESP32.


0 0 votos
Classificação do artigo
Inscrever-se
Notificar de
guest
0 Comentários
mais antigos
mais recentes Mais votado
Feedbacks embutidos
Ver todos os comentários

Related Post

0
Adoraria saber sua opinião, comente.x