Hitachi HD44780
LCD Display Driver
for Linux

Készítette: Szendrei Rudolf

Driver - verzió 1.00, kiadás dátuma 2007. Október 30.


Ez a driver csak 2 soros HD44780 chip kompatibilis vezérlővel szerelt LCD képernyőkkel működik együtt.

A driver egy EW162G0 típusú LCD kijelzővel lett tesztelve.

A driverrel kapcsolatos bugokat és kéréseket a következő címre írjátok: swap@inf.elte.hu

A teljes driver csomag, beleértve a forrásokat, binárisokat, stb.: >> AKTUÁLIS VERZIÓJA LETÖLTHETŐ ITT <<

!!! DRIVER HASZNÁLAT !!!


  • Töltsd le a driver-t
  • Csomagold ki az mc (midnight commander) vagy a tar program segítségével
  • Ha használat előtt újra akarod fordítani, akkor
    • Telepítsd fel a gcc-t
    • Bizonyosodj meg róla, hogy a kernel verziódnak megfelelő kernel header csomagot telepítetted
    • Futtasd a make parancsot: make
    • Ha sikeres volt a make futása, akkor a következő kernel modul fájlt kell kapnod: hd44780.ko
  • Driver installálása: ./install_hd44780_device install
    Ha mindent jól csináltál, akkor a következő jelenik meg az LCD kijelzőn:

    HD44780 Driver Loaded! :)

  • Driver eltávolítása: ./install_hd44780_device remove
    Ha sikeres az driver eltávolítása, akkor az LCD törli a képernyőtartalmát.

  • A driver tesztelése: cat > /dev/hd44780_lcd

    Bármit beírhatsz szövegnek.

    ENTER hatására az LCD kurzorja a 2. sor elejére ugrik,
    TAB hatására az képernyő törlődik és a kurzor visszaugrik az 1. sor elejére.

  • Egyszerűen használhatod a driver fájlt /dev/hd44780_lcd, mint bármely hagyományos fájlt.

  • MEGJEGYZÉS: A driver kölcsönös kizárást használ! Egyszerre csak egy alkalmazás tudja az LCD-t használni. A Driver az első open() kivételével nem enged további fájlmegnyitást mindaddig, amíg nem zárjuk le a fájlt close() művelettel.

hd44780.h - fejlécállomány (a chip-et vezérlő függvények)

Alapértékek, Include-ok, Függvény prototípusok


#define LCD_INSTRUCTION 0 #define LCD_DATA 1 #define LCD_WRITE 0 #define LCD_READ 1 #define WAIT_TIME 10 #include < asm/io.h > #include < linux/delay.h > void lcd_send_4_bits(char, char, int); void lcd_send_byte(char, char, int); void lcd_clear(void); void lcd_putc(char); void lcd_write(const char*, int); void lcd_gohome(void); void lcd_gotoxy(int, int); void lcd_setcharpattern(char, const char*); void lcd_init(void);

4-bites alacsony szintű adatátvitel


