home   articles   archive   forum   masthead  
Published at 13.11.2000
Author: Ronny Ziegler
Translator: Andy Ziegler
Languages: de nl
Printer printer-version
Support Us!

LCD Display

LCD If you have a Linux PC without a monitor working as a server, but want to be informed about the current status of the computer, you could use a Liquid Crystal Display.

LCD & Linux

The connection of a Liquid Crystal Display to a Linux computer has been described many times and we don't want to repeat old information.
Our article not only discusses the basic access to a LCD but also shows how an LCD and jslaunch can work together, so you do not get only a simple status report but also the PC can be steered interactively.

We will describe how you are able to access a LCD via the parallel port with the program lcd by Nils Fdrber. With four buttons that are checked by jslaunch you can navigate through your own menu and execute different commands. Everything without a huge effort in programming.

The Display

The program lcd can be used to communicate with LCDs with a Hitachi HD44780 chip.
You can get this at Conrad-Elektronik (Germany) and it costs about 70,- DM ($40) for 4 lines and 20 columns without (Best.-Nr. 187267) and about 80,- DM with a back light (Best.-Nr. 187275). If your computer is placed in a room that is not illuminated very well you should get a display with a back light.

Display with a back light

The display is connected to the parallel port and needs the following connections:

25 pin


In addition, pin 2 of the LCD panel has to be connected to the +5V power line and the pins 1 and 5 of the display and the pins 18 and 25 of the parallel port to ground.
A nice 5 Volt source inside the PC is the 2-wire floppy power cable (red cable +5V, black is ground -- test it first!).

The contrast of the display can be changed by a 100 ohm potentiometer. But it should be OK if you connect pin 3 of the display to the ground.

   +5V ---+
           \ <--+
           /    |
           \    |
    GND ---+    +--- VL (Pin 3 - driver input)

The final connection looks like:

         25 pin          LCD
          SUB D           Panel   Pin
                          GND     1  --+--- \ Connect to
                          +5V     2  --|--- / Gameport
                          R/W     5  --+    
          1               EN      6    |    
          2               DB1     7    |    
          3               DB2     8    |    
          4               DB3     9    |    
          5               DB4     10   |    
          6               DB5     11   |    
          7               DB6     12   |    
          8               DB7     13   |    
          9               DB8     14   |    
          14              RS      4    |    
          18-25           GND        --+    

The connection of pins 18-25 is very important, otherwise you would see flashing signs and boxes on the display.

If you correctly linked everything, you would see two rows with black boxes:

Display without any
  displayed information

The driver

The latest driver that is used to communicate with the LCD has the release number 0.152, but we were not able to compile this version. The previous release 0.151 worked fine for us.
You get this one at the FTP server ftp://ftp.unix-ag.uni-siegen.de/pub/os/linux/drivers/
(On the server you find a version 0.6.0. That one has the same name but is a different program.)
First check if you managed to compile the drivers before you go and buy an LCD. Only after being sure that you can communicate with the LCD is it worth spending the money!
We only succeeded in compiling the driver on a system with a 2.2.13 and an old 2.0.36 kernel. It failed on the 2.2.16 kernel. LCD-0.151 stopped with an error message. Maybe you will have more luck than us.
Before compiling, you choose your kernel in the file driver/Makefile (2.0.x or 2.2.x). You have to set the address of the parallel port in the file driver/hardware.h:

      #define LCD_ADDRESS 0x0378     /* corresponds to lpt1: */
   /* #define LCD_ADDRESS 0x0278  */ /* corresponds to lpt2: */
   /* #define LCD_ADDRESS 0x3bc   */ /* also a possible address for the parallel port */

Delete the comments /* and */ for your address.
If you do not know the address of the parallel port, plug in a printer, load the printer module:

  >> insmod lp
and have a look at:
  >> cat /proc/ioports 
There you find the address.
If you have a display with a different size than 20x4 you can set this in driver/hardware.h.

   #define LCD_COLS 20
   #define LCD_LINES 4

lcd needs the files /usr/src/linux/include/linux/modversions.h and /usr/src/linux-2.2.13/include/linux/modsetver.h for compiling the drivers. But both are missing in our copy of the 2.0.x kernel.
It would work if you copied these files from a 2.2.x kernel into the proper directory modsetver.h and modversions.h).

If everything was completed you could:

  >> make 
