/* * Serial LPT driver module for Hitachi HD44780 based LCD displays by * Andrew McMeikan. The LCD is operated in it's 4 bit-mode through a * 4094 shift register and supports a keypad. * * Copyright (c) 1999 Andrew McMeikan * modular driver 1999 Benjamin Tse * * Full connection details at http://members.xoom.com/andrewmuck/LCD.htm * * printer port 4094/LCD * D2 (4) EN (6 - LCD) * D3 (5) D (2 - 4094) * D4 (6) CLK (3 - 4094) * +Vcc OE, STR (15, 1 - 4094) * D7 (9) EN2 (6 - LCD2) (optional) * * 4094 LCD * Q1 (4) D4 (11) * Q2 (5) D5 (12) * Q3 (6) D6 (13) * Q4 (7) D7 (14) * Q6 (13) RS (4) * Gnd nRW (5) * * This file is released under the GNU General Public License. Refer to the * COPYING file distributed with this package. */ #include "hd44780-serialLpt.h" #include "port.h" // Hardware specific functions void lcdserLpt_HD44780_senddata(unsigned char displayID, unsigned char flags, unsigned char ch); static char lcdserLpt_HD44780_getkey(void); void rawshift(unsigned char r); void shiftreg(unsigned char displayID, unsigned char r); #define RS 16 #define LCDDATA 8 #define LCDCLOCK 16 #define EN1 4 #define EN2 32 static unsigned int lp; static char lastkey=0; // Initialisation int hd_init_serialLpt(HD44780_functions *hd44780_functions, lcd_logical_driver *driver, char *args, unsigned int port) { int displayID = EN1 | EN2; lp = port; hd44780_functions->senddata = lcdserLpt_HD44780_senddata; // TODO: enable keypad only if specified on command line driver->getkey = lcdserLpt_HD44780_getkey; // setup the lcd in 4 bit mode shiftreg(displayID,3); hd44780_functions->uPause(4100); shiftreg(displayID,3); hd44780_functions->uPause(100); shiftreg(displayID,3); hd44780_functions->uPause(40); shiftreg(displayID,2); hd44780_functions->uPause(40); // set display type functions lcdserLpt_HD44780_senddata(0, RS_INSTR, FUNCSET | IF_4BIT | TWOLINE | SMALLCHAR); // clear lcdserLpt_HD44780_senddata(0, RS_INSTR, CLEAR); hd44780_functions->uPause(1600); // Now turn on the display lcdserLpt_HD44780_senddata(displayID, RS_INSTR, ONOFFCTRL | DISPON | CURSOROFF | CURSORNOBLINK); hd44780_functions->uPause(1600); return 0; } void lcdserLpt_HD44780_senddata(unsigned char displayID, unsigned char flags, unsigned char ch) { unsigned char dispID = 0, portControl = 0, h = ch >> 4, l = ch & 15; if (displayID == 1) dispID |= EN1; else if (displayID == 2) dispID |= EN2; else dispID |= EN1 | EN2; if (flags == RS_DATA) portControl = RS; else portControl = 0; shiftreg(displayID,flags | portControl | h); shiftreg(displayID,flags | portControl | l); /* TODO: instead of delay read keys here */ } char lcdserLpt_HD44780_getkey() { // TODO: a keypad scan that does not use shift register // define a key table char keytr[]="ABCDEFGH"; int n; rawshift(0); //send all line on shift register low hd44780_functions->uPause(1); if ((port_in(lp+1)&32)==0) //test if line back is low - if not return(0) { //else //start walking a single zero across the eight lines for(n=7;n>=0;n--) { rawshift(255 - (1<uPause(1); if ((port_in(lp+1)&32)==0) // check if line back is low if yes debounce { if (lastkey==keytr[n]) return(0); // printf("key is %c %d\n",keytr[n],n); lastkey=keytr[n]; return(keytr[n]); //return correct key code. } } } //else fall out and return(0) [too transient a keypress] lastkey=0; return(0); } /* this function sends r out onto the shift register */ void rawshift (unsigned char r) { int i; for (i=7;i>=0;i--) /* MSB first */ { port_out(lp,((r>>i)&1)*LCDDATA); /*set up data */ port_out(lp,(((r>>i)&1)*LCDDATA)|LCDCLOCK);/*rising edge of clock */ } } // displayID = value on parallel port to toggle the correct display void shiftreg (unsigned char displayID, unsigned char r) { rawshift(r); port_out(lp,displayID); //latch it, to correct display port_out(lp,0); }