Ir ao conteúdo
  • Cadastre-se

Outro modbus rtu no esp8266 12e


wBB

Posts recomendados

Pessoal, estou precisando montar uma rede de comunicação Modbus RTU MASTER e também RTU SLAVE com ESP8266 12E (ou F, tanto faz), mas não consegui encontrar uma biblioteca que funcione bem. Tem várias páginas/blogs/vídeos fazendo referência às coisas da PDA Control ou a Trialcommand (que são a mesma biblioteca), mas não consegui fazer nenhuma funcionar bem. A única que ainda consegui fazer comunicar foi essa da PDA Control, mas mesmo assim ocorrem muitos erros de escrita e leitura, muitos timeouts, etc, mesmo setando a serial para trabalhar em 9600 em lugar de velocidades mais altas. 

 

Alguém conhece alguma biblioteca que funcione bem para ESP8266 ou alguma rotina de Modbus RTU que funcione (escrita em qualquer linguagem) e que eu possa usar para "traduzir" para a linguagem C usada no Arduino?

 

Já tentei usar sem sucesso essas bibliotecas:

https://github.com/Trialcommand/ESP8266-Modbus-RTU-Slave/tree/master/Modbus
https://github.com/pkourany/ModBusMaster
https://github.com/smarmengol/Modbus-Master-Slave-for-Arduino
https://github.com/JhonControl/ESP8266_ModbusRTU_Master_V2
https://github.com/4-20ma/ModbusMaster

 

 

Link para o comentário
Compartilhar em outros sites

Já resolvi. Implementei uma rotina simplificada do protocolo Modbus RTU, apenas com as funções necessárias. Seguem abaixo os dois arquivos do código do protocolo e um arquivo de exemplo com Arduino (funciona no ESP8266).

 

//==============================================================================
//                              ModbusRTU.cpp
//==============================================================================

/*-------------------------------------------------------------------------------
                              COMUNICAÇÃO MODBUS RTU

   Descrição:
      Implementação parcial do protocolo de cominicação Modbus RTU.

   Funções implementadas:
      1) Function 03 (03 hex): Read Holding Registers
      2) Function 06 (06 hex): Write Single Register
      3) Function 16 (10 hex): Write Multiple Registers

   REFERÊNCIAS:
      1) http://www.modbustools.com/modbus.html
      2) http://modbus.org/docs/Modbus_over_serial_line_V1_02.pdf


-------------------------------------------------------------------------------*/


#include "modbusRTU.h"


/*==============================================================================
Function  : CRC_16
Descrição : Executa o cálculo do CRC16 sobre os dados passados no parâmetro.
Parâmetros: nData  : Ponteiro para os dados sobre os quais o CRC16 será calculado;
            wLength: Quantidade de dados (em bytes) que serão processados no cálculo.
Retorno   : Valor do CRC calculado.
=========================================================== ===================*/
unsigned int CRC_16(const unsigned char *nData, unsigned int wLength) {
   unsigned char nTemp;
   unsigned int wCRCWord = 0xFFFF;

   while (wLength--) {
      nTemp = *nData++ ^ wCRCWord;
      wCRCWord >>= 8;
      wCRCWord  ^= wCRCTable[nTemp];
   }
   return wCRCWord;
}


