O protocolo Modbus em detalhes

Visão geral

O Modbus é um protocolo industrial desenvolvido em 1979 para possibilitar a comunicação entre dispositivos de automação. Originalmente implementado como um protocolo de nível de aplicação destinado a transferir dados por uma camada serial, o Modbus foi ampliado para incluir implementações em comunicações seriais, TCP/IP e UDP (user datagram protocol). Este documento oferece uma visão detalhada da implementação do protocolo.

Conteúdo

O que é o protocolo Modbus?

O Modbus é um protocolo de requisição-resposta que utiliza um relacionamento mestre-escravo. Em um relacionamento mestre-escravo, a comunicação sempre ocorre em pares — um dispositivo deve iniciar a requisição e então aguardar por uma resposta — e o dispositivo iniciador (o mestre) é responsável por iniciar cada interação. Tipicamente, o mestre é uma interface homem-máquina (IHM) ou sistema SCADA (Supervisory Control and Data Acquisition) e o escravo é um sensor, controlador lógico programável (CLP) ou controlador programável para automação (CPA). O conteúdo dessas requisições e respostas e as camadas de rede pelas quais essas mensagens são enviadas são definidos pelas diferentes camadas do protocolo.

Figura 1. Relacionamento de rede tipo mestre-escravo

Camadas do protocolo Modbus

Em sua implementação inicial, o Modbus era um protocolo simples, criado no topo da comunicação serial; dessa forma, não podia ser dividido em camadas. Ao longo do tempo, outras unidades de dados de aplicação foram sendo introduzidas para alterar o formato dos pacotes utilizados sobre o serial ou permitir o uso de TCP/IP e redes UDP (User Datagram Protocol). Isso levou a uma separação entre o protocolo básico, que define a unidade de dados de protocolo (PDU) e a camada de rede, que define a unidade de dados de aplicação (ADU).

Unidade de dados de protocolo

A PDU e seu código formam a base da especificação do protocolo de aplicação do Modbus. Essa especificação define o formato da PDU, os diversos conceitos de dados usados pelo protocolo, o uso de códigos de função para acessar esses dados e a implementação dos diversos códigos de função e as restrições específicas de cada um deles.

A PDU do Modbus é formada por um código de função seguido por um conjunto de dados associado. As dimensões e o conteúdo desses dados são definidos pelo código de função, mas toda a PDU (código de função e dados) não pode ultrapassar 253 bytes. Cada código de função tem um comportamento específico, que os escravos têm flexibilidade para implementar com base no comportamento desejado da aplicação. A especificação de PDU define os conceitos básicos para o acesso e manipulação dos dados; entretanto, um escravo pode tratar os dados de uma maneira não definida explicitamente na especificação.

Acesso aos dados no Modbus e o modelo de dados do Modbus

Os dados que podem ser acessados pelo Modbus são armazenados, de forma geral, em um dos quatro bancos de dados, ou faixas de endereço: coils, entradas discretas, registradores holding e registradores de entrada. Como ocorre com muitas partes da especificação, esses nomes podem variar, dependendo da indústria ou aplicação. Por exemplo, os registradores holding podem ser denominados registradores de saída, e os coils podem ser referidos como saídas digitais ou discretas. Esses bancos de dados definem o tipo e os direitos de acesso dos dados contidos. Os dispositivos escravo têm acesso direto a esses dados, que são hospedados localmente nos dispositivos. Os dados que podem ser acessados pelo Modbus são de forma geral um subconjunto da memória principal do dispositivo. Por outro lado, os mestres Modbus precisam solicitar acesso a esses dados, utilizando diversos códigos de função. O comportamento de cada bloco é descrito no quadro 1.

 

Bloco de memória Tipo de dados Acesso ao mestre Acesso ao escravo
Coils Booleano Leitura/escrita Leitura/escrita
Entradas discretas Booleano Somente leitura Leitura/escrita
Registradores holding Palavra não sinalizada Leitura/escrita Leitura/escrita
Registradores de entrada Palavra não sinalizada Somente leitura Leitura/escrita

