HD44780 update:

- supports new API
- major clean up, more consistent code
- uses configfile options
- serialLpt works also with only 2 output lines
- serialLpt can now use keypad
This commit is contained in:
robijn
2001-11-01 00:37:12 +00:00
parent 0619f03774
commit faa4861eb3
9 changed files with 786 additions and 494 deletions
+62 -49
View File
@@ -20,7 +20,11 @@
* D6 (8) EN (6)
* D7 (9) EN2 (LCD2 - 6) (optional)
*
* Backlight
* D5 (7) backlight (optional, see documentation)
*
* Extended interface (including LCD3 above)
* D5 (7) EN3
* STR (1) EN4
* LF (14) EN5
* INIT (16) EN6
@@ -66,34 +70,37 @@
#include <errno.h>
// Generally, any function that accesses the LCD control lines needs to be
// implemented separately for each HW design. This is typically just
// HD44780_senddata and HD44780_readkeypad
// implemented separately for each HW design. This is typically (but not
// restricted to):
// HD44780_senddata
// HD44780_readkeypad
void lcdstat_HD44780_senddata (unsigned char displayID, unsigned char flags, unsigned char ch);
void lcdstat_HD44780_backlight (unsigned char state);
unsigned char lcdstat_HD44780_readkeypad (unsigned int YData);
#define RS 0x10
#define RW 0x20
#define EN1 0x40
#define EN2 0x80
#define EN3 0x20
#define RS 0x10
#define RW 0x20
#define EN1 0x40
#define EN2 0x80
#define EN3 0x20
#define BL 0x20
// note that the above bits are all meant for the data port of LPT
static unsigned char EnMask[] = { EN1, EN2, EN3, STRB, LF, INIT, SEL };
static int EnMaskSize = sizeof (EnMask) / sizeof (unsigned char);
static int extIF = 0; // non-zero if extended interface
#define ALLEXT (STRB|LF|INIT|SEL)
// The above bits are on the control port of LPT
static unsigned int lptPort;
static char stuckinputs = 0; // if an input line is stuck, it will be ignored
static char stuckinputs = 0; // if an input line is stuck, it will be ignored
static char backlight_bit = 0; // default to low to enable three displays
// initialisation function
int
hd_init_4bit (HD44780_functions * hd44780_functions, lcd_logical_driver * driver, char *args, unsigned int port)
{
// TODO: remove magic numbers below
char *argv[64];
int argc;
int i;
int displayID = EN1 | EN2;
int enableLines = EN1 | EN2;
// Reserve the port registers
lptPort = port;
@@ -102,44 +109,36 @@ hd_init_4bit (HD44780_functions * hd44780_functions, lcd_logical_driver * driver
port_access(lptPort+2);
hd44780_functions->senddata = lcdstat_HD44780_senddata;
hd44780_functions->backlight = lcdstat_HD44780_backlight;
hd44780_functions->readkeypad = lcdstat_HD44780_readkeypad;
// parse command-line arguments
argc = get_args (argv, args, 64);
for (i = 0; i < argc; ++i) {
if (strcmp (argv[i], "-e") == 0 || strcmp (argv[i], "--extended") == 0) {
extIF = 1;
}
}
// powerup the lcd now
if (extIF) {
displayID |= EN3;
enableLines |= EN3;
port_out (lptPort + 2, 0 ^ OUTMASK);
}
port_out (lptPort, displayID | 0x03);
port_out (lptPort, enableLines | 0x03);
if (extIF)
port_out (lptPort + 2, (EnMask[3] | EnMask[4] | EnMask[5] | EnMask[6]) ^ OUTMASK);
port_out (lptPort + 2, ALLEXT ^ OUTMASK);
hd44780_functions->uPause (1);
port_out (lptPort, 0x03);
if (extIF)
port_out (lptPort + 2, 0 ^ OUTMASK);
hd44780_functions->uPause (4100);
port_out (lptPort, displayID | 0x03);
port_out (lptPort, enableLines | 0x03);
if (extIF)
port_out (lptPort + 2, (EnMask[3] | EnMask[4] | EnMask[5] | EnMask[6]) ^ OUTMASK);
port_out (lptPort + 2, ALLEXT ^ OUTMASK);
hd44780_functions->uPause (1);
port_out (lptPort, 0x03);
if (extIF)
port_out (lptPort + 2, 0 ^ OUTMASK);
hd44780_functions->uPause (100);
port_out (lptPort, displayID | 0x03);
port_out (lptPort, enableLines | 0x03);
if (extIF)
port_out (lptPort + 2, (EnMask[3] | EnMask[4] | EnMask[5] | EnMask[6]) ^ OUTMASK);
port_out (lptPort + 2, ALLEXT ^ OUTMASK);
hd44780_functions->uPause (1);
port_out (lptPort, 0x03);
if (extIF)
@@ -147,9 +146,9 @@ hd_init_4bit (HD44780_functions * hd44780_functions, lcd_logical_driver * driver
hd44780_functions->uPause (40);
// now in 8-bit mode... set 4-bit mode
port_out (lptPort, displayID | 0x02);
port_out (lptPort, enableLines | 0x02);
if (extIF)
port_out (lptPort + 2, (EnMask[3] | EnMask[4] | EnMask[5] | EnMask[6]) ^ OUTMASK);
port_out (lptPort + 2, ALLEXT ^ OUTMASK);
hd44780_functions->uPause (1);
port_out (lptPort, 0x02);
if (extIF)
@@ -168,16 +167,18 @@ hd_init_4bit (HD44780_functions * hd44780_functions, lcd_logical_driver * driver
// lcdstat_HD44780_senddata
void
lcdstat_HD44780_senddata (unsigned char displayID, unsigned char iflags, unsigned char ch)
lcdstat_HD44780_senddata (unsigned char displayID, unsigned char flags, unsigned char ch)
{
unsigned char enableLines = 0, flags = 0;
unsigned char enableLines = 0, portControl = 0;
unsigned char h = (ch >> 4) & 0x0f; // high and low nibbles
unsigned char l = ch & 0x0f;
if (iflags == RS_INSTR)
flags = 0;
else //if (iflags == RS_DATA)
flags = RS;
if (flags == RS_INSTR)
portControl = 0;
else //if (flags == RS_DATA)
portControl = RS;
portControl |= backlight_bit;
if (displayID <= 3) {
if (displayID == 0)
@@ -185,36 +186,43 @@ lcdstat_HD44780_senddata (unsigned char displayID, unsigned char iflags, unsigne
else
enableLines = EnMask[displayID - 1];
port_out (lptPort, flags | h);
port_out (lptPort, portControl | h);
hd44780_functions->uPause (2);
port_out (lptPort, enableLines | flags | h);
port_out (lptPort, enableLines | portControl | h);
hd44780_functions->uPause (4);
port_out (lptPort, flags | h);
port_out (lptPort, portControl | h);
port_out (lptPort, enableLines | flags | l);
port_out (lptPort, enableLines | portControl | l);
hd44780_functions->uPause (4);
port_out (lptPort, flags | l);
port_out (lptPort, portControl | l);
}
if (extIF && (displayID == 0 || displayID >= 4)) {
if (displayID == 0)
enableLines = EnMask[3] | EnMask[4] | EnMask[5] | EnMask[6];
enableLines = ALLEXT;
else
enableLines = EnMask[(displayID - 1) % EnMaskSize];
enableLines = EnMask[(displayID - 1)];
port_out (lptPort, flags | h);
port_out (lptPort, portControl | h);
hd44780_functions->uPause (2);
port_out (lptPort + 2, enableLines ^ OUTMASK);
hd44780_functions->uPause (4);
port_out (lptPort + 2, 0 ^ OUTMASK);
port_out (lptPort, flags | l);
port_out (lptPort, portControl | l);
port_out (lptPort + 2, enableLines ^ OUTMASK);
hd44780_functions->uPause (4);
port_out (lptPort + 2, 0 ^ OUTMASK);
}
}
void lcdstat_HD44780_backlight (unsigned char state)
{
backlight_bit = (state?0:0x20); // D5 line
port_out (lptPort, backlight_bit);
}
unsigned char lcdstat_HD44780_readkeypad (unsigned int YData)
{
unsigned char readval;
@@ -226,7 +234,12 @@ unsigned char lcdstat_HD44780_readkeypad (unsigned int YData)
port_out (lptPort + 2, ( ((~YData & 0x03C0) << 6 )) ^ OUTMASK);
}
// And convert it back.
// Read inputs
readval = ~ port_in (lptPort + 1) ^ INMASK;
// Put port back into idle state for backlight
port_out (lptPort, backlight_bit ^ OUTMASK);
// And convert value back.
return ( (readval >> 4 & 0x03) | (readval >> 5 & 0x04) | (readval >> 3 & 0x08) | (readval << 1 & 0x10) ) & ~stuckinputs;
}
+46 -24
View File
@@ -16,11 +16,13 @@
* D5 (7) D5 (12)
* D6 (8) D6 (13)
* D7 (9) D7 (14)
* nSEL (17) -
* nSTRB (1) RS (4)
* nLF (14) RW (5) (LCD2 - 6) (optional - pull all LCD RW low)
* INIT (16) EN (6)
*
* Backlight
* SEL (17) backlight (optional, see documentation)
*
* Keypad connection (optional):
* Some diodes and resistors are needed, see further documentation.
* printer port keypad
@@ -65,20 +67,17 @@
// HD44780_readkeypad
void lcdtime_HD44780_senddata (unsigned char displayID, unsigned char flags, unsigned char ch);
void lcdtime_HD44780_backlight (unsigned char state);
unsigned char lcdtime_HD44780_readkeypad (unsigned int YData);
#define nRS nSTRB
#define nRW nLF
#define EN1 INIT
#define METER_OFF nSEL
#define RS STRB
#define RW LF
#define EN1 INIT
#define BL SEL
#define SETUPLCD (METER_OFF | nRS)
#define CTRL (nRW | METER_OFF | nRS)
#define CHAR (nRW | METER_OFF)
static int extIF = 0; // non-zero if extended interface
static unsigned int lptPort;
static char stuckinputs = 0; // if an input line is stuck, it will be ignored
static char stuckinputs = 0; // if an input line is stuck, it will be ignored
static char backlight_bit = 0;
static int semid;
@@ -95,6 +94,7 @@ hd_init_ext8bit (HD44780_functions * hd44780_functions, lcd_logical_driver * dri
port_access(lptPort+2);
hd44780_functions->senddata = lcdtime_HD44780_senddata;
hd44780_functions->backlight = lcdtime_HD44780_backlight;
hd44780_functions->readkeypad = lcdtime_HD44780_readkeypad;
// setup the lcd in 8 bit mode
@@ -106,6 +106,11 @@ hd_init_ext8bit (HD44780_functions * hd44780_functions, lcd_logical_driver * dri
hd44780_functions->uPause (40);
common_init ();
if (have_keypad) {
// Remember which input lines are stuck
stuckinputs = lcdtime_HD44780_readkeypad (0);
}
return 0;
}
@@ -113,31 +118,42 @@ hd_init_ext8bit (HD44780_functions * hd44780_functions, lcd_logical_driver * dri
void
lcdtime_HD44780_senddata (unsigned char displayID, unsigned char flags, unsigned char ch)
{
unsigned char dispID = 0, portControl;
unsigned char enableLines = 0, portControl;
if (displayID == 1)
dispID |= EN1;
else //if (displayID == 0)
dispID |= EN1;
// Only one controller is supported
enableLines = EN1;
if (flags == RS_DATA)
portControl = CHAR;
else
portControl = CTRL;
if (flags == RS_INSTR)
portControl = 0;
else //if (iflags == RS_DATA)
portControl = RS;
portControl |= backlight_bit;
sem_wait (semid);
port_out (lptPort + 2, SETUPLCD);
port_out (lptPort + 2, portControl ^ OUTMASK);
port_out (lptPort, ch);
port_out (lptPort + 2, dispID | portControl);
port_out (lptPort + 2, (enableLines|portControl) ^ OUTMASK);
hd44780_functions->uPause (1);
port_out (lptPort + 2, portControl);
port_out (lptPort + 2, portControl ^ OUTMASK);
sem_signal (semid);
}
void lcdtime_HD44780_backlight (unsigned char state)
{
backlight_bit = (state?0:SEL);
// Semaphores not needed because backlight will not go together with
// the bacrgraph anyway...
port_out (lptPort + 2, backlight_bit ^ OUTMASK);
}
unsigned char lcdtime_HD44780_readkeypad (unsigned int YData)
{
unsigned char readval;
sem_wait (semid);
// 10 bits output
// Convert the positive logic to the negative logic on the LPT port
port_out (lptPort, ~YData & 0x00FF );
@@ -145,7 +161,13 @@ unsigned char lcdtime_HD44780_readkeypad (unsigned int YData)
port_out (lptPort + 2, ( ((~YData & 0x0100) >> 8) | ((~YData & 0x0200) >> 6)) ^ OUTMASK);
}
// And convert it back.
// Read inputs
readval = ~ port_in (lptPort + 1) ^ INMASK;
// Put port back into idle state for backlight
port_out (lptPort, backlight_bit ^ OUTMASK);
sem_signal (semid);
// And convert value back.
return ( (readval >> 4 & 0x03) | (readval >> 5 & 0x04) | (readval >> 3 & 0x08) | (readval << 1 & 0x10) ) & ~stuckinputs;
}
+13 -10
View File
@@ -14,26 +14,29 @@ typedef struct hwDependentFns {
// microsec pauses
void (*uPause) (int microSecondsTenths);
// senddata to the LCD
// Senddata to the LCD
// dispID - display to send data to (0 = all displays)
// flags - data or instruction command (RS_DATA | RS_INSTR)
// ch - character to display or instruction value
void (*senddata) (unsigned char dispID, unsigned char flags, unsigned char ch);
// position the cursor
// dispID - display to send data to (0 = all displays)
// DDaddr - display data address (see sect 2.5.2 of the LCD module FAQ)
void (*position) (int dispID, int DDaddr);
// Switch the backlight on or off
// state - to be or not to be on
void (*backlight) (unsigned char state);
// toggle vertical autoscroll on all displays
// on - non-zero turns autoscroll on, zero value turns it off
void (*autoscroll) (int on);
// read the keypad
// Read the keypad
// Ydata - the up to 11 bits that should be put on the Y side of the matrix
// return - the up to 5 bits that are read out on the X side of the matrix
unsigned char (*readkeypad) (unsigned int Ydata);
// Scan the keypad and return a scancode.
// The code is the Yvalue in the high nibble and the Xvalue in the low nibble.
// A subdriver should do only one of two things:
// - set readkeypad; or
// - override scankeypad.
unsigned char (*scankeypad) ();
} HD44780_functions; /* for want of a better name :-) */
extern HD44780_functions *hd44780_functions;
+62 -59
View File
@@ -36,6 +36,7 @@
* Q4 (7) Y3
* Q5 (14) Y4
* Q6 (13) Y5
* Q7 (12) Y6
* The 'output' of the keys should be connected to the following LPT pins:
* nACK (10) X0
* BUSY (11) X1
@@ -59,9 +60,9 @@
// Hardware specific functions
void lcdserLpt_HD44780_senddata (unsigned char displayID, unsigned char flags, unsigned char ch);
unsigned char lcdserLpt_HD44780_readkeypad (unsigned int YData);
void lcdserLpt_HD44780_backlight (unsigned char state);
static char lcdserLpt_HD44780_getkey (void); // old keypad code
unsigned char lcdserLpt_HD44780_scankeypad ();
void rawshift (unsigned char r);
void shiftreg (unsigned char displayID, unsigned char r);
@@ -72,9 +73,6 @@ void shiftreg (unsigned char displayID, unsigned char r);
#define EN2 32
static unsigned int lptPort;
static char stuckinputs = 0; // if an input line is stuck, it will be ignored
static char lastkey = 0; // currently not in use, old keypad code
// Initialisation
int
@@ -89,11 +87,9 @@ hd_init_serialLpt (HD44780_functions * hd44780_functions, lcd_logical_driver * d
port_access(lptPort+2);
hd44780_functions->senddata = lcdserLpt_HD44780_senddata;
hd44780_functions->readkeypad = lcdserLpt_HD44780_readkeypad;
hd44780_functions->backlight = lcdserLpt_HD44780_backlight;
hd44780_functions->scankeypad = lcdserLpt_HD44780_scankeypad;
if (have_keypad) {
driver->getkey = lcdserLpt_HD44780_getkey;
}
// Clear the shiftregister
rawshift (0);
@@ -114,17 +110,6 @@ hd_init_serialLpt (HD44780_functions * hd44780_functions, lcd_logical_driver * d
common_init ();
/*
// 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;
}
@@ -149,47 +134,67 @@ lcdserLpt_HD44780_senddata (unsigned char displayID, unsigned char flags, unsign
shiftreg (enableLines, portControl | h);
shiftreg (enableLines, portControl | l);
/* TODO: instead of delay read keys here */
}
char
lcdserLpt_HD44780_getkey ()
void
lcdserLpt_HD44780_backlight (unsigned char state)
{
// TODO: a keypad scan that does not use shift register
// define a key table
char keytr[] = "ABCDEFGH";
int n;
}
// disabled now !
return 0;
unsigned char lcdserLpt_HD44780_scankeypad ()
{
// Unfortunately just bit shifting does not work with the 2 IC version...
rawshift (0); //send all line on shift register low
hd44780_functions->uPause (1);
if ((port_in (lptPort + 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 << n));
hd44780_functions->uPause (1);
unsigned char keybits;
unsigned int shiftcount;
unsigned int shiftingbit;
unsigned char readval, inputs_zero, r;
int i;
unsigned int scancode = 0;
if ((port_in (lptPort + 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.
r = 0xFF; // This command will set the cursor position, so it's harmless
readval = ~ port_in (lptPort + 1) ^ INMASK;
inputs_zero = ( (readval >> 4 & 0x03) | (readval >> 5 & 0x04) | (readval >> 3 & 0x08) | (readval << 1 & 0x10) );
if( inputs_zero == 0 ) {
return 0;
}
// Scan the keypad while sending the first half of the command (high nibble)
for (i = 7; i >= 0; i--) { /* MSB first */
port_out (lptPort, ((r >> i) & 1) * LCDDATA); /*set up data */
port_out (lptPort, (((r >> i) & 1) * LCDDATA) | LCDCLOCK); /*rising edge of clock */
hd44780_functions->uPause (2);
// Do keyscan too !
if( !scancode ) {
// Read input line(s)
readval = ~ port_in (lptPort + 1) ^ INMASK;
keybits = ( (readval >> 4 & 0x03) | (readval >> 5 & 0x04) | (readval >> 3 & 0x08) | (readval << 1 & 0x10) );
if( keybits != inputs_zero ) {
shiftingbit = 1;
for (shiftcount=0; shiftcount<KEYPAD_MAXX && !scancode; shiftcount++) {
if ( (keybits ^ inputs_zero ) & shiftingbit) {
// Found !
scancode = ((8-i)<<4) | (shiftcount+1);
}
shiftingbit <<= 1;
}
}
}
} //else fall out and return(0) [too transient a keypress]
lastkey = 0;
return (0);
}
}
unsigned char lcdserLpt_HD44780_readkeypad (unsigned int YData)
{
return 0;
hd44780_functions->uPause (4);
// And again for the second half of the command (low nibble)
rawshift (r);
hd44780_functions->uPause (4);
return scancode;
}
/* this function sends r out onto the shift register */
@@ -197,6 +202,8 @@ void
rawshift (unsigned char r)
{
int i;
// r |= 0x80; // just to make sure ...
for (i = 7; i >= 0; i--) { /* MSB first */
port_out (lptPort, ((r >> i) & 1) * LCDDATA); /*set up data */
port_out (lptPort, (((r >> i) & 1) * LCDDATA) | LCDCLOCK); /*rising edge of clock */
@@ -207,13 +214,9 @@ rawshift (unsigned char r)
void
shiftreg (unsigned char enableLines, unsigned char r)
{
//unsigned char mr;
//mr = (r & 0xF0) | ((r<<3) & 0x0F) | ((r<<1) & 0x04) |
// ((r>>1) & 0x02) | ((r>>3) & 0x01);
rawshift (r | 0x80); // highest bit always set to 1 for Clear
port_out (lptPort, enableLines); //latch it, to correct display
rawshift (r | 0x80); // highest bit always set to 1 for Clear for wiring with 2 ICs
port_out (lptPort, enableLines); // latch it, to correct display
hd44780_functions->uPause (1);
port_out (lptPort, 0);
port_out (lptPort, 0); // for wiring with 1 IC
hd44780_functions->uPause (3);
}
+37 -28
View File
@@ -29,6 +29,9 @@
* INIT (16) RS (4)
* nSEL (17) EN2 (6 - LCD 2) (optional)
*
* Backlight
* SEL (17) backlight (optional, see documentation)
*
* Keypad connection (optional):
* Some diodes and resistors are needed, see further documentation.
* printer port keypad
@@ -64,32 +67,33 @@
#include <string.h>
#include <errno.h>
#include "port.h"
// Generally, any function that accesses the LCD control lines needs to be
// implemented separately for each HW design. This is typically (but not
// restricted to):
// HD44780_senddata
// HD44780_readkeypad
void lcdwinamp_HD44780_senddata (unsigned char displayID, unsigned char flags, unsigned char ch);
void lcdwinamp_HD44780_backlight (unsigned char state);
unsigned char lcdwinamp_HD44780_readkeypad (unsigned int YData);
#define EN1 STRB
#define EN2 SEL
#define EN3 LF
#define RS INIT
#define EN1 STRB
#define EN2 SEL
#define EN3 LF
#define RW LF
#define RS INIT
#define BL SEL
static unsigned char EnMask[] = { EN1, EN2, EN3 };
static int EnMaskSize = sizeof (EnMask) / sizeof (unsigned char);
static int extIF = 0; // non-zero if extended interface
static unsigned int lptPort;
static char stuckinputs = 0; // if an input line is stuck, it will be ignored
static char stuckinputs = 0; // if an input line is stuck, it will be ignored
static char backlight_bit = 0; // default to low to enable two displays
// initialise the driver
int
hd_init_winamp (HD44780_functions * hd44780_functions, lcd_logical_driver * driver, char *args, unsigned int port)
{
// TODO: remove magic numbers below
char *argv[64];
int argc;
int i;
// Reserve the port registers
lptPort = port;
port_access(lptPort);
@@ -97,16 +101,9 @@ hd_init_winamp (HD44780_functions * hd44780_functions, lcd_logical_driver * driv
port_access(lptPort+2);
hd44780_functions->senddata = lcdwinamp_HD44780_senddata;
hd44780_functions->backlight = lcdwinamp_HD44780_backlight;
hd44780_functions->readkeypad = lcdwinamp_HD44780_readkeypad;
// parse command-line arguments
argc = get_args (argv, args, 64);
for (i = 0; i < argc; ++i) {
if (strcmp (argv[i], "-e") == 0 || strcmp (argv[i], "--extended") == 0)
extIF = 1;
}
// setup the lcd in 8 bit mode
hd44780_functions->senddata (0, RS_INSTR, FUNCSET | IF_8BIT);
hd44780_functions->uPause (4100);
@@ -123,7 +120,7 @@ hd_init_winamp (HD44780_functions * hd44780_functions, lcd_logical_driver * driv
void
lcdwinamp_HD44780_senddata (unsigned char displayID, unsigned char flags, unsigned char ch)
{
unsigned char dispID = 0, portControl;
unsigned char enableLines = 0, portControl;
if (flags == RS_DATA)
portControl = RS;
@@ -131,29 +128,36 @@ lcdwinamp_HD44780_senddata (unsigned char displayID, unsigned char flags, unsign
portControl = 0;
if (displayID == 0)
dispID = EnMask[0] | EnMask[1] | ((extIF) ? EnMask[2] : 0);
enableLines = EnMask[0] | EnMask[1] | ((extIF) ? EnMask[2] : 0);
else
dispID = EnMask[displayID - 1];
enableLines = EnMask[displayID - 1];
// 40 nS setup time for RS valid to EN high, so set RS
port_out (lptPort + 2, portControl ^ OUTMASK);
port_out (lptPort + 2, (portControl|backlight_bit) ^ OUTMASK);
// Output the actual data
port_out (lptPort, ch);
// then set EN high
port_out (lptPort + 2, (dispID | portControl) ^ OUTMASK);
port_out (lptPort + 2, (enableLines|portControl|backlight_bit) ^ OUTMASK);
// 80 nS setup from valid data to EN low will be met without any delay
// unless you are running a REALLY FAST ISA bus (like 75 MHZ!)
// 230 nS minimum E high time provided by ISA bus delays as well...
// Set EN low and we're done...
port_out (lptPort + 2, portControl ^ OUTMASK);
port_out (lptPort + 2, (portControl|backlight_bit) ^ OUTMASK);
// 10 nS data hold time provided by the length of ISA write for EN
}
void lcdwinamp_HD44780_backlight (unsigned char state)
{
backlight_bit = (state?0:nSEL);
port_out (lptPort + 2, backlight_bit ^ OUTMASK);
}
unsigned char lcdwinamp_HD44780_readkeypad (unsigned int YData)
{
unsigned char readval;
@@ -163,7 +167,12 @@ unsigned char lcdwinamp_HD44780_readkeypad (unsigned int YData)
port_out (lptPort, ~YData & 0x00FF );
port_out (lptPort + 2, ( ((~YData & 0x0100) >> 7) | ((~YData & 0x0200) >> 7 )) ^ OUTMASK);
// And convert it back.
// Read inputs
readval = ~ port_in (lptPort + 1) ^ INMASK;
// Set output back to idle state for backlight
port_out (lptPort + 2, backlight_bit ^ INMASK );
// And convert value back.
return ( (readval >> 4 & 0x03) | (readval >> 5 & 0x04) | (readval >> 3 & 0x08) | (readval << 1 & 0x10) ) & ~stuckinputs;
}
+323 -282
View File
@@ -25,12 +25,14 @@
* Character mapping for correct display of some special ASCII chars added
* Sep 2001, Mark Haemmerling <mail@markh.de>.
*
* Modified October 2001 to read the configfile.
*
* This file is released under the GNU General Public License. Refer to the
* COPYING file distributed with this package.
*
* Copyright (c) 2000, 1999, 1995 Benjamin Tse <blt@Comports.com>
* 2001 Joris Robijn <joris@robijn.net>
* 2001 Mark Haemmerling <mail@markh.de>
* 2001 Mark Haemmerling <mail@markh.de>
* 2000 Charles Steinkuehler <cstein@newtek.com>
* 1999 Andrew McMeikan <andrewm@engineer.com>
* 1998 Richard Rognlie <rrognlie@gamerz.net>
@@ -48,8 +50,6 @@
#endif
#include "port.h"
#define atest(i)
// Uncomment one of the lines below to select your desired delay generation
// mechanism. If both defines are commented, the original I/O read timing
// loop is used. Using DELAY_NANOSLEEP seems to provide the best performance.
@@ -76,7 +76,7 @@
#endif
#include "shared/str.h"
#include "render.h"
#include "lcd.h"
#include "hd44780.h"
// #include "drv_base.h"
@@ -97,7 +97,7 @@ HD44780_functions *hd44780_functions;
// default value
static enum connectionType connection = HD_4bit;
static int connIdx = 0;
static int connectiontype_index = 0;
// spanList[line number] = display line number is in
static int *spanList = NULL;
@@ -112,15 +112,13 @@ static int numDisplays = 0;
// input span list but is kept to save some cpu cycles.
static int *dispSizes = NULL;
// Keypad option
// Keypad and backlight option
char have_keypad = 0; // off by default
// This var is not static, so it's accessable from all sub-drivers
char have_backlight = 0; // off by default
char extIF = 0; // off by default
// These vars is not static, so it's accessable from all sub-drivers
// Indeed, this should become cleaner... later...
// Maximum sizes of the keypad
// DO NOT CHANGE THESE 2 VALUES, unless you change the functions too
#define KEYPAD_MAXX 5
#define KEYPAD_MAXY 11
// Autorepeat values
#define KEYPAD_AUTOREPEAT_DELAY 500
#define KEYPAD_AUTOREPEAT_FREQ 15
@@ -132,25 +130,28 @@ static char keyMapDirect[KEYPAD_MAXX] = { 'A', 'B', 'C', 'D', 'E' };
// keyMapMatrix contrains an array with arrays of the ascii-codes that should be generated
// when a key in the matrix is pressed.
static char keyMapMatrix[KEYPAD_MAXY][KEYPAD_MAXX] = {
{ '1', '2', '3', 'A', 0 },
{ '4', '5', '6', 'B', 0 },
{ '7', '8', '9', 'C', 0 },
{ '*', '0', '#', 'D', 0 },
{ 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0 }};
{ '1', '2', '3', 'A', 'E' },
{ '4', '5', '6', 'B', 'F' },
{ '7', '8', '9', 'C', 'G' },
{ '*', '0', '#', 'D', 'H' },
{ 'I', 'J', 'K', 'L', 'M' },
{ 'N', 'O', 'P', 'Q', 'R' },
{ 'S', 'T', 'U', 'V', 'W' },
{ 'X', 'Y', 'Z', 'a', 'b' },
{ 'c', 'd', 'e', 'f', 'g' },
{ 'h', 'i', 'j', 'k', 'l' },
{ 'm', 'n', 'o', 'p', 'q' }};
static char pressed_key = 0;
static int pressed_key_repetitions = 0;
static struct timeval pressed_key_time;
// function declarations
void HD44780_close ();
void HD44780_flush ();
void HD44780_clear ();
void HD44780_chr (int x, int y, char ch);
void HD44780_string (int x, int y, char *s);
void HD44780_flush_box (int lft, int top, int rgt, int bot);
void HD44780_backlight (int on);
void HD44780_init_vbar ();
@@ -159,22 +160,15 @@ void HD44780_vbar (int x, int len);
void HD44780_hbar (int x, int y, int len);
void HD44780_init_num ();
void HD44780_num (int x, int num);
void HD44780_heartbeat (int type);
void HD44780_set_char (int n, char *dat);
void HD44780_icon (int which, char dest);
void HD44780_draw_frame (char *dat);
void HD44780_close ();
char HD44780_getkey ();
static void HD44780_linewrap (int on);
static void HD44780_autoscroll (int on);
static void HD44780_position (int x, int y);
static void HD44780_chr (int x, int y, char ch);
static void common_position (int display, int DDaddr);
static void common_autoscroll (int on);
void HD44780_position (int x, int y);
static void uPause (int delayCalls);
static void HD44780_senddata (unsigned char displayID, unsigned char flags, unsigned char ch);
static char HD44780_getkey ();
unsigned char HD44780_scankeypad();
static int parse_span_list (int *spanListArray[], int *spLsize, int *dispOffsets[], int *dOffsize, int *dispSizeArray[], char *spanlist);
/////////////////////////////////////////////////////////////////
@@ -185,96 +179,52 @@ HD44780_init (lcd_logical_driver * driver, char *args)
{
// TODO: remove the two magic numbers below
// TODO: single point of return
char *argv[64], *str;
int argc, i;
//char *argv[64];
//int i;
char buf[40];
char *s;
HD44780 = driver;
// get_args inserts \0 into args - nasty !
if (args)
if ((str = (char *) malloc (strlen (args) + 1)))
strcpy (str, args);
else {
fprintf (stderr, "Error mallocing\n");
return -1;
// TODO: replace DriverName with driver->name when that field exists.
#define DriverName "HD44780"
//// READ THE CONFIG FILE
port = driver->config_get_int( DriverName, "port", 0, 0x278 );
// Get and search for the connection type
s = driver->config_get_string( DriverName, "connectiontype", 0, "4bit" );
for (connectiontype_index = 0; strcmp (s, connectionMapping[connectiontype_index].connectionTypeStr) != 0 && connectionMapping[connectiontype_index].type != HD_unknown; ++connectiontype_index);
if (connectionMapping[connectiontype_index].type == HD_unknown) {
fprintf (stderr, "HD44780_init: Unknown connection type: %s\n", s);
return -1; // fatal error
} else
str = NULL;
connection = connectionMapping[connectiontype_index].type;
argc = get_args (argv, args, 64);
// arguments are passed in with -d HD44780 "-p 0x278"
// getopt will work well here
for (i = 0; i < argc; i++) {
if (0 == strcmp (argv[i], "-p") || 0 == strcmp (argv[i], "--port")) {
if (i + 1 >= argc) {
fprintf (stderr, "HD44780_init: %s requires an argument\n", argv[i]);
return -1;
} else {
int myport;
if (sscanf (argv[i + 1], "%i", &myport) != 1) {
fprintf (stderr, "HD44780_init: Couldn't read port address -" " using default value 0x%x\n", port);
return -1;
} else {
port = myport;
++i;
}
}
} else if (0 == strcmp (argv[i], "-c") || 0 == strcmp (argv[i], "--connect")) {
int j = 0;
if (i + 1 >= argc) {
fprintf (stderr, "HD44780_init: %s requires an argument\n", argv[i]);
return -1;
}
// search the next argument for the connection type
for (j = 0; strcmp (argv[i + 1], connectionMapping[j].connectionTypeStr) != 0 && connectionMapping[j].type != HD_unknown; ++j);
if (connectionMapping[j].type == HD_unknown) {
fprintf (stderr, "HD44780_init: Unknown connection type - using default %s driver\n", connectionMapping[0].connectionTypeStr);
connection = connectionMapping[0].type;
j = 0;
} else
connection = connectionMapping[j].type;
connIdx = j;
++i;
} else if (0 == strcmp (argv[i], "-v") || 0 == strcmp (argv[i], "--vspan")) {
if (i + 1 >= argc) {
fprintf (stderr, "HD44780_init: %s requires an argument\n", argv[i]);
return -1;
}
if (parse_span_list (&spanList, &numLines, &dispVOffset, &numDisplays, &dispSizes, argv[i + 1]) == -1) {
fprintf (stderr, "HD44780_init: invalid vspan argument\n");
return -1;
}
++i;
} else if (strcmp (argv[i], "-k") == 0 || strcmp (argv[i], "--keypad") == 0) {
have_keypad = 1;
printf( "HD44780 keypad extension enabled\n" );
} else if (0 == strcmp (argv[i], "-h") || 0 == strcmp (argv[i], "--help")) {
int i;
printf ("LCDproc HD44780 driver\n" "\t-p n\t--port n\tSelect the output device to use port n\n" "\t-c type\t--connect type\tSet the connection type (default 4 bit)\n" "\t\t\t\ttype = %s", connectionMapping[0].connectionTypeStr);
for (i = 1; connectionMapping[i].type != HD_unknown; ++i)
printf (" | %s", connectionMapping[i].connectionTypeStr);
printf ("\n\t-v spanlist\t--vspan spanlist\tvertical span n{,m}\n" "\t-h\t--help\t\tShow this help information\n" "\n\tNote that the '-t' option should precede the '-d' option\n");
if (connectionMapping[connIdx].type != HD_unknown) {
printf ("\n Parameters for %s driver\n", connectionMapping[connIdx].connectionTypeStr);
printf ("%s", connectionMapping[connIdx].helpMsg);
}
// Get and parse vspan only when specified
s = driver->config_get_string( DriverName, "vspan", 0, "" );
if( s[0] != 0 ) {
if (parse_span_list (&spanList, &numLines, &dispVOffset, &numDisplays, &dispSizes, s) == -1) {
fprintf (stderr, "HD44780_init: invalid vspan value: %s\n", s );
return -1;
}
/* ignore invalid arguments as they might be valid to the lower-level init
else
{
printf("Invalid parameter: %s\n", argv[i]);
}
*/
}
extIF = driver->config_get_bool( DriverName, "extended", 0, 0 );
have_keypad = driver->config_get_bool( DriverName, "keypad", 0, 0 );
have_backlight = driver->config_get_bool( DriverName, "backlight", 0, 0 );
// Get and parse size
s = driver->config_get_string( DriverName, "size", 0, "20x4" );
if( sscanf( s, "%dx%d", &(driver->wid), &(driver->hgt) ) != 2 ) {
fprintf( stderr, "HD44780_init: Cannot read size: %s\n", s );
}
// default case for when spans aren't indicated
// - add a sanity check against HD44780->hgt ??
// - this only works if the -t option is specified before -d
if (numLines == 0) {
if ((spanList = (int *) malloc (sizeof (int) * HD44780->hgt))) {
int i;
@@ -293,6 +243,8 @@ HD44780_init (lcd_logical_driver * driver, char *args)
} else
fprintf (stderr, "Error mallocing for display sizes list\n");
}
#if defined DELAY_NANOSLEEP
// Change to Round-Robin scheduling for nanosleep
{
@@ -306,8 +258,6 @@ HD44780_init (lcd_logical_driver * driver, char *args)
}
#endif
atest( port );
// Make sure the frame buffer is there...
if (!HD44780->framebuf)
HD44780->framebuf = (unsigned char *) malloc (HD44780->wid * HD44780->hgt);
@@ -318,27 +268,31 @@ HD44780_init (lcd_logical_driver * driver, char *args)
}
// Set the functions the driver supports...
// These are the default HD44780 functions
driver->clear = (void *) -1;
driver->string = (void *) -1;
driver->chr = HD44780_chr;
driver->vbar = HD44780_vbar;
driver->init_vbar = HD44780_init_vbar;
driver->hbar = HD44780_hbar;
driver->init_hbar = HD44780_init_hbar;
driver->num = HD44780_num;
driver->init_num = HD44780_init_num;
driver->init = HD44780_init;
driver->close = (void *) -1;
driver->close = HD44780_close;
driver->flush = HD44780_flush;
driver->flush_box = HD44780_flush_box;
//driver->contrast = HD44780_contrast; // contrast by potmeter
driver->backlight = HD44780_backlight;
driver->clear = HD44780_clear;
driver->chr = HD44780_chr;
driver->string = HD44780_string;
driver->flush_box = HD44780_flush_box; // TO BE REMOVED
//driver->contrast = HD44780_contrast; // contrast is set by potmeter we assume
//driver->output = HD44780_output; // not implemented
driver->init_vbar = HD44780_init_vbar;
driver->init_hbar = HD44780_init_hbar;
driver->vbar = HD44780_vbar;
driver->hbar = HD44780_hbar;
driver->init_num = HD44780_init_num;
driver->num = HD44780_num;
driver->heartbeat = HD44780_heartbeat;
driver->set_char = HD44780_set_char;
driver->icon = HD44780_icon;
driver->draw_frame = HD44780_draw_frame;
driver->draw_frame = HD44780_draw_frame; // TO BE REMOVED
if( have_keypad ) {
if ( have_backlight ) {
driver->backlight = HD44780_backlight;
}
if ( have_keypad ) {
driver->getkey = HD44780_getkey;
}
@@ -346,21 +300,27 @@ HD44780_init (lcd_logical_driver * driver, char *args)
return -1;
}
hd44780_functions->uPause = uPause;
hd44780_functions->position = common_position;
hd44780_functions->autoscroll = common_autoscroll;
hd44780_functions->scankeypad = HD44780_scankeypad;
connectionMapping[connIdx].init_fn (hd44780_functions, driver, str, port);
connectionMapping[connectiontype_index].init_fn (hd44780_functions, driver, args, port);
HD44780_autoscroll (0);
HD44780_clear ();
sprintf (buf, "HD44780 %dx%d", HD44780->wid, HD44780->hgt );
HD44780_string (1, 1, buf);
sprintf (buf, "LPT 0x%x %s %s", port, (have_backlight?"bl":""), (have_keypad?"key":"") );
HD44780_string (1, 2, buf);
HD44780_flush ();
sleep (1);
return port;
}
/////////////////////////////////////////////////////////////////
// Common initialisation sequence - sets cursor off and not blinking,
// clear display and homecursor
// Does not set twoline mode nor small characters (5x8). The init function of
// the connectiontype should do this.
//
void
common_init ()
{
@@ -372,7 +332,9 @@ common_init ()
hd44780_functions->uPause (1600);
}
/////////////////////////////////////////////////////////////////
// IO delay to avoid a task switch
//
void
uPause (int delayCalls)
{
@@ -408,26 +370,18 @@ uPause (int delayCalls)
#endif
}
// displayID - ID of display to use (0 = all displays)
static void
HD44780_senddata (unsigned char displayID, unsigned char flags, unsigned char ch)
{
hd44780_functions->senddata (displayID, flags, ch);
hd44780_functions->uPause (40); // Minimum exec time for all commands
}
/////////////////////////////////////////////////////////////////
// Clean-up
//
/*
void HD44780_close()
{
drv_base_close();
}
*/
void HD44780_close()
{
}
/////////////////////////////////////////////////////////////////
// Set position (not part of API)
//
// x and y here are for the virtual HD44780->hgt x HD44780->wid display
static void
void
HD44780_position (int x, int y)
{
int dispID = spanList[y];
@@ -435,37 +389,74 @@ HD44780_position (int x, int y)
int DDaddr;
// 16x1 is a special case
if (dispSizes[dispID - 1] == 1 && HD44780->wid == 16)
if (dispSizes[dispID - 1] == 1 && HD44780->wid == 16) {
if (x >= 8) {
x -= 8;
relY = 1;
}
}
DDaddr = x + (relY % 2) * 0x40;
if ((relY % 4) >= 2)
DDaddr += HD44780->wid;
hd44780_functions->position (dispID, DDaddr);
}
void
common_position (int display, int DDaddr)
{
hd44780_functions->senddata (display, RS_INSTR, POSITION | DDaddr);
hd44780_functions->senddata (dispID, RS_INSTR, POSITION | DDaddr);
hd44780_functions->uPause (40); // Minimum exec time for all commands
}
void HD44780_chr (int x, int y, char ch)
{
HD44780->framebuf[ (y * HD44780->wid) + x] = ch;
}
/////////////////////////////////////////////////////////////////
// Flush the framebuffer to the display
//
void
HD44780_flush ()
{
HD44780_draw_frame (HD44780->framebuf);
}
/////////////////////////////////////////////////////////////////
// Clear the framebuffer
//
void HD44780_clear ()
{
memset(HD44780->framebuf, ' ', HD44780->wid * HD44780->hgt);
}
/////////////////////////////////////////////////////////////////
// Place a character in the framebuffer
//
void
HD44780_chr (int x, int y, char ch)
{
y--;
x--;
HD44780->framebuf[ (y * HD44780->wid) + x] = ch;
}
/////////////////////////////////////////////////////////////////
// Place a string in the framebuffer
//
void
HD44780_string (int x, int y, char *s)
{
int i;
x --; // Convert 1-based coords to 0-based
y --;
for (i = 0; s[i]; i++) {
// Check for buffer overflows...
if ((y * HD44780->wid) + x + i > (HD44780->wid * HD44780->hgt))
break;
HD44780->framebuf[(y*HD44780->wid) + x + i] = s[i];
}
}
/////////////////////////////////////////////////////////////////
// Flush box
//
// TO BE REMOVED
//
void
HD44780_flush_box (int lft, int top, int rgt, int bot)
{
@@ -477,7 +468,9 @@ HD44780_flush_box (int lft, int top, int rgt, int bot)
HD44780_position (lft, y);
//printf("\n%d,%d :",lft,y);
for (x = lft; x <= rgt; x++) {
HD44780_senddata (spanList[y], RS_DATA, HD44780->framebuf[(y * HD44780->wid) + x]);
hd44780_functions->senddata (spanList[y], RS_DATA, HD44780->framebuf[(y * HD44780->wid) + x]);
hd44780_functions->uPause (40); // Minimum exec time for all commands
}
//write(fd, HD44780->framebuf[(y*HD44780->wid)+lft, rgt-lft+1]);
}
@@ -490,31 +483,7 @@ HD44780_flush_box (int lft, int top, int rgt, int bot)
void
HD44780_backlight (int on)
{
//hd44780_functions->backlight (on);
}
/////////////////////////////////////////////////////////////////
// Toggle the built-in linewrapping feature
//
static void
HD44780_linewrap (int on)
{
}
/////////////////////////////////////////////////////////////////
// Toggle the built-in automatic scrolling feature
//
static void
HD44780_autoscroll (int on)
{
hd44780_functions->autoscroll (on);
}
void
common_autoscroll (int on)
{
hd44780_functions->senddata (0, RS_INSTR, ENTRYMODE | E_MOVERIGHT | ((on) ? EDGESCROLL : NOSCROLL));
hd44780_functions->uPause (40);
hd44780_functions->backlight (on);
}
/////////////////////////////////////////////////////////////////
@@ -703,7 +672,7 @@ HD44780_hbar (int x, int y, int len)
void
HD44780_init_num ()
{
}
/////////////////////////////////////////////////////////////////
@@ -716,6 +685,38 @@ HD44780_num (int x, int num)
HD44780->framebuf[x+offset] = num + '0';
}
/////////////////////////////////////////////////////////////
// Does the heartbeat...
//
void
HD44780_heartbeat (int type)
{
static int timer = 0;
int whichIcon;
static int saved_type = HEARTBEAT_ON;
if (type)
saved_type = type;
if (type == HEARTBEAT_ON) {
// Set this to pulsate like a real heart beat...
whichIcon = (! ((timer + 4) & 5));
// This defines a custom character EVERY time...
// not efficient... is this necessary?
HD44780_icon (whichIcon, 0);
// Put character on screen...
HD44780_chr (HD44780->wid, 1, 0);
// change display...
HD44780_flush ();
}
timer++;
timer &= 0x0f;
}
/////////////////////////////////////////////////////////////////
// Sets a custom character from 0-7...
//
@@ -734,7 +735,8 @@ HD44780_set_char (int n, char *dat)
if (!dat)
return;
HD44780_senddata (0, RS_INSTR, SETCHAR | n * 8);
hd44780_functions->senddata (0, RS_INSTR, SETCHAR | n * 8);
hd44780_functions->uPause (40); // Minimum exec time for all commands
for (row = 0; row < HD44780->cellhgt; row++) {
letter = 0;
@@ -742,10 +744,14 @@ HD44780_set_char (int n, char *dat)
letter <<= 1;
letter |= (dat[(row * HD44780->cellwid) + col] > 0);
}
HD44780_senddata (0, RS_DATA, letter);
hd44780_functions->senddata (0, RS_DATA, letter);
hd44780_functions->uPause (40); // Minimum exec time for all commands
}
}
/////////////////////////////////////////////////////////////
// Set default icon into a userdef char
//
void
HD44780_icon (int which, char dest)
{
@@ -793,6 +799,7 @@ HD44780_icon (int which, char dest)
//
// Input is a character array, sized HD44780->wid*hgt
//
// TO BE REMOVED (move it into flush())
void
HD44780_draw_frame (char *dat)
{
@@ -802,15 +809,136 @@ HD44780_draw_frame (char *dat)
return;
for (y = 0; y < HD44780->hgt; y++) {
HD44780_position (0, y);
//printf("\n%d :",y);
for (x = 0; x < HD44780->wid; x++) {
HD44780_senddata (spanList[y], RS_DATA, HD44780_charmap[(unsigned char)dat[(y * HD44780->wid) + x]]);
if( x % 8 == 0 )
HD44780_position (x, y);
hd44780_functions->senddata (spanList[y], RS_DATA, HD44780_charmap[(unsigned char)dat[(y * HD44780->wid) + x]]);
hd44780_functions->uPause (40); // Minimum exec time for all commands
}
}
}
/////////////////////////////////////////////////////////////
// Get a key from the keypad (if there is one)
//
char HD44780_getkey()
{
unsigned char scancode;
char ch;
struct timeval curr_time, time_diff;
gettimeofday(&curr_time,NULL);
scancode = hd44780_functions->scankeypad();
if( scancode ) {
if( scancode & 0xF0 ) {
ch = keyMapMatrix[((scancode&0xF0)>>4)-1][(scancode&0x0F)-1];
}
else {
ch = keyMapDirect[scancode - 1];
}
}
else {
ch = 0;
}
if (ch) {
if (ch == pressed_key) {
timersub (&curr_time, &pressed_key_time, &time_diff);
if (((time_diff.tv_usec / 1000 + time_diff.tv_sec * 1000) - KEYPAD_AUTOREPEAT_DELAY) < 1000 * pressed_key_repetitions / KEYPAD_AUTOREPEAT_FREQ ) {
// The key is already pressed quite some time
// but it's not yet time to return a repeated keypress
return 0;
}
// Otherwise a keypress will be returned
pressed_key_repetitions ++;
}
else {
// It's a new keypress
pressed_key_time = curr_time;
pressed_key_repetitions = 0;
printf( "Key: %c (%d,%d)\n", ch, scancode&0x0F, (scancode&0xF0)>>4 );
}
}
// Store the key for the next round
pressed_key = ch;
return ch;
}
/////////////////////////////////////////////////////////////
// Scan the keypad
//
unsigned char HD44780_scankeypad()
{
unsigned int keybits;
unsigned int shiftcount;
unsigned int shiftingbit;
unsigned int Ypattern;
unsigned int Yval;
char exp;
unsigned char scancode = 0;
// First check if a directly connected key is pressed
// Put all zeros on Y of keypad
keybits = hd44780_functions->readkeypad (0);
if (keybits) {
// A directly connected key was pressed
// Which key was it ?
shiftingbit = 1;
for (shiftcount=0; shiftcount<KEYPAD_MAXX && !scancode; shiftcount++) {
if ( keybits & shiftingbit) {
// Found ! Return from function.
scancode = shiftcount+1;
}
shiftingbit <<= 1;
}
}
else {
// Now check the matrix
// First check with all 1's
Ypattern = (1 << KEYPAD_MAXY) - 1;
if( hd44780_functions->readkeypad (Ypattern)) {
// Yes, a key on the matrix is pressed
// OK, now we know a key is pressed.
// Determine which one it is
// First determine the row
// Do a 'binary search' to minimize I/O
Ypattern = 0;
Yval = 0;
for (exp=3; exp>=0; exp--) {
Ypattern = ((1 << (1 << exp)) - 1) << Yval;
keybits = hd44780_functions->readkeypad (Ypattern);
if (!keybits) {
Yval += (1 << exp);
}
}
// Which key is pressed in that row ?
keybits = hd44780_functions->readkeypad (1<<Yval);
shiftingbit=1;
for (shiftcount=0; shiftcount<KEYPAD_MAXX && !scancode; shiftcount++) {
if ( keybits & shiftingbit) {
// Found !
scancode = (Yval+1) << 4 | (shiftcount+1);
}
shiftingbit <<= 1;
}
}
}
return scancode;
}
/////////////////////////////////////////////////////////////
// Parse the span list
// spanListArray - array to store vertical spans
// spLsize - size of spanListArray
@@ -862,90 +990,3 @@ parse_span_list (int *spanListArray[], int *spLsize, int *dispOffsets[], int *dO
return retVal;
}
char HD44780_getkey()
{
unsigned int keybits;
unsigned int shiftcount;
unsigned int shiftingbit;
unsigned int Ypattern;
unsigned int Yval;
char exp;
char ch = 0;
char ch_set = 0;
struct timeval curr_time, time_diff;
gettimeofday(&curr_time,NULL);
// First check if a directly connected key is pressed
// Put all zeros on Y of keypad
keybits = hd44780_functions->readkeypad (0);
if (keybits) {
// A directly connected key was pressed
// Which key was it ?
shiftingbit = 1;
for (shiftcount=0; shiftcount<KEYPAD_MAXX && !ch; shiftcount++) {
if ( keybits & shiftingbit) {
// Found ! Return from function.
ch = keyMapDirect[shiftcount];
}
shiftingbit <<= 1;
}
}
else {
// Now check the matrix
// First check with all 1's
Ypattern = (1 << KEYPAD_MAXY) - 1;
if( hd44780_functions->readkeypad (Ypattern)) {
// Yes, a key on the matrix is pressed
// OK, now we know a key is pressed.
// Determine which one it is
// Do a 'binary search' to determine in what row a key is pressed
Ypattern = 0;
Yval = 0;
for (exp=3; exp>=0; exp--) {
Ypattern = ((1 << (1 << exp)) - 1) << Yval;
keybits = hd44780_functions->readkeypad (Ypattern);
if (!keybits) {
Yval += (1 << exp);
}
}
// Which key is pressed in that row ?
keybits = hd44780_functions->readkeypad (1<<Yval);
shiftingbit=1;
for (shiftcount=0; shiftcount<KEYPAD_MAXX && !ch; shiftcount++) {
if ( keybits & shiftingbit) {
// Found !
ch = keyMapMatrix[Yval][shiftcount];
}
shiftingbit <<= 1;
}
}
}
if (ch) {
if (ch == pressed_key) {
timersub (&curr_time, &pressed_key_time, &time_diff);
if (((time_diff.tv_usec / 1000 + time_diff.tv_sec * 1000) - KEYPAD_AUTOREPEAT_DELAY) < 1000 * pressed_key_repetitions / KEYPAD_AUTOREPEAT_FREQ ) {
// The key is already pressed quite some time
// but it's not yet time to return a repeated keypress
return 0;
}
// Otherwise a keypress will be returned
pressed_key_repetitions ++;
}
else {
// It's a new keypress
pressed_key_time = curr_time;
pressed_key_repetitions = 0;
printf( "Key: %c\n", ch );
}
}
// Store the key for the next round
pressed_key = ch;
return ch;
}
+8 -1
View File
@@ -16,7 +16,14 @@
#ifndef HD44780_H
#define HD44780_H
extern char have_keypad; // non-zero if the keypad code is activated
// Maximum sizes of the keypad
// DO NOT CHANGE THESE 2 VALUES, unless you change the functions too
#define KEYPAD_MAXX 5
#define KEYPAD_MAXY 11
extern char have_keypad; // non-zero if the keypad code is activated
extern char have_backlight; // non-zero if we can control the backlight
extern char extIF; // non-zero if we should control > 2 LCDs
int HD44780_init (struct lcd_logical_driver *driver, char *args);
/* The following methods can all be hidden. They are used through function ptrs