/*==============================================================================
Function  : ModbusRTU_Pack
Descrição : Faz a interpretação de mensagens Modbus RTU recebidas e também o 
            empacotamento de mensagens Modbus RTU.
Parâmetros: MBBuff         : Ponteiro para o array que representa o buffer original, 
                             proveniente da rotina chamadora;
            MBHoldingReg   : Ponteiro para o array dos registradores Modbus.
Retorno   : >0 : SUCESSO = Tamanho da mensagem a ser transmitida via TCP/IP.
            =0 : Erro ou não há mensagem a ser processada como resposta.
==============================================================================*/
unsigned char ModbusRTU_Pack(unsigned char *MBBuff, unsigned int *MBHoldingReg) {

   unsigned int DataByteLength;
   unsigned int RegisterStart;
   unsigned int RegistersCount;
   unsigned int MessageLength;
   unsigned int CRC_Ref;

   unsigned char DeviceAddr;
   unsigned char MB_Function;


   // Seleciona os parâmetros da mensagem de Request
   DeviceAddr     = MBBuff[MB_RTU_DEV_ADDR];
   MB_Function    = MBBuff[MB_RTU_FUNC];
   RegisterStart  = (MBBuff[MB_RTU_REGISTER_START] << 8) + MBBuff[MB_RTU_REGISTER_START +1]; 
   RegistersCount = (MBBuff[MB_RTU_REGISTER_COUNT] << 8) + MBBuff[MB_RTU_REGISTER_COUNT +1];

   // Os devices começam a partir do valor "1"
   if (DeviceAddr == 0) { return 0; }
   if (RegistersCount > MB_MAX_HOLDING_REGISTER) { return 0; }

   switch(MB_Function) {
      case MB_FC_NONE:
         MessageLength = 0;
         break;
      
      case MB_FC_READ_REGISTERS: // 03 Read Holding Registers

         // Verifica se é válido o CRC da mensagem de Request 
         CRC_Ref = (MBBuff[MB_RTU_CRC +1] << 8) + MBBuff[MB_RTU_CRC];

         if (CRC_Ref != CRC_16(MBBuff, 6)) { return 0; }

         // Empacota a resposta para o resquet corrente 
         DataByteLength             = RegistersCount * 2;
         MBBuff[MB_RTU_DEV_ADDR]    = DeviceAddr;
         MBBuff[MB_RTU_FUNC]        = MB_Function;
         MBBuff[MB_RTU_BYTE_COUNT]  = DataByteLength;
         
         // Seta na resposta os valores atuais dos registradores
         for (int i = 0; i < RegistersCount; i++) {
            MBBuff[ MB_RTU_RESPONSE_DATA      + i * 2] = (MBHoldingReg[RegisterStart + i] >> 8) & 0xFF;
            MBBuff[(MB_RTU_RESPONSE_DATA + 1) + i * 2] = MBHoldingReg[RegisterStart + i] & 0xFF;
         }

         // Calcula o CRC16
         #define HEADER_DATA_READ 3
         CRC_Ref = CRC_16(MBBuff, HEADER_DATA_READ + DataByteLength); // "3" = 3 bytes do cabeçalho
         MBBuff[HEADER_DATA_READ + DataByteLength]    = CRC_Ref & 0xFF;
         MBBuff[HEADER_DATA_READ + DataByteLength +1] = (CRC_Ref >> 8) & 0xFF;

         MessageLength = HEADER_DATA_READ + DataByteLength + MB_RTU_CRC_LEN; 
         break;
      
      
      case MB_FC_WRITE_REGISTER: // 06 Write Holding Register

         // Verifica se é válido o CRC da mensagem de Request 
         CRC_Ref = (MBBuff[MB_RTU_CRC +1] << 8) + MBBuff[MB_RTU_CRC];

         if (CRC_Ref != CRC_16(MBBuff, 6)) { return 0; }

         // Seta o registrador com o novo valor recebido no request
         MBHoldingReg[RegisterStart] = (MBBuff[MB_RTU_S_WRITE_DATA_START] << 8) + MBBuff[MB_RTU_S_WRITE_DATA_START +1];

         // Resposta: a resposta é um "echo" do request, que tem sempre tamanho "8"
         MessageLength = 8;
         break;

      
      case MB_FC_WRITE_MULTIPLE_REGISTERS: // 16 Write Holding Registers

         // Verifica se é válido o CRC da mensagem de Request 
         CRC_Ref = (MBBuff[MB_RTU_REGISTER_COUNT + 2 + 1 + RegistersCount * 2 + 1] << 8) +
                    MBBuff[MB_RTU_REGISTER_COUNT + 2 + 1 + RegistersCount * 2]; 

         if (CRC_Ref != CRC_16(MBBuff, MB_RTU_REGISTER_COUNT + 2 + 1 + RegistersCount * 2)) { return 0; }

         // Seta os registradores com os novos valores recebidos no request
         for (int i = 0; i < RegistersCount; i++)
            MBHoldingReg[RegisterStart + i] = (MBBuff[MB_RTU_M_WRITE_DATA_START + i * 2] << 8) + MBBuff[(MB_RTU_M_WRITE_DATA_START +1) + i * 2];

         // Empacota a resposta para o resquet corrente 
         MBBuff[MB_RTU_DEV_ADDR]          = DeviceAddr;
         MBBuff[MB_RTU_FUNC]              = MB_Function;
         MBBuff[MB_RTU_REGISTER_START]    = (RegisterStart >> 8) & 0xFF;
         MBBuff[MB_RTU_REGISTER_START +1] = RegisterStart & 0xFF;
         MBBuff[MB_RTU_REGISTER_COUNT]    = (RegistersCount >> 8) & 0xFF;
         MBBuff[MB_RTU_REGISTER_COUNT +1] = RegistersCount & 0xFF;

         // Calcula o CRC16
         #define WRITE_ANS_LENGTH 6
         CRC_Ref = CRC_16(MBBuff, WRITE_ANS_LENGTH);
         MBBuff[WRITE_ANS_LENGTH]    = CRC_Ref & 0xFF;
         MBBuff[WRITE_ANS_LENGTH +1] = (CRC_Ref >> 8) & 0xFF;

         // O comprimento da resposta é sempre tamanho "8"
         MessageLength = 8;
         break;


      default:
         // Se nenhuma função Modbus tiver sido processada, então apenas retorna "0"
         // para indicar que não há nada para ser enviado via TCP/IP
         MessageLength = 0;
         break;
   }

   return MessageLength;
}