Quadro 1. Blocos do modelo de dados do Modbus

Esses blocos dão a você a capacidade de restringir ou permitir acesso a diferentes elementos de dados e também fornecer mecanismos simplificados na camada de aplicação para o acesso a diferentes tipos de dados.

Os blocos são totalmente conceituais. Eles podem existir como endereços de memória distintos em um dado sistema, mas também podem se sobrepor entre si. Por exemplo, o coil 1 pode existir na mesma posição de memória que o primeiro bit da palavra representada pelo registrador holding 1. O esquema de endereçamento é totalmente definido pelo dispositivo escravo, e a interpretação de cada bloco de memória é uma parte importante do modelo de dados do dispositivo.

Endereçamento do modelo de dados

A especificação define que cada bloco contém um espaço de endereçamento de até 65.536 (216) elementos. Com a definição da PDU, o Modbus define o endereço de cada elemento de dados na faixa de 0 a 65.535. Entretanto, cada elemento de dados é numerado de 1 a n, onde n tem o valor máximo de 65.536. Assim, o coil 1 está no endereço 0 do bloco de coils, enquanto que o registrador holding 54 está no endereço 53 da seção de memória reservada pelo escravo para os registradores holding.

Não é obrigatório implementar as faixas completas permitidas pela especificação no dispositivo. Por exemplo, pode ser escolhido para um dado dispositivo não implementar coils, entradas discretas ou registradores de entrada e, em vez disso, utilizar registradores holding de 150 a 175 e 200 a 225. Isso é perfeitamente aceitável; nesse caso, tentativas de acesso inválidas seriam tratadas por exceções.

Faixas de endereçamento de dados

Embora a especificação defina que diferentes tipos de dados devem existir em blocos diferentes e atribua uma faixa de endereços local para cada tipo, isso não implica que haverá necessariamente um esquema de endereçamento intuitivo ou facilmente compreensível para a documentação da memória que pode ser acessada pelo Modbus para um determinado dispositivo. Para simplificar a discussão sobre as posições dos blocos de memória, foi introduzido um esquema de numeração que inclui prefixos ao endereço dos dados em questão.

Por exemplo, em vez de se referir a um item como registrador holding 14 no endereço 13, o manual do dispositivo pode se referir a um item de dados no endereço 4.014, 40.014 ou 400.014. Em todos esses casos, o primeiro número especificado é 4, que representa os registradores holding; os demais números especificam um endereço. A diferença entre 4XXX, 4XXXX e 4XXXXX depende do espaço de endereços utilizado pelo dispositivo. Se todos os 65.536 registradores estiverem em uso, utilizaremos a notação 4XXXXX, pois ela permite o uso da faixa de 400.001 a 465.536. Se apenas alguns registradores forem usados, uma prática comum é usar a faixa de 4.001 a 4.999.

Nesse esquema de endereçamento, cada tipo de dados recebe um prefixo, como mostrado no quadro 2.

 

Bloco de dados Prefixo
Coils 0
Entradas discretas 1
Registradores de entrada 3
Registradores holding 4

Quadro 2. Prefixos das faixas de dados

Coils utilizam o prefixo 0. Isso significa que a referência 4001 pode se referir ao registrador holding 1 ou ao coil 4001. Por esse motivo, é recomendado que todas as implementações novas utilizem o endereçamento de 6 dígitos com zeros na frente. Essa informação deverá ser anotada na documentação. Dessa forma, o registrador holding 1 é referenciado como 400.001 e o coil 4001 é referenciado como 004.001.

Valores iniciais dos endereços de dados

A diferença entre endereços de memória e números de referência inclui uma complicação adicional, representada pela indexação selecionada por uma determinada aplicação. Como mencionado anteriormente, o registrador holding 1 está localizado no endereço 0. Tipicamente, os números de referência são indexados em 1; nesse caso, o valor inicial de uma faixa será 1. Dessa forma, a tradução literal de 400.001 é registrador holding 00001, que está no endereço 0. Algumas implementações escolhem iniciar suas faixas em zero; dessa forma, 400.000 indica registrador holding no endereço zero. O quadro 3 demonstra esse conceito.

