Using LCD with multiple shields...no pins left

Hi everyone, I hope I'm posting this in the right place...

I have an Arduino Uno R3 and made a web controlled relay system using an Arduino ethernet shield and SainSmart 8 channel relay. It all works fine, but I also purchased a 20x4 LCD display that I would like to use (this one -> http://www.amazon.com/LCD-Module-Arduino-White-Blue/dp/B003B22UR0) and half of the pins the LCD needs to connect to on the Arduino are already used...The ethernet shield needs four, and my relay is taking up eight, and I'm guessing if I still connect to the pins using a breadboard it won't work because the code I have is already controlling those pins. What are my options?
I'm pretty new to Arduino, but it all seems pretty straightforward...maybe I'm missing something?
Thanks for any help!
-Ryan

What are my options?

Use a shift register. You can operate a char-lcd with 3 pins using a hc164, or 3/4 using a hc595.

Get one of these instead and use SPI interface. Share SCK/MISO/MOSI with the other devices, only need a chip select pin free.

Thanks! I think I'll try the shift register first, just to save money since I already have a display

If you still have pins 0 and 1 for USB serial support, in theory you could connect the phi-panel instead of the USB, and use the 20x4 terminal like you would the USB serial support. Most of the kits have the 20x4 screen, but one of them just has the just the PCB and the ATMEGA328P-PU loaded with firmware for $9 plus s/h. http://www.inmojo.com/store/liudr-arduino-and-physics-gadgets/item/serial-lcd-back-pack---phi-panel/

You can control it with only 2 pins using a shift register, 1 diode and 1 resistor.

I recommend using this library:
https://bitbucket.org/fmalpartida/new-liquidcrystal/wiki/Home
It is a direct replacement for the LiquidCrystal library. It MUCH
faster the than the LiquidCrystal that comes with the IDE.
It supports 4 bit, i2c, 3wire or 2wire shift register communication.
Even when using a shift register it is still much faster than the library
that comes with the Arduino IDE.

I did the 2wire mode code.
If you look in LiquidCrystal_SR2W.h you can find the information of how
to wire up a shift register for 2wire mode. It also supports backlight
control if you add a transistor.
The 2wire code allows you to use a 74xx595, 74LS164, or 4094
Note: The 4094 wiring diagram is not in the released code but if you want/need to use
that part, I can send you the wiring.

If you need parts, these guys sell cheap components including shift registers:
http://www.taydaelectronics.com/catalogsearch/result/?q=74hc595

--- bill

MichaelMeissner:
If you still have pins 0 and 1 for USB serial support, in theory you could connect the phi-panel instead of the USB, and use the 20x4 terminal like you would the USB serial support. Most of the kits have the 20x4 screen, but one of them just has the just the PCB and the ATMEGA328P-PU loaded with firmware for $9 plus s/h. http://www.inmojo.com/store/liudr-arduino-and-physics-gadgets/item/serial-lcd-back-pack---phi-panel/

Thanks for mentioning my phi-panels! The added benefit of using this panel is the option to use multiple keypad layouts, such as rotary encoders, matrix keypads, and buttons, all on the serial port, besides having a serial LCD. Besides, if you ever want to fully use your ethershield, with the SD card, you will need the SD card library, at the cost of 1.5KB of arduino's 2KB RAM. You will find it much better to not use any more libraries such as an LCD library written by anyone. Phi-panel has on board menu renderer and you don't even need a menu library if you render a menu, just send plain text and magic!

liudr:
Besides, if you ever want to fully use your ethershield, with the SD card, you will need the SD card library, at the cost of 1.5KB of arduino's 2KB RAM. You will find it much better to not use any more libraries such as an LCD library written by anyone.

While intelligent backpacks can make some things much easier to implement,
and potentially provide really nice capabilities like scrolling, and menus.
I don't think that it is a given that not using a LCD library is "better".

Cost:
Intelligent backpacks will cost more than directly connecting pins to the LCD
and typically cost more than simple interfaces like a shift register or i2c.

RAM usage:
I haven't looked closely at the RAM usage of the LCD libraries vs using HardwareSerial but it isn't obvious
that a LCD library would use more ram than the HardwareSerial buffers now that both TX and RX are
interrupt driven. HardwareSerial uses 128 bytes. I'm guessing that the LCD library will use less RAM.

CPU load:
Consider the worst case CPU load when sending a full LCD (20x4) of characters.
If using FM's library and 2wire mode with a SR, each character will use around 75us of time for
a total of around 6ms of lost CPU time to fully refresh the entire display.

If using a serial interface at 19200 the first 64 characters get buffered in HardwareSerial
then HardwareSerial will wait for room for the remaining 16 characters to be transfered
to the backpack. At 19200, 16 characters will take a little over 8ms.
If the backpack runs at 9600, then it jumps to 16ms.

LCD refresh rate:
WIth the SR interface, when the LCD library returns after 6ms, the full display has been updated.
The 2wire SR interface can update the 20x4 display around 167 times per second.

With an async serial interface at 19200, the full 20x4 display can be updated
about 25 times per second.

It always comes down to trade offs.
Cost vs Features vs convenience, vs timing, vs code size vs RAM usage.
I don't believe that there is an exact "best" single answer since there are a number of factors involved.
The choice can vary depending on the needs of the project and developer.

--- bill

Depending on how your implement it, many of the solutions can be reduced to two or even one wire.

The choice can vary depending on the needs of the project and developer.

Absolutely.

just the PCB and the ATMEGA328P-PU loaded with firmware for $9 plus s/h.

Wow!

A lot of 1%er out there, apparently.

You can use two shift registers daisy-chained to control both the relays and the LCD, although you'd
have to be careful not to let them interfere with each other. 3 pins to control 8 relays and an LCD...

I don't see what the problem is. The Arduino Uno has 20 I/O pins (D0-D13 and A0-A5), or 18 if you want to reserve pins 0 and 1 so that you can use the serial monitor. You are already using 4 for the Ethernet shield and 8 for the relay board. Your LCD needs 6, so that's 18 in total.

You can use ANY 6 pins (including the analog pins) to connect your LCD, you just need to declare which pins you are using in the code..

Cost:

Intelligent backpacks will cost more than directly connecting pins to the LCD
and typically cost more than simple interfaces like a shift register or i2c.

I know that my time is not worth much money but look around, how many newbies flew through even basic wiring of the LCD without problems. A few dollar extra gets you right where you need. Your shift register way works for someone with a dozen or so projects on their belts and likes hardware enough to test that out. I'd say I personally struggled with wiring and hours of my time were wasted with a single wrong connection, that's worth something.

RAM usage:

I haven't looked closely at the RAM usage of the LCD libraries vs using HardwareSerial but it isn't obvious
that a LCD library would use more ram than the HardwareSerial buffers now that both TX and RX are
interrupt driven. HardwareSerial uses 128 bytes. I'm guessing that the LCD library will use less RAM.

Unless you go into the arduino hardware library file and manually remove the hardware serial buffer yourself, which I wouldn't do, even thought I know how to, you will always have that buffer regardless you use any serial commands or not. The serial object is also always there, instantiated regardless you use serial command or not. I see this as a huge convenience made by arduino team. If you don't use liquidcrystal library and only use serial print char arrays, yes, you save memory in sram and flash. So I have to say you thought wrong.

CPU load:

Consider the worst case CPU load when sending a full LCD (20x4) of characters.
If using FM's library and 2wire mode with a SR, each character will use around 75us of time for
a total of around 6ms of lost CPU time to fully refresh the entire display.

If using a serial interface at 19200 the first 64 characters get buffered in HardwareSerial
then HardwareSerial will wait for room for the remaining 16 characters to be transfered
to the backpack. At 19200, 16 characters will take a little over 8ms.
If the backpack runs at 9600, then it jumps to 16ms.

This calculation is under the consumption that my panel only works at max or 19200, but it works at a maximal speed of 115200, so you are off by a factor of large quantity. I stated in a different thread that my panel understands ANSI escape code and ASCII control characters. One single \f clears the entire screen so no waiting lots or ms for raw screen clear command on LCD. All these are buffered on the panel hardware serial buffer and the screen also has a buffer. There is huge advantage of having a display buffer on board the panel, comparing with raw speed you are referring to.

LCD refresh rate:

WIth the SR interface, when the LCD library returns after 6ms, the full display has been updated.
The 2wire SR interface can update the 20x4 display around 167 times per second.

With an async serial interface at 19200, the full 20x4 display can be updated

about 25 times per second.

Again wrong with the wrong assumption of max serial speed and not having intelligence or screen buffer.

It always comes down to trade offs.
Cost vs Features vs convenience, vs timing, vs code size vs RAM usage.
I don't believe that there is an exact "best" single answer since there are a number of factors involved.
The choice can vary depending on the needs of the project and developer.

--- bill

Yes, it is a personal choice but FYI I never had a complaint that my panel is not the best, from those that did purchase these panels :wink:

Again, it is just a suggestion someone made to OP. Not to bribe you, If you are interested, I can send you an assembled kit for your evaluation if you want, just pm me if you want one :slight_smile:

Btw, intelligence= about 3,000 lines of code on board, so it is not a home made sparkfun serlcd clone. It's loaded.

each character will use around 75us of time for
a total of around 6ms of lost CPU time to fully refresh the entire display.

That figure is highly implementation dependent. With software spi (polling), I can send a byte in around 100us on a 1MIPS avr, or 6us on a 16MIPS avr. To refresh a 20x4 lcd, that means ~1ms (6us * 2 * 80, in 4bit mode) - much faster than the device can actually handle.

That time can be greatly reduced if you utilize interrupt-driven hardware spi: each byte transmission would be 20 ticks (1us or so. -> 200us per refresh).

each character will use around 75us of time for
a total of around 6ms of lost CPU time to fully refresh the entire display.

That figure is highly implementation dependent.

Of course if you look at the full quote --> "If using FM's library and 2wire mode with a SR, each character will use around 75us of time for
a total of around 6ms of lost CPU time to fully refresh the entire display." <-- it is quite clear that he did specify the implementation.

Don

liudr:
RAM usage:

I haven't looked closely at the RAM usage of the LCD libraries vs using HardwareSerial but it isn't obvious
that a LCD library would use more ram than the HardwareSerial buffers now that both TX and RX are
interrupt driven. HardwareSerial uses 128 bytes. I'm guessing that the LCD library will use less RAM.

Unless you go into the arduino hardware library file and manually remove the hardware serial buffer yourself, which I wouldn't do, even thought I know how to, you will always have that buffer regardless you use any serial commands or not. The serial object is also always there, instantiated regardless you use serial command or not. I see this as a huge convenience made by arduino team. If you don't use liquidcrystal library and only use serial print char arrays, yes, you save memory in sram and flash. So I have to say you thought wrong.

You are mistaken on the existence of the serial object (and serial code) when serial is not used
and on the resources used by serial vs LiquidCrystal.

Take a closer look at what really happens when creating the final .elf image.
Go run avr-objdump on the final .elf image created by the IDE.
Given the compiler and link options used by the IDE,
the linker will remove any function or data elements that are not referenced.
When the serial functions are not used, the HardwareSerial functions and the data they reserve
(rx_buffer and tx_buffer on an UNO board) are removed from the final linked image.

Serial uses more RAM, significantly more RAM depending
on which board is being used vs either of the two LiquidCrystal libraries.
Serial also use more flash than the stock LiquidCrystal Library
when using the mega 1280.

--- bill

proof can be seen below.


Here are some actual real numbers on flash and RAM usage for two "hello world" lcd sketches
using Arduino 1.0.1
One sketch uses the LiquidCrystal library and one that uses serial prints to a smart backpack.

Here is the LiquidCrystal sketch:

#include <LiquidCrystal.h>

// initialize the library with the numbers of the interface pins
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);

