LCD print within Interrupt Function

Hello,

What I’m trying to accomplish is that i have a door magnets, when they are not intacted the interrupt function turns on, the buzzer start beeping, and LCD should print “Enter a password”, and a person should enter a correct password to disable alarm. My problem is when I’m trying to print on LCD within interrupt function, it doesnt printing and it seems that arduino getting freeze. Any suggestions would be appreciated

#include <Keypad.h>
#include <Wire.h> 
#include <LiquidCrystal_I2C.h>

#define Password_Lenght 7 //


LiquidCrystal_I2C lcd(0x27,16,2);
 char Data[Password_Lenght]; // 6 is the number of chars it can hold + the null char = 7
 char Master[Password_Lenght] = "123456"; 
volatile byte data_count = 0, master_count = 0;
bool Pass_is_good;
char customKey;
volatile bool flag=0;

const byte ROWS = 4;
const byte COLS = 3;
char keys[ROWS][COLS] = {
  {'1','2','3'},
  {'4','5','6'},
  {'7','8','9'},
  {'*','0','#'}
};

byte rowPins[ROWS] = {
  36,38,40,42}; //connect to the row pinouts of the keypad
byte colPins[COLS] = {
  30,32,34}; //connect to the column pinouts of the keypad

Keypad customKeypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS); //initialize an instance of class NewKeypad 
#define Password_Lenght 7 // Give enough room for six chars + NULL char
const byte buzzer = 50;
const byte interruptPin = 18;
volatile byte state = LOW;
const byte ledPin=13;


void setup() {
  pinMode(ledPin, OUTPUT);
  pinMode(interruptPin, INPUT_PULLUP);
  attachInterrupt(5, blink, LOW);
  pinMode(50, OUTPUT);
  lcd.init();// initialize the lcd 
  lcd.backlight();
}

void loop() {
  digitalWrite(buzzer,LOW);
  digitalWrite(ledPin, state);
  lcd.clear();
  lcd.setCursor(0,0);
  lcd.print("Hello");

    
  }
 


void blink() {
 state = HIGH;
  digitalWrite(buzzer,state);
  lcd.clear();
  lcd.setCursor(0,0);
  lcd.print("Enter Password");*/
   customKey = customKeypad.getKey();
  if (customKey) // makes sure a key is actually pressed, equal to (customKey != NO_KEY)
  {
    Data[data_count] = customKey; // store char into data array
    lcd.setCursor(data_count,1); // move cursor to show each new char
    lcd.print(Data[data_count]); // print char at said cursor
    data_count++; // increment data array by 1 to store new char, also keep track of the number of chars entered
  }

  if(data_count == Password_Lenght-1) // if the array index is equal to the number of expected chars, compare data to master
  {
    lcd.clear();
    lcd.setCursor(0, 0);
    lcd.print("Password is ");

    if(!strcmp(Data, Master)) // equal to (strcmp(Data, Master) == 0)
      lcd.print("Good");
    else
      lcd.print("Bad");

    delay(1000);// added 1 second delay to make sure the password is completely shown on screen before it gets cleared.
    lcd.clear();
    clearData();   
  }
}

void clearData()
{
  while(data_count !=0)
  {   // This can be used for any array size, 
    Data[data_count--] = 0; //clear array for new data
  }
  return;
}

Hello,

Read this: Gammon Forum : Electronics : Microprocessors : Interrupts

I don't think that you need to use interrupts for what you are doing.

You should be checking in loop() for the change in the sensors and then call your blink function.

Also, you are writing 'Hello' hundreds of times a second in loop() - that is unnecessary, is likely to immediately write over anything else you may be printing and also results in a crappy looking LCD display.

Hello,

Let me try to explain what I’m trying to accomplish. I have a door magnets, when magnets are intacted, pin 50 reads HIGH, and main loop just prints “Hello World”, when the magnets are not intacted, pin 50 goes to LOW state and triggers the function “getPassword”, which asking to enter the correct password. What I’m trying the function “getPassword” to do is ask for a password, and if person enters the correct password, it should exit this function and continue to flow in a main loop, otherwise if person enters incorrect password it should ask him to enter a password again until he gets correct password. The whole picture of the project is look like this, if someone opens a door (magnets are not intacted) before prior authorizing, the alarm will turn on and LCD screen will ask for a password to disable it, if person enters the correct password, the alarm will turn off and exit the function and continue the normal flow in the main loop, otherwise if the person enters incorrect password, the alarm continue to be on and it will repeat asking for the password until the person gets correct password and continue normal flow in the main loop.
Thank you for any suggestion!!

