Hopefully, I can convey the issue in a clear concise manner. I designed a micro PLC with an ESP32 DEVKIT V1 at heart just for personal projects and to learn as I've always been fascinated with electronics. It has (8) digital inputs, (6) digital outputs, RS-485 connection, LCD connection, I2C connection (for potential future multiplexers to expand IO), and power port for necessary 5V and connecting all power commons together (for common reference point for external DI's power supply).
The digital inputs/outputs work just fine at least so far. The problem I am having is with Modbus RTU over RS-485. Modbus RTU is relatively new to me and I'm having a hard time knowing if the problem is with my hardware design or if it has to do with software. Unfortunately, I do not have a analyzer to help troubleshoot to find if it is software or hardware. My setup is Redlion HMI (CR30000700000420) as the master and the ESP32 PLC as the slave. Attached is the KiCad file for the PCB I designed, Arduino IDE program, and RedLion HMI screen shots of how it is configured. Right now I only have the two devices on the RS-485 network with a cable run of about 50foot max (120Ohm terminating resistor at the ESP32 PLC). Currently I am just trying to read a digital input value from the ESP32 modbus table and display what state it is in on the Redlion HMI. I've set all values to true (in the setup routine) in the ESP32 modbus table which I believe will hold a (1) value at the offset location. I try to read this value from the Redlion HMI master and turn on a red light for value (1) and green light for value (0). Right now it does not read any value and indicator on redlion hmi is transparent (no value present). I've tried everything I can think of and still have not been able to communicate.
From the Redlion HMI I wired a standard ethernet cable (T-568B) down to terminal blocks. The black wire is wired from A to A and white wire is B to B and ran to a test station in my barn (roughly 50ft run).
I know this is somewhat of a complex issue and any help would be appreciated. Hopefully, I've supplied enough information
The digital inputs/outputs work just fine at least so far. The problem I am having is with Modbus RTU over RS-485. Modbus RTU is relatively new to me and I'm having a hard time knowing if the problem is with my hardware design or if it has to do with software. Unfortunately, I do not have a analyzer to help troubleshoot to find if it is software or hardware. My setup is Redlion HMI (CR30000700000420) as the master and the ESP32 PLC as the slave. Attached is the KiCad file for the PCB I designed, Arduino IDE program, and RedLion HMI screen shots of how it is configured. Right now I only have the two devices on the RS-485 network with a cable run of about 50foot max (120Ohm terminating resistor at the ESP32 PLC). Currently I am just trying to read a digital input value from the ESP32 modbus table and display what state it is in on the Redlion HMI. I've set all values to true (in the setup routine) in the ESP32 modbus table which I believe will hold a (1) value at the offset location. I try to read this value from the Redlion HMI master and turn on a red light for value (1) and green light for value (0). Right now it does not read any value and indicator on redlion hmi is transparent (no value present). I've tried everything I can think of and still have not been able to communicate.
From the Redlion HMI I wired a standard ethernet cable (T-568B) down to terminal blocks. The black wire is wired from A to A and white wire is B to B and ran to a test station in my barn (roughly 50ft run).
I know this is somewhat of a complex issue and any help would be appreciated. Hopefully, I've supplied enough information
Code:
#include <ESPmDNS.h>
#include <WiFi.h>
#include <WiFiUdp.h>
#include <ArduinoOTA.h>
#include <ModbusRTU.h>
/********************************************************************/
/******************ESP32 PINOUT ASSIGNMENTS**********************************/
const int Input_Float_HH =13;
const int Input_Float_H =14;
const int Input_Float_L =15;
const int Input_Float_LL =16;
const int Input_Float_Refill =17;
const int Input_Start_RO_Cycle =18;
const int Input_Stop_RO_Cycle =19;
const int Input_8 =5;
const int Output_RO_Pump = 25;
const int Output_2 = 26;
const int Output_3 = 27;
const int Output_4 = 32;
const int Output_5 = 33;
const int Output_6 = 4;
const int I2C_SCL = 22;
const int I2C_SDA = 21;
const int I2C_SCL2 = 12;
const int I2C_SDA2 = 2;
const int RS_485_TX = 1;
const int RS_485_RX = 3;
const int RS_485_CNTRL_Pin = 23;
/********************************************************************/
// WiFi
// Make sure to update this for your own WiFi network!
const char* ssid = ""; ... removed for privacy
const char* password = "";... removed for privacy
/********************************************************************/
/******************Global Variables**********************************/
int Read_Input_Float_HH =0;
int Read_Input_Float_H =0;
int Read_Input_Float_L =0;
int Read_Input_Float_LL =0;
int Read_Input_Float_Refill =0;
int Read_Input_Start_RO_Cycle =0;
int Read_Input_Stop_RO_Cycle =0;
int Read_Input_8 =0;
int Start_RO_Cycle = 0;
int Stop_RO_Cycle = 0;
int Start_RO_Pump = 0;
int Stop_RO_Pump = 0;
int Main_PLC_Permissive = 1; // Bit sent to Main PLC to know current state of RO System. 0 = No error; 1 = Error or just starting.
bool High_Float_Error = false;
bool High_High_Float_Error = false;
bool Refill_Float_Error = false;
bool Low_Float_Error = false;
bool Low_Low_Float_Error = false;
/******************Global Variables******************************/
/******************Modbus Stuff**********************************/
#define SLAVE_ID 1
#define RO_Pump_Coil 1
#define Float_HH_DI 1
#define Float_H_DI 2
#define Float_Refill_DI 3
#define Float_L_DI 4
#define Float_LL_DI 5
#define RO_Cycle_Start_DI 6
#define RO_Cycle_Stop_DI 7
#define Main_PLC_Permissive_DI 8 // Bit sent to Main PLC to know current state of RO System. 0 = No error; 1 = Error or just starting.
#define High_Float_Error_DI 9
#define High_High_Float_Error_DI 10
#define Refill_Float_Error_DI 11
#define Low_Float_Error_DI 12
#define Low_Low_Float_Error_DI 13
ModbusRTU mb;
/******************Modbus Stuff**********************************/
void setup() {
/******************INITIALIZE INPUTS*****************************/
pinMode(Input_Float_HH, INPUT_PULLDOWN);
pinMode(Input_Float_H, INPUT_PULLDOWN);
pinMode(Input_Float_L, INPUT_PULLDOWN);
pinMode(Input_Float_LL, INPUT_PULLDOWN);
pinMode(Input_Float_Refill, INPUT_PULLDOWN);
pinMode(Input_Start_RO_Cycle, INPUT_PULLDOWN);
pinMode(Input_Stop_RO_Cycle, INPUT_PULLDOWN);
pinMode(Input_8, INPUT_PULLDOWN);
/******************INITIALIZE INPUTS**********************************/
/******************INITIALIZE OUTPUTS*********************************/
pinMode(Output_RO_Pump, OUTPUT); // Initialize pin as an output
digitalWrite(Output_RO_Pump, LOW);
pinMode(Output_2, OUTPUT);
digitalWrite(Output_2, LOW);
pinMode(Output_3, OUTPUT);
digitalWrite(Output_3, LOW);
pinMode(Output_4, OUTPUT);
digitalWrite(Output_4, LOW);
pinMode(Output_5, OUTPUT);
digitalWrite(Output_5, LOW);
pinMode(Output_6, OUTPUT);
digitalWrite(Output_6, LOW);
/******************INITIALIZE OUTPUTS*********************************/
/******************INITIALIZE SERIAL PORTS/MODBUS*********************/
Serial.begin(9600, SERIAL_8N1);
//Serial2.begin(9600, SERIAL_8N1, RS_485_RX, RS_485_TX, RS_485_CNTRL_Pin);
mb.begin(&Serial);
mb.slave(SLAVE_ID);
mb.addCoil(RO_Pump_Coil, false);
mb.addIsts(Float_HH_DI, true);
mb.addIsts(Float_H_DI, true);
mb.addIsts(Float_Refill_DI);
mb.addIsts(Float_L_DI, true);
mb.addIsts(Float_LL_DI, true);
mb.addIsts(RO_Cycle_Start_DI, true);
mb.addIsts(RO_Cycle_Stop_DI, true);
mb.addIsts(Main_PLC_Permissive_DI, true);
mb.addIsts(High_Float_Error_DI, true);
mb.addIsts(High_High_Float_Error_DI, true);
mb.addIsts(Refill_Float_Error_DI, true);
mb.addIsts(Low_Float_Error_DI, true);
mb.addIsts(Low_Low_Float_Error_DI, true);
/******************INITIALIZE SERIAL PORTS/MODBUS*********************/
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, password);
while (WiFi.waitForConnectResult() != WL_CONNECTED) {
Serial.println("Connection Failed! Rebooting...");
delay(5000);
ESP.restart();
}
// Port defaults to 3232
// ArduinoOTA.setPort(3232);
// Hostname defaults to esp3232-[MAC]
ArduinoOTA.setHostname("RO_System");
// No authentication by default
// ArduinoOTA.setPassword("admin");
// Password can be set with it's md5 value as well
// MD5(admin) = 21232f297a57a5a743894a0e4a801fc3
// ArduinoOTA.setPasswordHash("21232f297a57a5a743894a0e4a801fc3");
ArduinoOTA
.onStart([]() {
String type;
if (ArduinoOTA.getCommand() == U_FLASH)
type = "sketch";
else // U_SPIFFS
type = "filesystem";
// NOTE: if updating SPIFFS this would be the place to unmount SPIFFS using SPIFFS.end()
Serial.println("Start updating " + type);
})
.onEnd([]() {
Serial.println("\nEnd");
})
.onProgress([](unsigned int progress, unsigned int total) {
Serial.printf("Progress: %u%%\r", (progress / (total / 100)));
})
.onError([](ota_error_t error) {
Serial.printf("Error[%u]: ", error);
if (error == OTA_AUTH_ERROR) Serial.println("Auth Failed");
else if (error == OTA_BEGIN_ERROR) Serial.println("Begin Failed");
else if (error == OTA_CONNECT_ERROR) Serial.println("Connect Failed");
else if (error == OTA_RECEIVE_ERROR) Serial.println("Receive Failed");
else if (error == OTA_END_ERROR) Serial.println("End Failed");
});
ArduinoOTA.begin();
Serial.println("Ready");
Serial.print("IP address: ");
Serial.println(WiFi.localIP());
}
void loop() {
ArduinoOTA.handle();
mb.task();
Read_Inputs();
RO_System_Control();
Set_Modbus_Tables();
Alarm_Status();
Set_Digital_Outputs();
yield();
}
void Read_Inputs() {
Read_Input_Float_HH = digitalRead(Input_Float_HH);
Read_Input_Float_H = digitalRead(Input_Float_H);
Read_Input_Float_L = digitalRead(Input_Float_L);
Read_Input_Float_LL = digitalRead(Input_Float_LL);
Read_Input_Float_Refill = digitalRead(Input_Float_Refill);
Read_Input_Start_RO_Cycle = digitalRead(Input_Start_RO_Cycle);
Read_Input_Stop_RO_Cycle = digitalRead(Input_Stop_RO_Cycle);
if(Input_Start_RO_Cycle == 1){
Start_RO_Cycle =1;
Stop_RO_Cycle =0;
}
if(Input_Stop_RO_Cycle == 1){
Start_RO_Cycle =0;
Stop_RO_Cycle =1;
}
}
void RO_System_Control(){
if(Input_Start_RO_Cycle == 1 && Input_Stop_RO_Cycle == 0){
if(Read_Input_Float_HH == 0 || Read_Input_Float_H == 0){
Start_RO_Pump = 0;
Stop_RO_Pump = 1;
Main_PLC_Permissive = 0;
}
if(Read_Input_Float_Refill == 1){
Start_RO_Pump = 1;
Stop_RO_Pump = 0;
Main_PLC_Permissive = 0;
}
if(Read_Input_Float_L == 1 || Read_Input_Float_LL == 1){
Start_RO_Pump = 1;
Stop_RO_Pump = 0;
Main_PLC_Permissive = 0;
}
if(Read_Input_Float_LL == 1){
Start_RO_Pump = 1;
Stop_RO_Pump = 0;
Main_PLC_Permissive = 1;
}
}
}
void Set_Modbus_Tables(){
//***************SET DIGITAL OUTPUT MODBUS REGISTER**********************
//if(Output_RO_Pump == 1){
// mb.Coil(RO_Pump_Coil, true); // writes value of Output_RO_Pump to modbus register of RO_Pump_Coil
// }
// else{
// mb.Coil(RO_Pump_Coil, false); // writes value of Output_RO_Pump to modbus register of RO_Pump_Coil
//}
//***************SET DIGITAL OUTPUT MODBUS REGISTER**********************
//***************SET DIGITAL INPUT MODBUS REGISTER**********************
//if(Read_Input_Float_HH == 1){
// mb.Ists(Float_HH_DI,true); // writes value of Read_Input_Float_HH to modbus register of FLoat_HH_DI
//}
//else{
// mb.Ists(Float_HH_DI,false); // writes value of Read_Input_Float_HH to modbus register of FLoat_HH_DI
// }
//if(Read_Input_Float_H == 1){
//mb.Ists(Float_H_DI,true); // writes value of Read_Input_Float_H to modbus register of FLoat_H_DI
//}
//else{
// mb.Ists(Float_H_DI,false); // writes value of Read_Input_Float_H to modbus register of FLoat_H_DI
// }
// if(Read_Input_Float_Refill == 1){
//mb.Ists(Float_Refill_DI,true); // writes value of Read_Input_Float_Refill to modbus register of FLoat_Refill_DI
//}
//else{
//mb.Ists(Float_Refill_DI,false); // writes value of Read_Input_Float_Refill to modbus register of FLoat_Refill_DI
//}
//if(Read_Input_Float_L == 1){
// mb.Ists(Float_L_DI,true); // writes value of Read_Input_Float_L to modbus register of FLoat_L_DI
// }
//else{
// mb.Ists(Float_L_DI,false); // writes value of Read_Input_Float_L to modbus register of FLoat_L_DI
//}
//if(Read_Input_Float_LL == 1){
// mb.Ists(Float_LL_DI,true); // writes value of Read_Input_Float_LL to modbus register of FLoat_LL_DI
// }
// else{
//mb.Ists(Float_LL_DI,false); // writes value of Read_Input_Float_LL to modbus register of FLoat_LL_DI
//}
//if(Read_Input_Start_RO_Cycle == 1){
// mb.Ists(RO_Cycle_Start_DI,true); // writes value of Read_Input_Start_RO_Cycle to modbus register of RO_Cycle_Start_DI
// }
//else{
// mb.Ists(RO_Cycle_Start_DI,false); // writes value of Read_Input_Start_RO_Cycle to modbus register of RO_Cycle_Start_DI
//}
// if(Read_Input_Stop_RO_Cycle == 1){
// mb.Ists(RO_Cycle_Stop_DI,true); // writes value of Read_Input_Stop_RO_Cycle to modbus register of RO_Cycle_Stop_DI
//}
//else{
// mb.Ists(RO_Cycle_Stop_DI, false); // writes value of Read_Input_Stop_RO_Cycle to modbus register of RO_Cycle_Stop_DI
//}
// if(Main_PLC_Permissive == true){
// mb.Ists(Main_PLC_Permissive_DI, true);
//}
//else{
// mb.Ists(Main_PLC_Permissive_DI, false);
// }
// if(High_Float_Error == true){
// mb.Ists(High_Float_Error_DI, true);
//}
//else{
// mb.Ists(High_Float_Error_DI, false);
//}
// if(High_High_Float_Error == true){
// mb.Ists(High_High_Float_Error_DI, true);
//}
//else{
// mb.Ists(High_High_Float_Error_DI, false);
// }
//if(Refill_Float_Error == true){
// mb.Ists(Refill_Float_Error_DI, true);
//}
//else{
// mb.Ists(Refill_Float_Error_DI, false);
//}
// if(Low_Float_Error == true){
// mb.Ists(Low_Float_Error_DI, true);
//}
//else{
// mb.Ists(Low_Float_Error_DI, false);
//}
//if(Low_Low_Float_Error == true){
// mb.Ists(Low_Low_Float_Error_DI, true);
//}
//else{
// mb.Ists(Low_Low_Float_Error_DI, false);
//}
//***************SET DIGITAL INPUT MODBUS REGISTER**********************
//***************INSTRUCTIONS TO RETURN VALUE OF A MODBUS REGISTER**********************
//bool Coil (offset word).... DIGITAL OUTPUT
//Hreg word (word offset).... ANALOG OUTPUT
//bool Ists (offset word).... DIGITAL INPUT
//IREG word (word offset).... ANALOG INPUT
//***************INSTRUCTIONS TO RETURN VALUE OF A MODBUS REGISTER**********************
//***************INSTRUCTIONS TO SET VALUE OF A MODBUS REGISTER*************************
//bool Coil (offset word, bool value).... DIGITAL OUTPUT
//bool Hreg (offset word, word value).... ANALOG OUTPUT
//bool Ists (offset word, bool value).... DIGITAL INPUT
//bool IREG (offset word, word value).... ANALOG INPUT
//***************INSTRUCTIONS TO SET VALUE OF A MODBUS REGISTER*************************
}
void Alarm_Status(){
if(Read_Input_Float_HH == 0){
High_High_Float_Error = true;
}
else{
High_High_Float_Error = false;
}
if(Read_Input_Float_HH == 0 && (Read_Input_Float_Refill == 1 || Read_Input_Float_Refill == 1)){
High_Float_Error = true;
}
else{
High_Float_Error = false;
}
if((Read_Input_Float_H == 0 && Read_Input_Float_Refill == 0) || (Read_Input_Float_H == 0 && (Read_Input_Float_L == 1 || Read_Input_Float_LL == 1) && Read_Input_Float_Refill == 0) ){
Refill_Float_Error = true;
}
else{
Refill_Float_Error = false;
}
if((Read_Input_Float_H == 0 && Read_Input_Float_L == 0) || (Read_Input_Float_LL == 1 && Read_Input_Float_Refill == 1 && Read_Input_Float_L == 0)){
Low_Float_Error = true;
}
else{
Low_Float_Error = false;
}
if(Read_Input_Float_LL == 0 && (Read_Input_Float_L == 1 || Read_Input_Float_Refill == 1 || Read_Input_Float_H == 0 || Read_Input_Float_HH == 0)){
Low_Low_Float_Error = true;
}
else{
Low_Low_Float_Error = false;
}
}
void Set_Digital_Outputs(){
if(Start_RO_Pump == 1){
digitalWrite(Output_RO_Pump, HIGH);
}
if(Stop_RO_Pump == 1 || Start_RO_Pump == 0){
digitalWrite(Output_RO_Pump, LOW);
}
}
Attachments
-
45 KB Views: 12
-
46.7 KB Views: 8
-
66.9 KB Views: 11
-
47.6 KB Views: 11
-
49.4 KB Views: 4
-
2.6 MB Views: 5
-
432.7 KB Views: 12
-
495.1 KB Views: 13
-
160.6 KB Views: 12