Endereço Número do registrador Número (indexação em 1, padrão) Número (indexação em 0, alternativa)
0 1 400001 400000
1 2 400002 400001
2 3 400003 400002

Quadro 3. Esquemas de indexação dos registradores

 

Faixas indexadas em 1 são muito usadas e altamente recomendadas. De qualquer forma, o valor inicial de cada faixa sempre deverá ser indicado na documentação.

Tipos de dados para grandes valores

O padrão Modbus oferece um modelo de dados relativamente simples, que não inclui outros tipos de dados além do valor do bit e palavra não sinalizada. Esses valores podem ser suficientes para alguns sistemas, nos quais os valores de bit correspondem a solenóides e relés e os valores das palavras correspondem a valores ADC sem escala, mas não para sistemas avançados. Como resultado, muitas implementações do Modbus incluem tipos de dados que vão além das fronteiras do registrador. O módulo LabVIEW Datalogging and Supervisory Control (DSC) e o KEPServerEX definem alguns tipos de referência. Por exemplo, as strings armazenadas em um registrador holding seguem o formato padrão (400.001), mas são seguidas por um decimal, o comprimento e o byte que ordena a string (400.001.2H, uma string de 2 caracteres no registrador holding 1, onde o byte em nível alto corresponde ao primeiro caractere da string). Isso é necessário porque cada requisição tem tamanho finito; dessa forma, o mestre Modbus precisa saber exatamente onde a string começa e termina, em vez de procurar por um comprimento fixo ou delimitador, como o NULL.

Acesso a bit

Além de permitir acesso a dados que vão além das fronteira do registrador, alguns mestres Modbus permitem o uso de referências a bits individuais dentro de um registrador. Com isso, os dispositivos podem combinar dados de todos os tipos em uma mesma faixa de memória sem ter de separar dados binários no coil e faixas de entrada discretas. Normalmente, esse recurso é indicado pelo uso de um ponto decimal e o índice de bit ou número, dependendo da implementação. Ou seja, o primeiro bit do primeiro registrador pode ser 400.001.00 ou 400.001.01. É recomendado que toda documentação especifique o esquema de indexação utilizado.

Configuração endian dos dados

Os dados de múltiplos registros, como valores de ponto flutuante de precisão única, podem ser facilmente transferidos ao Modbus, com a separação dos dados em dois registradores. Como isso não é definido pelo padrão, a ordem de bit (endian) utilizada nessa separação também não está definida. Cada palavra não sinalizada deve ser enviada na ordem de bit usada pela rede (big endian) para satisfazer o padrão, mas muitos dispositivos invertem a ordem de bytes no caso de dados formados por vários bytes. A figura 2 mostra um exemplo incomum, mas válido, dessa implantação.

Figura 2. Inversão da ordem de bytes em dados formados por várias palavras

É de responsabilidade do mestre entender como o escravo está armazenando informações na memória e decodificá-las adequadamente. É recomendável que a documentação informe a ordem da palavra usada pelo sistema. A ordem endian pode também ser entendida como uma opção de configuração do sistema, com funções de codificação e decodificação, se for necessário ter flexibilidade na implementação.

Strings

Strings podem ser armazenadas facilmente em registradores Modbus. Por simplicidade, algumas implementações requerem que os comprimentos de string sejam múltiplos de 2 e que qualquer espaço adicional seja preenchido por valores nulos. A ordem dos bytes também é uma variável nas interações das strings. O formato das strings pode ou não incluir um NULL como valor final. Como exemplo dessa variabilidade, alguns dispositivos podem armazenar dados como mostrado na figura 3.

Figura 3. Inversão da ordem dos bytes em strings do Modbus

Códigos de função

