Modbus RTU rs485 between Arduino and HMI

Hello everyone. Sorry if I have any errors, I'm new to this forum (it's my first post :sweat_smile: ), so thank you if you have any recommendations.

I am trying to communicate a Kinco HMI (GL070E) with an arduino NANO using the Modbus RTU/RS-485 protocol and a MAX 485 converter module. In my case, I only want to send a percentage of opening of a valve, that is, an integer value between 0 and 100 (and maybe send this same value to the HMI, to more easily visualize the changes, but it is not mandatory).
To program the attributes of the object where I want to write that value (within a software called KincoDtools, for this HMI), it asks me for a series of information, as you can see:

The problem is that in the examples found where the arduino is used as a slave, none of these variables are written directly, so how can I ensure that the data is sent and stored correctly in the arduino? Or am I not understanding well how the Modbus slave libraries work?
Also, since I'm using the MAX 485 between the HMI and the arduino NANO, is there any additional information I should keep in mind when doing programming?

I hope I have been clear with my doubt, I am new to this world of communications.

If you know any example that can help me understand programming for this type of protocols a little more (specifically with Arduino and MAX 485) I would appreciate it, I am open to any advice.

PS: Adding some information about the Modbus protocol for this HMI.

image

Use Serial.print of the sent data, and serial monitor to see it is sent.

Do the same on the receiving side.

hello, I've found a code where you can write some value from the code in Arduino IDE, even it has their own library it's called "modbus_slave_HMI_Samkoon_V1.0.h"


#ifndef BUFFER_SIZE
#define BUFFER_SIZE 64
#endif
#ifndef ID_slave
#define ID_slave 01
#endif
byte RxData[BUFFER_SIZE];
uint8_t RxLength = 0;
byte Address_0x[BUFFER_SIZE];
byte Address_1x[BUFFER_SIZE];
uint16_t Address_3x[BUFFER_SIZE];
uint16_t Address_4x[BUFFER_SIZE];
byte TxData[BUFFER_SIZE];

///////////////////////////////////////
bool bitRead_0x(uint16_t add_0x);
void bitWrite_0x(uint16_t add_0x, uint8_t value);
void bitSet_0x(uint16_t add_0x);
void bitClear_0x(uint16_t add_0x);
uint16_t Read_4x(uint16_t add_4x);
void Write_4x(uint16_t add_4x, uint16_t value);
///////////////////////////////////////

void modbus_RTU_slave_HMI_samkoon(uint8_t *, uint8_t);
uint16_t CRC16(uint8_t *, uint8_t);
void ResPonse_0x01(uint8_t *, uint8_t);
void ResPonse_0x05(uint8_t *, uint8_t);
void ResPonse_0x03(uint8_t *, uint8_t);
void ResPonse_0x06(uint8_t *, uint8_t);
void sendData(uint8_t *, uint8_t);
bool bitRead_0x(uint16_t add_0x) {
  return(bitRead(Address_0x[add_0x/8],add_0x%8));
}
void bitWrite_0x(uint16_t add_0x, uint8_t value) {
  if (value ==0) bitClear(Address_0x[add_0x/8],add_0x%8);
  else bitSet(Address_0x[add_0x/8],add_0x%8);
}
void bitSet_0x(uint16_t add_0x) {
  bitSet(Address_0x[add_0x/8],add_0x%8);
}
void bitClear_0x(uint16_t add_0x) {
  bitClear(Address_0x[add_0x/8],add_0x%8);
}
uint16_t Read_4x(uint16_t add_4x){
  return(Address_4x[add_4x]);
}
void Write_4x(uint16_t add_4x, uint16_t value){
  Address_4x[add_4x]=value;
}
void serialEvent() {
  RxLength = Serial.readBytes(RxData, BUFFER_SIZE);
  if (RxLength > 0) {
    modbus_RTU_slave_HMI_samkoon(RxData, RxLength);
  }
}

