ESP8266 Slave Modbus TCP/IP No libraries
A large number of devices have the TCP/IP modbus protocol becoming one of the most commonly used protocols at industrial level, this time we created a routine for ESP8266 as a slave Mobdus TCP/IP, we created this routine based on this Example Update ESP8266 Industrial Modbus TCP IP V2.0.
.
No additional libraries
We performed numerous tests of the modbus library which used the Tinker library, with the result that certain applications that use delay’s affect communication, in that case we take the library and select the connection routines, master frame reading, frame creation, Reading and writing functions.
This routine created in Arduino IDE for ESP8266 performs master – slave communication without adding extra libraries, since the communication is done step by step.
Tests
The following addresses have been configured in the ESP8266 module:
- 10 Holding Read Registers for display on the ESP8266 serial terminal.
- 10 Holding Writing Registers in which we will send Random values to validate the changes in the Modbus Master (Simulator).
- Additionally from Holding register [14] we will activate the 14 – pin GPIO (D5)
ESP8266 Modbus Slave TCP / IP, No extra libraries
Arduino IDE Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 |
/* * More Tutorials: * Website http://trialcommand.com * In English: http://en.trialcommand.com * En Español: http://en.trialcommand.com */ #include < ESP8266WiFi.h > const char* ssid = "**********"; const char* password = "**********"; int ModbusTCP_port = 502; //////// Required for Modbus TCP / IP /// Requerido para Modbus TCP/IP ///////// #define maxInputRegister 20 #define 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 // #define MB_TCP_TID 0 #define MB_TCP_PID 2 #define MB_TCP_LEN 4 #define MB_TCP_UID 6 #define MB_TCP_FUNC 7 #define MB_TCP_REGISTER_START 8 #define MB_TCP_REGISTER_NUMBER 10 byte ByteArray[260]; unsigned int MBHoldingRegister[maxHoldingRegister]; ////////////////////////////////////////////////////////////////////////// WiFiServer MBServer(ModbusTCP_port); void setup() { pinMode(14, OUTPUT); Serial.begin(9600); delay(100) ; WiFi.begin(ssid, password); delay(100) ; Serial.println("."); while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); } MBServer.begin(); Serial.println("Connected "); Serial.print("ESP8266 Slave Modbus TCP/IP "); Serial.print(WiFi.localIP()); Serial.print(":"); Serial.println(String(ModbusTCP_port)); Serial.println("Modbus TCP/IP Online"); } void loop() { // Check if a client has connected // Modbus TCP/IP WiFiClient client = MBServer.available(); if (!client) { return; } boolean flagClientConnected = 0; byte byteFN = MB_FC_NONE; int Start; int WordDataLength; int ByteDataLength; int MessageLength; // Modbus TCP/IP while (client.connected()) { if(client.available()) { flagClientConnected = 1; int i = 0; while(client.available()) { ByteArray[i] = client.read(); i++; } client.flush(); ///// code here --- codigo aqui ///////// Holding Register [0] A [9] = 10 Holding Registers Escritura ///////// Holding Register [0] A [9] = 10 Holding Registers Writing MBHoldingRegister[0] = random(0,12); MBHoldingRegister[1] = random(0,12); MBHoldingRegister[2] = random(0,12); MBHoldingRegister[3] = random(0,12); MBHoldingRegister[4] = random(0,12); MBHoldingRegister[5] = random(0,12); MBHoldingRegister[6] = random(0,12); MBHoldingRegister[7] = random(0,12); MBHoldingRegister[8] = random(0,12); MBHoldingRegister[9] = random(0,12); ///////// Holding Register [10] A [19] = 10 Holding Registers Lectura ///// Holding Register [10] A [19] = 10 Holding Registers Reading int Temporal[10]; Temporal[0] = MBHoldingRegister[10]; Temporal[1] = MBHoldingRegister[11]; Temporal[2] = MBHoldingRegister[12]; Temporal[3] = MBHoldingRegister[13]; Temporal[4] = MBHoldingRegister[14]; Temporal[5] = MBHoldingRegister[15]; Temporal[6] = MBHoldingRegister[16]; Temporal[7] = MBHoldingRegister[17]; Temporal[8] = MBHoldingRegister[18]; Temporal[9] = MBHoldingRegister[19]; /// Enable Output 14 digitalWrite(14, MBHoldingRegister[14] ); //// debug for (int i = 0; i < 10; i++) { Serial.print("["); Serial.print(i); Serial.print("] "); Serial.print(Temporal[i]); } Serial.println(""); //// end code - fin //// rutine Modbus TCP byteFN = ByteArray[MB_TCP_FUNC]; Start = word(ByteArray[MB_TCP_REGISTER_START],ByteArray[MB_TCP_REGISTER_START+1]); WordDataLength = word(ByteArray[MB_TCP_REGISTER_NUMBER],ByteArray[MB_TCP_REGISTER_NUMBER+1]); } // Handle request switch(byteFN) { case MB_FC_NONE: break; case MB_FC_READ_REGISTERS: // 03 Read Holding Registers ByteDataLength = WordDataLength * 2; ByteArray[5] = ByteDataLength + 3; //Number of bytes after this one. ByteArray[8] = ByteDataLength; //Number of bytes after this one (or number of bytes of data). for(int i = 0; i < WordDataLength; i++) { ByteArray[ 9 + i * 2] = highByte(MBHoldingRegister[Start + i]); ByteArray[10 + i * 2] = lowByte(MBHoldingRegister[Start + i]); } MessageLength = ByteDataLength + 9; client.write((const uint8_t *)ByteArray,MessageLength); byteFN = MB_FC_NONE; break; case MB_FC_WRITE_REGISTER: // 06 Write Holding Register MBHoldingRegister[Start] = word(ByteArray[MB_TCP_REGISTER_NUMBER],ByteArray[MB_TCP_REGISTER_NUMBER+1]); ByteArray[5] = 6; //Number of bytes after this one. MessageLength = 12; client.write((const uint8_t *)ByteArray,MessageLength); byteFN = MB_FC_NONE; break; case MB_FC_WRITE_MULTIPLE_REGISTERS: //16 Write Holding Registers ByteDataLength = WordDataLength * 2; ByteArray[5] = ByteDataLength + 3; //Number of bytes after this one. for(int i = 0; i < WordDataLength; i++) { MBHoldingRegister[Start + i] = word(ByteArray[ 13 + i * 2],ByteArray[14 + i * 2]); } MessageLength = 12; client.write((const uint8_t *)ByteArray,MessageLength); byteFN = MB_FC_NONE; break; } } } |
Conclusions
We have tested this library for several hours and consider that implementing the esp8266 with more robust hardware, could be used in monitoring and control applications of Controllers. PAC, PLC, OPC, SCADA and Node-RED.
Recommendations
Verify that adding delay or libraries with delay’s do not affect the communication between Master and slave since a continuous communication must be maintained and the master’s timeout could determine the communication as failed.
References
Hello,
Great work on node esp8266.
Functions 03 and 06 work perfectly.
Sorry, there is a problem with Functions 16.
I use the PLS Schneider M251, which does not support Functions 6.
and I need to use function 16.
Has this feature been built with you?
After all the attempts I failed to use.