Ao contrário do modelo de dados, que pode variar significativamente de um dispositivo a outro, os códigos de função e seus dados são definidos explicitamente pela norma. Cada função segue um padrão. Em primeiro lugar, o escravo valida entradas como, por exemplo, código de função, endereço dos dados e faixa de dados. Em seguida, ele executa a ação requisitada e envia a resposta apropriada ao código. Se qualquer etapa desse processo falhar, uma exceção será enviada de volta ao requisitante. O transporte de dados dessas solicitações é a PDU.

A PDU do Modbus

A PDU é formada por um código de função de 1 byte seguido por até 252 bytes de dados de função.

Figura 4. A PDU do Modbus

O código de função é o primeiro item a ser validado. Se o código de função não for reconhecido pelo dispositivo que recebe a requisição, ele responderá com uma exceção. Se o código de função for aceito, o dispositivo escravo começará a decompor os dados conforme a definição da função.

 

Como o tamanho do pacote é limitado a 254 bytes, os dispositivos são limitados com relação à quantidade de dados que pode ser transferida. Os códigos de função mais comuns podem transferir entre 240 e 250 bytes de dados do modelo de dados do escravo, dependendo do código.

Execução da função pelo escravo

Conforme definido pelo modelo de dados, diferentes funções são definidas para acessar diferentes blocos conceituais de dados. Uma implementação muito usada faz os códigos acessarem posições estáticas de memória, mas outros comportamentos podem ser usados. Por exemplo, código de função 1 (ler coils) e 3 (ler registradores holding) podem acessar a mesma posição física na memória. Por outro lado, o código de função 3 (ler registradores holding) e 16 (escrever em registradores holding) podem acessar posições de memória completamente diferentes. Dessa forma, a execução de cada código de função é melhor considerada como parte da definição do modelo de dados do escravo.

Independentemente do comportamento executado, todos os dispositivos escravo devem seguir um diagrama de estados simples para cada requisição. A figura 5 mostra um exemplo baseado no código 1, ler coils.

Figura 5. Diagrama de estado de leitura de coils conforme a especificação do protocolo Modbus

Cada escravo precisará validar o código de função, quantidade de entradas, endereço inicial, faixa total e a execução da função pelo escravo que fará a leitura.

Embora sejam mostradas faixas de endereços estáticos no diagrama de estados acima, as necessidades dos sistemas do mundo real podem causar alguma variação com relação aos números definidos. Em alguns casos, os dispositivos escravo não conseguem transferir a quantidade máxima de bytes definida pelo protocolo. Isso significa não permitir que um mestre requisite 0x07D0 entradas se eles só podem responder com 0x0400. De maneira similar, um modelo de dados de escravo pode definir a faixa de valores de coil aceitáveis como os endereços de 0 a 500. Se um mestre fizer uma requisição de 125 endereços a partir do endereço 0, isso estará OK, mas se fizer a mesma requisição a partir do endereço 400, o coil final estaria no endereço 525, que está fora da faixa para esse dispositivo, o que resultaria na exceção 02, conforme definido pelo diagrama de estados.

Códigos de função padrão

A definição de cada código de função padrão é fornecida na especificação. Mesmo para os códigos de função mais comumente usados, é inevitável haver algum descasamento entre as funções habilitadas no mestre e aquelas que podem ser tratadas pelo escravo. Para lidar com isso, as versões mais recentes da especificação TCP do Modbus definiu três classes de conformidade. O documento oficial Modbus Conformance Test Specification não faz referência a essas classes; em vez disso, define conformidade para cada função. Entretanto, elas ainda podem facilitar a compreensão. É recomendado que qualquer documentação siga a especificação do teste e defina sua conformidade pelos códigos que pode utilizar, e não pelas classificações usadas anteriormente.

Códigos da classe 0

Os códigos da classe 0 são considerados em geral o mínimo para um dispositivo Modbus utilizável, pois dão a um mestre a capacidade de ler ou escrever no modelo de dados.