void modbus_RTU_slave_HMI_samkoon(uint8_t *Data_Modbus, uint8_t DataLen) {
  uint16_t crc = CRC16(Data_Modbus, DataLen - 2);  // crc check
  uint16_t crc_Receive = Data_Modbus[DataLen - 2] << 8 | Data_Modbus[DataLen - 1];
  if ((Data_Modbus[0] == ID_slave) && (crc == crc_Receive)) {
    switch (Data_Modbus[1]) {
      case 0x01:
        {
          ResPonse_0x01(Data_Modbus, DataLen);
          break;
        }
      case 0x03:
        {
          ResPonse_0x03(Data_Modbus, DataLen);
          break;
        }
      case 0x05:
        {
          ResPonse_0x05(Data_Modbus, DataLen);
          break;
        }
      case 0x06:
        {
          ResPonse_0x06(Data_Modbus, DataLen);
          break;
        }
    }
  }
}
void ResPonse_0x01(uint8_t *Data_Modbus, uint8_t DataLen) {
  uint16_t add_register = Data_Modbus[2] << 8 | Data_Modbus[3];
  uint16_t num_coils = Data_Modbus[4] << 8 | Data_Modbus[5];
  uint8_t Byte_Count = (num_coils - 1) / 8 + 1;
  TxData[0] = ID_slave;
  TxData[1] = 0X01;        //phan hoi 0x01
  TxData[2] = Byte_Count;  //SO BYTE TRUYEN
  int i = 0;
  for (i = 0; i < Byte_Count; i++) {
    TxData[i + 3] = Address_0x[add_register + i];
  }
  uint16_t crc = CRC16(TxData, Byte_Count + 3);
  TxData[i + 3] = highByte(crc);  // >> 8) & 0xFF; // CRC HIGH
  TxData[i + 4] = lowByte(crc);   // & 0xFF; // CRC LOW
  sendData(TxData, Byte_Count + 5);
}
void ResPonse_0x05(uint8_t *Data_Modbus, uint8_t DataLen) {
  uint16_t add_coil = Data_Modbus[2] << 8 | Data_Modbus[3];
  uint16_t add_register_0x = add_coil / 8;
  uint16_t add_register_0x_bit = add_coil % 8;
  if (Data_Modbus[4] == 0xFF) bitSet(Address_0x[add_register_0x], add_register_0x_bit);
  else bitClear(Address_0x[add_register_0x], add_register_0x_bit);
  TxData[0] = ID_slave;
  TxData[1] = 0X05;            //phan hoi 0x05
  TxData[2] = Data_Modbus[2];  //add high
  TxData[3] = Data_Modbus[3];  //add low
  TxData[4] = Data_Modbus[4];  //Byte high data = 0xFF or 0x00
  TxData[5] = Data_Modbus[5];  //Byte low data = 0x00
  uint16_t crc = CRC16(TxData, 6);
  TxData[6] = highByte(crc);  // >> 8) & 0xFF; // CRC HIGH
  TxData[7] = lowByte(crc);   // & 0xFF; // CRC LOW
  sendData(TxData, 8);
}
void ResPonse_0x03(uint8_t *Data_Modbus, uint8_t DataLen) {
  uint16_t add_register = Data_Modbus[2] << 8 | Data_Modbus[3];
  uint16_t num_registers = Data_Modbus[4] << 8 | Data_Modbus[5];
  uint8_t Byte_Count = num_registers * 2;
  TxData[0] = ID_slave;
  TxData[1] = 0X03;        //phan hoi 0x03
  TxData[2] = Byte_Count;  //num byte
  int i = 0;
  for (i = 0; i < num_registers; i++) {
    TxData[2 * i + 3] = highByte(Address_4x[add_register + i]);
    TxData[2 * i + 4] = lowByte(Address_4x[add_register + i]);
  }
  uint16_t crc = CRC16(TxData, Byte_Count + 3);
  TxData[2 * i + 3] = highByte(crc);  // >> 8) & 0xFF; // CRC HIGH
  TxData[2 * i + 4] = lowByte(crc);   // & 0xFF; // CRC LOW
  sendData(TxData, Byte_Count + 5);
}
void ResPonse_0x06(uint8_t *Data_Modbus, uint8_t DataLen) {
  uint16_t add_4x = Data_Modbus[2] << 8 | Data_Modbus[3];
  Address_4x[add_4x] = Data_Modbus[4] << 8 | Data_Modbus[5];
  TxData[0] = ID_slave;
  TxData[1] = 0X06;                          //phan hoi 0x04
  TxData[2] = Data_Modbus[2];                //add high
  TxData[3] = Data_Modbus[3];                //add low
  TxData[4] = highByte(Address_4x[add_4x]);  //data high
  TxData[5] = lowByte(Address_4x[add_4x]);   //data low
  uint16_t crc = CRC16(TxData, 6);
  TxData[6] = highByte(crc);  //>> 8) & 0xFF; // CRC HIGH
  TxData[7] = lowByte(crc);   // & 0xFF; // CRC LOW
  sendData(TxData, 8);
}
void sendData(uint8_t *DataSend, uint8_t DataLen) {
  for (int i = 0; i < DataLen; i++) {
    Serial.write(DataSend[i]);
  }
}


