Trying to use a Rotary Encoder and LCD I2C to create a dial combination lock

I am trying to use a rotary encoder to display a password on my LCD. I have gotten the lcd to read the encoder when it is turning to raise or lower the number. I also use a long press on the encoder to delete the inputted password. The trouble that I am running into is using a single click. I want it when a click occurs, the previously inputted number is saved and then the next character on the Arduino is activated to input a second, third, fourth number. I'm also having trouble actually making it so the password means anything to the Arduino. I'll post the code below.

Thanks.

#include <Arduino.h>
#include <Wire.h>
#include <OneButton.h>
#include <LiquidCrystal_I2C.h>

// Define the IO Pins Used
#define CLK    2   // Used for generating interrupts using CLK signal
#define DT    3   // Used for reading DT signal
#define SW     4   // Used for the Rotary push button switch
#define V     5   // Set to HIGH to be the 5V pin for the Rotary Encoder
#define GND    6   // Set to LOW to be the GND pin for the Rotary Encoder

// OneButton class handles Debounce and detects button press
OneButton btnRot(SW, HIGH);      // Rotary Select button

LiquidCrystal_I2C lcd(0x27, 16, 2);

// Used for the Rotary Encoder interrupt routines PinA() and PinB()
volatile int rotaryCount = 0; 

// Disables the Rotary Encoder interrupts while the LCD is being updated
byte rotaryDisabled;

volatile byte aFlag = 0; // lets us know when we're expecting a rising edge on pinA 
             // to signal that the encoder has arrived at a detent
volatile byte bFlag = 0; // lets us know when we're expecting a rising edge on pinB 
             // to signal that the encoder has arrived at a detent 
             // (opposite direction to when aFlag is set)
volatile byte reading = 0; //somewhere to store the direct values we read from our interrupt 
               // pins before checking to see if we have moved a whole detent
int btnState;
unsigned long lastButtonPress = 0;

//Array Setup
byte count = 0;
int correctcode[] = {2,3,4,5};
int code[4]

// PinA() - Called by the Interrupt pin when the Rotary Encoder Turned
void PinA() {

  if (rotaryDisabled) return;

  cli(); //stop interrupts happening before we read pin values
       // read all eight pin values then strip away all but pinA and pinB's values
  reading = PIND & 0xC;

  //check that both pins at detent (HIGH) and that we are expecting detent on this pin's rising edge
  if (reading == B00001100 && aFlag) {
    rotaryRight();
    bFlag = 0; //reset flags for the next turn
    aFlag = 0; //reset flags for the next turn
  }
  //signal that we're expecting pinB to signal the transition to detent from free rotation
  else if (reading == B00000100) bFlag = 1;
  sei(); //restart interrupts
}


// PinB() - Called by the Interrupt pin when the Rotary Encoder Turned
void PinB() {

  if (rotaryDisabled) return;

  cli(); //stop interrupts happening before we read pin values
       //read all eight pin values then strip away all but pinA and pinB's values
  reading = PIND & 0xC;
  //check that both pins at detent (HIGH) and that we are expecting detent on this pin's rising edge 
  if (reading == B00001100 && bFlag) {
    rotaryLeft();
    bFlag = 0; //reset flags for the next turn
    aFlag = 0; //reset flags for the next turn
  }
  //signal that we're expecting pinA to signal the transition to detent from free rotation
  else if (reading == B00001000) aFlag = 1;
  sei(); //restart interrupts
}


// rotaryRight() - Rotary Encoder is turned 1 detent to the Right (clockwise)

void rotaryRight()
{
  rotaryCount++;
}

// rotaryLeft() - Rotary Encoder is turned 1 detent to the Left (counter-clockwise)

void rotaryLeft()
{
  rotaryCount--;
}


// rotaryClick() - Rotary Encoder Select Switch is pressed
void rotaryClick()
{ 
  
      
}


// rotaryLongPress() - Rotary Encoder Select Switch is Held Down (Long Press)
void rotaryLongPress()
{
  rotaryCount = 0;
}

// initializeRotaryEncoder() - Initialize the pins and interrupt functions for the Rotary Encdoer
                      