Código Descrição
3 Read Multiple Registers
16 Write Multiple Registers

Quadro 4. Códigos em conformidade com a classe 0

Códigos da classe 1

Os códigos de função da classe 1 compreendem outros códigos necessários para acessar todos os tipos do modelo de dados. Na definição original, essa lista incluía o código de função 7 (ler exceção). Entretanto, esse código é definido pela especificação atual como código somente serial.

Código Descrição
1 Read Coils
2 Read Discrete Inputs
4 Read Input Registers
5 Write Single Coil
6 Write Single Register
7 Read Exception Status (somente serial)

Quadro 5. Códigos em conformidade com a classe 1

Códigos da classe 2

Os códigos de função da classe 2 são funções mais especializadas, implementadas com menor frequência. Por exemplo, Read/Write Multiple Registers pode ajudar a reduzir a quantidade total de ciclos de requisição-resposta, mas o comportamento ainda pode ser implementado com códigos de classe 0.

 Código Descrição
15 Write Multiple Coils
20 Read File Record
21 Write File Record
22 Mask Write Register
23 Read/Write Multiple Registers
24 Read FIFO

Quadro 6. Códigos em conformidade com a classe 2

 
Interface encapsulada do Modbus

O código de interface encapsulada do Modbus (MEI), função 43, é usado para encapsular outros dados dentro de um pacote Modbus. Até o momento, há dois números de MEI disponíveis, 13 (CANopen) e 14 (Device Identification).

A função 43/14 (Device Identification) é útil por permitir a transferência de até 256 objetos exclusivos. Alguns desses objetos são pré-definidos e reservados, como nome do fornecedor e código do produto, mas aplicações podem definir outros objetos a serem transferidos como conjuntos de dados genéricos.

Esse código não é implementado comumente.

Exceções

Os escravos usam exceções para indicar diversas condições problemáticas, de requisições mal formadas a entradas incorretas. Entretanto, as exceções podem também ser geradas como resposta no nível da aplicação a uma requisição inválida. Os escravos não respondem a requisições emitidas com uma exceção. Nesses casos, o escravo ignora uma requisição incompleta ou corrompida e começa a esperar pela chegada de uma nova mensagem.

Exceções são relatadas em um formato de pacote definido. Em primeiro lugar, um código de função é enviado de volta ao mestre solicitante igual ao código de função original com exceção de seu conjunto de bits mais significativo. Isso equivale a incluir 0x80 ao valor do código de função original. Em vez dos dados normais associados à resposta a uma determinada função, as respostas à exceção incluem um único código de exceção.

No padrão, os quatro códigos de exceção mais comuns são 01, 02, 03 e 04. Esses códigos são mostrados no quadro 7, com os significados padrão para cada função.

Código de exceção Significado
01 O código de função recebido não é suportado. Para confirmar o código de função original, subtraia 0x80 do valor retornado.
02 A requisição tentou acessar um endereço inválido. No padrão, isso pode acontecer somente se o endereço inicial e a quantidade de valores requisitada ultrapassar 216. Entretanto, alguns dispositivos podem limitar ainda mais esse espaço de endereços em seus modelos de dados.
03 A requisição tem dados incorretos. Em alguns casos, isso significa que houve algum descasamento entre parâmetros, por exemplo, entre o número de registradores enviados e o campo "byte count". Mais comumente, o mestre solicitou mais dados do que permitido pelo escravo ou pelo protocolo. Por exemplo, um mestre pode ler apenas 125 registradores holding por vez, e dispositivos com recursos limitados podem reduzir ainda mais esse número de registradores.
04 Ocorreu um erro não recuperável durante uma tentativa de processar a requisição. Esse é um código de exceção geral, que indica que a requisição era válida, mas o escravo não conseguiu executá-la.

Quadro 7. Códigos comuns de exceção do Modbus

 

O diagrama de estado para cada código de função deve cobrir pelo menos o código de exceção 01 e normalmente incluir os códigos 04, 02 e 03; quaisquer outros códigos de exceção definidos são opcionais.