#include <Keypad.h>
#include <Wire.h> 
#include <LiquidCrystal_I2C.h>

#define Password_Lenght 7 // Give enough room for six chars + NULL char

LiquidCrystal_I2C lcd(0x27,16,2);
char Data[Password_Lenght]; // 6 is the number of chars it can hold + the null char = 7
char Master[Password_Lenght] = "123456"; 
byte data_count = 0, master_count = 0;
bool Pass_is_good;
char customKey;

const byte ROWS = 4;
const byte COLS = 3;
char keys[ROWS][COLS] = {
  {'1','2','3'},
  {'4','5','6'},
  {'7','8','9'},
  {'*','0','#'}
};

byte rowPins[ROWS] = {
  36,38,40,42}; //connect to the row pinouts of the keypad
byte colPins[COLS] = {
  30,32,34}; //connect to the column pinouts of the keypad

Keypad customKeypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS); //initialize an instance of class NewKeypad 

void setup()
{
  lcd.init();// initialize the lcd 
  lcd.backlight();
  pinMode(50,INPUT);
}

void loop()
{
    lcd.init();
    lcd.clear();
    lcd.backlight();
    lcd.print("Hello World");
    if(digitalRead(50)==LOW){
      getPassword();
      }
}

void getPassword()
{
  
  lcd.setCursor(0,0);
  lcd.print("Enter Password");

  customKey = customKeypad.getKey();
  if (customKey) // makes sure a key is actually pressed, equal to (customKey != NO_KEY)
  {
    Data[data_count] = customKey; // store char into data array
    lcd.setCursor(data_count,1); // move cursor to show each new char
    lcd.print(Data[data_count]); // print char at said cursor
    data_count++; // increment data array by 1 to store new char, also keep track of the number of chars entered
  }

  if(data_count == Password_Lenght-1) // if the array index is equal to the number of expected chars, compare data to master
  {
    lcd.clear();
    lcd.setCursor(0, 0);
    lcd.print("Password is ");

    if(!strcmp(Data, Master)) // equal to (strcmp(Data, Master) == 0)
      lcd.print("Good");
    else
      lcd.print("Bad");

    delay(1000);// added 1 second delay to make sure the password is completely shown on screen before it gets cleared.
    lcd.clear();
    clearData();   
  }
   return; }

void clearData()
{
  while(data_count !=0)
  {   // This can be used for any array size, 
    Data[data_count--] = 0; //clear array for new data
  }
  return;
}
void loop()
{
    lcd.init();

It is NOT necessary to init() the lcd on every pass through loop().

You don't seem to understand that loop() loops. If the pin is low, the getPassword() function is called. It does NOT get the password. It looks to see if a key is pressed. If not, it does nothing, and returns, causing loop() to iterate again.

As long as the switch is swill low, getPassword() will be called over and over, but NOT displaying the accumulated password because you keep erasing the LCD.

After who knows how many iterations through loop() and getPassword(), the user has finally entered 6 characters. The message "Password is good" or "Password is bad" will be displayed for one second, and then the screen is cleared, and the user is prompted to enter the password again.

What are you trying to accomplish?

It seems to me that expect getPassword() to block until a password has been entered, and for something magic to happen when the password is correct. If so, you are a long ways from there.

timur2070:
Hello,

What I’m trying to accomplish is that i have a door magnets, when they are not intacted the interrupt function turns on, the buzzer start beeping, and LCD should print “Enter a password”, and a person should enter a correct password to disable alarm. My problem is when I’m trying to print on LCD within interrupt function, it doesnt printing and it seems that arduino getting freeze. Any suggestions would be appreciated

As guix already directed you, you should know by now that you can’t print inside interrupts, or at least you shouldn’t.
What you should do if you really wants to use an interrupt to detect the magnets is set a flag inside the interrupt and check if that flag is true in the loop function.

Besides that, as marco_c already pointed too you are printing hello hundreds of times, you should check if sometime has elapsed since the last print using millis, before printing again, I added a check for 1 second (1000ms).

It end up something like this:

#include <Keypad.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>

#define Password_Lenght 7 //

LiquidCrystal_I2C lcd(0x27, 16, 2);
char Data[Password_Lenght]; // 6 is the number of chars it can hold + the null char = 7
char Master[Password_Lenght] = "123456";
volatile byte data_count = 0, master_count = 0;
bool Pass_is_good;
char customKey;
volatile bool flag = 0;

const byte ROWS = 4;
const byte COLS = 3;
char keys[ROWS][COLS] = {
  {'1', '2', '3'},
  {'4', '5', '6'},
  {'7', '8', '9'},
  {'*', '0', '#'}
};

byte rowPins[ROWS] = {36, 38, 40, 42}; //connect to the row pinouts of the keypad
byte colPins[COLS] = {30, 32, 34}; //connect to the column pinouts of the keypad

Keypad customKeypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS); //initialize an instance of class NewKeypad
#define Password_Lenght 7 // Give enough room for six chars + NULL char
const byte buzzer = 50;
const byte interruptPin = 18;
volatile byte state = LOW;
const byte ledPin = 13;