//==============================================================================
//                              ModbusRTU.h 
//==============================================================================

#ifndef DefModbus
   #define DefModbus

//------------------------------------------------------------------------------
//                   FUNÇÕES RELACIONADAS AO PROTOCOLO MODBUS

// Função de cálculo do CRC16 Modbus
unsigned int CRC_16(const unsigned char *nData, unsigned int wLength);

// Função de empacotamento de dados
unsigned char ModbusRTU_Pack(unsigned char *MBBuff, unsigned int *MBHoldingReg);


//------------------------------------------------------------------------------
//                      CONSTANTES DE COMUNICAÇÃO MODBUS

   #define MB_MAX_HOLDING_REGISTER        20 // maxHoldingRegister 20

   #define MB_FC_NONE                     0
   #define MB_FC_READ_REGISTERS           3  //implemented
   #define MB_FC_WRITE_REGISTER           6  //implemented
   #define MB_FC_WRITE_MULTIPLE_REGISTERS 16 //implemented

   // MODBUS Error Codes
   #define MB_EC_NONE                     0
   #define MB_EC_ILLEGAL_FUNCTION         1
   #define MB_EC_ILLEGAL_DATA_ADDRESS     2
   #define MB_EC_ILLEGAL_DATA_VALUE       3
   #define MB_EC_SLAVE_DEVICE_FAILURE     4

   // MODBUS MBAP offsets
   // READ
   #define MB_RTU_DEV_ADDR                0
   #define MB_RTU_FUNC                    1
   #define MB_RTU_REGISTER_START          2
   #define MB_RTU_REGISTER_COUNT          4
   #define MB_RTU_CRC                     6

   // WRITE SIMPLE
   #define MB_RTU_S_WRITE_DATA_START      4

   // WRITE MULTIPLE
   #define MB_RTU_M_WRITE_DATA_START      7

   #define MB_RTU_BYTE_COUNT              2
   #define MB_RTU_RESPONSE_DATA           3

   // MODBUS REF
   #define MB_RTU_CRC_LEN                 2



//------------------------------------------------------------------------------
//                      TABELA CRC16 MODBUS

