#include <EEPROM.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <ModbusMaster.h>
// Struktur data timer
struct timer_data {
bool IN;
bool Q;
bool BP1;
unsigned long TN;
int PT;
int ET;
};
LiquidCrystal_I2C lcd(0x27, 20, 4);
// Pin untuk tombol dan relay
const int numButtons = 25;
const int buttonPins[numButtons] = { 15, 14, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10 };
bool lastButtonState[numButtons] = { false };
const int numRelays = 25;
const int relayPins[numRelays] = { 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52 };
bool S[26] = { false };
bool S_P[26] = { false };
bool R[26] = { false };
bool B[26] = { false };
bool BM[26] = { false };
bool S_PD[26] = { false };
bool R_PD[26] = { false };
int PT_PD[26] = { 0 };
int ET_PD[26] = { 0 };
unsigned long lastDebounceTime[numButtons]; // Waktu debounce terakhir untuk setiap tombol
const unsigned long debounceDelay = 50; // Penundaan debounce dalam milidetik
timer_data T[26]; //TON
char data = 0;
// Modbus
bool coils[26];
bool discreteInputs[50];
uint16_t holdingRegisters[50];
uint16_t inputRegisters[26];
ModbusMaster modbus;
// Fungsi delay timer
void TON(timer_data& Var) {
if (Var.IN) {
if (!Var.BP1) {
Var.TN = millis();
Var.BP1 = true;
}
if (!Var.Q) {
Var.ET = (millis() - Var.TN) / 6000;
if (Var.ET >= Var.PT) Var.Q = true;
}
} else {
Var.Q = false;
Var.BP1 = false;
Var.ET = 0;
}
}
// Memperbarui status tombol
void DI_Update() {
for (int i = 0; i < numButtons; i++) {
int currentState = !digitalRead(buttonPins[i]);
if (currentState != lastButtonState[i]) {
lastDebounceTime[i] = millis();
}
if ((millis() - lastDebounceTime[i]) > debounceDelay) {
S[i + 1] = !currentState;
}
lastButtonState[i] = currentState;
}
}
// Memperbarui status relay
void DO_Update() {
for (int i = 1; i < numRelays + 1; i++) {
digitalWrite(relayPins[i - 1], R[i]);
}
}
// Memperbarui timer
void Timer_Update() {
for (int i = 1; i < numRelays + 1; i++) {
if (BM[i]) {
if (!S_P[i]) {
S_P[i] = true;
R[i] = !R[i];
LCD_Update();
}
} else {
S_P[i] = false;
}
T[i].IN = R[i];
TON(T[i]);
if (T[i].Q) {
R[i] = false;
LCD_Update();
}
}
}
// Status relay sebagai string
String R_Status(bool status) {
if (status) {
return "ON";
} else {
return "OFF";
}
}
// Memperbarui LCD
void LCD_Update() {
lcd.setCursor(3, 0);
lcd.print("CONTROL PENGENDALI");
lcd.setCursor(0, 1);
lcd.print("AUTO1:" + R_Status(R[1]) + ":" + "KM13/L1:" + R_Status(R[3]));
lcd.setCursor(0, 2);
lcd.print("AUTO2:" + R_Status(R[2]) + ":" + "KM14/L2:" + R_Status(R[4]));
lcd.setCursor(0, 3);
lcd.print("KM1/L1:" + R_Status(R[5]) + ":" + "KM1/L2:" + R_Status(R[6]));
}
// Memeriksa perubahan data
void CheckDataChanges() {
for (int i = 0; i < numRelays + 1; i++) {
if (S[i] != S_PD[i]) {
SendDatatoESP32();
S_PD[i] = S[i];
Serial.println("update1");
break;
}
if (R[i] != R_PD[i]) {
SendDatatoESP32();
R_PD[i] = R[i];
break;
}
if (T[i].PT != PT_PD[i]) {
SendDatatoESP32();
EEPROM.put((i * 2), T[i].PT);
PT_PD[i] = T[i].PT;
break;
}
if (T[i].ET != ET_PD[i]) {
SendDatatoESP32();
ET_PD[i] = T[i].ET;
break;
}
}
}
// Menerima data dari ESP32
void ReceiveDataformESP32() {
for (int i = 1; i < numRelays + 1; i++) {
B[i] = false;
}
if (Serial2.available() > 0) {
Serial.println("ok");
String input = Serial2.readStringUntil('\n');
Serial.println(input);
for (int i = 0; i < 8; i++) {
if (input == String(i)) {
B[i] = true;
break;
}
if (input.startsWith(String("t") + String(i) + "-")) {
String valueStr = input.substring(3);
bool isNumeric = true;
for (size_t j = 0; j < valueStr.length(); j++) {
if (!isDigit(valueStr.charAt(j))) {
isNumeric = false;
break;
}
}
if (isNumeric) {
T[i].PT = valueStr.toInt();
Serial.println(T[i].PT);
}
}
}
}
}
// Memperbarui Modbus
void Modbus_Update() {
for (int i = numRelays + 1; i < 40; i++) {
discreteInputs[i] = true;
}
for (int i = 0; i < numRelays; i++) {
discreteInputs[i] = R[i + 1];
inputRegisters[i] = (T[i + 1].PT - T[i + 1].ET);
modbus.poll();
BM[i + 1] = coils[i];
if (holdingRegisters[i] != T[i + 1].PT) {
T[i + 1].PT = holdingRegisters[i];
holdingRegisters[i] = T[i + 1].PT;
}
delay(10);
}
}
// Mengirim data ke ESP32
void SendDatatoESP32() {
char buffer[51];
buffer[0] = 0;
buffer[2] = 0;
for (int i = 0; i < 8; i++) {
bitWrite(buffer[0], i, S[i]);
bitWrite(buffer[2], i, R[i]);
}
buffer[1] = ' ';
for (int i = 0; i < 8; i++) {
int j = (i * 3) + 3;
int k = (i * 3) + 27;
buffer[j] = ' ';
buffer[j + 1] = (byte)(T[i].PT >> 8);
buffer[j + 2] = (byte)T[i].PT;
buffer[k] = ' ';
buffer[k + 1] = (byte)(T[i].ET >> 8);
buffer[k + 2] = (byte)T[i].ET;
}
for (int i = 0; i < 51; i++) {
Serial2.print((byte)buffer[i]);
}
Serial2.print("\n");
}
void setup() {
lcd.begin(20, 4);
lcd.backlight();
for (int i = 0; i < numButtons; i++) {
pinMode(buttonPins[i], INPUT);
}
for (int i = 0; i < numRelays; i++) {
pinMode(relayPins[i], OUTPUT);
}
Serial.begin(115200);
Serial2.begin(9600);
modbus.begin(1, Serial);
for (int i = 0; i < numRelays; i++) {
int test;
EEPROM.get((i * 2), test);
T[i + 1].PT = (test < 0) ? 200 : test;
S_PD[i] = S[i];
R_PD[i] = R[i];
PT_PD[i] = T[i + 1].PT;
ET_PD[i] = T[i + 1].ET;
}
}
void loop() {
DI_Update();
Timer_Update();
DO_Update();
CheckDataChanges();
Modbus_Update();
ReceiveDataformESP32();
}