the program lcd.
Then you'll find the compiled module lcd.o in the subdirectory driver/, which is needed to talk to the LCD.
Finally, you have to create the pseudo file /dev/lcd that will be the device talking to the LCD. This creation is done using the script mkdevice in the subdirectory driver/ (as root).
Next you have to connect the hardware in the right way.


We wrote about Jslaunch in an earlier issue (Jslaunch -- PC steering via Joystick ).
In combination with an LCD, the usefulnes of the program is extended.
The program jslaunch checks in well-defined time intervals if the buttons of a joystick connected to the gameport of the sound card were pressed and would execute commands depending on the button combination that was pressed.
Jslaunch can be used very comfortably because it does not need any kernel module to read the joystick port, but gets the information directly and can be installed easily.
Due to the high stability of the program, it can be used as an emergency reset. If a few important components of the system crashed (e.g. keyboard, network and/or Xserver) you would be able to halt or reboot the system and would not have to use the hard-reset button.
The easiest way would be if you got a joystick (maybe broken but with the buttons are still working) and separate the cables and buttons from the stick.
If the display had to have a professional look, you could substitute the buttons with better looking buttons you would get in any well-stocked electronics shop.
The program jslaunch does not take much work; you just have to compile it (>> make).

first test

After everything is connected correctly, you should test the display.
To do this, you have to load the module of the LCD driver (as root in the subdirectory driver/):

  >> /sbin/insmod lcd.o 
Then you should see a flashing cursor in the upper left corner. If everything worked well you could copy the module into the directory /lib/modules/2.2.*/misc/ and you do not have to change into the driver/ directory any longer.

To produce an output on the LCD you change into the subdirectory tools/proclcd and compile the program with a

  >> make
The program is started and the output is piped to the /dev/lcd device:
  >> ./proclcd > /dev/lcd
Then you should see an output on the display like:

Proclcd test

By the way, the driver can be removed using:

  >> /sbin/rmmod lcd
This would only work if no running process accessed the LCD.

Next you test the joystick.
Start jslaunch with the command:

  >> jslaunch -r 1 "echo 1" -r 2 "echo 2" -r 3 "echo 3" -r 4 "echo 4"
If you pressed a button, jslaunch would show which button was pressed.
You should write down which number belongs to which button because you will need it later for the LCD steering.

If both (LCD and joystick buttons) worked well, you could place both into the housing of the PC.
A free slot would be ideal to fix the display and the four buttons. If the parallel port and/or joystick port was not fixed on a slot card but was fixed with a cable on the backside of the PC you could remove it and place it inside of the PC.

The menu

This part describes how you can construct your own menu which can be used via the joystick buttons. This is not a complicate program, just a few simple bash scripts. Even an inexperienced programmer is able to modify these to his desired LCD output.

First, you create a new directory where you collect the scripts for the LCD:

  >> mkdir /usr/local/etc/display/
There, you create the file own that has to be an executable:
  >> touch /usr/local/etc/display/own
  >> chmod a+x /usr/local/etc/display/own
