Unable to write data from HMI to Arduino using RS485 MODBUS

Hi, First of all, sorry for my poor English!
I am working on a project in which I have to display some integer values on Weintek HMI and after several intervals of time, I want to write data on Arduino UNO from HMI (to change the speed of the DC motor). Using Arduino UNO and MAX485, I established the communication between Arduino & HMI, and values were successfully displayed on HMI. But I am unable to set communication for writing data on Arduino UNO from HMI . I want to set the speed of the DC motor connected to the Arduino at any time when the process is executing. Code is here

#include <modbus.h>
#include <modbusDevice.h>
#include <modbusRegBank.h>
#include <modbusSlave.h>
modbusDevice regBank;
modbusSlave slave;

#define RS485TxEnablePin 2
#define RS485Baud 9600
#define RS485Format SERIAL_8E1

// Nema 23 
#include <AccelStepper.h>
AccelStepper stepper (AccelStepper::DRIVER, 9,8); 
int gearRatio = 10;
int RpmSet = 10;
int DirRpm = -(RpmSet);
int Speed = DirRpm*gearRatio*3.333334;
unsigned long previousmillis = 0;

// Vacuum Motor 
#define RPWM 5
#define LPWM 6
//int Vacuumspeed = 150;
//int Vacuumspeed ;
// seed counting
int A_V;
int seedcount, missing, doubling, interval = 0;
int null, flag, flag1, flag2, flag3 = 0;
unsigned long PST=0;
float single;
int singulation=100;

void setup()
{ //Serial.begin(9600);
 //Assign the modbus device ID.  
 regBank.setId(1);

 //Add Analog Input registers to the register bank
 regBank.add(30001);  //Singulation
 regBank.add(30002);  //Seed Counted
 regBank.add(30003);  //Seed Missed
 regBank.add(30004);  //Seed doubled
 regBank.add(30005);  //seed to seed distance
 regBank.add(30009);  //Nema RPM
 
 //Add Analog OUTPUT registers to the register bank
 regBank.add(40001);  //Vacuum speed

 slave._device = &regBank;  
 slave.setBaud(&Serial,RS485Baud,RS485Format,RS485TxEnablePin);

 // Vacuum 
 pinMode(RPWM, OUTPUT);
 pinMode(LPWM, OUTPUT);
 analogWrite(LPWM, 0);

 //Nema 
 stepper.setMaxSpeed(1000);
 stepper.setSpeed(Speed);	
}

void loop()
{ //int Vacuumspeed;
 word Vacuumspeed = regBank.get(40001);
  
  analogWrite(RPWM, Vacuumspeed); //vacuum 
  stepper.runSpeed(); //nema  
        
  //Seed
  A_V = analogRead(A0);
  //Serial.println(A_V);

  if (A_V >=30 && flag == 0) 
   {  
      seedcount = seedcount+1;
      unsigned long SeedT = millis();
      //Serial.println(SeedT);
      if(PST==0 ){  
        null =1;
        flag1=1;
        PST = SeedT;
      }
      
      if( null == 0 && flag1 == 1){
        interval = SeedT-PST;
        flag1=0;
        
      }
      if( null==1 && flag1==1){
        null=0;
      }

      if(((SeedT-PST) >= (interval+80)) && flag2 == 0) { 
        missing = missing+1;  // missing
        flag2=1;
      }
      if(((SeedT-PST) < (interval+15)) && flag2 == 1){
        flag2 = 0;
      }
      if(((SeedT-PST) < (interval-30)) && flag3 == 0){
        doubling = doubling+1;  // doubling
        flag3=1;  
      }
      if(((SeedT-PST) > (interval-20)) && flag3 == 1){
        flag3=0;
      }
      
      PST = SeedT;
      single = seedcount*100/(missing+seedcount);  //singulation
      singulation = single;
      
      flag=1; 
      //Serial.println(seedcount);
      //Serial.println(missing);
      //slave.run();  
    }

  else if (A_V < 23 && flag == 1)
    {
     flag = 0;
    }
   
   regBank.set(30001, (int) singulation);
   regBank.set(30002, (int) seedcount);
   regBank.set(30003, (int) missing);
   regBank.set(30004, (int) doubling);
   regBank.set(30005, (int) interval);
   regBank.set(30009, (int) RpmSet);
   //regBank.set(30007, (int) Vacuumspeed); //from 0 - 1023 
   
   slave.run();
   //delay(300);
  
}

I am using 4x 1 register to set the speed of the motor. every time I set the value on HMI, nothing happens to the motor.

I have followed this tutorial to understand MODBUS communication and used the same RS485 module & MODBUS library provided.

you can find the library in the provided link.
using the analog input registers (as in the code), values are displayed on the HMI screen but the problem is only while writing data to Arduino. I am beginner in programming and really need your help. I also opened the modbusSlave.cpp file to understand the functionality of the RS485 enabler pin but still unable to fix the problem. I am also familiar with the half duplex and full duplex mode of RS485. Plz help me how to modify that code or any thing that will be helpful for me.
Thankyou in Advance.
regards

Might we ask to explain in more detail what those problems are? Do you get an error on the HMI? Which error? The library you use should be able to handle the function codes you need for that, so I don't see what problems you might have given the HMI does it's side correctly.

I am using 4x registers to write data on Arduino from HMI. when I enter any number on HMI eg 50, 100, it will again 0 in a second, and nothing will be written on arduino. I read the slave.cpp file of the ModbusSlave library, there is an option of generating a reply in which the reception is enabled for the Arduino for a specific period of time and then automatically Arduino will be switched in transmission mode. If you read the last few lines of slave.cpp file, you can understand my situation. here are these few lines of library:

//if a reply was generated
	if(_len)
	{
		int i;
		//send the reply to the serial UART
		//Senguino doesn't support a bulk serial write command....
		digitalWrite(TxEnablePin, HIGH);
		
		for(i = 0 ; i < _len ; i++)
			(*ModbusPort).write(_msg[i]);
		//free the allocated memory for the reply message
		free(_msg);		
		delay(_len*2);
		//reset the message length		
		_len = 0;		
		digitalWrite(TxEnablePin, LOW);		
		
	}

this is the code written in the ModbusSlave Library for writing something on arduino means generating reply from HMI. You can see the behaviour of Rs485 enabler pin in this code. But my code in the orignal post was not able to send reply from HMI to the arduino.
The first 3 lines in Void Loop() shows the code written for receiving data from HMI. But it does not work.

But you did register only one register. You're using a library that doesn't implement the standard Modbus but tries to be compatible with some ancient PLCs that selects the function by the register number. So if you write to holding register 0 the value will be placed in position 40001 in the regBank.

That's the relevant line in the code:

//else add 40001 to the register and set it's value to val|
_device->set(reg + 40001, val);|
1 Like

please elaborate it a little bit more

If a street has only one house on it and that has the number 5 it doesn't matter if you send letters to the number 15, 23 and 50 on that street, they won't ever arrive.

That's the same with your code. If you define one register on the slave side it doesn't matter how many registers you try to address in the master, you cannot set more than that single register you defined on the slave.

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