/* Table of CRC values for high–order byte */
static unsigned char auchCRCHi[] = {
  0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81,
  0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
  0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01,
  0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
  0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81,
  0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
  0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01,
  0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
  0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81,
  0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
  0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01,
  0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
  0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81,
  0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
  0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01,
  0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
  0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81,
  0x40
};

//unsigned uIndex ; /* will index into CRC lookup table */
static char auchCRCLo[] = {
  0x00, 0xC0, 0xC1, 0x01, 0xC3, 0x03, 0x02, 0xC2, 0xC6, 0x06, 0x07, 0xC7, 0x05, 0xC5, 0xC4,
  0x04, 0xCC, 0x0C, 0x0D, 0xCD, 0x0F, 0xCF, 0xCE, 0x0E, 0x0A, 0xCA, 0xCB, 0x0B, 0xC9, 0x09,
  0x08, 0xC8, 0xD8, 0x18, 0x19, 0xD9, 0x1B, 0xDB, 0xDA, 0x1A, 0x1E, 0xDE, 0xDF, 0x1F, 0xDD,
  0x1D, 0x1C, 0xDC, 0x14, 0xD4, 0xD5, 0x15, 0xD7, 0x17, 0x16, 0xD6, 0xD2, 0x12, 0x13, 0xD3,
  0x11, 0xD1, 0xD0, 0x10, 0xF0, 0x30, 0x31, 0xF1, 0x33, 0xF3, 0xF2, 0x32, 0x36, 0xF6, 0xF7,
  0x37, 0xF5, 0x35, 0x34, 0xF4, 0x3C, 0xFC, 0xFD, 0x3D, 0xFF, 0x3F, 0x3E, 0xFE, 0xFA, 0x3A,
  0x3B, 0xFB, 0x39, 0xF9, 0xF8, 0x38, 0x28, 0xE8, 0xE9, 0x29, 0xEB, 0x2B, 0x2A, 0xEA, 0xEE,
  0x2E, 0x2F, 0xEF, 0x2D, 0xED, 0xEC, 0x2C, 0xE4, 0x24, 0x25, 0xE5, 0x27, 0xE7, 0xE6, 0x26,
  0x22, 0xE2, 0xE3, 0x23, 0xE1, 0x21, 0x20, 0xE0, 0xA0, 0x60, 0x61, 0xA1, 0x63, 0xA3, 0xA2,
  0x62, 0x66, 0xA6, 0xA7, 0x67, 0xA5, 0x65, 0x64, 0xA4, 0x6C, 0xAC, 0xAD, 0x6D, 0xAF, 0x6F,
  0x6E, 0xAE, 0xAA, 0x6A, 0x6B, 0xAB, 0x69, 0xA9, 0xA8, 0x68, 0x78, 0xB8, 0xB9, 0x79, 0xBB,
  0x7B, 0x7A, 0xBA, 0xBE, 0x7E, 0x7F, 0xBF, 0x7D, 0xBD, 0xBC, 0x7C, 0xB4, 0x74, 0x75, 0xB5,
  0x77, 0xB7, 0xB6, 0x76, 0x72, 0xB2, 0xB3, 0x73, 0xB1, 0x71, 0x70, 0xB0, 0x50, 0x90, 0x91,
  0x51, 0x93, 0x53, 0x52, 0x92, 0x96, 0x56, 0x57, 0x97, 0x55, 0x95, 0x94, 0x54, 0x9C, 0x5C,
  0x5D, 0x9D, 0x5F, 0x9F, 0x9E, 0x5E, 0x5A, 0x9A, 0x9B, 0x5B, 0x99, 0x59, 0x58, 0x98, 0x88,
  0x48, 0x49, 0x89, 0x4B, 0x8B, 0x8A, 0x4A, 0x4E, 0x8E, 0x8F, 0x4F, 0x8D, 0x4D, 0x4C, 0x8C,
  0x44, 0x84, 0x85, 0x45, 0x87, 0x47, 0x46, 0x86, 0x82, 0x42, 0x43, 0x83, 0x41, 0x81, 0x80,
  0x40
};
uint16_t CRC16(uint8_t *puchMsg, uint8_t usDataLen) {
  unsigned char uchCRCHi = 0xFF; /* high byte of CRC initialized */
  unsigned char uchCRCLo = 0xFF; /* low byte of CRC initialized */
  unsigned uIndex;               /* will index into CRC lookup table */
  //while (usDataLen––) /* pass through message buffer */
  while (usDataLen--) {
    uIndex = uchCRCHi ^ *puchMsg++; /* calculate the CRC */
    uchCRCHi = uchCRCLo ^ auchCRCHi[uIndex];
    uchCRCLo = auchCRCLo[uIndex];
  }
  return (uchCRCHi << 8 | uchCRCLo);
}