void setup() {
  // set up the LCD's number of columns and rows: 
  lcd.begin(16, 2);
  // Print a message to the LCD.
  lcd.print("hello, world!");
}

void loop() {
  // set the cursor to column 0, line 1
  // (note: line 1 is the second row, since counting begins with 0):
  lcd.setCursor(0, 1);
  // print the number of seconds since reset:
  lcd.print(millis()/1000);
}

Here is the equivalent using the serial port
(ignore baud rate for now as that does not affect code or data size)

void setup() {
  // set up the LCD's number of columns and rows: 
  Serial.begin(19200);
  Serial.print("\e[20;4L~");
  delay(500);
  // Print a message to the LCD.
  Serial.print("hello, world!");
}

void loop() {
  // NOTE: Serial backpack device uses 1 based vs 0 based addressing
  // this will position the cursor to first column, second line from top.
  Serial.print("\e[1;2H~");

  // print the number of seconds since reset:
  Serial.print(millis()/1000);
}

And here is the sizing information for each when using an UNO board:
LiquidCrystal

Idx Name          Size      VMA       LMA       File off  Algn
  0 .data         0000001e  00800100  000009ec  00000a60  2**0
  1 .text         000009ec  00000000  00000000  00000074  2**1
  2 .bss          0000001e  0080011e  00000a0a  00000a7e  2**0