The script should look like:

   # Just a dumb script copying some nice system information values
   # to our LCD device
   export SLEEP=10
   #Button 1,2,4: Menu -- button 3: reboot
   echo -n -e "\33c" > /dev/lcd
   echo -n  -e "\33h" > /dev/lcd
   echo -e "    " > /dev/lcd
   echo -e "  Please wait ..." > /dev/lcd
   echo -e "  ==============" > /dev/lcd
   killall jslaunch
   sleep 4
   /usr/local/jslaunch-2.0/jslaunch  -r 1 "killall own && /usr/local/etc/display/menu1"\ 
   -r 3 "killall own && /usr/local/etc/display/reboot"\ 
   -r 4 "killall own && /usr/local/etc/display/menu1"\ 
   -r 2 "killall own && /usr/local/etc/display/menu1"&
   #The buttons 1,2 and 4 start the menu
   #button 3 reboots the computer
   echo -n -e "\33c" > /dev/lcd
   while true; do
    echo -n -e "\33c" 
    echo -n -e "\33h"
   #The following lines collect information about the PC and show these
   #on the LCD step by step
   #-- Number of the apache users
   export WEB=$(apachectl status | grep reques | cut -d " " -f 4) .
   #-- Number of the ftp users
   export FTP=$(ftpcount | grep local | cut -d " " -f 22)
   #-- Size of the free memory
   export MEM=$(cat /proc/meminfo |fgrep "MemFree"|cut -b 13-24)
   #-- Uptime of the PC
   export UPT=$(uptime | cut -d "," -f 1)
   #-- Number of the users logged in
   export USER=$(uptime | cut -d "," -f 2)
   #-- CPU usage
   export LOAD=$(cat /proc/loadavg | cut -d " " -f 1)
   #-- The following lines display the information about a 
   #   few mounted devices
   #   (Zip-drive, cdrom, local-partition...)
   export ZIP=$(df | grep "zip" | cut -d "%" -f 2,2)
   export LOCAL=$(df | grep "local" | cut -d "%" -f 2,2)
   export CDROM=$(df | grep "cdrom" | cut -d "%" -f 2,2)
   export ZIP_P=$(df | grep "zip" | cut -b 50-53)
   export LOCAL_P=$(df | grep "local" | cut -b 50-53)
   export CDROM_P=$(df | grep "cdrom" | cut -b 50-53)
   # ***** SCREEN 1 *******
   # Here the collected information is shown
   # Uptime, Memory, HTTP/FTP-User and Load
     echo -e $UPT
     echo -e "MEM "$MEM
     echo -e "HTTP "$WEB" --  FTP" $FTP" "
     echo -e  $USER " load:" $LOAD
     sleep $SLEEP
     # The sleeping time sets how log the info is shown
   # ***** SCREEN 2 *******
   # List of the mounted devices
     echo -n -e "\33c"
    echo -n -e "\33h"
    echo -e  $ZIP_P $ZIP
    echo -e  $LOCAL_P $LOCAL
    echo -e  $CDROM_P $CDROM
    sleep $SLEEP
   # ***** SCREEN 3 *******
   # List of all entries in the printer spool
    echo -n -e "\33c"
    echo -n -e "\33h"
    export DRUCK=$(lpq | grep bytes | cut -b 8-18 | tail -n 6)
    echo -e "printer queue:"
    echo -e $DRUCK
    sleep $SLEEP
   # ***** SCREEN 4 *******
   # Some information about the network device
    echo -n -e "\33c"
    echo -n -e "\33h"
   export ETH_R=$(cat /proc/net/dev | grep eth0 | cut -b 8-14)
   export ETH_S=$(cat /proc/net/dev | grep eth0 | cut -b 36-43)
   export IPP_R=$(cat /proc/net/dev | grep ippp0 | cut -b 8-14)
   export IPP_S=$(cat /proc/net/dev | grep ippp0 | cut -b 36-43)
   export IPP_E=$(cat /proc/net/dev | grep ippp0 | cut -b 44-48)
   export ETH_E=$(cat /proc/net/dev | grep eth0 | cut -b 44-48)
     echo -e "      eth0   ippp0"
     echo -e "rec " $ETH_R" "$IPP_R
     echo -e "sen " $ETH_S" "$IPP_S
     echo -e "err      " $ETH_E"    "$IPP_E
    sleep $SLEEP
   done > /dev/lcd

The scripts are very simple. The required information is shown with a small command and can be obtained with the tools "grep" and "cut". On different distributions, this can cause a few problems because the format of the output of the programs can be different and so the specified columns in the cut command can be incorrect.
If the specific information did not appear on the display, you should check the commands by hand and determine the appropriate values.

The information is written in to a variable (e.g. $ETH_E for the number of all received corrupt packages of the network device) and then printed via echo.
Instead of this, you could use another program, too: e.g. procload.

As you can see in line 18, the menu (own) would be killed if you pressed the buttons 1,2 and 4 and the corresponding menu (here it is menu 1 for all) would be started.
The following script has to be placed in the directory /usr/local/etc/display, too, and needs to be an executable.
The file could look like:

