// Include necessary libraries
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <Keypad.h>
// Define I2C Address and LCD dimensions
LiquidCrystal_I2C lcd(0x27, 20, 4);
const uint8_t ROWS = 4;
const uint8_t COLS = 3;
char keys[ROWS][COLS] = {
{ '1', '2', '3'},
{ '4', '5', '6'},
{ '7', '8', '9'},
{ '*', '0', '#' }
};
uint8_t colPins[COLS] = { 9, 8, 7 }; // Pins connected to C1, C2, C3
uint8_t rowPins[ROWS] = { 13, 12, 11, 10 }; // Pins connected to R1, R2, R3, R4
Keypad keypad = Keypad(makeKeymap(keys), rowPins, colPins, ROWS, COLS);
volatile long frameCount = 0; // Frame count
volatile int dir = 0; // Direction
long feet35 = 0; // Feet for 35MM
long feet16 = 0; // Feet for 16MM
long temp = 0; // Temporary storage for frameCount comparison
int inputNumber = 0; // Store the current number input by the user
bool isInputtingNumber = false; // Track if the user is inputting a number
// Function to update frame count based on direction
void updateIndexCount() {
if (dir == 0) {
frameCount++;
} else {
frameCount--;
}
feet35 = frameCount / 4; // 35MM calculation
feet16 = frameCount / 8; // 16MM calculation
}
// Function to detect the direction of the encoder
void updateIndexCountD() {
if (digitalRead(2) == digitalRead(4)) {
dir = 1; // Reverse direction
} else {
dir = 0; // Forward direction
}
}
void setup() {
lcd.init();
lcd.backlight();
Serial.begin(9600);
// Pin setups to encoder
pinMode(3, INPUT);
pinMode(2, INPUT_PULLUP);
pinMode(4, INPUT_PULLUP);
pinMode(6, INPUT);
// Attach interrupts
attachInterrupt(digitalPinToInterrupt(3), updateIndexCount, RISING);
attachInterrupt(digitalPinToInterrupt(2), updateIndexCountD, CHANGE);
// Initial display setup
lcd.setCursor(0, 1);
lcd.print("FRAMES");
lcd.setCursor(0, 2);
lcd.print("--------------------");
lcd.setCursor(0, 3);
lcd.print("FEET");
updateFilmTypeDisplay();
}
// Function to update the film type display
void updateFilmTypeDisplay() {
lcd.setCursor(8, 0);
if (digitalRead(6) == 0) {
lcd.print("35MM");
} else {
lcd.print("16MM");
}
}
// Function to display feet count and clear any extra characters
void displayFeetCount(long feet, int column) {
lcd.setCursor(column - 5, 3); // Clear the 6-digit space for feet
lcd.print(" "); // Ensure the space is cleared
// Display logic for feet count
lcd.setCursor(column - String(feet).length(), 3);
lcd.print(feet);
}
// Function to display frame count and clear any extra characters
void displayFrameCount(long frames, int column) {
lcd.setCursor(column - 5, 1); // Clear the 6-digit space for frames
lcd.print(" "); // Ensure the space is cleared
// Display logic for frame count
lcd.setCursor(column - String(frames).length(), 1);
lcd.print(frames);
}
void loop() {
// Read the key from the keypad
char key = keypad.getKey();
// Only update when frameCount changes
if (frameCount != temp) {
lcd.setCursor(19, 1);
displayFrameCount(frameCount, 19);
// Update feet count based on film type
updateFilmTypeDisplay();
if (digitalRead(6) == 0) { // 35MM film
displayFeetCount(feet35, 19);
} else { // 16MM film
displayFeetCount(feet16, 19);
}
temp = frameCount;
}
// If a key is pressed
if (key != NO_KEY) {
if (key >= '0' && key <= '9') {
// If the user is inputting a number, keep adding digits
if (isInputtingNumber) {
inputNumber = (inputNumber * 10) + (key - '0'); // Shift digits and add new key
} else {
inputNumber = key - '0'; // Start a new number
isInputtingNumber = true;
}
Serial.print("Key pressed: ");
Serial.println(key);
Serial.print("Current input number: ");
Serial.println(inputNumber);
} else if (key == '#') {
// Confirm the number and set it as frameCount
frameCount = inputNumber;
lcd.setCursor(19, 1);
displayFrameCount(frameCount, 19);
Serial.print("Frame count set to: ");
Serial.println(frameCount);
// Calculate and display feet count immediately
feet35 = frameCount / 4; // 35MM calculation
feet16 = frameCount / 8; // 16MM calculation
if (digitalRead(6) == 0) { // 35MM film
displayFeetCount(feet35, 19);
} else { // 16MM film
displayFeetCount(feet16, 19);
}
// Reset input tracking
inputNumber = 0;
isInputtingNumber = false;
} else if (key == '*') {
// Cancel the current input
inputNumber = 0;
isInputtingNumber = false;
Serial.println("Input canceled.");
}
}
}