FM LiquidCrystal

Idx Name          Size      VMA       LMA       File off  Algn
  0 .data         00000036  00800100  00000c3e  00000cb2  2**0
  1 .text         00000c3e  00000000  00000000  00000074  2**1
  2 .bss          00000020  00800136  00000c74  00000ce8  2**0

Serial

Idx Name          Size      VMA       LMA       File off  Algn
  0 .data         00000030  00800100  00000918  0000098c  2**0
  1 .text         00000918  00000000  00000000  00000074  2**1
  2 .bss          000000b0  00800130  00000948  000009bc  2**0

You can see in the LiquidCrystal sizes that clearly the two 64 byte buffers
are not in the .bss area.

You can see that the LiquidCrystal code (.text) is larger than the serial code
and FM LiquidCrystal is quite a bit larger.

The RAM result was as I had predicted:
The RAM (.bss) usage was larger for the Serial implementation.

One thing that really surprised me in this exercise is the difference when using
a MEGA 1280 board vs an Uno board.
The spread on resources really shifts against serial.
I had no idea their MEGA code was that bad....
They way they wrote the code and dealt with the ISRs causes
all the code and data buffers for all serial ports to be dragged in
even if you only use 1 of them.

LiquidCrystal

Idx Name          Size      VMA       LMA       File off  Algn
  0 .data         0000001e  00800200  00000c28  00000c9c  2**0
  1 .text         00000c28  00000000  00000000  00000074  2**1
  2 .bss          0000001e  0080021e  00000c46  00000cba  2**0