File /usr/local/etc/display/menu1
   #  First you have to stop the old jslaunch because it still owns the
   #  old configuration
   killall jslaunch
   #  If the previous menu stayed in the sleep modus it has to be 
   #  stopped, too.
   killall sleep
   #  This sleeping time is necessary because the user needs enough 
   #  time to release the button. Otherwise jslaunch does not 
   #  start again.
   echo -n -e "\33c" > /dev/lcd
   echo -n -e "\33h" > /dev/lcd
   echo -e "    " > /dev/lcd
   echo -e "  Please wait..." >/dev/lcd
   echo -e "  ==============" > /dev/lcd
   sleep 4
   #  Here some information which button has which option
   export VERZ=/usr/local/etc/display 
   echo -n -e "\33c" > /dev/lcd
   echo -n -e "\33h" > /dev/lcd
   echo "   --== Menu ==--" > /dev/lcd
   echo " 1 mount zip module" > /dev/lcd
   echo " 2 unmount zip module" > /dev/lcd
   echo " 3 next" > /dev/lcd
   #  Now it starts jslaunch with the new options
   #  1 == mount Zip 
   #  2 == unmount Zip
   #  3 == e.g. menu, to mount a CD Rom -- the line is
   #       not active
   #  4 == Reboot
    -r 1 "killall menu1 && /usr/local/etc/display/zip_on"\ 
    -r 3 "killall menu1 && /usr/local/etc/display/reboot"\ 
   #  -r 4 "killall menu1 && /usr/local/etc/display/cdrom"\ 
    -r 2 "killall menu1 && /usr/local/etc/display/zip_off" &
   # After 15 seconds the menu would go back to the main menu if 
   # no button was pressed.
   sleep 15

The script to reboot looks like the following (also here you could add a security question like "Really reboot?").

File /usr/local/etc/display/reboot
   killall jslaunch
   killall sleep
   echo -n -e "\33c" > /dev/lcd
   echo -n -e "\33h" > /dev/lcd
   echo -e "    " > /dev/lcd
   echo -e "  Reboot now ..." >/dev/lcd
   echo -e "  ==============" > /dev/lcd
   echo -e " See you soon ;-) "> /dev/lcd
   sleep 4

In menu1 we commented out button 3 because it should now be clear how you could create your scripts. With button 3, you could got to an additional menu where you would be able to mount or unmount the CD-ROM drive, for example.
But any other display could be made, like special status reports.
Every menu has to be placed in a new script file in the directory /usr/local/etc/display/, that has to be constructed like:

Basic structure
   killall jslaunch
   killall sleep
   echo -n -e "\33c" > /dev/lcd
   echo -n -e "\33h" > /dev/lcd
   echo -e "    " > /dev/lcd
   echo -e "  Please wait ..." >/dev/lcd
   echo -e "  ==============" > /dev/lcd
   sleep 4
   #  Here a few information about the commands that are executed after
   #  pressing a button
   export VERZ=/usr/local/etc/display 
   echo -n -e "\33c" > /dev/lcd
   echo -n -e "\33h" > /dev/lcd
   echo "   --== Menu ==--" > /dev/lcd
   echo " 1 Button 1 does..." > /dev/lcd
   echo " 2 Button 2 does..." > /dev/lcd
   echo " 3 next" > /dev/lcd
   #  Every button gets a command or menu
    -r 1 "killall this_menu && /usr/local/etc/display/Script1"\ 
    -r 3 "killall this_menu && /usr/local/etc/display/Script2"\ 
   #  -r 4 "killall this_menu && /usr/local/etc/display/Script3"\ 
    -r 2 "killall this_menu && /usr/local/etc/display/Script4" &
   sleep 15

Using this method you can build your own menu structure without any big effort or great knowledge in any programming language.

start it automatically

The LCD display is ideal for a PC without any monitor or keyboard, but without those the menu has to be started automatically while booting.

Two options exist to accomplish this. Either you add the command that starts the service into the boot.local (placed at /sbin/init.d), or you write a short init script and place this at /sbin/init.d (SuSE) or /etc/rc.d/init.d (RedHat).

The commands that have to be executed start the LCD module and then start the menu script:

  /sbin/insmod lcd
  sleep 2
  /usr/local/etc/display/own &
If you did not copy the LCD module into a subdirectory of /lib/modules (see above) you would have to specify the full path instead.

So, there it is. The LCD should work and if you wanted to see how it looks in the final state, look at this picture:

Self made LCD setup

http://www.home.unix-ag.org/nils/lcd.html Homepage of the program lcd
http://www.linux-magazin.de/ausgabe/1999/08/LCD/lcd.html lcd programmer`s article in the German Linux Magazine
ftp://sunsite.org.uk/Mirrors/contrib.redhat.com/libc6/i386/ Sorry but jslaunch does not have a homepage of its own
http://lcdproc.omnipotent.net/ Drivers for several displays connected to the serial port
http://www.mv.com/ipusers/cdwalker/lpt_driver.html Drivers for several displays connected to the parallel port

Talkback Area

Enter Own Comment