LCD interaction problem with interrupts in 4 bit mode

I’m helping my daughter with a project that is using an LCD in 4 bit mode and two buttons hooked to Arduino UNO R3 pins 2, and 3.
If she runs the code without the LCD it works just fine and the interrupts are properly detected. If she enables the LCD code the interrupts are missed or misbehave.

I hooked an 0scope to the pins 2, and 3 and observed the logic levels of the pins when both code sequences were run.

Without the LCD the full 5V is input the pin and it goes low when the button is pressed.
With the LCD code the logic level is about 1V and occasionally it goes to 5v in a pulse. Clearly the LiquidCrystal code is interacting with the interrupts. Here is a test sequence with the LCD enabled and all the interrupt code removed. Were just looking at the button wires with this code and observing the logic level. She is not really doing any interrupt handling yet as it’s clear that would not work until the logic levels can be sorted out.

She is NOT using pin 2 or 3 in the LCD definition. Is the library using these pins anyway?

// include the library code:
#include <LiquidCrystal.h>
#define RSPin 12
#define EnablePin 8
#define DS4 4
#define DS5 5
#define DS6 6
#define DS7 7

const int LearnPin = 2; // pin for the learn button
const int RunPin = 3;   // pin for the run button

// initialize the library with the pin numbers used to hook up the LCD
LiquidCrystal lcd(RSPin,EnablePin,DS4,DS5,DS6,DS7);

volatile int LearnPin_State =  false;   // Set up the pin variable for Learn
volatile int RunPin_State = false;      // Set up the pin variable for Run

// the following variables are long's because the time, measured in miliseconds,
// will quickly become a bigger number than can be stored in an int.
long debounce = 50; // the debounce time, increase if the LCD output flickers

