Hi! I got an arduino mega with a rotary encoderstrong text and an LCD I2C module. I attatched an interrupt to the button pin of the Rotary Encoder (which yes, is on a compatible pin, PIN 18 of the MEGA), and that interrupt wakes up the lcd whenever it is pressed. After 5 seconds, the LCD Backlight is shut down again and so on.
The problem is: It doesn't work. Whenever I press the encoder, the code literally freezes. I tried opening and closing the backlight at a distance of 1 second in the main loop and it DID work, but for some reason, if I do it as a function call it crashes... Here is the relevant part of the code:
A_Global_Variables.ino
#include <LiquidCrystal_I2C.h>
// Rotary Encoder
#define outputA 19
#define outputB 45
#define encoderBtn 18
LiquidCrystal_I2C lcd(0x27, 16, 2); // I2C address 0x27, 16 column and 2 rows
unsigned long tsms=0; // time since menu started
unsigned long ct; //current time
void lcd_power_save_on();
void lcd_power_save_off();
And the LCD DOES shut down after 5 seconds with the lcd_power_save_off() function, but it fails to open when the button is pressed. When I try to print, it also doesn't print the full word:
I couldn't find the good encoder in Fritzing, but it's GND, VCC, SW, DT, CLK from left to right. I also updated the code above with the pins. Is everything clear now?
This is a spaghetti schematic (uncooked).
Hand drawn would be better.
Shouldn't you look for falling edge in your attachinterrupt? Now you will have 2 calls, 1 when you press the button and 1 when you release it
Did you confirm that the supply rail pins on the proto board are not split in the middle? Some have that, and then the power and ground connections do not extend all the way between the two ends.
In your if you should subtract two unsigned integers. You need to rearrange the equation. Now it will have problems during rollover. But that is not the problem of today, so we need to look further.
This is my standard advice to get started for a complex project:
Keep it simple and stupid firstly.
Run some tutorials for the hardware selected.
If you are happy with the results of the tutorials you can merge these to your project.
Have a nice day and enjoy coding in C++.
It is not possible to use the I2C bus inside a interrupt, because the Wire library is interrupt driven. Using a delay() will also crash the sketch and Serial can only be used for testing. Using Serial functions inside a interrupt is made possible since a year or so, but it is still a bad idea.
If you want to do something from a interrupt, then you can send a message to the loop(), so that the code in the loop() can do all kind of things and use libraries. That "message" is just a boolean variable with true and false.
// For: https://forum.arduino.cc/t/interrupt-freezes-arduino-and-stops-code-from-working/1081767
//
// Changes:
// - Using the KISS rule.
// - Changed to hd4470 library.
// - It is not possible to use I2C (interrupt driven).
// or delay() in a interrupt. Serial.print() should be avoided.
// - Interrupt at falling edge to toggle the background.
//
// Conclusion:
// This does not feel right.
// The button can be checked in the loop().
// A interrupt makes debouncing harder.
// The Encoder library can deal with the encoder:
// https://www.pjrc.com/teensy/td_libs_Encoder.html
//
#include <Wire.h>
#include <hd44780.h>
#include <hd44780ioClass/hd44780_I2Cexp.h>
hd44780_I2Cexp lcd;
// LCD geometry
const int LCD_COLS = 16;
const int LCD_ROWS = 2;
const int encoderCLK = 19;
const int encoderDT = 45;
const int encoderBtn = 18;
bool backlight = true; // the current status of the backlight
volatile bool trigger = false; // to send a trigger from interrupt routine
void setup()
{
Serial.begin(115200);
pinMode(encoderBtn, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(encoderBtn), lcd_power_toggle, FALLING);
Wire.begin(); // not really needed, lcd.begin will do this
int status = lcd.begin(LCD_COLS, LCD_ROWS); // also turn on backlight
if(status) // non zero status means it was unsuccesful
{
Serial.println("Display was not found");
}
lcd.setCursor(0, 0); // column, row
lcd.print( "To Freeze Or");
lcd.setCursor(0, 1); // column, row
lcd.print( "Not To Freeze");
}
void loop()
{
if(trigger)
{
trigger = false; // reset the trigger
backlight = !backlight; // toggle between true and false
if( backlight)
{
lcd.backlight(); // turn backlight on.
}
else
{
lcd.noBacklight(); // turn backlight off.
}
}
delay(20); // slow down the sketch, avoid button bounce trouble.
}
void lcd_power_toggle()
{
trigger = true;
}
You can try the sketch in Wokwi simulation:
To start the Wokwi simulation, click the start button in the upper-middle of the screen. After it has started, click the encoder button to toggle the backlight.