#include "LiquidCrystal_I2C.h"
LiquidCrystal_I2C lcd = LiquidCrystal_I2C(0x27, 16, 2);
#define BUTTON_ENTER 2
#define BUTTON_UP 3
#define BUTTON_DOWN 4
#define BUTTON_SETTING 5
#define BUTTON_BACK 6
#define DISPLAY_ROWS 2
#define PER_SPACE 1
// unsigned long lastDebounceTime = 0;
// unsigned long debounceDelay = 50;
// unsigned long checkButtonTaskTimer = 0;
// const unsigned long checkButtonTaskInterval = 300;
// unsigned long updateLCDTaskTimer = 0;
// const unsigned long updateLCDTaskInterval = 400;
// unsigned char selected = 1;
// unsigned char prev_key;
// bool isKeyDisabled = false;
// char buttonPressed = '0';
// char lastButtonState = '0';
// bool isBlinking = false;
// unsigned long lastBlinkTime = 0;
// int digitPlaces = 4; //number of digits that you want to enter
// int currentPosition = 0;
// bool isSetLengthMode = false;
// bool isSetBredthMode = false;
// bool isSetDiameterMode = false;
// bool isMenuMode = false;
// bool isRectangleSelected = true; // Flag to track the selected shape
// int lengthInput[4] = {0}; // Array to store user input
// int bredthInput[4] = {0};
// int diameterInput[4] = {0};
// float length = 0.0;
// float bredth = 0.0;
// float diameter = 0.0;
// float pressure = 0.0;
// float force = 0.0;
// float area_rectangle = 0.0;
// float area_circle = 0.0;
// float area = 0.0;
unsigned long lastDebounceTime = 0;
unsigned long debounceDelay = 40;
unsigned long checkButtonTaskTimer = 0;
const unsigned long checkButtonTaskInterval = 300;
unsigned long updateLCDTaskTimer = 0;
const unsigned long updateLCDTaskInterval = 400;
unsigned char selected = 1;
unsigned char prev_key;
bool isKeyDisabled = false;
char buttonPressed = '0';
char lastButtonState = '0';
bool isBlinking = false;
unsigned long lastBlinkTime = 0;
int digitPlaces = 4; // number of digits that you want to enter
int currentPosition = 0;
int hh = 0, mm = 0, ss = 0;
int currentDigit =
0; // Current digit being edited (0 for day, 1 for month, 2 for year)
int dateInput[3]; // Array to store user input for day, month, and year
int timeInput[6]; // Array to store user input for hours tens, hours ones,
// minutes tens, minutes ones, seconds tens, and seconds ones
bool isSetLengthMode = false;
bool isSetBredthMode = false;
bool isSetDiameterMode = false;
bool isMenuMode = false;
bool isDateMode = false;
bool isSetDateMode = false;
bool isTimeMode = false;
bool isSetTimeMode = false; // Flag to indicate if in set time mode
bool invalidDate = false;
bool isRectangleSelected = true; // Flag to track the selected shape
int lengthInput[4] = {0}; // Array to store user input
int bredthInput[4] = {0};
int diameterInput[4] = {0};
float length = 0.0;
float bredth = 0.0;
float diameter = 0.0;
float pressure = 0.0;
float force = 0.0;
float area_rectangle = 0.0;
float area_circle = 0.0;
float area = 0.0;
const float minVoltage = 800; // mV
const float maxVoltage = 4000; // mV
const float minPressure = 0; // bar
const float maxPressure = 600; // bar
bool isResetPrompt = false;
bool isFactoryResetSelected = false;
typedef const struct MenuStructure
{
const char *text;
unsigned char num_menupoints;
unsigned char up;
unsigned char down;
unsigned char enter;
unsigned char back;
void (*E_fp) (void);
void (*B_fp) (void);
} MenuEntry;
void start(void);
void show_menu(void);
void checkButtons(bool isMenuMode);
void processButton(char buttonPressed);
void handleEnterButton();
void handleUpButton();
void handleDownButton();
void handleBackButton();
void handleSettingsButton();
void values();
void display_values();
void area_length();
void area_bredth();
void area_diameter();
void date();
void displayDate();
void adjustDate(int direction);
void switch_digit();
void set_date();
void time();
void displayTime();
void adjustTime(int direction);
void set_time();
void blinkDigit(int input[], int currentPosition);
void showArea(int input[], int currentPosition, bool isBlinking);
void displayArea(int input[], int digitPlaces, float &output);
// void readPressureSensor();
void calculateForce();
void goToNextDigit();
void factoryReset();
void resetPrompt();
void updateResetSelection();
void performFactoryReset();
// Define custom characters for up and down arrows
byte upArrow[] = {
0b00100, // *
0b01110, // ***
0b10101, // * * *
0b00100, // *
0b00100, // *
0b00100, // *
0b00100, // *
0b00100 // *
};
byte downArrow[] = {
0b00100, // *
0b00100, // *
0b00100, // *
0b00100, // *
0b00100, // *
0b10101, // * * *
0b01110, // ***
0b00100 // *
};
byte backArrow[] = {
0B00100, // *
0B01100, // **
0B11110, // ****
0B01101, // ** *
0B00101, // * *
0B00001, // *
0B00010, // *
0B11100 // ***
};
const char menu_000[] = " Settings: "; // 0
const char menu_001[] = " Set Area "; // 1
const char menu_002[] = " View Data "; // 2
const char menu_003[] = " Calibration "; // 3
const char menu_004[] = " Set Date "; // 4
const char menu_005[] = " Set Time "; // 5
const char menu_006[] = " Factory Reset"; // 6
const char menu_100[] = " Set Area: "; // 7
const char menu_101[] = " Rectangle "; // 8
const char menu_102[] = " Circle "; // 9
const char menu_103[] = " In mm.. "; // 10
const char menu_104[] = " Length "; // 11
const char menu_105[] = " Bredth "; // 12
const char menu_106[] = " In mm.. "; // 13
const char menu_107[] = " Diameter "; // 14
MenuEntry menu[] = {
// text, num_menupoints, up, down, enter, back, *E_fp, *B_fp
{menu_000, 7, 0, 0, 0, 0, 0, 0}, // 0 // Settings:
{menu_001, 7, 1, 2, 8, 1, 0, values}, // 1 // Set Area
{menu_002, 7, 1, 3, 2, 2, 0, values}, // 2 // View Data
{menu_003, 7, 2, 4, 3, 3, 0, values}, // 3 // Calibration
{menu_004, 7, 3, 5, 4, 4, date, values}, // 4 // Set Date
{menu_005, 7, 4, 6, 5, 5, time, values}, // 5 // Set Time
{menu_006, 7, 5, 6, 6, 6, factoryReset, values}, // 6 // Factory Reset
{menu_100, 3, 0, 0, 0, 0, 0, 0}, // 7 // Set Area:
{menu_101, 3, 8, 9, 11, 1, 0, 0}, // 8 // Rectangle
{menu_102, 3, 8, 9, 14, 1, 0, 0}, // 9 // Circle
{menu_103, 3, 0, 0, 0, 0, 0, 0}, // 10 // In mm..
{menu_104, 3, 10, 12, 11, 8, area_length, 0}, // 11 // Length
{menu_105, 3, 11, 12, 12, 8, area_bredth, 0}, // 12 // Bredth
{menu_106, 3, 0, 0, 0, 0, 0, 0}, // 13 // In mm..
{menu_107, 3, 14, 14, 14, 9, area_diameter, 0}, // 14 // Diameter
};
void setup() {
lcd.clear();
lcd.begin(16, 2);
lcd.backlight();
lcd.createChar(0, upArrow);
lcd.createChar(1, downArrow);
lcd.createChar(2, backArrow);
pinMode(BUTTON_ENTER, INPUT_PULLUP);
pinMode(BUTTON_UP, INPUT_PULLUP);
pinMode(BUTTON_DOWN, INPUT_PULLUP);
pinMode(BUTTON_SETTING, INPUT_PULLUP);
pinMode(BUTTON_BACK, INPUT_PULLUP);
Serial.begin(9600);
lcd.setCursor(0,0);
lcd.print("VEDANTRIK");
lcd.setCursor(0,1);
lcd.print("TECHNOLOGIES");
delay(2000);
lcd.clear();
}
void loop() {
if (millis() >= checkButtonTaskTimer + checkButtonTaskInterval) {
checkButtonTaskTimer += checkButtonTaskInterval;
// do the task
checkButtons(isMenuMode);
}
if (isSetLengthMode) {
blinkDigit(lengthInput, currentPosition);
}
if (isSetBredthMode){
blinkDigit(bredthInput, currentPosition);
}
if (isSetDiameterMode){
blinkDigit(diameterInput, currentPosition);
}
if (!isMenuMode && !isDateMode &&
!isTimeMode && !isResetPrompt) { // Check if neither menu mode nor date mode is active
display_values();
readPressureSensor();
calculateForce();
} else if (isDateMode) { // Check if date mode is active
displayDate(); // Display the date
} else if (isTimeMode) {
displayTime();
} else if (isResetPrompt) {
resetPrompt();
}
if (millis() >= updateLCDTaskTimer + updateLCDTaskInterval) {
updateLCDTaskTimer += updateLCDTaskInterval;
// do the task
//show_menu();
}
}
void values(){
lcd.clear();
isMenuMode = false;
display_values();
}
void display_values() {
lcd.setCursor(0,0);
lcd.print("F:");
lcd.setCursor(2,0);
lcd.print(force,2);
lcd.setCursor(9,0);
lcd.print("kN");
lcd.setCursor(0,1);
lcd.print("A:");
lcd.print(area);
lcd.setCursor(9,1);
lcd.print("P:");
lcd.print(pressure);
}
// Function to calculate the area of the rectangle
float calculateRectangleArea(float length, float bredth) {
return length * bredth;
}
// Function to calculate the area of the circle
float calculateCircleArea(float diameter) {
return 3.14 * diameter;
}
// Function to calculate force based on the selected shape
void calculateForce() {
if (isRectangleSelected && length != 0.0 && bredth != 0.0) {
// Rectangle is selected
area_rectangle = calculateRectangleArea(length, bredth);
area_circle = 0.0; // Set circle area to 0
area = area_rectangle;
force = pressure * area_rectangle;
} else if (!isRectangleSelected && diameter != 0.0) {
// Circle is selected
area_rectangle = 0.0; // Set rectangle area to 0
area_circle = calculateCircleArea(diameter);
area = area_circle;
force = pressure * area_circle;
} else {
// Handle error case where neither rectangle nor circle is selected
force = 0.0;
area = 0.0;
}
}
// Function to simulate reading pressure from a sensor (replace this with your actual sensor reading)
float readPressureSensor() {
// Replace this with your actual sensor reading logic
return 1.0; // Default value for illustration
}
// Function to switch between rectangle and circle input
void switchShape() {
isRectangleSelected = !isRectangleSelected;
// Reset length, bredth, and diameter when switching shapes
length = 0.0;
bredth = 0.0;
diameter = 0.0;
}
void date(){
}
void time(){
}
void area_length() {
currentPosition = 0;
showArea(lengthInput, currentPosition, isBlinking);
isKeyDisabled = true;
isSetLengthMode = true;
isRectangleSelected = true;
}
void area_bredth() {
currentPosition = 0;
showArea(bredthInput, currentPosition, isBlinking);
isKeyDisabled = true;
isSetBredthMode = true;
isRectangleSelected = true;
}
void area_diameter() {
currentPosition = 0;
showArea(diameterInput, currentPosition, isBlinking);
isKeyDisabled = true;
isSetDiameterMode = true;
isRectangleSelected = false;
}
void blinkDigit(int input[], int currentPosition) {
// Toggle the blinking state every 500 milliseconds
if (millis() - lastBlinkTime >= 500) {
isBlinking = !isBlinking;
lastBlinkTime = millis();
showArea(input, currentPosition, isBlinking);
}
}
void showArea(int input[], int currentPosition, bool isBlinking) {
lcd.setCursor(11, 1);
for (int i = 0; i < digitPlaces; i++) {
if (i == 2) {
lcd.print("."); // Print the decimal point
}
if (i == currentPosition && isBlinking) {
lcd.print(" "); // Blink the current digit by printing a space
} else {
lcd.print(input[i]); // Print the actual digit
}
}
}
void displayArea(int input[], int digitPlaces, float &output) {
float value = 0.0;
for (int i = 0; i < digitPlaces; i++) {
value += input[i] * pow(10, digitPlaces - i - 1);
}
output = value * pow(0.1, digitPlaces - 2); // Adjust for decimal places
lcd.setCursor(10, 1);
lcd.print(":");
lcd.print(output, 2); // Display with 2 decimal places
Serial.println(output);
for (int i = 0; i < digitPlaces; i++) {
Serial.println(input[i]);
}
}
void factoryReset(){
lcd.clear();
isFactoryResetSelected = false;
isResetPrompt = true;
isKeyDisabled = true;
isMenuMode = false;
}
void resetPrompt(){
lcd.setCursor(0, 0);
lcd.print(" Factory Reset?");
updateResetSelection();
}
void updateResetSelection(){
lcd.setCursor(0, 1);
if (isFactoryResetSelected) {
lcd.print(">Yes No");
} else {
lcd.print(" Yes >No");
}
}
void performFactoryReset(){
lcd.clear();
lcd.setCursor(0,0);
lcd.print("Resetting...");
delay(2000);
lcd.clear();
isFactoryResetSelected = false;
isResetPrompt = false;
isKeyDisabled = false;
isMenuMode = true;
}
void checkButtons(bool isMenuMode) {
int buttonEnterState = digitalRead(BUTTON_ENTER);
int buttonUpState = digitalRead(BUTTON_UP);
int buttonDownState = digitalRead(BUTTON_DOWN);
int buttonSettingState = digitalRead(BUTTON_SETTING);
int buttonBackState = digitalRead(BUTTON_BACK);
char buttonPressed = '0';
if (!isMenuMode && !isDateMode && !isTimeMode && !isResetPrompt) {
// Only the setting button is active during the initial display
if (buttonSettingState == LOW) {
buttonPressed = 'M';
}
} else {
// All buttons are active during menu mode
if (buttonEnterState == LOW) {
buttonPressed = 'E';
} else if (buttonUpState == LOW) {
buttonPressed = 'U';
} else if (buttonDownState == LOW) {
buttonPressed = 'D';
} else if (buttonSettingState == LOW) {
buttonPressed = 'M';
} else if (buttonBackState == LOW) {
buttonPressed = 'B';
}
}
processButton(buttonPressed); // Call your existing button processing function
}
void processButton(char buttonPressed) {
switch ( buttonPressed ) {
case 'E':
if (isKeyDisabled ) {
if (isSetLengthMode) {
showArea(lengthInput, currentPosition, isBlinking);
goToNextDigit();
} else if (isSetBredthMode) {
showArea(bredthInput, currentPosition, isBlinking);
goToNextDigit();
} else if (isSetDiameterMode) {
showArea(diameterInput, currentPosition, isBlinking);
goToNextDigit();
} else if (isResetPrompt) {
if (isFactoryResetSelected) {
performFactoryReset();
} else {
lcd.clear();
lcd.setCursor(0,0);
lcd.print("Cancelled");
delay(2000);
// lcd.clear();
isMenuMode = true;
isFactoryResetSelected = false;
isResetPrompt = false;
isKeyDisabled = false;
}
}
} else {
if (menu[selected].E_fp != 0)
{
menu[selected].E_fp();
}
prev_key = selected;
selected = menu[selected].enter;
show_menu();
}
break;
case 'U': // Up
if (isKeyDisabled) {
if (isSetLengthMode) {
lengthInput[currentPosition]++;
if (lengthInput[currentPosition] > 9) {
lengthInput[currentPosition] = 0;
}
showArea(lengthInput, currentPosition, isBlinking);
} else if (isSetBredthMode) {
bredthInput[currentPosition]++;
if (bredthInput[currentPosition] > 9) {
bredthInput[currentPosition] = 0;
}
showArea(bredthInput, currentPosition, isBlinking);
} else if (isSetDiameterMode) {
diameterInput[currentPosition]++;
if (diameterInput[currentPosition] > 9) {
diameterInput[currentPosition] = 0;
}
showArea(diameterInput, currentPosition, isBlinking);
} else if (isResetPrompt) {
isFactoryResetSelected = true;
updateResetSelection();
}
} else {
prev_key = selected;
selected = menu[selected].up;
show_menu();
}
break;
case 'D': // Down
if (isKeyDisabled) {
if (isSetLengthMode) {
lengthInput[currentPosition]--;
if (lengthInput[currentPosition] < 0) {
lengthInput[currentPosition] = 9;
}
showArea(lengthInput, currentPosition, isBlinking);
} else if (isSetBredthMode) {
bredthInput[currentPosition]--;
if (bredthInput[currentPosition] < 0) {
bredthInput[currentPosition] = 9;
}
showArea(bredthInput, currentPosition, isBlinking);
} else if (isSetDiameterMode) {
diameterInput[currentPosition]--;
if (diameterInput[currentPosition] < 0) {
diameterInput[currentPosition] = 9;
}
showArea(diameterInput, currentPosition, isBlinking);
} else if (isResetPrompt) {
isFactoryResetSelected = false;
updateResetSelection();
}
} else {
prev_key = selected;
selected = menu[selected].down;
show_menu();
}
break;
case 'B': // Back button
if (isKeyDisabled) {
// Perform the same action as the save button
if (isSetLengthMode) {
displayArea(lengthInput, digitPlaces, length);
isKeyDisabled = false;
isSetLengthMode = false;
} else if (isSetBredthMode) {
displayArea(bredthInput, digitPlaces, bredth);
isKeyDisabled = false;
isSetBredthMode = false;
} else if (isSetDiameterMode) {
displayArea(diameterInput, digitPlaces, diameter);
isKeyDisabled = false;
isSetDiameterMode = false;
} else if (isResetPrompt) {
lcd.clear();
lcd.setCursor(0,0);
lcd.print("Cancelled");
delay(2000);
lcd.clear();
isFactoryResetSelected = false;
isResetPrompt = false;
isKeyDisabled = false;
isMenuMode = true;
}
lcd.clear(); // Clear the LCD after displaying the value
show_menu(); // Display the menu again
} else {
// Go to the function at B_fp if defined
if (menu[selected].B_fp != 0) {
menu[selected].B_fp();
}
prev_key = selected;
selected = menu[selected].back; // Use the back button navigation
show_menu();
}
break;
case 'M': //Setting
if (isKeyDisabled) {
// Handle the case where setting is interrupted by pressing the setting button
if (isSetLengthMode) {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Length Not Set!");
// Initialize variables for scrolling
String message = "Press ";
message += (char)2; // Insert back arrow character
message += " to save input next time"; // Your message to be scrolled
int messageLength = message.length();
int displayLength = 16; // Assuming your display is 16 characters wide
int scrollDelay = 500; // Adjust as needed for scrolling speed
// Scroll the message until the end is reached
for (int i = 0; i <= messageLength - displayLength; i++) {
lcd.setCursor(0, 1);
lcd.print(message.substring(i, i + displayLength));
delay(scrollDelay);
}
delay(2000);
isSetLengthMode = false; // Reset length setting mode
isKeyDisabled = false; // Re-enable key
selected = prev_key; // Restore previous menu selection
show_menu(); // Show menu again
}
if (isSetBredthMode) {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Bredth Not Set!");
// Initialize variables for scrolling
String message = "Press ";
message += (char)2; // Insert back arrow character
message += " to save input next time"; // Your message to be scrolled
int messageLength = message.length();
int displayLength = 16; // Assuming your display is 16 characters wide
int scrollDelay = 500; // Adjust as needed for scrolling speed
// Scroll the message until the end is reached
for (int i = 0; i <= messageLength - displayLength; i++) {
lcd.setCursor(0, 1);
lcd.print(message.substring(i, i + displayLength));
delay(scrollDelay);
}
delay(2000);
isSetBredthMode = false; // Reset length setting mode
isKeyDisabled = false; // Re-enable key
selected = prev_key; // Restore previous menu selection
show_menu(); // Show menu again
}
if (isSetDiameterMode) {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Diameter Not Set!");
// Initialize variables for scrolling
String message = "Press ";
message += (char)2; // Insert back arrow character
message += " to save input next time"; // Your message to be scrolled
int messageLength = message.length();
int displayLength = 16; // Assuming your display is 16 characters wide
int scrollDelay = 500; // Adjust as needed for scrolling speed
// Scroll the message until the end is reached
for (int i = 0; i <= messageLength - displayLength; i++) {
lcd.setCursor(0, 1);
lcd.print(message.substring(i, i + displayLength));
delay(scrollDelay);
}
delay(2000);
isSetBredthMode = false; // Reset length setting mode
isKeyDisabled = false; // Re-enable key
selected = prev_key; // Restore previous menu selection
show_menu(); // Show menu again
}
if (isResetPrompt) {
lcd.clear();
lcd.setCursor(0,0);
lcd.print("Cancelled");
delay(2000);
lcd.clear();
isFactoryResetSelected = false;
isResetPrompt = false;
isKeyDisabled = false;
isMenuMode = true;
}
}
isMenuMode = true;
currentPosition = 0;
selected = 1;
show_menu();
break;
default:
break;
}
}
void goToNextDigit() {
currentPosition++;
if (currentPosition >= digitPlaces) {
currentPosition = 0;
}
}
void show_menu(void)
{
if (isMenuMode) {
unsigned char line_cnt = 0;
unsigned char from = 0;
unsigned char till = 0;
unsigned char temp = 0;
bool hasUpArrow = false;
bool hasDownArrow = false;
// lcd.clear();
while (till <= selected) {
till += menu[till].num_menupoints;
}
from = till - menu[selected].num_menupoints;
till--;
temp = from;
Serial.print("Selected: "); Serial.println(selected);
Serial.print("From: "); Serial.println(from);
Serial.print("Till: "); Serial.println(till);
Serial.print("Selected - From: "); Serial.println(selected - from);
if(((selected - from) == 1) && !(isSetLengthMode) && !(isSetBredthMode) && !(isSetDiameterMode)){ //topmost part
hasUpArrow = false;
hasDownArrow = true;
} else if((selected == till) && !(isSetLengthMode) && !(isSetBredthMode) && !(isSetDiameterMode)) { //bottommost part
hasUpArrow = true;
hasDownArrow = false;
} else if(((selected - from) > 1) && ((selected - from) < till) && !(isSetLengthMode) && !(isSetBredthMode) && !(isSetDiameterMode)) { //middle part
hasUpArrow = true;
hasDownArrow = true;
} else {
hasUpArrow = false;
hasDownArrow = false;
}
if (hasUpArrow) {
lcd.setCursor(15, 0); // Rightmost position on the first line
lcd.write(0); // Display up arrow
} else {
lcd.setCursor(15, 0);
lcd.print(" "); // Clear the position if no arrow
}
if (hasDownArrow) {
lcd.setCursor(15, 1); // Rightmost position on the second line
lcd.write(1); // Display down arrow
} else {
lcd.setCursor(15, 1);
lcd.print(" "); // Clear the position if no arrow
}
// browsing somewhere in the middle
if ((selected >= (from + PER_SPACE)) && (selected <= till)) {
from = selected - PER_SPACE;
till = from + (DISPLAY_ROWS - 1);
for (from; from <= till; from++) {
lcd.setCursor(0, line_cnt);
lcd.print(menu[from].text);
line_cnt = line_cnt + 1;
}
}
// browsing somewhere in the top or the bottom
else {
// top of the menu
if (selected < (from + PER_SPACE)) // 2 lines
{
till = from + (DISPLAY_ROWS - 1); // 2 lines
for (from; from <= till; from++) {
lcd.setCursor(0, line_cnt);
lcd.print(menu[from].text);
line_cnt = line_cnt + 1;
}
}
// bottom of the menu
if (selected == till) {
from = till - (DISPLAY_ROWS - 1); // 2 lines
for (from; from <= till; from++) {
lcd.setCursor(0, line_cnt);
lcd.print(menu[from].text);
line_cnt = line_cnt + 1;
}
}
}
lcd.setCursor(0, selected - from);
lcd.print(">");
} else {
if(!isResetPrompt){
// Display values when isMenuMode is false
display_values();
}
}
}