Unidade de dados de aplicação

Além das funções definidas no núcleo da PDU do protocolo Modbus, você pode usar diversos protocolos de rede. Os protocolos mais usados são TCP/IP e serial, mas você também pode usar outros, como o UDP. Para transmitir os dados necessários para o Modbus em todas essas camadas, o Modbus inclui um conjunto de variantes de ADU feitas especificamente para cada protocolo de rede.

Recursos comuns

O Modbus requer determinados recursos para fornecer comunicação confiável. O Unit ID ou Address é usado em todos os formatos de ADU para fornecer informações de roteamento à camada de aplicação. Cada ADU é fornecida com uma PDU completa, incluindo o código de função e os dados associados a uma determinada requisição. Para aumentar a confiabilidade, todas as mensagens contêm informações de verificação de erro. Além disso, todas as ADUs possuem um mecanismo que determina o início e o fim do quadro da requisição, mas os implementa de formas diferentes.

Formatos padrão

Os três formatos padrão para as ADUs são TCP, RTU (unidade de terminal remoto) e ASCII. As ADUs dos tipos RTU e ASCII são tradicionalmente utilizadas por uma linha serial, enquanto que o TCP é usado em redes TCP/IP ou UDP/IP modernas.

TCP/IP

As ADUs do tipo TCP são formadas pelo cabeçalho do Modbus Application Protocol (MBAP) concatenado com a PDU do Modbus. O MBAP é um cabeçalho de uso geral, que depende de uma camada de rede confiável. O formato dessa ADU, incluindo o header, é mostrado na figura 6.

Figura 6. A ADU do tipo TCP/IP

Os campos de dados do cabeçalho indicam seu uso. Em primeiro lugar, ele contém um identificador de transações. Esse é um recurso valioso em uma rede que pode ter várias requisições em processamento simultaneamente. Com isso, por exemplo, um mestre pode enviar requisições 1, 2 e 3. Em algum ponto posteriormente, um escravo pode responder na ordem 2, 1, 3. Nesse caso, o mestre pode combinar as requisições com suas respostas e interpretar os dados corretamente. Esse é um recurso útil para redes Ethernet.

O identificador do protocolo normalmente é zero, mas você pode usá-lo para expandir o comportamento do protocolo. O campo Length é usado pelo protocolo para delinear o comprimento do restante do pacote. A posição desse elemento também indica a dependência desse formato do cabeçalho em uma camada de rede confiável. Como os pacotes TCP possuem verificação de erro incorporada e garantem a coerência e entrega dos dados, o comprimento do pacote pode estar localizado em qualquer parte do cabeçalho. Em uma rede inerentemente menos confiável, como uma rede serial, um pacote pode ser perdido. Nesse caso, mesmo que um feixe de dados lido pela aplicação incluísse informações válidas de transação e protocolo, a informação corrompida de comprimento tornaria o cabeçalho inválido. O TCP oferece um razoável grau de proteção contra essa situação.

O campo Unit ID normalmente não é utilizado para dispositivos TCP/IP. Entretanto, o Modbus é um protocolo tão utilizado que muitos gateways diferentes foram desenvolvidos, o que converte o protocolo Modbus em outro protocolo. Em sua destinação original, o gateway Modbus de TCP/IP para serial poderia ser usado para permitir a conexão entre novas redes TCP/IP e redes seriais mais antigas. Em um ambiente como esse, a Unit ID é usada para determinar o endereço do dispositivo escravo para o qual a PDU é realmente destinada.

Para finalizar, a ADU contém uma PDU. O comprimento dessa PDU é ainda limitado a 253 bytes no protocolo padrão.

RTU

A ADU da RTU parece ser muito mais simples, como mostrado na figura 7.

Figura 7. ADU da RTU

