#include <Wire.h>
#include <LiquidCrystal_I2C.h>
// Define the LCD I2C address and dimensions
#define I2C_ADDR 0x27
LiquidCrystal_I2C lcd(I2C_ADDR, 20, 4);
// Define pin numbers
#define ENCODER_BUTTON_PIN 14 // Adjust according to your wiring
#define PinForClk 12 // Adjust according to your wiring
#define PinForData 13 // Adjust according to your wiring
#define ALARM_LED_PIN 4 // LED pin
#define COUNT_INPUT_PIN 16 // Adjust according to your wiring
int lastEncoderClkState;
char number[7] = "000000";
int currentDigit = 0;
unsigned long lastFlashTime = 0;
bool isFirstCharVisible = true;
bool countingUp = true;
bool lastCountInputState = LOW;
enum Mode { SET_DIGIT, CHOOSE_TYPE, COUNTING };
Mode mode = SET_DIGIT;
unsigned long previousMillis = 0;
int countsInInterval = 0;
const unsigned long interval = 60000; // 60,000 ms for 1 minute
int calculatedPcsPerMin = 0;
int lastDisplayedPcsPerMin = -1; // Initial previous value as -1 to ensure first display
// New variable for button press timing
unsigned long buttonPressStartTime = 0;
bool isButtonPressed = false;
// Variable to store the counter value
int counter = 0;
// Variable to store the alarm state
bool alarmFlag = false;
// Variable to track encoder pulses
int encoderPulseCount = 0;
void setup() {
Serial.begin(115200);
lcd.init();
lcd.backlight();
pinMode(ENCODER_BUTTON_PIN, INPUT_PULLUP);
pinMode(PinForClk, INPUT_PULLUP);
pinMode(PinForData, INPUT_PULLUP);
pinMode(ALARM_LED_PIN, OUTPUT);
pinMode(COUNT_INPUT_PIN, INPUT_PULLUP);
lastEncoderClkState = digitalRead(PinForClk);
displayDefaultScreen();
}
void loop() {
handleLongPress(); // Check for a long press to reset
switch (mode) {
case SET_DIGIT:
handleEncoderRotation();
handleEncoderButtonPress();
handleFlashingEffect();
break;
case CHOOSE_TYPE:
chooseCounterType();
break;
case COUNTING:
handleCounting();
calculateLineSpeed();
break;
}
}
// Function to refresh the LCD display
void refreshLCD() {
lcd.setCursor(0, 1);
lcd.print(number);
}
void displayDefaultScreen() {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Set Counter:");
refreshLCD();
}
void handleEncoderRotation() {
int encoderClkState = digitalRead(PinForClk);
if (encoderClkState != lastEncoderClkState) {
if (digitalRead(PinForData) != encoderClkState) {
encoderPulseCount++;
} else {
encoderPulseCount--;
}
lastEncoderClkState = encoderClkState;
}
if (abs(encoderPulseCount) >= 2) {
changeDigit(encoderPulseCount > 0 ? 1 : -1);
refreshLCD();
encoderPulseCount = 0; // Reset pulse count after every 2nd pulse
}
}
void changeDigit(int change) {
int digitValue = number[currentDigit] - '0';
digitValue = (digitValue + change + 10) % 10;
number[currentDigit] = digitValue + '0';
}
void handleEncoderButtonPress() {
static bool lastButtonState = HIGH;
bool buttonState = digitalRead(ENCODER_BUTTON_PIN);
if (lastButtonState != buttonState && buttonState == LOW) {
delay(50); // Debounce delay
if (digitalRead(ENCODER_BUTTON_PIN) == LOW) {
if (currentDigit < 5) {
currentDigit++;
} else {
if (strcmp(number, "000000") != 0) {
delay(700); // Add 0.7 seconds delay before changing mode
mode = CHOOSE_TYPE;
displayTypeScreen();
} else {
// Show error message if no digits are set
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Set all digits!");
delay(1000);
displayDefaultScreen();
}
}
}
}
lastButtonState = buttonState;
}
void handleFlashingEffect() {
if (millis() - lastFlashTime > 500) {
lastFlashTime = millis();
lcd.setCursor(currentDigit, 1);
if (isFirstCharVisible) {
lcd.print(" ");
} else {
lcd.print(number[currentDigit]);
}
isFirstCharVisible = !isFirstCharVisible;
for (int i = 0; i < 6; i++) {
if (i != currentDigit) {
lcd.setCursor(i, 1);
lcd.print(number[i]);
}
}
}
}
void displayTypeScreen() {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Counter mode:");
lcd.setCursor(0, 1);
lcd.print(" UP DOWN");
lastFlashTime = millis();
}
void chooseCounterType() {
int encoderClkState = digitalRead(PinForClk);
if (encoderClkState != lastEncoderClkState && encoderClkState == HIGH) {
int encoderDtState = digitalRead(PinForData);
countingUp = encoderDtState == encoderClkState;
lastFlashTime = millis();
}
handleFlashingType();
bool buttonState = digitalRead(ENCODER_BUTTON_PIN);
if (buttonState == LOW) {
delay(50); // Debounce delay
if (digitalRead(ENCODER_BUTTON_PIN) == LOW) {
mode = COUNTING;
if (!countingUp) {
counter = atoi(number); // Initialize counter from preset value if counting down
}
displayCountingScreen();
}
}
lastEncoderClkState = encoderClkState;
}
void handleFlashingType() {
const unsigned long flashInterval = 500;
if (millis() - lastFlashTime > flashInterval) {
lastFlashTime = millis();
lcd.setCursor(2, 1);
if (countingUp) {
if (isFirstCharVisible) {
lcd.print("UP ");
} else {
lcd.print(" ");
}
} else {
lcd.print("UP");
}
lcd.setCursor(8, 1);
if (!countingUp) {
if (isFirstCharVisible) {
lcd.print("DOWN ");
} else {
lcd.print(" ");
}
} else {
lcd.print("DOWN");
}
isFirstCharVisible = !isFirstCharVisible;
}
}
void displayCountingScreen() {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Counting: ");
lcd.print(countingUp ? "UP" : "DOWN");
delay(3000);
displayCountedScreen();
}
void displayCountedScreen() {
lcd.clear();
if (countingUp) {
lcd.setCursor(0, 0);
lcd.print("Counted:");
lcd.setCursor(0, 1);
lcd.print("0");
} else {
lcd.setCursor(0, 0);
lcd.print("Counting down:");
lcd.setCursor(0, 1);
lcd.print(atoi(number)); // Print the preset number without leading zeros
}
lcd.setCursor(0, 2);
lcd.print("Line speed");
}
void handleCounting() {
bool countInputState = digitalRead(COUNT_INPUT_PIN);
if (countInputState != lastCountInputState) {
delay(50); // Debounce delay
if (digitalRead(COUNT_INPUT_PIN) == countInputState) {
if (countInputState == LOW) {
if (countingUp) {
counter++;
countsInInterval++;
if (counter >= atoi(number)) {
alarmFlag = true;
}
} else {
counter--;
countsInInterval++;
if (counter < 0) {
alarmFlag = true;
}
}
lcd.setCursor(0, 1);
lcd.print(String(counter) + " ");
}
}
}
lastCountInputState = countInputState;
if (alarmFlag) {
ledFlash();
displayAlarmMessage();
}
// Display the line speed only if it has changed
if (calculatedPcsPerMin != lastDisplayedPcsPerMin) {
lastDisplayedPcsPerMin = calculatedPcsPerMin;
lcd.setCursor(0, 3);
lcd.print(" "); // Clear previous text
lcd.setCursor(0, 3);
lcd.print(calculatedPcsPerMin);
lcd.setCursor(7, 3);
lcd.print(" pcs/min");
}
}
void calculateLineSpeed() {
unsigned long currentMillis = millis();
if (currentMillis - previousMillis >= interval) {
previousMillis = currentMillis;
calculatedPcsPerMin = countsInInterval;
countsInInterval = 0;
}
}
void ledFlash() {
static bool ledState = false;
static unsigned long lastToggleTime = 0;
const unsigned long toggleInterval = 500;
if (millis() - lastToggleTime > toggleInterval) {
lastToggleTime = millis();
ledState = !ledState;
digitalWrite(ALARM_LED_PIN, ledState);
}
}
void displayAlarmMessage() {
lcd.setCursor(10, 1);
lcd.print("Alarm!");
}
void handleLongPress() {
// Check if the button is currently pressed
if (digitalRead(ENCODER_BUTTON_PIN) == LOW) {
if (!isButtonPressed) {
// Record the time when the button was first pressed
buttonPressStartTime = millis();
isButtonPressed = true;
} else {
// Check how long the button has been pressed
if (millis() - buttonPressStartTime >= 3000 && mode != SET_DIGIT) {
// Reset to initial state after 3 seconds if not already in SET_DIGIT mode
resetToInitialState();
}
}
} else {
isButtonPressed = false;
}
}
void resetToInitialState() {
strcpy(number, "000000"); // Clear the counter values
currentDigit = 0; // Reset the current digit position
mode = SET_DIGIT; // Set the mode to SET_DIGIT
displayDefaultScreen(); // Update the display to the initial screen
// Reset the counter value to zero
counter = 0;
// Reset the alarm state
alarmFlag = false;
digitalWrite(ALARM_LED_PIN, LOW); // Turn off the alarm LED
// Update the display to show the reset counter value
displayCountedScreen();
}