Alamat
Tampin, 73000 Negeri Sembilan
Waktu Bekerja
Isnin to Jumaat: 8AM - 6PM
Alamat
Tampin, 73000 Negeri Sembilan
Waktu Bekerja
Isnin to Jumaat: 8AM - 6PM

Biasanya kita dengar PLC digunakan dalam industri untuk mengawal. Pernah terfikir untuk kawal actuator atau sensor industri dengan ESP32? Sepatutnya boleh buat Modbus TCP – ESP32. Tapi saya tak pernah cuba dengan peralatan sebenar. Setakat cuba dengan simulasi di perisian FactoryIO sahaja.
Modbus TCP – ESP32. Bagi membolehkan esp32 berhubung dengan PLC pastikan bahawa esp32 dan plc boleh berhubung melalui rangkaian. Secara ringkas sambungan ditunjukkan oleh rajah berikut:

IO antara server dan client boleh ditunjukkan seperti rajah berikut:

Dalam factoryIO link adalah seperti berikut:



/*
Modbus TCP - ESP32
------------------
Fungsi:
- Fill Button -> Modbus Coil 0
- Drain Button -> Modbus Coil 1
- Fill Valve -> Input Status 0
- Fill LED -> Input Status 1
- Drain Valve -> Input Status 2
- Drain LED -> Input Status 3
- Timer -> Input Register 0
Timer:
- FILL = 5 saat
- DRAIN = 10 saat
Library:
ModbusIP_ESP8266
*/
#ifdef ESP8266
#include <ESP8266WiFi.h>
#else
#include <WiFi.h>
#endif
#include <ModbusIP_ESP8266.h>
// ======================================================
// WIFI
// ======================================================
const char* WIFI_SSID = "yyyyyyyy";
const char* WIFI_PASSWORD = "xxxxxxxxx";
// ======================================================
// MODBUS REGISTER ADDRESS
// ======================================================
// Input Status
const uint16_t FILLVALVE_ISTS = 0;
const uint16_t FILLLED_ISTS = 1;
const uint16_t DRAINVALVE_ISTS = 2;
const uint16_t DRAINLED_ISTS = 3;
// Coil
const uint16_t FILLBTN_COIL = 0;
const uint16_t DRAINBTN_COIL = 1;
// Input Register
const uint16_t TIMER_IREG = 0;
const int N = 3; // samakan dengan count dalam Configuration Factory IO
// ======================================================
// GPIO
// ======================================================
const uint8_t FILL_BUTTON_PIN = 26;
const uint8_t DRAIN_BUTTON_PIN = 25;
const uint8_t FILL_LED_PIN = 32;
const uint8_t DRAIN_LED_PIN = 33;
// ======================================================
// TIMER
// ======================================================
const unsigned long TIMER_INTERVAL = 1000;
// Fill = 5 saat
const int FILL_TIMER_START = 5;
// Drain = 10 saat
const int DRAIN_TIMER_START = 10;
// ======================================================
// MODBUS OBJECT
// ======================================================
ModbusIP mb;
// ======================================================
// SYSTEM MODE
// ======================================================
enum SystemMode
{
MODE_NORMAL = 0,
MODE_FILL = 1,
MODE_DRAIN = 2
};
SystemMode mode = MODE_NORMAL;
// ======================================================
// SYSTEM VARIABLES
// ======================================================
bool fillButton = false;
bool drainButton = false;
bool fillIO = false;
bool drainIO = true;
int timer = 0;
unsigned long previousMillis = 0;
// ======================================================
// SETUP MODBUS REGISTERS
// ======================================================
void setupModbus()
{
// --------------------------------------------------
// Input Status
// --------------------------------------------------
mb.addIsts(FILLVALVE_ISTS);
mb.addIsts(FILLLED_ISTS);
mb.addIsts(DRAINVALVE_ISTS);
mb.addIsts(DRAINLED_ISTS);
// --------------------------------------------------
// Coils
// --------------------------------------------------
mb.addCoil(FILLBTN_COIL, false, N);
mb.addCoil(DRAINBTN_COIL, true, N);
// --------------------------------------------------
// Input Register
// --------------------------------------------------
mb.addIreg(TIMER_IREG);
}
// ======================================================
// RESET SYSTEM
// ======================================================
void resetSystem()
{
mode = MODE_NORMAL;
timer = 0;
// Reset timer register
mb.Ireg(TIMER_IREG, 0);
// --------------------------------------------------
// Fill
// --------------------------------------------------
mb.Ists(FILLVALVE_ISTS, 0);
mb.Ists(FILLLED_ISTS, 0);
// --------------------------------------------------
// Drain
// --------------------------------------------------
mb.Ists(DRAINVALVE_ISTS, 0);
mb.Ists(DRAINLED_ISTS, 0);
}
// ======================================================
// START FILL
// ======================================================
void startFill()
{
mode = MODE_FILL;
// Fill timer = 5 saat
timer = FILL_TIMER_START;
mb.Ireg(TIMER_IREG, timer);
// --------------------------------------------------
// Fill ON
// --------------------------------------------------
mb.Ists(FILLVALVE_ISTS, 1);
mb.Ists(FILLLED_ISTS, 1);
// --------------------------------------------------
// Drain OFF
// --------------------------------------------------
mb.Ists(DRAINVALVE_ISTS, 0);
mb.Ists(DRAINLED_ISTS, 0);
// Reset timer
previousMillis = millis();
Serial.println();
Serial.println("====================");
Serial.println("MODE : FILL");
Serial.println("TIMER: 5 seconds");
Serial.println("====================");
}
// ======================================================
// START DRAIN
// ======================================================
void startDrain()
{
mode = MODE_DRAIN;
// Drain timer = 10 saat
timer = DRAIN_TIMER_START;
mb.Ireg(TIMER_IREG, timer);
// --------------------------------------------------
// Fill OFF
// --------------------------------------------------
mb.Ists(FILLVALVE_ISTS, 0);
mb.Ists(FILLLED_ISTS, 0);
// --------------------------------------------------
// Drain ON
// --------------------------------------------------
mb.Ists(DRAINVALVE_ISTS, 1);
mb.Ists(DRAINLED_ISTS, 1);
// Reset timer
previousMillis = millis();
Serial.println();
Serial.println("====================");
Serial.println("MODE : DRAIN");
Serial.println("TIMER: 10 seconds");
Serial.println("====================");
}
// ======================================================
// READ PHYSICAL BUTTON
// ======================================================
void updateButtons()
{
/*
INPUT_PULLUP:
Button tidak ditekan = HIGH
Button ditekan = LOW
Oleh itu:
!digitalRead()
akan menghasilkan:
Tidak ditekan = false
Ditekan = true
*/
fillButton = digitalRead(FILL_BUTTON_PIN);
drainButton = digitalRead(DRAIN_BUTTON_PIN);
fillIO = mb.Coil(FILLBTN_COIL);
drainIO = mb.Coil(DRAINBTN_COIL);
}
// ======================================================
// PROCESS COMMAND
// ======================================================
void processCommand()
{
/*
Hanya boleh memulakan proses baru
apabila timer sudah tamat.
*/
if (timer > 0)
{
return;
}
// --------------------------------------------------
// FILL
// Fill button = ON
// Drain button = ON
// --------------------------------------------------
if ((!fillButton && drainButton) || (fillIO && drainIO))
{
startFill();
}
// --------------------------------------------------
// DRAIN
// Fill button = OFF
// Drain button = OFF
// --------------------------------------------------
else if ((fillButton && !drainButton) || (!fillIO && !drainIO))
{
startDrain();
}
}
// ======================================================
// UPDATE TIMER
// ======================================================
void updateTimer()
{
// Tiada proses berjalan
if (timer <= 0)
{
return;
}
unsigned long currentMillis = millis();
// Tunggu 1 saat
if (currentMillis - previousMillis >= TIMER_INTERVAL)
{
previousMillis = currentMillis;
// Countdown
timer--;
// Update Modbus Input Register
mb.Ireg(TIMER_IREG, timer);
// Papar pada Serial Monitor
Serial.print("Mode: ");
if (mode == MODE_FILL)
{
Serial.print("FILL");
}
else if (mode == MODE_DRAIN)
{
Serial.print("DRAIN");
}
else
{
Serial.print("NORMAL");
}
Serial.print(" | Timer: ");
Serial.println(timer);
// ------------------------------------------------
// Timer tamat
// ------------------------------------------------
if (timer == 0)
{
resetSystem();
Serial.println("Timer tamat");
Serial.println("MODE: NORMAL");
}
}
}
// ======================================================
// UPDATE LED
// ======================================================
void updateLED()
{
// Fill LED
digitalWrite(
FILL_LED_PIN,
mb.Ists(FILLLED_ISTS)
);
// Drain LED
digitalWrite(
DRAIN_LED_PIN,
mb.Ists(DRAINLED_ISTS)
);
}
// ======================================================
// SETUP
// ======================================================
void setup()
{
// --------------------------------------------------
// Serial
// --------------------------------------------------
Serial.begin(115200);
delay(100);
// --------------------------------------------------
// GPIO
// --------------------------------------------------
pinMode(
FILL_BUTTON_PIN,
INPUT_PULLUP
);
pinMode(
DRAIN_BUTTON_PIN,
INPUT_PULLUP
);
pinMode(
FILL_LED_PIN,
OUTPUT
);
pinMode(
DRAIN_LED_PIN,
OUTPUT
);
// Pastikan LED OFF
digitalWrite(
FILL_LED_PIN,
LOW
);
digitalWrite(
DRAIN_LED_PIN,
LOW
);
// --------------------------------------------------
// WiFi
// --------------------------------------------------
Serial.println();
Serial.println("==============================");
Serial.println("Connecting to WiFi...");
Serial.println("==============================");
WiFi.begin(
WIFI_SSID,
WIFI_PASSWORD
);
while (WiFi.status() != WL_CONNECTED)
{
delay(500);
Serial.print(".");
}
Serial.println();
Serial.println("WiFi connected");
Serial.print("IP Address: ");
Serial.println(
WiFi.localIP()
);
// --------------------------------------------------
// Modbus TCP Server
// --------------------------------------------------
mb.server();
setupModbus();
// --------------------------------------------------
// Initial State
// --------------------------------------------------
resetSystem();
Serial.println();
Serial.println("==============================");
Serial.println("Modbus TCP Server Started");
Serial.println("==============================");
}
// ======================================================
// LOOP
// ======================================================
void loop()
{
// --------------------------------------------------
// Process Modbus TCP
// --------------------------------------------------
mb.task();
// --------------------------------------------------
// Physical Button
// -> Modbus Coil
// --------------------------------------------------
updateButtons();
// --------------------------------------------------
// Process Fill / Drain
// --------------------------------------------------
processCommand();
// --------------------------------------------------
// Timer
// --------------------------------------------------
updateTimer();
// --------------------------------------------------
// LED
// --------------------------------------------------
updateLED();
}C++