unsigned long lastMillis = 0;
boolean enterPassword = false;

void setup() {
  pinMode(ledPin, OUTPUT);
  pinMode(interruptPin, INPUT_PULLUP);
  attachInterrupt(5, blink, LOW);
  pinMode(50, OUTPUT);
  lcd.init();// initialize the lcd
  lcd.backlight();
}

void loop() {
  if (millis() - lastMillis >= 1000) {
    digitalWrite(buzzer, LOW);
    digitalWrite(ledPin, state);
    lcd.clear();
    lcd.setCursor(0, 0);
    lcd.print("Hello");
    lastMillis = millis();
  }
  else if (enterPassword) {
    customKey = customKeypad.getKey();
    if (customKey) // makes sure a key is actually pressed, equal to (customKey != NO_KEY)
    {
      Data[data_count] = customKey; // store char into data array
      lcd.setCursor(data_count, 1); // move cursor to show each new char
      lcd.print(Data[data_count]); // print char at said cursor
      data_count++; // increment data array by 1 to store new char, also keep track of the number of chars entered
    }

    if (data_count == Password_Lenght - 1) // if the array index is equal to the number of expected chars, compare data to master
    {
      lcd.clear();
      lcd.setCursor(0, 0);
      lcd.print("Password is ");

      if (!strcmp(Data, Master)) // equal to (strcmp(Data, Master) == 0)
        lcd.print("Good");
      else
        lcd.print("Bad");

      delay(1000);// added 1 second delay to make sure the password is completely shown on screen before it gets cleared.
      lcd.clear();
      clearData();
    }
  }
}



void blink() {
  state = HIGH;
  digitalWrite(buzzer, state);
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("Enter Password"); * /
  enterPassword = true;
}

void clearData()
{
  while (data_count != 0)
  { // This can be used for any array size,
    Data[data_count--] = 0; //clear array for new data
  }
  return;
}

You don't want interrupts for this unless you envision the door being opened and closed again within a few microseconds. In the real world you'd poll that from loop.

@timur2070, I merged your two threads because I believe it will help others to help you if they have the background information.

I see now, because the the threads overlap, that was probably a bad idea. Posts #3 and #4 are the most relevant at this point.

timur2070:
My problem is when I'm trying to print on LCD within interrupt function, it doesnt printing and it seems that arduino getting freeze. Any suggestions would be appreciated

The technical answer to this is it cannot be done, even if you really really want to.

The reason is that the I2C LCD library uses the Wire library and the Wire library calls the twi code which sets up twowire/i2c h/w registers inside the AVR and then the twi code spins waiting on the operation to complete. The way th twi code "knows" that the h/w has completed is that it uses a s/w state that is updated through interrupts.

The twi code will spin forever waiting for its s/w state to change but the state won't change since the s/w state can only change when twi h/w interrupts occur and interrupts are disabled since the code was called from an ISR.

So if you are inside an interrupt routine and attempt to use the Wire library it will hang since no further interrupts will occur.

You will have to modify your design.

--- bill

(deleted)

Wow, a thread that is over 4 years old!

The way to avoid excessive updates is to only update when something changes.

Every time you update one of the status values, set a global boolean variable (a 'flag') to true that tells you that the display needs updating. Somewhere in loop (I usually put it at the start or end) the code checks the flag. If the flag is set, do the update and reset the flag.

This way that all the updates that occurred in the last loop are updated as soon as possible without doing it ALL the time.