FM LiquidCrystal

Idx Name          Size      VMA       LMA       File off  Algn
  0 .data         00000036  00800200  00000f7a  00000fee  2**0
  1 .text         00000f7a  00000000  00000000  00000074  2**1
  2 .bss          00000020  00800236  00000fb0  00001024  2**0

Serial

Idx Name          Size      VMA       LMA       File off  Algn
  0 .data         00000030  00800200  00000ed0  00000f44  2**0
  1 .text         00000ed0  00000000  00000000  00000074  2**1
  2 .bss          000002a5  00800230  00000f00  00000f74  2**0

You can see that the ram usage for the two LiquidCrystal libraries does not
change when moving to the 1280 board while the RAM usage goes up significantly
when using serial.

When using a Mega 1280 board
Serial now uses more code and more ram than the stock LiquidCrystal library.

--- bill

Bill,

Sorry for the wrong assumption on the serial object :cold_sweat:. I only read the source code =( (not sure how many times now but many). I didn't analyze the compiled results. Thank you for showing me these results. Anyway, the existence of interrupt-driven serial receive for arduino 1.0 really makes it easy for arduino to just dump results to the phi-panel as fast as arduino serial can do and let the panel deal with the LCD :wink:
Screen clear only takes 0.1ms to send over since it is just one byte :smiley: