# Reading info from an LCD display

OK, so I've quite recently stepped in to the world of Arduino, and I seem to get the "overall" view of it.

But I have a long way to go before I'm putting "Expert" on my card... :smiley-confuse:

So to my project

• I have a heater in the basement (For "house heating", not "water heating").
• I would like to read some (or all) of the information on the heaters display.
• I've seen a tutorial online on how to do this "in general", and I know it can be done.
• I need some help with how to proceed with this "codewise". Right now I'm stuck in the use of HD44780 library test-file "Readwrite".

I have:

• Arduino Nano hooked up to the as described in the codeline const int rs=D8, rw=A0, en=D9, db4=D4, db5=D5, db6=D6, db7=D7; // for esp8266 devices of the heaters display
• The displays data sheet
• The displaycontroller data sheet
• HD44780 library downloaded and installed (It's an example-sketch from this I'm using)

My problem:

• I connected my Raspberry Pi to my Arduino Nano and uploaded the file xxx, and then turned on the heater. The LCD shows "strange" characters, and the heater "starts and stops" frequently.
• If I unplug the USB between the Raspberry and the Arduino, the heater works normally.

Questions:

a) I can't verify the code correctly, I get 4 different errors. What could be wrong?

1. ReadWrite.ino: In function ‘void setup()’:
2. ReadWrite.ino:74:15: error: ‘fatalError’ was not declared in this scope
3. ReadWrite.ino: In function ‘void loop()’:
4. ReadWrite.ino:104:24: error: ‘PrintUpTime’ was not declared in this scope (I "//":ed out error 2 and 4 before uploading the file to Arduino.)

b) I believe I have hooked up the cables correctly, but is there anything strange you see in the image of the connections?

The LCD display is "faced down" under the right breadboard, with it's connection-pins facing "away" from the pint of view.

Picture(s) added in the end for clarification.

Code used at this moment (file "ReadWrite"):

// vi:ts=4
// ----------------------------------------------------------------------------
// Created by Bill Perry 2016-08-19
// bperrybap@opensource.billsworld.billandterrie.com
//
// This example code is unlicensed and is released into the public domain
// ----------------------------------------------------------------------------
//
// This sketch is for LCDs that are directly controlled with Arduino pins.
//
// The purpose of the sketch is demonstrate the ability to read data from
// the LCD. As such, it requires an extra Arduino pin to control the R/W LCD
// pin. See below for configuring the Arduino pins used.
//
// Sketch will print the amount of time since the Arduino has been reset
// on the top row and then read the data from the LCD to print it on the
// second row
//
// If there are errors and the arduino supports a built in LED,
// an error status code will blink on the built in LED.
// Error codes:
// (1) lcd device initialization failed
// (2) lcd device does not support reads
// (3) error reading data from lcd device
// (4) error writing data to lcd device
//

#include <hd44780.h>
#include <hd44780ioClass/hd44780_pinIO.h> // Arduino pin i/o class header

// declare Arduino pins used for LCD functions
// and the lcd object

// Note: this can be with or without backlight control:

// without backlight control:
// note that ESP8266 based arduinos must use the Dn defines rather than
// raw pin numbers.
#if defined (ARDUINO_ARCH_ESP8266)
const int rs=D8, rw=A0, en=D9, db4=D4, db5=D5, db6=D6, db7=D7; // for esp8266 devices
#else
const int rs=8, rw=A0, en=9, db4=4, db5=5, db6=6, db7=7;
#endif
hd44780_pinIO lcd(rs, rw, en, db4, db5, db6, db7);

//with backlight control:
//  backlight control requires two additional parameters
//  - an additional pin to control the backlight
//  - backlight active level which tells the library the level
//      needed to turn on the backlight.
//      note: If the backlight control pin supports PWM, dimming can be done
//
//const int rs=8, rw=A0, en=9, db4=4, db5=5, db6=6, db7=7, bl=10, blLevel=HIGH;
//hd44780_pinIO lcd(rs, rw, en, db4, db5, db6, db7, bl, blLEvel);

// LCD geometry
const int LCD_ROWS = 2;
const int LCD_COLS = 16;

void setup()
{
// initialize LCD with number of columns and rows:
if( lcd.begin(LCD_COLS, LCD_ROWS))
{
// begin() failed so blink the onboard LED if possible
fatalError(1);
}

// check to see if device can read by attempting to read
// the lcd status register. If it fails then assume it was
// because the lcd device does not support reads.
if(lcd.status() < 0)
{
fatalError(2);
}
}

void loop()
{
static unsigned long lastsecs = -1; // pre-initialize with non zero value
unsigned long secs;

secs = millis() / 1000;

// see if 1 second has passed
// so the display is only updated once per second
if(secs != lastsecs)
{
lastsecs = secs; // keep track of last seconds

// set the cursor position to top line: column 0, row 0
lcd.setCursor(0, 0);

// print uptime on lcd device: (time since last reset)
PrintUpTime(lcd, secs);

// Now copy the characters from the top line to the 2nd line
// This is done character by character by:
// - setting the character position to read
// - setting the character position to write
// - writing the charcter read
for(int col = 0; col < LCD_COLS; col++)
{
int c;

lcd.setCursor(col, 0);
if((c = lcd.read()) < 0) // if a read error, bomb out
{
lcd.clear();
fatalError(3);
}

// check for ':' characters in col 2 and 5
// if not there, consider it a fatal read error
if((col == 2 || col == 5) && c != ':')
{
lcd.clear();
fatalError(5);
}

lcd.setCursor(col, 1);
if(lcd.write((uint8_t) c) != 1)
{
lcd.clear();
lcd.print("write fail");
fatalError(4);
}
}
}
}

// PrintUpTime(outdev, secs) - print uptime in HH:MM:SS format
// outdev - the device to send output
//   secs - the total number of seconds uptime
void PrintUpTime(Print &outdev, unsigned long secs)
{
unsigned int hr, mins, sec;

// convert total seconds to hours, mins, seconds
mins =  secs / 60;  // how many total minutes
hr = mins / 60;     // how many total hours
mins = mins % 60;   // how many minutes within the hour
sec = secs % 60;    // how many seconds within the minute

// print uptime in HH:MM:SS format
// Print class does not support fixed width formatting
// so insert a zero if number smaller than 10
if(hr < 10)
outdev.write('0');
outdev.print((int)hr);
outdev.write(':');
if(mins < 10)
outdev.write('0');
outdev.print((int)mins);
outdev.write(':');
if(sec < 10)
outdev.write('0');
outdev.print((int)sec);
}

// fatalError() - loop & blink and error code
void fatalError(int ecode)
{
hd44780::fatalError(ecode); // does not return
}


UPDATE EDIT:

This is what I've come up with so far:

• The first attached code and library HD44780 I intended to use could not be used, since it's used when the Arduino itself is the source of signals to the LCD display.

• So I have used the Logical Analyzer and found out that:

1. We're dealing with a 4 bit communication to the LCD
2. The timeline for the signals are as attached image NOTE: (Pin "(4)RS" should be named pin "(6)E" in the image.
3. I tried to get this code transferred into "Arduino Nano" language, but I'm struggling with 3 errors still:

pinMode(d4, INPUT_PULLDOWN); sketch_apr18a.ino:41:17: error: 'INPUT_PULLDOWN' was not declared in this scope

if(pinReadFast(rs) == 0){ sketch_apr18a.ino:70:22: error: 'pinReadFast' was not declared in this scope

upperNibble = (GPIOB -> IDR & 0B0000000011110000) >> 4; sketch_apr18a.ino:72:25: error: 'GPIOB' was not declared in this scope

Question: Is it possible to see by this picture if the "timeline" for when "E" drops is enough for snooping the data?

• How is your raspberry pi powered, and what else is connected to it? Sounds like you may have a grounding issue (in addition to other issues). If thats not a problem, there might be some issue with your usb communication (although it doesn't look like you have any anyway). – BeB00 Apr 17 at 18:10
• why do you need the HD44780 library? ... you said that the LCD is connected to the heater ... please describe clearly what is connected to what and how is it connected – jsotola Apr 17 at 18:23
• Unless I'm confused about what "HD44780 library" you have, it's for your Arduino to control a display. I think it's very unlikely that you have a library which will let you snoop on what some other controller is doing with the display. Not that snooping is impossible to do - I just think that it's vanishingly improbable that someone has published an Arduino library to do it. – brhans Apr 17 at 18:35
• you said uploaded the file xxx ... how can that be true when the sketch does not compile? – jsotola Apr 18 at 1:01
• See this program for what you need to get started with decoding – lights0123 Apr 18 at 3:00

The library you have does not do what you think it does.

The purpose of that library is to use an Arduino to read data from a character-based LCD display device with the assumption that the Arduino is the only device connected to the display and has complete control over it.

Your situation is much different and much more difficult. You are trying to observe the LCD control lines while some other controller drives it. I think that task will require a much more capable device than an ATmega-based Arduino.

• Thanks for clarification, I just saw now what the code I use actually does also: It puts the time of last "update" from the Arduino to line 1 on the LCD. It then reads the info on line 1 of the LCD and copy it to line 2 on the LCD, and so on. I will take a look at the logic analyzer ,emtioned below. – Mr C Apr 18 at 6:25

As already mentioned you CANNOT do what you intend with the HD44780 library. This library is intended where you want the Arduino to control the LCD. The fact that you can read registers in the LCD does NOT mean you can read them while some other MCU tries to control the LCD. You could write your own code to sense (all your pin connections would be inputs) the actions being taken by the other MCU driving the LCD. In essence you'd be making an LCD emulator to allow trapping all the control actions and register read/writes.

There may be a shorter path for you. You could implement an Arduino Logic analyzer. There are a heap of open source versions, here is just one. You could then 'capture' a refresh cycle of the LCD and figure out what was being written to it. The data could be transferred to the R'Pi over the serial port and you could do your analysis in the R'Pi.

Good luck.

• Thanks for a kick in the correct direction :) I downloaded the Logic Analyzer, but I seem to be missing file(s) or maybe some standard library? I get the following error of file missing from code snippet "#include <c_types.h>": ESP8266.ino:8:21: fatal error: c_types.h – Mr C Apr 18 at 7:30

Stop connecting two outputs to drive the display in parallel - it won't work!

You don't want to read from the LCD while it is being connected to the original circuit, you want to sniff the bus what the original controller writes to it.

Basically you could with the same wires sniff the bus, just change all pins to inputs and choose a pin that can generate interrupts on falling edge, and that will become the E pin to trigger on the LCD bus cycles.

There might be another way to read the pixels, which may depend on which LCD chipset it has and how it has been manufactured.

Since it is a 16x2 display, it can't be driven by a single HD44780 or compatible LCD glass controller, because it needs another chip for expansion. Between these two chips, there is sync and pixel data transmitted over D, CL and M pins. If you can tap onto these wires, just maybe you can capture the pixel data.

• I just saw from the code that it actualy is writing to the display, wich oufcourse was not my intention. So if I'm getting this right in the "big" view: 1. put digital pins A0 to A3 to "input" 2. Set A0 to read for a "falling edge" frm the LCD BUS 3. Generate interrupt with pin A7 4 Read bus info? – Mr C Apr 18 at 7:44
• I am not sure if you have the big picture right. All pins must be inputs, E RS RW and Data pins.. React on falling edge of E. Read all other bus pins, RS, RW and Data. But do you even know if the LCD is driven by the heater controller with 8-bit bus or 4-bit bus? You need all 8 data wires if it uses 8-bit bus. – Justme Apr 18 at 8:08
• That link does not work. It depends on how the processor in the heater has been connected to it, and even if 8 bit bus is wired, the software might still use any bus width it wants. – Justme Apr 18 at 9:10
• Would sniffing the bits give me the same info as a logic analyzer would? – Mr C Apr 18 at 9:49