this is the code that I found (both files must be open when you run the code)


#define ID_slave 1                         //ID del esclavo (arduino)
#include "modbus_slave_HMI_Samkoon_V1.0.h" //libreria comunicación
void setup (){
  Serial.begin(9600);          //monitor serial a 9600 baudios
Serial.setTimeout(100);      //
pinMode (13, OUTPUT);        //LED D1 A LA DIRECCIÓN DE ENTRADA EN COM1 0x0
pinMode (12, OUTPUT);        //LED PRUEBA
pinMode (2, INPUT_PULLUP);   //BOTÓN DE ENCENDIDO
pinMode (3, INPUT_PULLUP);   //BOTÓN DE APAGADO
}
void loop(){
 bool state_0x0 = bitRead_0x(0);
digitalWrite(13,state_0x0);           //dirección de estado en 0x0
if(digitalRead(2)==0) bitSet_0x(0);   //set 
if(digitalRead(3)==0) bitClear_0x(0); //reset
// mostrar datos en display 8888
int var1 = 1234;       //mostrar dato 
Write_4x(0,var1);    //escribir numero Y MOSTRAR
int var2 = Read_4x(1);  //escribir datos 
if(var2==38){           //si el valor es igual a 38, el led en el pin 12 enciende,  si este es diferente al 38, el led pin 12 no encenderá
  digitalWrite(12, HIGH); //condicion para valor == "38"
}
else{
digitalWrite(12, LOW);     //condicion para valor diferente de "38",  el led no enciende
}
}

I just do this by simulation between the HMI kinco GL070E and my arduino UNO by RS232/modbus

BUT!!!!!! it doesn't work physicaly

Add diagram that I used


Currently I'm working in the same team but this time I'm going to work with RS485, communication between Arduino MKR 1010 WIFI and my HMI kinco GL070E, I think is the same process but I need search more information. If you have question, make me know bro.


sorry for the quality but actually it works

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.