#include <Wire.h>
#include <LiquidCrystal_I2C.h>
// Define the LCD I2C address and dimensions
#define I2C_ADDR 0x27
LiquidCrystal_I2C lcd(I2C_ADDR, 16, 4);
// Define pin numbers
#define ENCODER_BUTTON_PIN 14 // Adjust according to your wiring
#define PinForClk 0 // Adjust according to your wiring
#define PinForData 2 // 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;
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;
}
}
void displayDefaultScreen() {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Set Counter:");
lcd.setCursor(0, 1);
lcd.print(number);
}
void handleEncoderRotation() {
int encoderClkState = digitalRead(PinForClk);
if (encoderClkState != lastEncoderClkState && encoderClkState == HIGH) {
int encoderDtState = digitalRead(PinForData);
changeDigit(encoderDtState == encoderClkState ? -1 : 1);
displayDefaultScreen();
}
lastEncoderClkState = encoderClkState;
}
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);
if (digitalRead(ENCODER_BUTTON_PIN) == LOW) {
if (currentDigit < 5) {
currentDigit++;
} else {
if (strcmp(number, "000000") != 0) {
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);
if (digitalRead(ENCODER_BUTTON_PIN) == LOW) {
mode = COUNTING;
displayCountingScreen();
}
}
lastEncoderClkState = encoderClkState;
}
void handleFlashingType() {
const unsigned long flashInterval = 500;
if (millis() - lastFlashTime > flashInterval) {
lastFlashTime = millis();
lcd.setCursor(countingUp ? 2 : 8, 1);
if (isFirstCharVisible) {
lcd.print(countingUp ? "UP" : "DOWN");
} else {
lcd.print(" ");
}
isFirstCharVisible = !isFirstCharVisible;
}
}
void displayCountingScreen() {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Counting: ");
lcd.print(countingUp ? "UP" : "DOWN");
delay(1500); // Display for 1.5 seconds
displayCountedScreen();
}
void displayCountedScreen() {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Counted:");
lcd.setCursor(0, 1);
lcd.print(countingUp ? "0" : number);
lcd.setCursor(0, 2);
lcd.print("Line speed:");
lcd.setCursor(0, 3);
lcd.print("0 pcs/min");
}
void handleCounting() {
static int counter = countingUp ? 0 : atoi(number);
static bool alarm = false;
bool countInputState = digitalRead(COUNT_INPUT_PIN);
if (countInputState != lastCountInputState) {
delay(50);
if (digitalRead(COUNT_INPUT_PIN) == countInputState) {
if (countInputState == LOW) {
if (countingUp) {
counter++;
countsInInterval++;
if (counter >= atoi(number)) {
alarm = true;
}
} else {
counter--;
if (counter <= 0) {
alarm = true;
}
}
lcd.setCursor(0, 1);
lcd.print(String(counter) + " ");
}
}
}
lastCountInputState = countInputState;
if (alarm) {
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");
currentDigit = 0;
mode = SET_DIGIT;
displayDefaultScreen();
}