static const unsigned int wCRCTable[] = {
   0X0000, 0XC0C1, 0XC181, 0X0140, 0XC301, 0X03C0, 0X0280, 0XC241,
   0XC601, 0X06C0, 0X0780, 0XC741, 0X0500, 0XC5C1, 0XC481, 0X0440,
   0XCC01, 0X0CC0, 0X0D80, 0XCD41, 0X0F00, 0XCFC1, 0XCE81, 0X0E40,
   0X0A00, 0XCAC1, 0XCB81, 0X0B40, 0XC901, 0X09C0, 0X0880, 0XC841,
   0XD801, 0X18C0, 0X1980, 0XD941, 0X1B00, 0XDBC1, 0XDA81, 0X1A40,
   0X1E00, 0XDEC1, 0XDF81, 0X1F40, 0XDD01, 0X1DC0, 0X1C80, 0XDC41,
   0X1400, 0XD4C1, 0XD581, 0X1540, 0XD701, 0X17C0, 0X1680, 0XD641,
   0XD201, 0X12C0, 0X1380, 0XD341, 0X1100, 0XD1C1, 0XD081, 0X1040,
   0XF001, 0X30C0, 0X3180, 0XF141, 0X3300, 0XF3C1, 0XF281, 0X3240,
   0X3600, 0XF6C1, 0XF781, 0X3740, 0XF501, 0X35C0, 0X3480, 0XF441,
   0X3C00, 0XFCC1, 0XFD81, 0X3D40, 0XFF01, 0X3FC0, 0X3E80, 0XFE41,
   0XFA01, 0X3AC0, 0X3B80, 0XFB41, 0X3900, 0XF9C1, 0XF881, 0X3840,
   0X2800, 0XE8C1, 0XE981, 0X2940, 0XEB01, 0X2BC0, 0X2A80, 0XEA41,
   0XEE01, 0X2EC0, 0X2F80, 0XEF41, 0X2D00, 0XEDC1, 0XEC81, 0X2C40,
   0XE401, 0X24C0, 0X2580, 0XE541, 0X2700, 0XE7C1, 0XE681, 0X2640,
   0X2200, 0XE2C1, 0XE381, 0X2340, 0XE101, 0X21C0, 0X2080, 0XE041,
   0XA001, 0X60C0, 0X6180, 0XA141, 0X6300, 0XA3C1, 0XA281, 0X6240,
   0X6600, 0XA6C1, 0XA781, 0X6740, 0XA501, 0X65C0, 0X6480, 0XA441,
   0X6C00, 0XACC1, 0XAD81, 0X6D40, 0XAF01, 0X6FC0, 0X6E80, 0XAE41,
   0XAA01, 0X6AC0, 0X6B80, 0XAB41, 0X6900, 0XA9C1, 0XA881, 0X6840,
   0X7800, 0XB8C1, 0XB981, 0X7940, 0XBB01, 0X7BC0, 0X7A80, 0XBA41,
   0XBE01, 0X7EC0, 0X7F80, 0XBF41, 0X7D00, 0XBDC1, 0XBC81, 0X7C40,
   0XB401, 0X74C0, 0X7580, 0XB541, 0X7700, 0XB7C1, 0XB681, 0X7640,
   0X7200, 0XB2C1, 0XB381, 0X7340, 0XB101, 0X71C0, 0X7080, 0XB041,
   0X5000, 0X90C1, 0X9181, 0X5140, 0X9301, 0X53C0, 0X5280, 0X9241,
   0X9601, 0X56C0, 0X5780, 0X9741, 0X5500, 0X95C1, 0X9481, 0X5440,
   0X9C01, 0X5CC0, 0X5D80, 0X9D41, 0X5F00, 0X9FC1, 0X9E81, 0X5E40,
   0X5A00, 0X9AC1, 0X9B81, 0X5B40, 0X9901, 0X59C0, 0X5880, 0X9841,
   0X8801, 0X48C0, 0X4980, 0X8941, 0X4B00, 0X8BC1, 0X8A81, 0X4A40,
   0X4E00, 0X8EC1, 0X8F81, 0X4F40, 0X8D01, 0X4DC0, 0X4C80, 0X8C41,
   0X4400, 0X84C1, 0X8581, 0X4540, 0X8701, 0X47C0, 0X4680, 0X8641,
   0X8201, 0X42C0, 0X4380, 0X8341, 0X4100, 0X81C1, 0X8081, 0X4040 };

#endif



//==============================================================================
//                              MB_RTU.ino 
//==============================================================================

// EXEMPLO DE APLICAÇÃO DA FUNÇÃO MODBUS COM ARDUINO / ESP8266


#include "modbusRTU.h"

// Buffer para comunicação serial via protocolo Modbus
byte MBBuffer[260];

// Registradores Modbus
unsigned int MBHoldingRegister[MB_MAX_HOLDING_REGISTER];

int i, MB_msg_length;


void setup() {
   for (i = 0; i < MB_MAX_HOLDING_REGISTER; i++)
      MBHoldingRegister[i] = 0;

   Serial.begin(9600);
   Serial.println("");
   Serial.println("Sistema Iniciado...");
}

void loop() {

   int i = 0;
   while(Serial.available()){
      MBBuffer[i] = Serial.read();
      i++;
   }

   if (i > 0) {
      // Atualiza as informações nos registradores as informações recebidas na porta serial
      MB_msg_length = ModbusRTU_Pack(MBBuffer, MBHoldingRegister);

      if (MB_msg_length > 0){
         // Devolve a resposta Modbus
         Serial.write((const uint8_t *)MBBuffer, MB_msg_length);
         Serial.flush();
      }
   }
}

 

Link para o comentário
Compartilhar em outros sites

Crie uma conta ou entre para comentar

Você precisa ser um usuário para fazer um comentário

Criar uma conta

Crie uma nova conta em nossa comunidade. É fácil!

Crie uma nova conta

Entrar

Já tem uma conta? Faça o login.

Entrar agora

Sobre o Clube do Hardware

No ar desde 1996, o Clube do Hardware é uma das maiores, mais antigas e mais respeitadas comunidades sobre tecnologia do Brasil. Leia mais

Direitos autorais

Não permitimos a cópia ou reprodução do conteúdo do nosso site, fórum, newsletters e redes sociais, mesmo citando-se a fonte. Leia mais

×
×
  • Criar novo...

 

GRÁTIS: ebook Redes Wi-Fi – 2ª Edição

EBOOK GRÁTIS!

CLIQUE AQUI E BAIXE AGORA MESMO!