/*
File : Digital Timer
Author : leveletech.com / wa 081214584114
Date : 2024 03 04
Description : Digital Timer
*/
//--------------------------------- Include Libraries-----------------------------------------------
#include <LiquidCrystal_I2C.h>
#include <modbus.h>
#include <modbusDevice.h>
#include <modbusRegBank.h>
#include <modbusSlave.h>
//--------------------------------- Include Libraries-----------------------------------------------
//--------------------------------- Hardware Setting------------------------------------------------
//--------------------------------- Hardware Setting------------------------------------------------
//--------------------------------- Define and Constant---------------------------------------------
const int numElements = 8;
//--------------------------------- Define and Constant---------------------------------------------
//--------------------------------- User Define Data Type-------------------------------------------
struct timer_data {
bool IN;
bool Q;
bool BP1; //button pressed
bool BP2; //button pressed
int PT; //preset time
int ET; //elapsed time
unsigned long TN;//time now
};
//--------------------------------- User Define Data Type-------------------------------------------
//----------------------------------Global Variable-------------------------------------------------
LiquidCrystal_I2C lcd(0X27, 20, 4);
// Assign push button pins
const int buttonPins[] = {2, 3, 4, 5, 6, 7, 8}; // Array of pins for buttons
const int numButtons = 7; // Number of buttons
bool lastButtonState[numButtons] = {false, false, false, false, false, false, false};
// Assign relay pins
const int relayPins[] = {48, 49, 50, 51, 52, 53, 46}; // Array of pins for relays
const int numRelays = 7; // Number of relays
bool S[8] = {false, false, false, false, false, false, false, false};
bool S_P[8] = {false, false, false, false, false, false, false, false};
bool R[8] = {false, false, false, false, false, false, false, false};
bool B[8] = {false, false, false, false, false, false, false, false};
bool BM[8] = { false, false, false, false, false, false, false, false };
bool S_PD[8] = { false, false, false, false, false, false, false, false };
bool R_PD[8] = { false, false, false, false, false, false, false, false };
int PT_PD[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
int ET_PD[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
unsigned long lastDebounceTime[numButtons]; // Array to store the last debounce time for each button
const unsigned long debounceDelay = 50; // Debounce delay in milliseconds
timer_data T[8]; //TON
char data = 0;
//modsbus
modbusDevice regBank;
modbusSlave slave;
//----------------------------------Global Variable-------------------------------------------------
//----------------------------------User Defined Function Stage 1-----------------------------------
void TON(timer_data & Var) { //Timer On delay function
if (Var.IN)
{
if (!Var.BP1)
{
Var.TN = millis();
Var.BP1 = true;
}
if (!Var.Q)
{
Var.ET = (millis() - Var.TN) / 1000;
if (Var.ET >= Var.PT) Var.Q = true;
}
} else
{
Var.Q = false;
Var.BP1 = false;
Var.ET = 0;
}
}
void DI_Update() {
for (int i = 0; i < numButtons; i++) {
// Read the current state of the button
int currentState = digitalRead(buttonPins[i]);
// Check if the button state has changed and debounce it
if (currentState != lastButtonState[i]) {
// Reset the debounce timer
lastDebounceTime[i] = millis();
}
// Check if enough time has passed to consider it a valid state change
if ((millis() - lastDebounceTime[i]) > debounceDelay) {
// If enough time has passed, update the state
S[i + 1] = !currentState;
}
// Store the current state for the next iteration
lastButtonState[i] = currentState;
}
}
void DO_Update() {
for (int i = 1; i < numRelays + 1; i++) {
digitalWrite(relayPins[i - 1], !R[i]);
}
}
void Timer_Update() {
for (int i = 1; i < numRelays + 1; i++) {
if (S[i] || B[i]|| 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();
}
}
}
String R_Status(bool status) {
if (status) {
return "ON ";
} else {
return "OFF";
}
}
void LCD_Update() {
lcd.setCursor (3, 0);
lcd.print ("DIGITAL TIMER");
lcd.setCursor (0, 1);
lcd.print ("R1:" + R_Status(R[1]) + " " + "R4:" + R_Status(R[4]) + " " + "R7:" + R_Status(R[7]));
lcd.setCursor (0, 2);
lcd.print ("R2:" + R_Status(R[2]) + " " + "R5:" + R_Status(R[5]));
lcd.setCursor (0, 3);
lcd.print ("R3:" + R_Status(R[3]) + " " + "R6:" + R_Status(R[6]));
}
void CheckDataChanges() {
for (int i = 0; i < 8; 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];
//Serial.println("update2");
break;
}
if (T[i].PT != PT_PD[i]) {
SendDatatoESP32();
PT_PD[i] = T[i].PT;
//Serial.println("update3");
break;
}
if (T[i].ET != ET_PD[i]) {
SendDatatoESP32();
ET_PD[i] = T[i].ET;
//Serial.println("update4");
break;
}
}
}
void ReceiveDataformESP32() {
// berikut code untuk membaca data dari perangkat lain
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; // Exit the loop once the condition is met
}
// Check if input starts with "t1-"
if (input.startsWith(String("t") + String(i) + "-")) {
String valueStr = input.substring(3); // Extract numeric part after "t1-"
bool isNumeric = true;
// Check if all characters after "t1-" are numeric
for (size_t i = 0; i < valueStr.length(); i++) {
if (!isDigit(valueStr.charAt(i))) {
isNumeric = false;
break;
}
}
if (isNumeric) {
int value = valueStr.toInt(); // Convert the numeric part to an integer
// Do something with the value if needed
T[i].PT = value;
Serial.println(T[i].PT);
}
}
}
}
}
void Modbus_Update() {
for (int i = 1; i < numRelays + 1; i++) {
int DOx = regBank.get(i);
if (DOx <= 0) BM[i] = false;
if (DOx >= 1) BM[i] = true;
int myInt = R[i] ? 1 : 0;
regBank.set(10000 + i, myInt);
regBank.set(30000 + i, (T[i].PT) - T[i].ET);
word AOx = regBank.get(40000 + i);
T[i].PT = AOx;
//if (AOx != T[i].PT) {
// T[i].PT = AOx;
//regBank.set(40000 + i, T[i].PT);
// }
slave.run();
delay(10);
}
}
//----------------------------------User Defined Function Stage 1-----------------------------------
//----------------------------------User Defined Function Stage 2-----------------------------------
void SendDatatoESP32() {
// Declare a buffer to hold the packed data
char buffer[51]; // 8 booleans + 16 ints * 2 bytes + 7 spaces
// Pack boolean arrays S and R into the buffer
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] = ' ';
// Pack integer arrays PT and ET into the buffer
for (int i = 0; i < 8; i++) {
int j = (i * 3) + 3;
int k = (i * 3) + 27;
buffer[j] = ' '; // Most significant byte
buffer[j + 1] = (byte)(T[i].PT >> 8); // Most significant byte
buffer[j + 2] = (byte)T[i].PT; // Least significant byte
buffer[k] = ' '; // Most significant byte
buffer[k + 1] = (byte)(T[i].ET >> 8); // Most significant byte
buffer[k + 2] = (byte)T[i].ET; // Least significant byte
}
// Send the packed data
for (int i = 0; i < sizeof(buffer); i++) {
if (buffer[i] == ' ') {
//Serial.print((char)buffer[i]);
Serial2.print((char)buffer[i]);
} else {
Serial2.print(buffer[i]);
}
}
Serial.println(); // Move to the next line after printing the buffer
}
//----------------------------------User Defined Function Stage 2-----------------------------------
//----------------------------------User Defined Function Stage 3-----------------------------------
//----------------------------------User Defined Function Stage 3-----------------------------------
//----------------------------------Testing Function------------------------------------------------
//----------------------------------Testing Function------------------------------------------------
//--------------------------------- Setup----------------------------------------------
void setup() {
Serial.begin(9600);
Serial2.begin(9600);
//Pin Initialization
// Initialize push button pins as inputs
for (int i = 0; i < numButtons; i++) {
pinMode(buttonPins[i], INPUT_PULLUP); // Using internal pull-up resistors
}
// Initialize relay pins as outputs
for (int i = 0; i < numRelays; i++) {
pinMode(relayPins[i], OUTPUT);
digitalWrite(relayPins[i], LOW); // Turn off all relays initially
}
//Start Services
lcd.init ();
lcd.backlight ();
//Timer Initialization (dalam detik)
T[0].PT = 1; // update to ESP32
T[1].PT = 5; //
T[2].PT = 5; //
T[3].PT = 5; //
T[4].PT = 5; //
T[5].PT = 5; //
T[6].PT = 5; //
T[7].PT = 5; //
LCD_Update();
for (int i = 0; i < 8; i++) {
S_PD[i] = S[i];
R_PD[i] = R[i];
PT_PD[i] = T[i].PT;
ET_PD[i] = T[i].ET;
}
Serial.println("ok");
//modsbus
regBank.setId(1);
slave._device = ®Bank;
slave.setBaud(4800);
//Add Digital Output registers 00001-00016 to the register bank
//BM1-BM7
regBank.add(1);
regBank.add(2);
regBank.add(3);
regBank.add(4);
regBank.add(5);
regBank.add(6);
regBank.add(7);
//Add Digital Input registers 10001-10008 to the register bank
//R1-R7
regBank.add(10001);
regBank.add(10002);
regBank.add(10003);
regBank.add(10004);
regBank.add(10005);
regBank.add(10006);
regBank.add(10007);
//Add Analog Input registers 30001-30008 to the register bank
regBank.add(30001);
regBank.add(30002);
regBank.add(30003);
regBank.add(30004);
regBank.add(30005);
regBank.add(30006);
regBank.add(30007);
//Add Analog Output registers 40001-40020 to the register bank
//T[1].PT - T[7].PT
regBank.add(40001);
regBank.add(40002);
regBank.add(40003);
regBank.add(40004);
regBank.add(40005);
regBank.add(40006);
regBank.add(40007);
for (int i = 1; i < numRelays + 1; i++) {
regBank.set(40000 + i, T[i].PT);
}
}
//--------------------------------- Setup----------------------------------------------
//--------------------------------- Loop-----------------------------------------------
void loop() {
//Update Input
DI_Update();
//Process Update
Timer_Update();
ReceiveDataformESP32();
CheckDataChanges();
Modbus_Update();
//Update Output
DO_Update();
}
//--------------------------------- Loop-----------------------------------------------
//--------------------------------- Note-----------------------------------------------
/*
*/
//--------------------------------- Note-----------------------------------------------