// Setup - Only runs one time at power up or reset
void setup(){
  //configure pin2 and pin3 as an input and enable the internal pull-up resistor (use external pullups for more consistent operation)
  pinMode(LearnPin, INPUT);
  digitalWrite(LearnPin, HIGH);
  delay (100);
  pinMode(RunPin, INPUT);
  digitalWrite(RunPin, HIGH);

  pinMode(13, OUTPUT); 

  // set up the LCD's number of columns and rows: 
   lcd.begin(16, 2);
   // Print a message to the LCD.
   // set the cursor to column 0, line 1
   // (note: line 1 is the second row, since counting begins with 0):
   lcd.setCursor(0, 1);
   // Write to the LCD
   lcd.print("Val2    Val3    ");
   lcd.setCursor(6, 1);
   lcd.setCursor(14, 1);
   lcd.setCursor(0, 1); 

void loop(){
  delay (1000);

I don't see the interrupts being attached anywhere.

WE removed that piece of code to debug it. Essentially were looking at the state of the physical pins with a scope and while the LCD code is enabled the natural state of pin 3 is to go to about 1V to 3V. We remove the LCD code and the logic level is fine. Obviously we can't enable interrupts or use them in general until the levels are sorted out. I feel confident once the LCD and the proper logic levels are seen at the pins then the interrupts can be enabled and the rest of the code will work. Just frustrating as I've done numerous projects with LCD's and never had an issue like this. In the past always used 8 bit mode. This is one of the first times a 4 bit mode is attempted. She does not have enough spare pins to do eight bit mode.

.ps WE tried it on an older Arduino and the same thing happens. Not the hardware. Pins 2 and 3 properly go to 5V while in reset so I know the hardware is fine. Is there a unique way to force the LCD code to go into 4 bit mode?

What exactly do you expect the code in your original post (the only code that we can evaluate) to do as far as the LCD display is concerned.

What does it actually do?

What is the purpose of the delay in loop()?

What happens when you leave loop() completely empty?


The loop code was just to debug the problem. The removal of attach interrupts was also to debug the problem. So far I changed chips on the Uno board and that helps slightly. Now the logic level is 4V and the input is properly decoded. There still is an interaction between the INT1 (PIN3) and the LCD code in 4 bit mode. I see a regular square wave pattern on the scope every 725uS. The pin goes from 5V (expected level) to 4V. If the LCD code is disabled the steady high of 5V is seen.

I’ve never sen anything this strange before and it clearly was not present in earlier 8 bit mode code. I’m going o find a wall wart to see if there is something taxing the USB port for current. It just seems strange that only when the LCD code is running does this occur. I will attach an image from the scope.

NewFile0.bmp (146 KB)

The pin goes from 5V (expected level) to 4V. If the LCD code is disabled the steady high of 5V is seen.

So as far as the microprocessor is concerned the logic level is always 'high'. What did you expect?

How about providing answers to my previous questions so I can formulate some ideas concerning your problem?


The LiquidCrystal code will only use the pins you specify and leave all others alone.
If you only specify 4 data pins in the constructor, then it uses 4bit mode.

We need more information.
Is the LCD displaying text as expected?
Do you see this voltage variation on the 5v or Vin signals?
with/without LCD attached?

A few more questions.
What all is wired up to the Arduino?

  • External Power?
  • usb?
  • connections to Arduino pins.

Also, how is the LCD wired up?
(What is connected to each of the 16 pins?)
Maybe there is a wiring issue that draws too much current
and craters the power supply.
i.e. maybe when the LCD is initalized it creates a short, drops the voltage
or blows the USB fuse and eventually resets the AVR over and over again.
Check to see if setup() is being called over and over again.
Maybe toggle pin 13 in setup() and check with your scope.

— bill

All good suggestions. I went and changed the chip on the board and some of the issues cleared up. I no longer see the steady state DC level on the Pin3 input down in the 1-3V range. It's now consistently about 4.5V so that is OK. I still see the strange toggling as shown when I power the device from the USB port. I was also having programming problems being intermittent. I added a wall wart supply and now the programming is much more stable and controllable. The odd toggling also seems to be improved.

As for the LCD interacting with the interrupts... Now that the wall wart was added and the chip changed out the issue is gone. As for other loads on the board... There are multiple flex sensors from SparkFun along with the two buttons. There are connections for servo's but they were not hooked to the system in the tests and of course the LCD display that was powered. The backlight for the LCD did have a current limit resistor.

So after adding the wall wart and seeing that many of the strange programming issues seemed to have been fixed as well I finally narrowed this problem down to a poorly supplied board from a really bad USB port on this PC. I switched to a laptop and the system board seems to work fine! All this trouble over a dodgy USB host and a questionably bad chip. I should have suspected this when I initially started to see the odd button behavior. The daughter took over the programming now that the hardware has been cleared. So far so good. Thanks for the suggestions but as with some of these problems it only takes lots of time and beating the problem to death slowly and methodically.

It is probably not a good idea to make your first posting of the code, a "moving target" by updating the code in it. Since you are correctly using "code" tags, feel free to put new versions in successive posts.

I cannot quite follow the code as such, but my more general comment is that you should not be using interrupts for pushbuttons, only for things that demand very rapid response. By the time you press or release a button, the processor has executed many millions of operations, even thousands between spark firings of an internal combustion engine, so for these tasks, it is far more appropriate to "poll" the input, and particularly so as you need to execute a debounce procedure.

The most crude debounce procedure is to wait for a button event, then delay for say 10 ms and poll again to see if it is still in the new state. Much better is to poll every millisecond and make a count of how many times the input holds a "new" state, zeroing the count if it drops back to the old and registering a valid new state when the count reaches, say, ten. A corollary is that having determined the valid new state, it will not register a new event until the input reverts to the other state reliably for the same period.

All this is predicated on "non-blocking" code, containing no "delay()" or "while" functions; the whole main loop cycles continuously on the order of many thousands of times per second, reading the time ("millis()") and comparing it to necessary schedule values. It is a an essential discipline to adopt this approach from the very beginning rather than to discover it painfully later when you realise you have "painted yourself into a corner". :D

General rules of the assistance process here are (and in decreasing order of priority):

Post the code. (You have - well, only one version so far ... sort of)

Post the circuit.

Post a photograph of the rig (so that that wires can be clearly identified at each end and not confused in the middle). Most important if it is not working at all, but apparently "minor" wiring blunders can cause very curious consequences.