Diferentemente da ADU mais complexa do TCP/IP, essa ADU contém apenas duas partes de informação além da PDU base. Em primeiro lugar, um endereço é usado para definir a qual escravo a PDU é destinada. Na maior parte das redes, o endereço 0 é o endereço de "difusão". Isso significa que se um mestre enviar um comando ao endereço 0, todos os escravos deverão processar a requisição, mas nenhum deles deverá responder. Além desse endereço, um CRC é usado para garantir a integridade dos dados.

Entretanto, nas implementações mais modernas a realidade está muito longe de ser simples. O pacote é delimitado por um par de intervalos de silêncio — ou seja, períodos nos quais não há comunicação no barramento. Para a taxa de bauds de 9.600, esse intervalo é de aproximadamente 4 ms. O padrão define um intervalo de silêncio mínimo, independente da taxa de bauds, um pouco menor que 2 ms.

 

Em primeiro lugar, isso traz uma desvantagem ao desempenho, pois o dispositivo precisa esperar o término desse tempo de guarda antes de processar o pacote. Um problema maior, entretanto, foi o surgimento de outras tecnologias utilizadas em transferências seriais e taxas de baud muito maiores do que as existentes quando o padrão foi lançado. Ao utilizar um cabo de conversão USB-serial, por exemplo, você não tem controle sobre o empacotamento e transferência dos dados. Testes mostram que usar um cabo USB-serial com o driver NI-VISA introduz grandes lacunas de tamanho variável no feixe de dados, e essas lacunas — períodos de silêncio — confundem o código que segue a especificação, fazendo-o acreditar que a mensagem foi concluída. Como a mensagem não está completa, isso normalmente leva a um CRC inválido e à interpretação pelo dispositivo de que a ADU foi corrompida.

Além dos problemas com a transmissão, as modernas tecnologias de drivers abstraem significativamente a comunicação serial e tipicamente requerem um mecanismo de polling do código de aplicação. Por exemplo, nem o .NET Framework 4.5 SerialPort Class nem o NI-VISA fornecem um mecanismo para detectar silêncio em uma linha serial além do polling em bytes na porta. Isso resulta em uma escolha de baixo desempenho (se o polling for realizado lentamente demais) ou alta utilização da CPU (se o polling for executado rapidamente demais).

Um método muito usado para tratar desses problemas é separar a camada de abstração entre a PDU do Modbus e a camada de rede. Com isso, o código serial interroga o pacote da PDU do Modbus para determinar o código de função. Em conjunto com outros dados no pacote, o comprimento do pacote restante pode ser descoberto e utilizado para determinar o final do pacote. Tendo essa informação, é possível usar um tempo de timeout muito maior, permitindo lacunas na transmissão, e o polling da aplicação pode ocorrer muito mais lentamente. Esse mecanismo é recomendado para novos desenvolvimentos. Caso o seu código não empregue esse mecanismo, você poderá ter uma quantidade de pacotes "corrompidos" maior que a esperada.

ASCII

A ADU do ASCII é mais complexa que a RTU mostrada na figura 8, mas também evita muitos dos problemas do pacote de RTU. Entretanto, ela tem suas próprias desvantagens.

Figura 8. ADU do ASCII

Para resolver o problema da determinação do tamanho do pacote, a ADU do ASCII tem início e fim únicos e bem definidos para cada pacote. Cada pacote é iniciado por ":" e é encerrado com os caracteres CR (carriage return) e LF (line feed). Além disso, APIs seriais como NI-VISA e o .NET Framework SerialPort Class podem facilmente ler dados em um buffer até que um caractere específico — como CR/LR — seja recebido. Essas características tornam mais fácil processar a transmissão de dados na linha serial de maneira eficiente nos modernos códigos das aplicações.

A desvantagem da ADU de ASCII é que todos os dados são transferidos como caracteres hexadecimais codificados em ASCII. Isso significa que em vez de enviar um único byte para o código de função 3, 0x03, ela envia os caracteres ASCII “0” e “3”, ou 0x30/0x33. Isso facilita a leitura do protocolo por um ser humano, mas isso também significa ser necessário transferir o dobro dos dados pela rede serial, além disso, as aplicações de envio e recepção devem ser capazes de interpretar os valores ASCII.

