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
+28 -11
View File
@@ -37,8 +37,8 @@
[server]
# Server section with all kinds of settings for the LCDd server
Driver=HD44780
#Driver=curses
Driver=curses
#Driver=HD44780
#Driver=MtxOrb
#
# Tells the server to load the given drivers. Multiple lines can be given.
@@ -46,7 +46,7 @@ Driver=HD44780
Bind=127.0.0.1
# Tells the driver to bind to the given interface
Port=3777
Port=13666
# Listen on this specified port; defaults to 13666.
#Debug=5
@@ -59,10 +59,10 @@ User=nobody
# User to run as. LCDd will drop its root priviledges,
# if any, and run as this user instead.
EnableServerScreen=yes
ServerScreen=no
# Enables the server screen also when other screens are active.
Foreground=no
Foreground=yes
# The server will stay in the foreground if set to true.
@@ -94,13 +94,30 @@ Arguments="-d /dev/ttyS0 -t 20x2 -c 120"
# Hitachi HD44780 driver
# See docs/hd44780_howto.txt
Arguments="-p 0x378 -c 4bit -k -b"
Port=0x378
# Port where the LPT is. Usual values are 0x278, 0x378 and 0x3BC
# Meaning:
# -p <port> Use the given port
# -c <ct> Use the given connectiontype
# -k Keypad support
# -b Backlight support
ConnectionType=4bit
# Select what type of connection. See documentation for types.
Keypad=no
# If you have a keypad connected. Keypad layout is currently not
# configureable from the config file.
Backlight=no
# If you have a switchable backlight.
Size=20x4
# Specifies the size of the LCD.
# In case of multiple combined displays, this should be the total size.
#vspan=1,2
# For multiple displays: at what 'logical' lines do the individual displays
# start.
#extended=yes
# If you want to use more than 3 HD44780 controllers on the LPT, you need to
# specify this. See documentation.
[LB216]
+207 -30
View File
@@ -79,7 +79,7 @@ to the input pins.
If you connect a key like sketched below, then you can only connect one key
per input pin. It is a simple solution if you need only few keys.
+ 5V
O 5V
|
|
-
@@ -136,7 +136,7 @@ Y1 o---|<---@--@--@
| | |
Y2 o---|<---@--@--@
| | |
Y3 o---|<---@--@--@ + 5V
Y3 o---|<---@--@--@ O 5V
| | | |
diodes | | | ___ |
1N4148 +----------|___|---+
@@ -168,6 +168,54 @@ You can buy arrays of keys that are connected like this in the electronics
shop. They usually call it a matrix keypad. To hook it to lcdproc, you
would only need to add the resistors and diodes.
If the driver generates keypresses without that you actually press a key,
it might be that the unconnected input lines are picking up
electromagnetic waves from the air. In that case connect the unconnected
input lines (pin 10, 11, 12, 13 and 15 of the LPT) to VCC.
1.1.3 Backlight
---------------
A small extension allows you to switch the backlight of the display on
and off. At the moment only the 4bit and winamp connection types support
this. The extension uses one output pin, you cannot use that pin for other
functions anymore. The wiring looks like this:
O 5V
___ |
+---|___|--------+
LPT Sub-D connector | 4k7 |
| |e
| ___ b |/
BL pin o---------------+---|___|------|
330E |\
bc327 |c
| LCD connector
|
+--------o 15 backlight
+--------o 16 GND backlight
|
=== GND
Note: 4k7 means 4,7 kohm and 330E means 330 ohm.
The BC327 has the following connections:
_____
| |
|bc327|
|_____|
| | |
| | |
| | |
c b e
Sometimes the backlight connections are not on the 'main' connector, but on
the side. If that is the case, there is usually NO RESISTOR present to limit
the current through the LEDs. Therefor you should add a resistor after
the transistor of 10 ohm.
1.2 4-bit
----------
@@ -219,6 +267,8 @@ The optional keypad can be connected as follows:
SELIN (13) X3
nFAULT (15) X4
The optional backlight wiring should be connected to D5, pin 7.
1.3 8-bit "Winamp"
-------------------
@@ -267,6 +317,8 @@ The optional keypad can be connected as follows:
SELIN (13) X3
nFAULT (15) X4
The optional backlight wiring should be connected to nSEL, pin 17.
1.4 Extended 8-bit "lcdtime"
-----------------------------
@@ -280,6 +332,9 @@ http://metalab.unc.edu/pub/linux/system/status/lcdtime-0.2.tar.gz
http://metalab.unc.edu/pub/linux/system/status/meter-0.2.tar.gz
http://metalab.unc.edu/pub/linux/system/status/portato-1.2.tar.gz
Theoretically this wiring sends the data over twice as slow as the
winamp or ext8bit wirings, because it only sends 4 bits at a time.
The LCD connections are:
printer port LCD
@@ -321,16 +376,153 @@ The optional keypad can be connected as follows:
SELIN (13) X3
nFAULT (15) X4
The backlight wiring should be attached to nSEL, pin 17. Because the portato
program (mentioned above) also uses this pin to control the bargraph, you
cannot use the backlight control together with the bargraph.
1.5 Serial LPT
---------------
This interface uses a handful of wires to interface to the
HD44780. Suitable for high noise, long connections. Designed by
Andrew McMeikan <andrewm@engineer.com>. Refer to
http://members.xoom.com/andrewmuck for details of the connections.
Andrew McMeikan <andrewm@engineer.com>. The original wiring and
driver can be found at:
http://members.xoom.com/andrewmuck
Note from Joris: I still need to add keypad stuff here
I (Joris) have extended this driver and the wiring a bit. It now supports
keys again (it had earlier supported keys, but some time did not).
Further I have extended the driver and the wiring to be able to run
using 2 instead of 3 output pins. That's even one less pin ! :)
Of course the use of fewer lines than the other wirings can not stay
without drawbacks. In this case the simplicity of the long feeding wires
is compensated by some intelligence in the decoding of the data. If you
have no experience with the soldering iron, I do not recommend to build
this wiring.
OK, so here is the wiring. First of the 'simple' 3 wires version. IC1 is
the shift register, a 4094. Do not forget to connect the 5V to pin 16 and
GND to pin 8 of the IC.
IC1
-----------
| 4094 |
5V | shift reg | display
O | | /keys
| 1| |3
+----|STR Q0|---------------------o 7 D0
| | |4 /Y0
Data | 2| Q1|---------------------o 8 D1
D3 5 o---------------------------|D |5 /Y1
| | Q2|---------------------o 9 D2
| 3|CK |6 /Y2
D4 6 o---------------------------| Q3|---------------------o 10 D3
| | |10 /Y3
| 15| Q4|---------------------o Y4
+----|OE |11
| Q5|---------------------o 4 RS
| |12 /Y5
| Q6|---------------------o Y6
| |13
| Q7|---------------------o Y7
| |9
| QS|-- +--o 5 RW
| __|10 |
| QS|-- ===
| |
-----------
D2 4 o-------------------------------------------------------------o 6 EN
D7 9 o-------------------------------------------------------------o 6 EN2
(2nd LCD)
5V O-----+--------+----------------------------------+-----o 2 VCC
| | |
| | |
|100n O 16 .-.
--- IC1 | |<---o 3 Vlcd
--- O 8 | |10k
| | '-'
GND | | |
18..25 o-----------+--------+--------------------------+-------+-----o 1 GND
|
=== GND
The second possible wiring is with 2 output lines. This one is a bit more
complex. If you do not understand the schematic, do not build it.
IC2
-----------
| 74HCT164 |
| shift reg | display
| | /keys
Data 1| |3
D3 5 o-----------------------+---|D Q0|---------------------o 7 D0
| | |4 /Y0
| 2| Q1|---------------------o 8 D1
+---|D |5 /Y1
| Q2|---------------------o 9 D2
| |6 /Y2
| Q3|---------------------o 10 D3
| |10 /Y3
Clock 8| Q4|---------------------o Y4
D4 6 o---------------------------|CK |11
| Q5|---------------------o 4 RS
___ 9|\ 8 9|_ |12 /Y5
+--|___|--+----| >o----|R Q6|---------------------o Y6
| 22k | |/ | |13
| --- IC1 | Q7|---+ +--o 5 RW
| --- | | | 5V |
| |100p ----------- | O ===
| | | |
| === | .-.
| | | |22k
+--------------------------------------+ | |
| '-'
| ___ 11|\ 10 | 5|\ 6
+--|___|--+----| >o-------------------||----+-----| >o---o 6 EN
22k | |/ 22p |/
--- IC1 IC1
---
|22p
| IC1=74HCT14 (6x Schmitt trigger inverter)
===
5V O--+-------+------+------+------------------------+-----o 2 VCC
| | | | 13|\ 12 |
| | | +---| >o- |
|100n O 14 O 14 |/ .-.
--- IC1 IC2 | |<---o 3 Vlcd
--- O 7 O 7 1|\ 2 3|\ 4 | |10k
| | | +--| >o- +--| >o- '-'
GND | | | | |/ | |/ |
18..25 o--------+-------+------+-------+----------+-----+------+-----o 1 GND
|
=== GND
Also the serialLpt wiring supports a keypad. The 3 wires version supports
8 keys, or if you use multiple return lines up to 8 x 5 = 40 lines. The
2 wires version supports 7 keys, or with multiple return lines
7 x 5 = 35 keys.
The return lines are the following:
nACK (10) X0
BUSY (11) X1
PAPEREND (12) X2
SELIN (13) X3
nFAULT (15) X4
To understand some of this keypad documentation, do also read the keypad
section in this document.
2. Compiling
@@ -344,33 +536,17 @@ can be done by specifying "--enable-drivers=all" or by
3. Running
----------
Keep in mind the following points.
Modify the LCDd.conf file before you run LCDd. In this config file are
detailed instructions on how to configure the HD44780 driver.
- When specifying the lcd size, do so before the -d argument.
- Arguments that need to be passed to the driver should be in quotes after
the -d HD44780 arguments.
- Use the "-e" argument for extended interfaces (e.g. 3 or more displays as
indicated by "optional" connections above).
- Use "-k" to enable the keypad code.
Then as usual, start LCDd with the correct config file:
LCDd -c ./LCDd.conf
for example.
EXAMPLES:
For a 4bit connection, 16x2 display on port 0x278
LCDd -t 16x2 -d HD44780 "-p 0x278"
For a 4bit, 40x4 display (effectively two 40x2 displays)
LCDd -t 40x4 -d HD44780 "-v 2,2"
For a Winamp connection, 20x2 and 20x1 displays
LCDd -t 20x3 -d HD44780 "-c winamp -v 2,1"
For a 4bit, 16x2, 16x4 and 16x1 displays
LCDd -t 16x7 -d HD44780 "-v 2,4,1 -e"
For help on the parameters for the 8-bit driver (make sure --help is the
last arguments in quotes):
LCDd -d HD44780 "-c 8bit --help"
If you want to override the driver selection in LCDd.conf then use:
LCDd -c ./LCDd.conf -d HD44780
If you use this, the HD44780 driver will read the options from the config
file.
4. Miscellania
@@ -381,3 +557,4 @@ This text originally taken from a message by Bill Farrow
Updated February 2000, Benjamin Tse (blt@ComPorts.com)
Updated October 2001, Joris Robijn (joris at robijn.net)
+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