void lcd_send_4_bits(char c, char rs, int Wait) { c = c << 4; outb((c | 0x04) | rs, LPT_PORT); // ENABLE (Prepare) outb((c & 0xf0) | rs, LPT_PORT); // DISABLE (Transmit) mdelay(Wait); }

A 8-bites üzemmódú adatátvitel emulálása 4-bites módban


void lcd_send_byte(char c, char rs, int Wait) { lcd_send_4_bits( (c >> 4), rs, Wait ); lcd_send_4_bits( (c & 15), rs, Wait ); }

Egyszerű műveletek: képernyő törlése, karakter kiírása, kurzor pozicionálása


void lcd_clear() { lcd_send_byte( 0x01, LCD_INSTRUCTION, 5 ); } void lcd_putc(char c) { lcd_send_byte( c, LCD_DATA, 1 ); } void lcd_gohome() { lcd_send_byte( 0x02, LCD_INSTRUCTION, 5 ); } void lcd_gotoxy(int x = 0, int y = 0) { char c = 0x80 | (x & 0x3f) | (y << 6); lcd_send_byte( c, LCD_INSTRUCTION, 1); }

Függvény a karakterek bittérképének átdefiniálására


void lcd_setcharpattern(char c_pos, char* pattern) { char c = 0x40 | ((c_pos & 0x3f) << 3); // SELECT CGRAM ADDRESS lcd_send_byte( c, LCD_INSTRUCTION, 1); // UPLOAD FONT PATTERN lcd_send_byte( pattern[0], LCD_DATA, 1 ); lcd_send_byte( pattern[1], LCD_DATA, 1 ); lcd_send_byte( pattern[2], LCD_DATA, 1 ); lcd_send_byte( pattern[3], LCD_DATA, 1 ); lcd_send_byte( pattern[4], LCD_DATA, 1 ); lcd_send_byte( pattern[5], LCD_DATA, 1 ); lcd_send_byte( pattern[6], LCD_DATA, 1 ); lcd_send_byte( pattern[7], LCD_DATA, 1 ); }

A képernyő inicializálása


void lcd_init(void) { int i; char init[10]; init[0] = 0x03; // INIT init[1] = 0x02; init[2] = 0x08; init[3] = 0x0C; // DISPLAY ON init[4] = 0x06; // ENTRY MODE SET outb(0, LPT_PORT); // FUNCTION SET 4 BIT INIT for (i = 0; i < 3; i++) lcd_send_4_bits( init[0], LCD_INSTRUCTION, 20 ); // FUNCTION SET 4 BIT INIT for (i = 0; i < 2; i++) lcd_send_4_bits( init[1], LCD_INSTRUCTION, 20 ); // LINES 2, 5x8 FONT lcd_send_4_bits( init[2], LCD_INSTRUCTION, 20 ); // DISPLAY ON lcd_send_byte( init[3], LCD_INSTRUCTION, 10 ); // DISPLAY CLEAR lcd_clear(); // ENTRY MODE SET lcd_send_byte( init[4], LCD_INSTRUCTION, 5 ); }

Example 1. Szöveg kiírása az LCD képernyőre (a driver-ben)


char str[] = {"Testing 1,2,3 " "It' Works ! "}; int len = strlen(str); for(int j = 0; j < len; j++) lcd_putc(str[j]); Mint látható, minden sorhoz 40 bájtnyi RAM tartozik, noha csak 16 karakter látható. Ennek két oka van: az egyik, hogy gördíteni tudjuk a szöveget a képernyőn anélkül, hogy újra kéne írnunk a memória tartalmát, másrészt nagyobb kijelzőkhöz is használható a gyártáskor ugyanaz a chip.

Example 2. Kurzor pozicionálása a 2. sor 10. helyére (a driver-ben)


lcd_gotoxy(10,1);

Example 3. Az ASCII 2-es karakter megjelenésének átdefiniálása és megjelenítése a kijelzőn (a driver-ben)


char pattern_temp[] = { 0x0F, 0x0C, 0x0F, 0x0C, \ 0x0E, 0x11, 0x1F, 0x0E }; lcd_setcharpattern(2, (char*)pattern_temp); lcd_putc(2); Ez a példa jól mutatja, hogy minden karakter 8 sorból áll, és minden sort egy-egy bájt ábrázol, de mivel egy karakter csak 5 pixel széles, ezért csak az alsó 5 bitet használjuk az adott sor bájtjából.


hd44780.c - modul forrása

Includ-ok, Licensz beállítása a kernel számára, Változók deklarációja


#include < linux/kernel.h > #include < linux/module.h > #include < linux/init.h > #include < linux/tty.h > #include < linux/ioport.h > #include < linux/fs.h > #include < asm/uaccess.h > #include < linux/cdev.h > MODULE_LICENSE("GPL"); #define DEVNAME "HD44780_LCD" static char msg[200]; static dev_t dev; static struct cdev my_cdev; static int DevMajor; static int isOpened = 0; static int LPT_PORT = 0x378; /* LOOKING FOR COMMAND LINE ARGUMENTS */ module_param(LPT_PORT, int, 0);

LCD core driver include-ja, Függvény prototípusok


/* INCLUDE THE DRIVER CORE */ #include "hd44780.h" /* FUNCTION PROTOTYPES */ int print_msg(char*); static int device_open(struct inode*, struct file*); static int device_release(struct inode*, struct file*); static ssize_t device_write(struct file*, const char*, size_t, loff_t*);

A karakteres device létrehozásához szükséges adatok és függvények definiálása


/* FILE OPERATION STRUCT TO REGISTER CHARACTER DEVICE */ static struct file_operations fops = { .write = device_write, .open = device_open, .release = device_release, .owner = THIS_MODULE }; /* DEVICE OPERATIONS */ static int device_open(struct inode* in, struct file* f) { if (isOpened) return -EBUSY; isOpened = 1; return 0; } static int device_release(struct inode* in, struct file* f) { isOpened = 0; return 0; } static ssize_t device_write(struct file* f, const char* buf, \ size_t len, loff_t* off) { int i; for (i = 0; i < len; ++i) { switch(buf[i]) { case 9: lcd_clear(); break; case 10: case 13: lcd_gotoxy(0,1); break; default: lcd_putc(buf[i]); } } return len; } Fontos, hogy a hd44780.h include-ját megelőzze az LPT_PORT változó deklarálása, ezért ezek nem felcserélhetőek.

Helper függvény az aktuáls tty konzolra való íráshoz


/* HELPER FUNCTION TO DEBUG MESSAGES TO CONSOLE*/ int print_msg(char* str) { struct tty_struct *driver_tty = current->signal->tty; if (!driver_tty) return -ENOTTY; (driver_tty->driver->write)(driver_tty, str, strlen(str)); return 0; }

Module Inicializálás és Felszabadítás


/* MODULE INITIALISATION */ int LCD_driver_init(void) { int res; res = alloc_chrdev_region(&dev, 0, 1, DEVNAME); if (res < 0) return res; DevMajor = MAJOR(dev); cdev_init(&my_cdev, &fops); my_cdev.owner = THIS_MODULE; res = cdev_add(&my_cdev, dev, 1); if (res < 0) { unregister_chrdev_region(dev, 1); return res; } // INIT LCD lcd_init(); lcd_write("HD44780 Driver", 14); lcd_gotoxy(0,1); lcd_write("Loaded!", 7); print_msg("HD44780 LCD Driver loaded.\n\r"); sprintf(msg, "Major number: %d.\n\r", DevMajor); print_msg(msg); return 0; } /* MODULE EXIT */ void LCD_driver_exit(void) { lcd_clear(); cdev_del(&my_cdev); unregister_chrdev_region(dev, 1); sprintf(msg, "HD44780 LCD Driver unloaded.\n\r"); print_msg(msg); } module_init(LCD_driver_init); module_exit(LCD_driver_exit);


Makefile - Kernel > 2.6.00 verzióhoz


ifneq ($(KERNELRELEASE),) obj-m := hd44780.o else KDIR := /lib/modules/`uname -r`/build PWD := $(shell pwd) default: $(MAKE) -C $(KDIR) M=$(PWD) modules endif clean: @rm -rf *~ *.o *.mod.c .*.cmd .tmp_versions


install_44780_device - Driver telepítő / eltávolító szkript


#!/bin/bash module="hd44780" devname="HD44780_LCD" device="hd44780_lcd" if [ "$1" = "install" ] then echo "Installing..."; shift; insmod ./$module.ko $* major=`awk "\\$2==\"$devname\" {print \\$1}" /proc/devices` echo "Device major = $major" mknod /dev/$device c $major 0 elif [ "$1" = "remove" ] then echo "Removing..."; rm /dev/$device rmmod $module else echo "To install driver: ./$0 install"; echo "To remove driver: ./$0 remove"; fi