Extensão do Modbus

O Modbus é um padrão relativamente simples e aberto, que pode ser modificado conforme as necessidades de uma determinada aplicação. Esse é o protocolo mais usado na comunicação entre uma IHM e CLP ou CPA, pois essa é uma situação na qual uma única organização controla as duas pontas do protocolo. Os desenvolvedores de sensores, por exemplo, têm maior probabilidade de aderir ao padrão escrito, porque eles tipicamente somente controlam a implementação de seus escravos, e a interoperabilidade é desejável.

De forma geral, não é recomendável modificar o protocolo. Esta seção é simplesmente fornecida como um reconhecimento dos mecanismos que outros já usaram para ajustar o comportamento do protocolo.

Novos códigos de função

Alguns códigos de função estão definidos, mas o padrão Modbus permite que você desenvolva outros códigos de função. Especificamente os códigos de função de 1 a 64, 73 a 99 e de 111 a 127 são códigos públicos, reservados e com exclusividade garantida. Os códigos restantes, de 65 a 72 e 100 a 110 são para uso definido pelo usuário. Com esses códigos definidos pelo usuário, você pode usar qualquer estrutura de dados. Os dados podem até mesmo ultrapassar o limite de 253 bytes para a PDU do Modbus, mas toda a aplicação deve ser validada para garantir que as outras camadas trabalharão como esperado quando a PDU ultrapassar o limite padrão. Os códigos de função acima de 127 são reservados para respostas a exceções.

Camadas de rede

O Modbus pode ser executado em muitas camadas de rede além de serial e TCP. Uma implementação potencial é o UDP, por ser adequado ao estilo de comunicação do Modbus. O Modbus é basicamente um protocolo baseado em mensagem; assim, a capacidade da UDP de enviar um pacote bem definido de informação sem qualquer informação adicional no nível da aplicação, como um caractere inicial ou comprimento, torna a implementação do Modbus extremamente simples. Em vez de exigir uma ADU adicional ou reutilizar uma ADU existente, os pacotes de PDU do Modbus podem ser enviados pelo uso de uma API de UDP e serem recebidos totalmente formados na outra extremidade. Embora o TCP seja vantajoso para alguns protocolos, devido ao seu sistema interno de acknowledgement, o Modbus realiza esse acknowledgement na camada de aplicação. Entretanto, usar o UDP dessa maneira elimina o campo de identificador de transação da ADU do TCP, o que impede a possibilidade de haver diversas transações simultâneas. Assim, o mestre deve ser síncrono ou o pacote do UDP deve ter um identificador que ajude o mestre a organizar requisições e respostas. Uma sugestão de implementação seria usar a ADU do TCP/IP em uma camada de rede do UDP.

Modificações da ADU

Para finalizar, uma aplicação pode escolher modificar uma ADU ou usar partes não utilizadas de uma ADU existente, como o TCP. Por exemplo, o TCP define um campo de 16 bits, um protocolo de 16 bits e uma Unit ID de 8 bits. Dado que a maior PDU do Modbus tem 253 bytes, o maior byte do comprimento é sempre zero. Para Modbus/TCP, o campo de protocolo e a Unit ID são sempre zero. Uma extensão simples do protocolo poderia enviar três pacotes simultaneamente alterando o campo de protocolo para um número diferente de zero e usando os dois bytes não utilizados (Unit ID e maior byte do campo de comprimento) para o envio dos comprimentos das duas PDUs adicionais (veja a figura 9).

Figura 9. Exemplo de modificação da ADU do TCP

Recursos adicionais

Especificação do protocolo de aplicações Modbus

Por que o OPC UA é importante

Sobre o OPC

Tecnologia EtherNet/IP—CIP em Ethernet

Suporte a Digi

Biblioteca Modbus para Java