void initializeRotaryEncoder()
{
  // Set the Directions of the I/O Pins
  pinMode(CLK, INPUT_PULLUP);
  pinMode(DT, INPUT_PULLUP);
  pinMode(SW, INPUT_PULLUP);
  pinMode(GND, OUTPUT);
  pinMode(V, OUTPUT);

  // Set the 5V and GND pins for the Rotary Encoder
  digitalWrite(GND, LOW);
  digitalWrite(V, HIGH);
  digitalWrite(SW, HIGH);

  // set an interrupt on PinA and PinB, looking for a rising edge signal and 
  // executing the "PinA" and "PinB" Interrupt Service Routines
  attachInterrupt(0, PinA, RISING);
  attachInterrupt(1, PinB, RISING);

  // Define the functions for Rotary Encoder Click and Long Press
  btnRot.attachClick(&rotaryClick);
  btnRot.attachLongPressStart(&rotaryLongPress);
  btnRot.setPressTicks(2000);

  rotaryDisabled = 0;

  Serial.begin(9600);
}

// initializeLcd() - Initialize the LCD
void initializeLcd()
{
  lcd.init();
  lcd.backlight();
  lcd.clear();
  lcd.setCursor(0, 0);
  
}


// updateLcd() - Update the LCD with current Rotary Encoder detent count
void updateLcd()
{
  rotaryDisabled = 1;
  lcd.setCursor(0, 0);
  lcd.print(F("Password = "));
  lcd.print(rotaryCount);
  lcd.print(F("       "));
  Serial.print(rotaryCount);
  rotaryDisabled = 0;
}


// setup() - Initialization Function
void setup()
{
  initializeRotaryEncoder();
  initializeLcd();
}


// loop() - Main Program Loop Function
void loop()
{
  updateLcd();
  btnRot.tick();
  delay(50);
}

I was also wondering if it would be easier to do this kind of a lock with a 7 segment display and not a LCD.

The 7 seg vs LCD should really not affect the basis of your lock program. I would go with an LCD, easier to use since you already have it and have the library.

I think what you are trying to achieve is to store e.g a4 digit password.
Some pseudo-code:

  • display the chars on your LCD
  • read in one char at a time
  • create a char array to store the password
  • read the input chat and store it in the array

To unlock:

  • read the input chars into an array
  • then compare one char at at time with the stored array

You don't need to stop and start interrupts, within an interrupt function. They are off by default, and restarted automatically upon function exit.

Your program will run a lot smoother and more efficiently if you update the LCD only when something in the display needs to be changed, rather than every pass through loop.

Other than that, if you describe your problems more clearly, forum members may be able to help.

I am trying to get it so whenever I push down on the encoder, it switches to the next character on the LCD. I have been able to do it so it switches once but it wont again. I have looked up how to make it incremental so every time I press, it goes to the next one. For example, it starts on (0,0) and when I press, it moves to (1,0) and then the next would be to (2,0) but meanwhile, storing the previous numbers. I have tried to define a variable to be incremental by one for the lcd.setCursor function but I haven't had success.

I will try that. Thank you for the input!

Sorry, I don't understand your explanation of the problem, and can't see from the code how the program is supposed to work.

I suggest to go back to the examples in the button library and learn how to use it properly. Learn how to distinguish and take separate actions on a short press and long press. Then you will be better prepared to write the final project code.

I've been able to distinguish separate actions for short press and long press. A previous version of the code had it set so every click would add 100 to the number that was already being read. There is nothing there right now though. Is there a way that I can increase the x value in the coordinates for the cursor on the LCD display by one time each time a short click occurs. I have been able to set the cursor once with a click, however after one click, it wouldn't move anymore.

Use setCursor() to set the cursor coordinates.

If you want help with a specific bit of code, post that code, using code tags.

int INC=++;
void rotaryClick() {
lcd.setCursor( INC, 0 );
}

Would this make sense or is there another way to increase the x coordinate consistently per click that I am unaware off

volatile int INC; // where you declare the variables; suggest giving it a longer, more descriptive name

void rotaryClick()
{ 
  INC ++;  // you want this variable to increment every time Click is called
  lcd.setCursor( INC, 0 );
      
}

I would use the 5V pin of the Uno directly to attach to the 5V pin of the encoder. No need to use a digital pin, and they also have limits on current output.

Not to me, but maybe to you.

This worked! Thank you so much.

hey BoogieFL do you have any Circuit diagram ?

do you have a circuit diagram