first commit
This commit is contained in:
25
libraries/hd44780/hd44780ioClass/README.md
Normal file
25
libraries/hd44780/hd44780ioClass/README.md
Normal file
@@ -0,0 +1,25 @@
|
||||
hd44780ioclass
|
||||
==============
|
||||
|
||||
This directory contains the source code for each of the i/o classes that are
|
||||
included in the hd44780 library package.
|
||||
Each i/o class has its own .h file.
|
||||
|
||||
#### The library currenly comes with the following i/o subclasses:
|
||||
|
||||
* `hd44780_HC1627_I2C` control LCD with native i2c interface (Tsingtek Display HC1627)
|
||||
|
||||
* `hd44780_I2Cexp` control LCD using i2c i/o exapander backpack (PCF8574 or MCP23008)
|
||||
|
||||
* `hd44780_I2Clcd` control LCD with native i2c interface (PCF2116, PCF2119x, etc...)
|
||||
|
||||
* `hd44780_NTCU165ECPB` control Noritake CU165ECBP-T2J LCD display over SPI
|
||||
|
||||
* `hd44780_NTCU20025ECPB_pinIO` control Noritake CU20025ECPB using direct Arduino pin connections
|
||||
|
||||
* `hd44780_NTCUUserial` control Noritake CU-U Series VFD display in serial mode
|
||||
|
||||
* `hd44780_pinIO` control LCD using direct Arduino Pin connections
|
||||
|
||||
See each header file for further details.
|
||||
|
||||
223
libraries/hd44780/hd44780ioClass/hd44780_HC1627_I2C.h
Normal file
223
libraries/hd44780/hd44780ioClass/hd44780_HC1627_I2C.h
Normal file
@@ -0,0 +1,223 @@
|
||||
// vi:ts=4
|
||||
// ---------------------------------------------------------------------------
|
||||
// hd44780_HC1627_I2C.h - hd44780_HC1627_I2C i/o subclass for hd44780 library
|
||||
// Copyright (c) 2020 Bill Perry
|
||||
//
|
||||
// The API functionality provided by this library class is compatible
|
||||
// with the API functionality of the Arduino LiquidCrystal library.
|
||||
//
|
||||
// ---------------------------------------------------------------------------
|
||||
//
|
||||
// This file is part of the hd44780 library
|
||||
//
|
||||
// hd44780_HC1627_I2C is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation version 3 of the License.
|
||||
//
|
||||
// hd44780_HC1627_I2C is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with hd44780_HC1627_I2C. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
// ---------------------------------------------------------------------------
|
||||
//
|
||||
// It implements all the hd44780 library i/o methods to control an LCD based
|
||||
// on the Tsingtek Display Co HC1627 LCD devices in i2c mode which have
|
||||
// a native I2C interface rather than use a simple I2C i/o expander chip
|
||||
// such as a PCF8574 or MCP23008
|
||||
// This device uses two i2c address:
|
||||
// - base address for RS clear
|
||||
// - one higher for RS set
|
||||
// The communication interface is very simple:
|
||||
// 8 bit data is sent using the base address
|
||||
// command/status use the base address +1
|
||||
//
|
||||
// Here are examples of such a device:
|
||||
// HC1627-B-LWH-I2C-30
|
||||
// HC1627_I2C-SYH-I2C-30
|
||||
// http://dvtecnologia.com.br/imagens/HC1627_I2C-SYH-I2C-30_Eng%2CA.pdf
|
||||
// This device has 2 address pins to configure the base address.
|
||||
//
|
||||
// The configurable base address can be:
|
||||
// 0x38, 0x3A, 0x3C, 0x3E
|
||||
|
||||
// It overlaps with the addresses for the PCF8574A and PCF2116/PCF2119x
|
||||
// NOTE:
|
||||
// This device needs pullups on the bus signals.
|
||||
// While it will usually work on an AVR platform without external pullups,
|
||||
// it doesn't always work.
|
||||
//
|
||||
// The I2C can only control the LCD and does not have the capability
|
||||
// to control the backlight so the backlight will always remain on.
|
||||
//
|
||||
// 2020.06.26 bperrybap - initial creation (hd44780_IIClcd)
|
||||
//
|
||||
// @author Bill Perry - bperrybap@opensource.billsworld.billandterrie.com
|
||||
//
|
||||
// ---------------------------------------------------------------------------
|
||||
#ifndef hd44780_HC1627_I2C_h
|
||||
#define hd44780_HC1627_I2C_h
|
||||
|
||||
#if (ARDUINO < 101) && !defined(MPIDE)
|
||||
#error hd44780_HC1627_I2C i/o class requires Arduino 1.0.1 or later
|
||||
#endif
|
||||
|
||||
class hd44780_HC1627_I2C : public hd44780
|
||||
{
|
||||
public:
|
||||
// ====================
|
||||
// === constructors ===
|
||||
// ====================
|
||||
|
||||
hd44780_HC1627_I2C(uint8_t i2c_addr=0) : _Addr(i2c_addr) {} // zero addres means auto locate
|
||||
|
||||
private:
|
||||
// ====================
|
||||
// === private data ===
|
||||
// ====================
|
||||
|
||||
uint8_t _Addr; // I2C base Address of the LCD
|
||||
|
||||
// ==================================================
|
||||
// === hd44780 i/o subclass virtual i/o functions ===
|
||||
// ==================================================
|
||||
//
|
||||
// Note:
|
||||
// It is not possible to control the backlight nor
|
||||
// is it possible to read from the device.
|
||||
// so iosetbacklight() and ioread()
|
||||
// will not be defined and will use the defaults in
|
||||
// hd44780
|
||||
|
||||
// ioinit() - Returns non zero if initialization failed.
|
||||
int ioinit()
|
||||
{
|
||||
int status;
|
||||
|
||||
/*
|
||||
* First, initialize the i2c (Wire) library.
|
||||
* This really shouldn't be here
|
||||
* because Wire.begin() should only be called once, but
|
||||
* unfortunately, there is no way to know if anybody
|
||||
* else has called this.
|
||||
* I believe that it is unreasonable to require the the user
|
||||
* sketch code to do it, because all that should change between
|
||||
* interfaces should be the constructor
|
||||
* So we go ahead and call it here.
|
||||
*/
|
||||
Wire.begin();
|
||||
|
||||
/*
|
||||
* If i2c address was not specified go try to locate device
|
||||
*/
|
||||
if(!_Addr)
|
||||
{
|
||||
if( !(_Addr = LocateDevice())) // failed to find device
|
||||
{
|
||||
return(hd44780::RV_ENXIO);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Check to see if the device is responding
|
||||
*/
|
||||
Wire.beginTransmission(_Addr);
|
||||
if( (status = Wire.endTransmission()) )
|
||||
{
|
||||
if(status == 1)
|
||||
status = hd44780::RV_EMSGSIZE;
|
||||
else if(status == 2)
|
||||
status = hd44780::RV_ENXIO;
|
||||
else
|
||||
status = hd44780::RV_EIO;
|
||||
}
|
||||
|
||||
/*
|
||||
* this device only runs in 8 bit mode
|
||||
*/
|
||||
_displayfunction = HD44780_8BITMODE;
|
||||
return ( status );
|
||||
}
|
||||
|
||||
//
|
||||
// iowrite(type, value) - send either a command or data byte to lcd
|
||||
// returns zero on success, non zero on failure
|
||||
int iowrite(hd44780::iotype type, uint8_t value)
|
||||
{
|
||||
uint8_t addr;
|
||||
/*
|
||||
* No need to look for 4 bit commands as all bits are already in
|
||||
* proper upper nibble and unsued bits are zero.
|
||||
* This allows the special 4 bit commands to be sent "As is" when
|
||||
* using an 8 bit interface - which is what this i2c LCD uses.
|
||||
*/
|
||||
|
||||
if(type == hd44780::HD44780_IOdata)
|
||||
{
|
||||
addr = _Addr + 1; // RS bit is set by using 1 higher address
|
||||
}
|
||||
else
|
||||
{
|
||||
addr = _Addr; // RS is clear when using base address
|
||||
}
|
||||
|
||||
/*
|
||||
* ensure that previous LCD instruction finished.
|
||||
* There is a 25us offset since there will be at least 1 byte
|
||||
* (the i2c address) transmitted over i2c before the next LCD instruction
|
||||
* information could get to the LCD.
|
||||
* At 400Khz (max rate supported by the LCD) 8 bits plus start and stop
|
||||
* bits is 25us.
|
||||
* So there is at least 25us of time overhead in the physical interface.
|
||||
*/
|
||||
|
||||
waitReady(-25);
|
||||
|
||||
/*
|
||||
* Send the next LCD instruction
|
||||
*/
|
||||
|
||||
Wire.beginTransmission(addr);
|
||||
Wire.write(value); // send data/cmd
|
||||
|
||||
if(Wire.endTransmission())
|
||||
return(hd44780::RV_EIO);
|
||||
else
|
||||
return(hd44780::RV_ENOERR);
|
||||
}
|
||||
|
||||
// ================================
|
||||
// === internal class functions ===
|
||||
// ================================
|
||||
// LocateDevice() - Locate I2C LCD device
|
||||
uint8_t LocateDevice()
|
||||
{
|
||||
uint8_t error, address;
|
||||
|
||||
// Search for 4 base address pairs
|
||||
for(address = 0x38; address <= 0x3E; address += 2 )
|
||||
{
|
||||
Wire.beginTransmission(address);
|
||||
error = Wire.endTransmission();
|
||||
|
||||
// chipkit i2c screws up if you do a beginTransmission() too quickly
|
||||
// after an endTransmission()
|
||||
// below 20us will cause it to fail,
|
||||
// we use delay(1) here to accomdate that as well as ensure that
|
||||
// systems with watchdog timers like ESP8266 won't have issues.
|
||||
delay(1);
|
||||
|
||||
if(error == 0) // if no error we found something
|
||||
{
|
||||
return(address);
|
||||
}
|
||||
}
|
||||
return(0); // could not locate device address
|
||||
}
|
||||
|
||||
|
||||
}; // end of class definition
|
||||
#endif
|
||||
1218
libraries/hd44780/hd44780ioClass/hd44780_I2Cexp.h
Normal file
1218
libraries/hd44780/hd44780ioClass/hd44780_I2Cexp.h
Normal file
File diff suppressed because it is too large
Load Diff
271
libraries/hd44780/hd44780ioClass/hd44780_I2Clcd.h
Normal file
271
libraries/hd44780/hd44780ioClass/hd44780_I2Clcd.h
Normal file
@@ -0,0 +1,271 @@
|
||||
// vi:ts=4
|
||||
// ---------------------------------------------------------------------------
|
||||
// hd44780_I2Clcd.h - hd44780_I2Clcd i/o subclass for hd44780 library
|
||||
// Copyright (c) 2013-2020 Bill Perry
|
||||
//
|
||||
// The API functionality provided by this library class is compatible
|
||||
// with the API functionality of the Arduino LiquidCrystal library.
|
||||
//
|
||||
// ---------------------------------------------------------------------------
|
||||
//
|
||||
// This file is part of the hd44780 library
|
||||
//
|
||||
// hd44780_I2Clcd is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation version 3 of the License.
|
||||
//
|
||||
// hd44780_I2Clcd is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with hd44780_I2Clcd. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
// ---------------------------------------------------------------------------
|
||||
//
|
||||
// It implements all the hd44780 library i/o methods to control an LCD based
|
||||
// on the Hitachi HD44780 and compatible chipsets which have
|
||||
// a native I2C interface rather than use a simple I2C i/o expander chip
|
||||
// such as a PCF8574 or MCP23008
|
||||
//
|
||||
// Here is a example of such a device:
|
||||
// https://seeeddoc.github.io/Grove-LCD_RGB_Backlight/res/JHD1214Y_YG_1.0.pdf
|
||||
// This device uses address 0x3E and incorrectly responds to read requests
|
||||
// It overlaps with the addresses for the PCF8574A
|
||||
// It will lock up module and/or the AVR i2c h/w and require a power cycle to reset.
|
||||
// NOTE:
|
||||
// This device needs pullups on the bus signals.
|
||||
// While it will usually work on an AVR platform without external pullups,
|
||||
// it doesn't always work.
|
||||
//
|
||||
// PCF2119x chips use this protocol and slave addresses are 0x3A and 0x3B
|
||||
// This is defined in the allocated i2c address table Group 7
|
||||
// It overlaps with the addresses for the PCF8574A
|
||||
// This device has extended function set commands that are not directly
|
||||
// supported by the library but can be used through the command() API
|
||||
//
|
||||
// PCF2116 chips use this protocol and slave addresses are 0x3A and 0x3B
|
||||
// It overlaps with the addresses for the PCF8574A
|
||||
//
|
||||
// Raystar RC1602B5-LLH-JWV is jumper settable to 0x3c, 0x3d, 0x3e, 0x3f
|
||||
// and appears to only be able to be written to.
|
||||
// It overlaps with the addresses for the PCF8574A
|
||||
//
|
||||
// Known addresses for this type of device:
|
||||
// 0x3a PCF2116/PCF2119x
|
||||
// 0x3b PCF2116/PCF2119x
|
||||
// 0x3c Raystar
|
||||
// 0x3d Raystar
|
||||
// 0x3e Raystar
|
||||
// 0x3f Raystar
|
||||
//
|
||||
// The interface consists of sending 2 bytes over I2C for each hd44780
|
||||
// data/cmd.
|
||||
// The first byte is a control byte which sets the RS signal
|
||||
// The second byte is the data.
|
||||
//
|
||||
// The I2C can only control the LCD and does not have the capability
|
||||
// to control the backlight so the backlight will always remain on.
|
||||
//
|
||||
// Attempting to read from some of these devices will lockup the AVR Wire
|
||||
// library.
|
||||
//
|
||||
// 2018.08.06 bperrybap - removed TinyWireM work around (TinyWireM was fixed)
|
||||
// 2017.05.12 bperrybap - now requires IDE 1.0.1 or newer
|
||||
// This is to work around TinyWireM library bugs
|
||||
// 2016.12.26 bperrybap - added auto i2c address location
|
||||
// 2016.09.08 bperrybap - changed param order of iowrite() to match ioread()
|
||||
// 2016.08.06 bperrybap - changed iosend() to iowrite()
|
||||
// 2016.07.27 bperrybap - added return status for iosend()
|
||||
// 2017.07.21 bperrybap - merged all class code into header
|
||||
// 2017.07.20 bperrybap - merged into hd44780 library
|
||||
// 2016.06.09 bperrybap - changed name to hd44780_I2Clcd
|
||||
// 2016.06.08 bperrybap - removed pre IDE 1.0 support
|
||||
// 2016.06.03 bperrybap - added smart execution delays
|
||||
// 2014.02.15 bperrybap - changed to use hd44780 base class library
|
||||
// 2013.06.01 bperrybap - initial creation (hd44780_IIClcd)
|
||||
//
|
||||
// @author Bill Perry - bperrybap@opensource.billsworld.billandterrie.com
|
||||
//
|
||||
// ---------------------------------------------------------------------------
|
||||
#ifndef hd44780_I2Clcd_h
|
||||
#define hd44780_I2Clcd_h
|
||||
|
||||
// A bug in TinyWireM is that requestFrom() returns incorrect status
|
||||
// so its return status can't be used. Instead the code will check the return
|
||||
// from Wire.read() which will return -1 if there no data was transfered.
|
||||
|
||||
#if (ARDUINO < 101) && !defined(MPIDE)
|
||||
#error hd44780_I2Clcd i/o class requires Arduino 1.0.1 or later
|
||||
#endif
|
||||
|
||||
class hd44780_I2Clcd : public hd44780
|
||||
{
|
||||
public:
|
||||
// ====================
|
||||
// === constructors ===
|
||||
// ====================
|
||||
|
||||
hd44780_I2Clcd(uint8_t i2c_addr=0) : _Addr(i2c_addr) {} // zero addres means auto locate
|
||||
|
||||
private:
|
||||
// ====================
|
||||
// === private data ===
|
||||
// ====================
|
||||
|
||||
// Control byte bit values
|
||||
|
||||
// RS signal in HD44780 interface
|
||||
// set for data writes, clear for cmds
|
||||
// note: some datasheets call this A0 bit
|
||||
static const uint8_t I2Clcd_RS = (1 << 6);
|
||||
|
||||
// set if another control byte following data
|
||||
// clear if last control byte
|
||||
static const uint8_t I2Clcd_CO = (1 << 7);
|
||||
|
||||
uint8_t _Addr; // I2C Address of the LCD
|
||||
|
||||
// ==================================================
|
||||
// === hd44780 i/o subclass virtual i/o functions ===
|
||||
// ==================================================
|
||||
//
|
||||
// Note:
|
||||
// It is not possible to control the backlight nor
|
||||
// is it possible to read from the device.
|
||||
// so iosetbacklight() and ioread()
|
||||
// will not be defined and will use the defaults in
|
||||
// hd44780
|
||||
|
||||
// ioinit() - Returns non zero if initialization failed.
|
||||
int ioinit()
|
||||
{
|
||||
int status;
|
||||
|
||||
/*
|
||||
* First, initialize the i2c (Wire) library.
|
||||
* This really shouldn't be here
|
||||
* because Wire.begin() should only be called once, but
|
||||
* unfortunately, there is no way to know if anybody
|
||||
* else has called this.
|
||||
* I believe that it is unreasonable to require the the user
|
||||
* sketch code to do it, because all that should change between
|
||||
* interfaces should be the constructor
|
||||
* So we go ahead and call it here.
|
||||
*/
|
||||
Wire.begin();
|
||||
|
||||
/*
|
||||
* If i2c address was not specified go try to locate device
|
||||
*/
|
||||
if(!_Addr)
|
||||
{
|
||||
if( !(_Addr = LocateDevice())) // failed to find device
|
||||
{
|
||||
return(hd44780::RV_ENXIO);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Check to see if the device is responding
|
||||
*/
|
||||
Wire.beginTransmission(_Addr);
|
||||
if( (status = Wire.endTransmission()) )
|
||||
{
|
||||
if(status == 1)
|
||||
status = hd44780::RV_EMSGSIZE;
|
||||
else if(status == 2)
|
||||
status = hd44780::RV_ENXIO;
|
||||
else
|
||||
status = hd44780::RV_EIO;
|
||||
}
|
||||
|
||||
/*
|
||||
* this device only runs in 8 bit mode
|
||||
*/
|
||||
_displayfunction = HD44780_8BITMODE;
|
||||
return ( status );
|
||||
}
|
||||
|
||||
//
|
||||
// iowrite(type, value) - send either a command or data byte to lcd
|
||||
// returns zero on success, non zero on failure
|
||||
int iowrite(hd44780::iotype type, uint8_t value)
|
||||
{
|
||||
uint8_t ctlbyte;
|
||||
|
||||
/*
|
||||
* No need to look for 4 bit commands as all bits are already in
|
||||
* proper upper nibble and unsued bits are zero.
|
||||
* This allows the special 4 bit commands to be sent "As is" when
|
||||
* using an 8 bit interface - which is what this i2c LCD uses.
|
||||
*/
|
||||
|
||||
if(type == hd44780::HD44780_IOdata)
|
||||
{
|
||||
ctlbyte = I2Clcd_RS; // control byte with RS and no continue
|
||||
}
|
||||
else
|
||||
{
|
||||
ctlbyte = 0; // control byte with no RS and no continue
|
||||
}
|
||||
|
||||
/*
|
||||
* ensure that previous LCD instruction finished.
|
||||
* There is a 25us offset since there will be at least 1 byte
|
||||
* (the i2c address) transmitted over i2c before the next LCD instruction
|
||||
* information could get to the LCD.
|
||||
* At 400Khz (max rate supported by the LCD) 8 bits plus start and stop
|
||||
* bits is 25us.
|
||||
* So there is at least 25us of time overhead in the physical interface.
|
||||
*/
|
||||
|
||||
waitReady(-25);
|
||||
|
||||
/*
|
||||
* Send the next LCD instruction
|
||||
*/
|
||||
|
||||
Wire.beginTransmission(_Addr);
|
||||
Wire.write(ctlbyte); // send control byte
|
||||
Wire.write(value); // send data/cmd
|
||||
|
||||
if(Wire.endTransmission())
|
||||
return(hd44780::RV_EIO);
|
||||
else
|
||||
return(hd44780::RV_ENOERR);
|
||||
}
|
||||
|
||||
// ================================
|
||||
// === internal class functions ===
|
||||
// ================================
|
||||
// LocateDevice() - Locate I2C LCD device
|
||||
uint8_t LocateDevice()
|
||||
{
|
||||
uint8_t error, address;
|
||||
|
||||
// Search for 6 addresses
|
||||
for(address = 0x3a; address <= 0x3f; address++ )
|
||||
{
|
||||
Wire.beginTransmission(address);
|
||||
error = Wire.endTransmission();
|
||||
|
||||
// chipkit i2c screws up if you do a beginTransmission() too quickly
|
||||
// after an endTransmission()
|
||||
// below 20us will cause it to fail,
|
||||
// we use delay(1) here to accomdate that as well as ensure that
|
||||
// systems with watchdog timers like ESP8266 won't have issues.
|
||||
delay(1);
|
||||
|
||||
if(error == 0) // if no error we found something
|
||||
{
|
||||
return(address);
|
||||
}
|
||||
}
|
||||
return(0); // could not locate device address
|
||||
}
|
||||
|
||||
|
||||
}; // end of class definition
|
||||
#endif
|
||||
447
libraries/hd44780/hd44780ioClass/hd44780_NTCU165ECPB.h
Normal file
447
libraries/hd44780/hd44780ioClass/hd44780_NTCU165ECPB.h
Normal file
@@ -0,0 +1,447 @@
|
||||
// vi:ts=4
|
||||
// ---------------------------------------------------------------------------
|
||||
// hd44780_NTCU165ECPB.h - hd44780_NTCU165ECPB i/o subclass for hd44780 library
|
||||
// Copyright (c) 2016-2020 Bill Perry
|
||||
//
|
||||
// The API functionality provided by this library class is compatible
|
||||
// with the API functionality of the Arduino LiquidCrystal library.
|
||||
//
|
||||
// ---------------------------------------------------------------------------
|
||||
//
|
||||
// This file is part of the hd44780 library
|
||||
//
|
||||
// hd44780_NTCU165ECPB is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation version 3 of the License.
|
||||
//
|
||||
// hd44780_NTCU165ECPB is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with hd44780_NTCU165ECPB. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
// ---------------------------------------------------------------------------
|
||||
//
|
||||
// It implements hd44780 library subclass i/o methods to control a
|
||||
// Noritake CU165ECBP-T2J display.
|
||||
// The Noritake CU165ECBP-T2J display is a 16x1 line VFD display.
|
||||
// It is not a hd44780 display. So while this device is supported by hd44780,
|
||||
// it will not be capable of supporting all the hd44780 capabilities.
|
||||
// The subclass will do its best to emulatate hd44780 functions and map
|
||||
// them to equivalent functionality when possible but certain capabilities
|
||||
// will not be possible.
|
||||
//
|
||||
// Datasheet can be found here:
|
||||
// http://www.blog.zapro.dk/wp-content/CU165.pdf
|
||||
// Full datasheet/release notes:
|
||||
// http://www.blog.zapro.dk/wp-content/CU165ECPB_T2J_specification.pdf
|
||||
//
|
||||
// The device uses SPI for communication.
|
||||
// Pinout:
|
||||
// 1 Vcc
|
||||
// 2 GND
|
||||
// 3 /CS (SS)
|
||||
// 4 CLK (SCK)
|
||||
// 5 DATA (MOSI)
|
||||
//
|
||||
// ---------------------------------------------------------------------------
|
||||
// history
|
||||
//
|
||||
// 2017.12.23 bperrybap - added support LCD API 1.0 init()
|
||||
// 2016.08.22 bperrybap - initial creation
|
||||
//
|
||||
// @author Bill Perry - bperrybap@opensource.billsworld.billandterrie.com
|
||||
//
|
||||
// ---------------------------------------------------------------------------
|
||||
#ifndef hd44780_NTCU165ECPB_h
|
||||
#define hd44780_NTCU165ECPB_h
|
||||
|
||||
class hd44780_NTCU165ECPB : public hd44780
|
||||
{
|
||||
public:
|
||||
// ====================
|
||||
// === constructors ===
|
||||
// ====================
|
||||
|
||||
// no parameters: use h/w spi signals
|
||||
// Note: This doesn't work for Leonardo since SS is not available and only drives an LED
|
||||
hd44780_NTCU165ECPB() : hd44780(16,1), _cs(SS), _clk(SCK), _data(MOSI) { }
|
||||
|
||||
// supply alternate chip/slave select
|
||||
// will use h/w spi with alternate chip select
|
||||
hd44780_NTCU165ECPB(int cs) : hd44780(16,1), _cs(cs), _clk(SCK), _data(MOSI) { }
|
||||
|
||||
// supply pins for chip select, clock, and data
|
||||
hd44780_NTCU165ECPB(int cs, int clock, int data) : hd44780(16,1), _cs(cs), _clk(clock), _data(data) { }
|
||||
|
||||
|
||||
private:
|
||||
// ====================
|
||||
// === private data ===
|
||||
// ====================
|
||||
|
||||
// Arduino Pin information
|
||||
|
||||
const uint8_t _cs; // arduino pint for slave select (chip select)
|
||||
const uint8_t _clk; // arduino pin for clock
|
||||
const uint8_t _data; // arduino pin for master out slave in (data)
|
||||
|
||||
// other internal variables
|
||||
uint8_t _cgmode; // set when in cgramaddr mode
|
||||
uint8_t _udf[5]; // udf buffer area
|
||||
uint8_t _cgindx; // index into cgdata (will be 0 to 7)
|
||||
uint8_t _cgchar; // custom character (0 to 7, this board goes to f)
|
||||
|
||||
|
||||
// device commands
|
||||
|
||||
static const uint8_t CMD_SETDISPLAYLEN = 0x00; // lower 3 bits sets total digits/cols
|
||||
// to display
|
||||
// 0 is 9 and 7 means all 16 digits/cols
|
||||
|
||||
static const uint8_t CMD_SETBRIGHTNESS = 0x08; // lower 3 bits sets brigtness
|
||||
// 0 is 1/16 and 7 is 14/16 max
|
||||
static const uint8_t CMD_SETDIGSCAN160 = 0xF6; // set digit scan time to 160us
|
||||
static const uint8_t CMD_SETDIGSCAN320 = 0xF7; // set digit scan time to 320us
|
||||
static const uint8_t CMD_SETDIGPOINTER = 0xE0; // set column, lower 4 bits sets column
|
||||
static const uint8_t CMD_NOAUTOINCREMENT = 0xF0; // no auto advance to next column
|
||||
static const uint8_t CMD_AUTOINCREMENT = 0xF1; // auto advance to next column
|
||||
|
||||
static const uint8_t CMD_DISPLAYOFF = 0xF0; // all digits/dots off
|
||||
static const uint8_t CMD_DISPLAYON = 0xF1; // normal display mode
|
||||
static const uint8_t CMD_DISPLAYALLON = 0xF3; // all digits, all dots on
|
||||
|
||||
static const uint8_t CMD_STOREUDF = 0xFC; // begin user defined font (custom char)
|
||||
// There are 16 custom chars, they are
|
||||
// accessed/printed using 0x90-0x9F
|
||||
// they are programmed using locations 0-F
|
||||
// Each character glyph is 5 bytes.
|
||||
// Each byte is vertical 7 pixels with the
|
||||
// MSB at the top and the LSB dropped.
|
||||
// The first byte is the left most column of
|
||||
// the glyph.
|
||||
// full command data is 7 bytes:
|
||||
// 0xFC,<location (0-f)> 5 bytes of data
|
||||
|
||||
// start of custom user defined font (UDF) characters
|
||||
// There are 16 UDF characters that start here
|
||||
static const uint8_t UDF_BASE = 0x90;
|
||||
|
||||
|
||||
// ==================================================
|
||||
// === hd44780 i/o subclass virtual i/o functions ===
|
||||
// ==================================================
|
||||
//
|
||||
// Note:
|
||||
// It is not possible to read from the device.
|
||||
// so ioread(), and & iostatus()
|
||||
// will not be defined and will use the defaults in
|
||||
// hd44780 which will return an apropriate error status
|
||||
|
||||
// ioinit() - Returns non zero if initialization failed.
|
||||
int ioinit()
|
||||
{
|
||||
int status = 0;
|
||||
|
||||
// setup SPI signals
|
||||
digitalWrite(_cs, HIGH);
|
||||
pinMode(_cs, OUTPUT);
|
||||
|
||||
pinMode(_clk, OUTPUT);
|
||||
digitalWrite(_clk, LOW);
|
||||
pinMode(_data, OUTPUT);
|
||||
|
||||
// check to see if SPI has beginTransaction() and endTransaction()
|
||||
// this was added in IDE 1.06 and so if using an IDE older than that,
|
||||
// H/W spi will not be used
|
||||
// This requires that <SPI.h> be included prior to this header
|
||||
#if (defined(SPI_HAS_TRANSACTION) && !defined(ARDUINO_ARCH_ESP32)) || \
|
||||
(defined(ARDUINO_ARCH_ESP32) && defined(_SPI_H_INCLUDED) && defined(SPI_HAS_TRANSACTION))
|
||||
// check to see if h/w spi can be used
|
||||
if((_data == MOSI) && (_clk == SCK))
|
||||
SPI.begin();
|
||||
#endif
|
||||
|
||||
// maybe look at cols to see how many should be turned on?
|
||||
devicewrite(CMD_SETDISPLAYLEN|0x7); // show all 16 characters
|
||||
|
||||
devicewrite(CMD_SETDIGSCAN320); // set digit scan time to 320us
|
||||
devicewrite(CMD_AUTOINCREMENT); // set auto advance to next column on writes
|
||||
|
||||
// for now turn on display and "backlight"
|
||||
// clear and set to "home" address position
|
||||
devicewrite(CMD_DISPLAYON);
|
||||
devicewrite(CMD_SETBRIGHTNESS | 0x7); // max brightness
|
||||
device_clear();
|
||||
|
||||
return ( status );
|
||||
}
|
||||
|
||||
//
|
||||
// iowrite() - send either a command or data byte to lcd
|
||||
// returns zero on success, non zero on failure
|
||||
//
|
||||
// Things are a bit tricky here since this is not a hd44780 device.
|
||||
// The code must look at the commands and emulate them or drop them
|
||||
//
|
||||
int iowrite(hd44780::iotype type, uint8_t value)
|
||||
{
|
||||
|
||||
/*
|
||||
* waitReady() is not called as this module does not need any execution time
|
||||
* delays even when using a 4mHz h/w clock.
|
||||
*/
|
||||
|
||||
/*
|
||||
* 4 bit commands are part of low level hd44780 initalization.
|
||||
* since this is not a hd44780 display, just throw them away
|
||||
* and say they "worked"
|
||||
*/
|
||||
|
||||
if(type == hd44780::HD44780_IOcmd4bit)
|
||||
return(0);
|
||||
|
||||
if(type == hd44780::HD44780_IOcmd)
|
||||
{
|
||||
return(hd44780cmd(value));
|
||||
}
|
||||
|
||||
if(_cgmode)
|
||||
{
|
||||
// in cgram mode so have to process custom character data.
|
||||
// hd44780 font data is stored horizontally in 8 bytes
|
||||
// with each byte being 1 row of dots
|
||||
// with upper 3 bits of each byte ignored.
|
||||
// first byte of the 8 bytes is upper row of dots.
|
||||
// Noritake UDF format is vertical columns of 5 bytes with
|
||||
// the LSB of each byte ignored as it only has 5x7 dots.
|
||||
// the first byte is the right most column of 7 dots of the font.
|
||||
//
|
||||
// Because of this mismatch, the bits & bytes have to be flipped
|
||||
// around and stored in the 5 UDF bytes until the full 8 hd44780 font
|
||||
// bytes come in. Once all 8 hd44780 font bytes are in,
|
||||
// the 5 byte UDF font definition can be pushed to the device.
|
||||
|
||||
for(int i = 0; i < 5; i++)
|
||||
{
|
||||
if( (value & (1<< i)))
|
||||
{
|
||||
_udf[4-i] |= (1 << (7- _cgindx));
|
||||
}
|
||||
else
|
||||
{
|
||||
_udf[4-i] &= ~(1 << (7-_cgindx));
|
||||
}
|
||||
}
|
||||
_cgindx++;
|
||||
if(_cgindx > 7) // is this the last of the 8 bytes?
|
||||
{
|
||||
// 0xFC,<location (0-f)> 5 bytes of data
|
||||
devicewrite(CMD_STOREUDF);
|
||||
devicewrite(_cgchar);
|
||||
for(int i = 0; i < 5; i++)
|
||||
{
|
||||
devicewrite(_udf[i]);
|
||||
}
|
||||
|
||||
// now send it again for the 8-f version
|
||||
// to emulate the hd44780 custom chars
|
||||
// that duplicate 0-7 at 8-f
|
||||
devicewrite(CMD_STOREUDF);
|
||||
devicewrite(_cgchar+8);
|
||||
for(int i = 0; i < 5; i++)
|
||||
{
|
||||
devicewrite(_udf[i]);
|
||||
}
|
||||
|
||||
// note, cgmode is still in effect.
|
||||
// the UDF/font byte index is reset back to 0,
|
||||
// and the cgchar location is bumped.
|
||||
// this is to allow for the case when the code may
|
||||
// be attempting to program more than a single character at once.
|
||||
_cgindx = 0;
|
||||
_cgchar++;
|
||||
_cgchar &= 0xf;
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
|
||||
// upper 32 bytes are for commands so drop chars that are in the 0xE0 to 0xFF range
|
||||
if(value >= 0xE0)
|
||||
{
|
||||
return(0);
|
||||
}
|
||||
|
||||
// check for hd44780 custom font characters,
|
||||
// The hd44780 character code must be mapped to the UDF characters
|
||||
// which start at a different location.
|
||||
if(value < 16)
|
||||
{
|
||||
value += UDF_BASE;
|
||||
}
|
||||
|
||||
devicewrite(value);
|
||||
return(0);
|
||||
}
|
||||
|
||||
// iosetBacklight() - set backlight brightness
|
||||
// Since this display does not use a backlight but can control pixel intensity
|
||||
// use the backlight brightness to set the pixel intensity.
|
||||
//
|
||||
// Note:
|
||||
// The dimmer value on the CU165 is 3 bit value
|
||||
// other than the 000 value it looks like the value is mapped to a 4 bit
|
||||
// value by adding a 0 msb.
|
||||
// 000 is 1/16
|
||||
// 001 is 2/16
|
||||
// 010 is 4/16
|
||||
// 011 is 6/16
|
||||
// 100 is 8/16
|
||||
// 101 is 10/16
|
||||
// 110 is 12/16
|
||||
// 111 is 14/16
|
||||
//
|
||||
// Becauswe of this, an API dimvalue of 0 does not turn off the display pixels
|
||||
// so the code must check for that and explicitly turn off the display if the
|
||||
// API dimvalue is zero.
|
||||
int iosetBacklight(uint8_t dimvalue)
|
||||
{
|
||||
if(dimvalue)
|
||||
{
|
||||
// the dim value is 0-255 so devide by 32 to get a value 0-7
|
||||
devicewrite(CMD_SETBRIGHTNESS | (dimvalue/32));
|
||||
devicewrite(CMD_DISPLAYON);
|
||||
}
|
||||
else
|
||||
{
|
||||
devicewrite(CMD_DISPLAYOFF);
|
||||
}
|
||||
return(RV_ENOERR);
|
||||
}
|
||||
|
||||
// ================================
|
||||
// === internal class functions ===
|
||||
// ================================
|
||||
|
||||
// devicwrite() - send a byte to the device
|
||||
void devicewrite(uint8_t value)
|
||||
{
|
||||
|
||||
// use h/w spi if we can
|
||||
// note: checking for SPI support (SPI.h included) is messy since
|
||||
// ESP32 core always defines SPI_HAS_TRANSACTION even when SPI.h is not included
|
||||
|
||||
#if (defined(SPI_HAS_TRANSACTION) && !defined(ARDUINO_ARCH_ESP32)) || \
|
||||
(defined(ARDUINO_ARCH_ESP32) && defined(_SPI_H_INCLUDED) && defined(SPI_HAS_TRANSACTION))
|
||||
if((_data == MOSI) && (_clk == SCK))
|
||||
{
|
||||
// NOTE: spec says 2Mhz is max, 4Mhz seems to work.
|
||||
SPI.beginTransaction(SPISettings(4000000, MSBFIRST, SPI_MODE0));
|
||||
digitalWrite(_cs,LOW); // select device
|
||||
SPI.transfer(value);
|
||||
delayMicroseconds(1); // must delay at least 130ns before de-selecting
|
||||
digitalWrite(_cs,HIGH); // deselect device
|
||||
SPI.endTransaction();
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
digitalWrite(_cs,LOW); // select device
|
||||
myshiftOut(_data, _clk, MSBFIRST, value);
|
||||
delayMicroseconds(1); // must delay at least 130ns before de-selecting
|
||||
digitalWrite(_cs,HIGH); // deselect device
|
||||
}
|
||||
}
|
||||
|
||||
// can't use standard shiftOut() on esp32 because it is too fast for display
|
||||
//
|
||||
void myshiftOut(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder, uint8_t val)
|
||||
{
|
||||
uint8_t i;
|
||||
|
||||
for (i = 0; i < 8; i++) {
|
||||
if (bitOrder == LSBFIRST) {
|
||||
digitalWrite(dataPin, val & 1);
|
||||
val >>= 1;
|
||||
} else {
|
||||
digitalWrite(dataPin, (val & 128) != 0);
|
||||
val <<= 1;
|
||||
}
|
||||
|
||||
// insert delay on super fast processors to slow down clock
|
||||
// and allow a bit of time for slew rate rise when using 3v processor with 5v logic
|
||||
#if (F_CPU > 40000000)
|
||||
delayMicroseconds(1); // min pulse width is 230ns
|
||||
#endif
|
||||
digitalWrite(clockPin, HIGH);
|
||||
|
||||
#if (F_CPU > 40000000) // insert delay on super fast processors to slow down clock
|
||||
delayMicroseconds(1); // min pulse width is 230ns
|
||||
#endif
|
||||
digitalWrite(clockPin, LOW);
|
||||
}
|
||||
}
|
||||
|
||||
// hd44780cmd() - emulate hd44780 commands best we can
|
||||
// for now, silently drop unsupported commands
|
||||
int hd44780cmd(uint8_t value)
|
||||
{
|
||||
// detect the hd44780 command
|
||||
if(value & HD44780_SETDDRAMADDR)
|
||||
{
|
||||
_cgmode = 0; // back to ddram mode
|
||||
devicewrite(CMD_SETDIGPOINTER | (value & 0xf));
|
||||
}
|
||||
else if(value & HD44780_SETCGRAMADDR)
|
||||
{
|
||||
_cgmode = 1; // enter cgram mode
|
||||
_cgindx = 0;
|
||||
_cgchar = (value >> 3) & 0x7; // for now limmit to 8 custom like hd44780
|
||||
}
|
||||
else if(value & HD44780_FUNCTIONSET)
|
||||
{
|
||||
// not supported
|
||||
}
|
||||
else if(value & HD44780_CURDISPSHIFT)
|
||||
{
|
||||
// not supported
|
||||
}
|
||||
else if(value & HD44780_DISPLAYCONTROL)
|
||||
{
|
||||
if(value & HD44780_DISPLAYON)
|
||||
devicewrite(CMD_DISPLAYON);
|
||||
else
|
||||
devicewrite(CMD_DISPLAYOFF);
|
||||
}
|
||||
else if(value & HD44780_ENTRYMODESET)
|
||||
{
|
||||
// not supported
|
||||
}
|
||||
else if(value & HD44780_RETURNHOME)
|
||||
{
|
||||
_cgmode = 0; // back to ddram mode
|
||||
devicewrite(CMD_SETDIGPOINTER);
|
||||
}
|
||||
else if(value & HD44780_CLEARDISPLAY)
|
||||
{
|
||||
_cgmode = 0; // back to ddram mode
|
||||
device_clear();
|
||||
}
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
void device_clear()
|
||||
{
|
||||
devicewrite(CMD_SETDIGPOINTER);
|
||||
for(uint8_t col = 0; col < 16; col++)
|
||||
{
|
||||
devicewrite(' ');
|
||||
}
|
||||
devicewrite(CMD_SETDIGPOINTER);
|
||||
}
|
||||
|
||||
}; // end of class definition
|
||||
#endif
|
||||
402
libraries/hd44780/hd44780ioClass/hd44780_NTCU20025ECPB_pinIO.h
Normal file
402
libraries/hd44780/hd44780ioClass/hd44780_NTCU20025ECPB_pinIO.h
Normal file
@@ -0,0 +1,402 @@
|
||||
// vi:ts=4
|
||||
// ---------------------------------------------------------------------------
|
||||
// hd44780_NTCU20025ECPB_pinIO.h -
|
||||
// hd44780_NTCU20025ECPB_pinIO i/o subclass for hd44780 library
|
||||
// Copyright (c) 2019-2020 Bill Perry
|
||||
// ---------------------------------------------------------------------------
|
||||
//
|
||||
// This file is part of the hd44780 library
|
||||
//
|
||||
// hd44780_NTCU20025ECPB_pinIO is free software: you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation version 3 of the License.
|
||||
//
|
||||
// hd44780_NTCU20025ECPB_pinIO is distributed in the hope that it will be
|
||||
// useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with hd44780_NTCU20025ECPB_pinIO.
|
||||
// If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
// ---------------------------------------------------------------------------
|
||||
//
|
||||
// It implements hd44780 library subclass i/o methods to control Noritake
|
||||
// CU-U series displays like the Noritake CU20025ECPB-U1J or CU20025ECPB-W1J
|
||||
// The Noritake CU20025ECPB display is a 20x2 line VFD display.
|
||||
// It is not a hd44780 display but is nearly fully compatible with a hd44780
|
||||
// display. The only real difference is the backlight control.
|
||||
// So while this device is supported by the hd44780 library,
|
||||
// the subclass will do its best to emulatate hd44780 functions and map
|
||||
// them to equivalent functionality when possible.
|
||||
//
|
||||
// ---------------------------------------------------------------------------
|
||||
// Note:
|
||||
// The CU20025 device is very compatible with a standard hd44780 display.
|
||||
// The only difference is that it provides dimming control of the pixels
|
||||
// whereas a standard hd44780 display does not have dimming control, but
|
||||
// often has a backlight that is controlled with h/w outside of the hd44780
|
||||
// chipset.
|
||||
//
|
||||
// Datasheets:
|
||||
//
|
||||
// Full Data sheet: (requires registration):
|
||||
// https://www.noritake-elec.com/user/datasheet?SCID=147&VFDID=116&PSID=5908e690167775b2f6241569268c741e&FMTP=2#
|
||||
// https://www.noritake-elec.com/products/vfd-display-module/character-display/cu-u-series
|
||||
// https://www.noritake-elec.com/products/vfd-display-module/lineup?cu-u
|
||||
//
|
||||
// Summary Datasheet:
|
||||
// https://media.digikey.com/pdf/Data%20Sheets/Noritake%20PDFs/CU20025ECPB-U1J.pdf
|
||||
// http://www.farnell.com/datasheets/49448.pdf
|
||||
// https://media.digikey.com/pdf/Data%20Sheets/Noritake%20PDFs/CU20025ECPB-W1J.pdf
|
||||
//
|
||||
// AppNote:
|
||||
// http://www.northstardatasheet.com/datasheet/APN1100-01.pdf
|
||||
// https://www.datasheet.directory/index.php?title=Special:PdfViewer&url=https%3A%2F%2Fdatasheet.iiic.cc%2Fdatasheets-0%2Fnoritake%2FCU20025ECPB-W1J.pdf
|
||||
//
|
||||
// CU20025 pinout:
|
||||
// 1 - LCD gnd
|
||||
// 2 - VCC (5v)
|
||||
// 3 - not connected (assuming JP1 pins 1 and 2 are not shorted)
|
||||
// 4 - RS Register Select (rs)
|
||||
// 5 - Read/Write
|
||||
// 6 - Enable (en)
|
||||
// 7 - Data 0 (db0) ----
|
||||
// 8 - Data 1 (db1) |-------- Not used in 4 bit mode
|
||||
// 9 - Data 2 (db2) |
|
||||
// 10 - Data 3 (db3) ----
|
||||
// 11 - Data 4 (db4)
|
||||
// 12 - Data 5 (db5)
|
||||
// 13 - Data 6 (db6)
|
||||
// 14 - Data 7 (db7)
|
||||
//
|
||||
// ---------------------------------------------------------------------------
|
||||
//
|
||||
// The API functionality provided by this library class is compatible
|
||||
// with the functionality of the Arduino LiquidCrystal library.
|
||||
//
|
||||
//
|
||||
// 2019.11.23 bperrybap - initial creation from hd44780_pinIO i/o class
|
||||
//
|
||||
// @author Bill Perry - bperrybap@opensource.billsworld.billandterrie.com
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
#ifndef hd44780_NTCU20025ECPB_pinIO_h
|
||||
#define hd44780_NTCU20025ECPB_pinIO_h
|
||||
|
||||
#include <hd44780.h>
|
||||
// For STUPID versions of gcc that don't hard error on missing header files
|
||||
#ifndef hd44780_h
|
||||
#error Missing hd44780.h header file
|
||||
#endif
|
||||
#include <pins_arduino.h> // to get PWM detection macros
|
||||
|
||||
class hd44780_NTCU20025ECPB_pinIO : public hd44780
|
||||
{
|
||||
public:
|
||||
// ====================
|
||||
// === constructors ===
|
||||
// ====================
|
||||
|
||||
// 4 bit mode constructor without r/w control
|
||||
hd44780_NTCU20025ECPB_pinIO(uint8_t rs, uint8_t en,
|
||||
uint8_t d4, uint8_t d5, uint8_t d6, uint8_t d7) :
|
||||
hd44780(20,2), _rs(rs), _rw(0xff), _en(en),
|
||||
_d4(d4), _d5(d5), _d6(d6), _d7(d7) { }
|
||||
|
||||
// 4 bit mode constructor with r/w control
|
||||
hd44780_NTCU20025ECPB_pinIO(uint8_t rs, uint8_t rw, uint8_t en,
|
||||
uint8_t d4, uint8_t d5, uint8_t d6, uint8_t d7) :
|
||||
hd44780(20,2), _rs(rs), _rw(rw), _en(en),
|
||||
_d4(d4), _d5(d5), _d6(d6), _d7(d7) { }
|
||||
|
||||
private:
|
||||
// ====================
|
||||
// === private data ===
|
||||
// ====================
|
||||
|
||||
// Arduino Pin information
|
||||
uint8_t _rs; // hd44780 rs arduino pin
|
||||
uint8_t _rw; // hd44780 rw arduino pin
|
||||
uint8_t _en; // hd44780 en arduino pin
|
||||
uint8_t _d4; // hd44780 d4 arduino pin
|
||||
uint8_t _d5; // hd44780 d4 arduino pin
|
||||
uint8_t _d6; // hd44780 d4 arduino pin
|
||||
uint8_t _d7; // hd44780 d4 arduino pin
|
||||
|
||||
// ==================================================
|
||||
// === hd44780 i/o subclass virtual i/o functions ===
|
||||
// ==================================================
|
||||
|
||||
// ioinit() - initialize the h/w
|
||||
int ioinit()
|
||||
{
|
||||
// initialize Arduino pins used for hd44780 signals
|
||||
// NOTE:
|
||||
// _rw and _en pins are set to low even though they should
|
||||
// default to this from a an initial reset.
|
||||
// the reason is it is possible initilization is called without
|
||||
// without resetting the processor. In that case the state of the
|
||||
// bit in the port register would be unknown, so it is safest to set
|
||||
// to the desired state (LOW).
|
||||
|
||||
pinMode(_rs, OUTPUT);
|
||||
|
||||
if(_rw != 0xff)
|
||||
{
|
||||
pinMode(_rw, OUTPUT);
|
||||
// if r/w is used it be will set to be low,
|
||||
// it will only be turned hi during a read and
|
||||
// then set back to low. This offers a slight boost
|
||||
// for writes since normally reads are not done very often
|
||||
digitalWrite(_rw, LOW);
|
||||
}
|
||||
|
||||
pinMode(_en, OUTPUT);
|
||||
digitalWrite(_en, LOW);
|
||||
|
||||
pinMode(_d4, OUTPUT);
|
||||
pinMode(_d5, OUTPUT);
|
||||
pinMode(_d6, OUTPUT);
|
||||
pinMode(_d7, OUTPUT);
|
||||
|
||||
return(hd44780::RV_ENOERR); // all is good
|
||||
}
|
||||
|
||||
// ioread(type) - read a byte from LCD DDRAM
|
||||
//
|
||||
// returns:
|
||||
// success: 8 bit value read
|
||||
// failure: negative value: reading not supported
|
||||
//
|
||||
int ioread(hd44780::iotype type)
|
||||
{
|
||||
uint8_t data = 0;
|
||||
|
||||
// check if r/w control supported
|
||||
if(_rw == 0xff)
|
||||
return(hd44780::RV_ENOTSUP);
|
||||
|
||||
waitReady(); // ensure previous instruction finished
|
||||
|
||||
// put all the LCD data pins into input mode.
|
||||
pinMode(_d4, INPUT);
|
||||
pinMode(_d5, INPUT);
|
||||
pinMode(_d6, INPUT);
|
||||
pinMode(_d7, INPUT);
|
||||
|
||||
// set RS based on type of read (data or status/cmd)
|
||||
if(type == hd44780::HD44780_IOdata)
|
||||
{
|
||||
digitalWrite(_rs, HIGH); // RS high to access data reg
|
||||
}
|
||||
else
|
||||
{
|
||||
digitalWrite(_rs, LOW); // RS LOW to access status/cmd reg
|
||||
}
|
||||
|
||||
// r/w HIGH for reading
|
||||
digitalWrite(_rw, HIGH);
|
||||
|
||||
// raise E to allow reading the data.
|
||||
digitalWrite(_en, HIGH);
|
||||
|
||||
// allow for hd44780 tDDR (Data delay time) before reading data
|
||||
// this could be much shorter but this is portable for all CPUs.
|
||||
// and it will ensure that hd44780 PWEH timing is honored as well.
|
||||
delayMicroseconds(1);
|
||||
|
||||
// read pins for d4-d7 into upper nibble of byte
|
||||
if(digitalRead(_d4) == HIGH)
|
||||
data |= (1 << 4);
|
||||
|
||||
if(digitalRead(_d5) == HIGH)
|
||||
data |= (1 << 5);
|
||||
|
||||
if(digitalRead(_d6) == HIGH)
|
||||
data |= (1 << 6);
|
||||
|
||||
if(digitalRead(_d7) == HIGH)
|
||||
data |= (1 << 7);
|
||||
|
||||
// lower E after reading nibble
|
||||
digitalWrite(_en, LOW);
|
||||
|
||||
// allow for hd44780 1/2 of tcycE (Enable cycle time)
|
||||
// this could be much shorter but this is portable for all CPUs.
|
||||
delayMicroseconds(1);
|
||||
|
||||
// raise E to allow reading the lower nibbly of the byte
|
||||
digitalWrite(_en, HIGH);
|
||||
|
||||
// allow for hd44780 tDDR (Data delay time) before reading data
|
||||
// this could be shorter but this is portable for all CPUs.
|
||||
// and it will ensure that hd44780 PWEH timing is honored as well.
|
||||
delayMicroseconds(1);
|
||||
|
||||
// read pins for d4-d7 into upper nibble of byte
|
||||
if(digitalRead(_d4) == HIGH)
|
||||
data |= (1 << 0);
|
||||
|
||||
if(digitalRead(_d5) == HIGH)
|
||||
data |= (1 << 1);
|
||||
|
||||
if(digitalRead(_d6) == HIGH)
|
||||
data |= (1 << 2);
|
||||
|
||||
if(digitalRead(_d7) == HIGH)
|
||||
data |= (1 << 3);
|
||||
|
||||
|
||||
// lower E after reading nibble
|
||||
digitalWrite(_en, LOW);
|
||||
|
||||
//
|
||||
// put all pins back into state for writing to LCD
|
||||
//
|
||||
|
||||
// put all the LCD data pins into input mode.
|
||||
pinMode(_d4, OUTPUT);
|
||||
pinMode(_d5, OUTPUT);
|
||||
pinMode(_d6, OUTPUT);
|
||||
pinMode(_d7, OUTPUT);
|
||||
|
||||
// r/w LOW for Writing
|
||||
digitalWrite(_rw, LOW);
|
||||
|
||||
return(data);
|
||||
}
|
||||
|
||||
|
||||
// iowrite(type, value) - send either a command or data byte to lcd
|
||||
// returns zero on success, non zero on failure
|
||||
int iowrite(hd44780::iotype type, uint8_t value)
|
||||
{
|
||||
if(type == hd44780::HD44780_IOdata)
|
||||
digitalWrite(_rs, HIGH);
|
||||
else
|
||||
digitalWrite(_rs, LOW);
|
||||
|
||||
// "4 bit commands" are special.
|
||||
// They are used only during initalization and
|
||||
// are used to reliably get the LCD and host in nibble sync
|
||||
// with each other and to get the LCD into 4 bit mode.
|
||||
// 8 bit host interfaces don't have to worry about this,
|
||||
// but 4 bit host interfaces must only send the upper nibble.
|
||||
|
||||
// note:
|
||||
// waitReady() is explicitly called as late as possible *after* the Arduino
|
||||
// pins for the LCD control and data signals are set to allow
|
||||
// overhead of the digitalWrite() calls to be hidden under execution time.
|
||||
|
||||
write4bits(value>>4); // setup uppper nibble d4-d7 lcd pins
|
||||
waitReady(); // ensure previous instruction finished
|
||||
pulseEnable(); // send upper nibble to LCD
|
||||
|
||||
// send lower nibble if not a 4 bit command
|
||||
// (sends nibble for both data and "normal" commands)
|
||||
if (type != hd44780::HD44780_IOcmd4bit )
|
||||
{
|
||||
write4bits((value & 0x0F));// setup lower nibble on d4-d7 lcd pins
|
||||
pulseEnable(); // send lower nibble to LCD
|
||||
}
|
||||
return(hd44780::RV_ENOERR); // it never fails
|
||||
}
|
||||
|
||||
// iosetBacklight() - set backlight brightness
|
||||
// Since this display does not use a backlight but can control pixel intensity
|
||||
// use the backlight brightness to set the pixel intensity.
|
||||
//
|
||||
// Note:
|
||||
// The brightness control byte on the CU20025 is 2 bit value
|
||||
// 00 is 100%
|
||||
// 01 is 75%
|
||||
// 10 is 50%
|
||||
// 11 is 25%
|
||||
// To handle 0% the display will be turned off
|
||||
//
|
||||
// dimvalue levels will be mapped as follows:
|
||||
// 0 - 0% / display off
|
||||
// 01 - 63 - 25%
|
||||
// 64 -127 - 50%
|
||||
// 128-191 - 75%
|
||||
// 192-255 -100%
|
||||
|
||||
int iosetBacklight(uint8_t dimvalue)
|
||||
{
|
||||
if(dimvalue)
|
||||
{
|
||||
// brightness is set by sending a brightness control byte after a function set
|
||||
// Data which follows the FunctionSet command is considered as brightness data.
|
||||
|
||||
// send a function set,
|
||||
// this is effectively a NOP, since it will set mode to what it already is
|
||||
// Data which follows
|
||||
command(HD44780_FUNCTIONSET | _displayfunction);
|
||||
|
||||
// send the brightness control byte to set brightness level
|
||||
_write(3 - dimvalue / 64);
|
||||
|
||||
display(); // turn display on in case it was off
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
noDisplay(); // turn off display for 0% brightness
|
||||
}
|
||||
|
||||
// can't tell if it really worked with pin i/o, so say it always worked.
|
||||
return(hd44780::RV_ENOERR); // it never fails
|
||||
}
|
||||
|
||||
// ================================
|
||||
// === internal class functions ===
|
||||
// ================================
|
||||
|
||||
// write4bits() - set the 4 hd44780 data lines
|
||||
void write4bits(uint8_t value)
|
||||
{
|
||||
// write the bits on the LCD data lines but don't send the data
|
||||
if(value & 1)
|
||||
digitalWrite(_d4, HIGH);
|
||||
else
|
||||
digitalWrite(_d4, LOW);
|
||||
|
||||
if(value & 2)
|
||||
digitalWrite(_d5, HIGH);
|
||||
else
|
||||
digitalWrite(_d5, LOW);
|
||||
|
||||
if(value & 4)
|
||||
digitalWrite(_d6, HIGH);
|
||||
else
|
||||
digitalWrite(_d6, LOW);
|
||||
|
||||
if(value & 8)
|
||||
digitalWrite(_d7, HIGH);
|
||||
else
|
||||
digitalWrite(_d7, LOW);
|
||||
}
|
||||
|
||||
// pulseEnable() - toggle en to send data to hd44780 module
|
||||
void pulseEnable(void)
|
||||
{
|
||||
digitalWrite(_en, HIGH);
|
||||
#if defined (ARDUINO_ARCH_ESP8266)
|
||||
// the extra delay here is not for the LCD, it is to allow signal lines time
|
||||
// to settle when using 3v esp modules with 5v LCDs.
|
||||
// 3v outputs on 5v inputs is already a bit out of spec and
|
||||
// without this, the slew rate isn't fast enough to get "reliable"
|
||||
// signal levels
|
||||
// while it isn't needed for 3v LCDs, the time penalty isn't much
|
||||
// to always do it.
|
||||
delayMicroseconds(2); // enable pulse must be >450ns
|
||||
#else
|
||||
delayMicroseconds(1); // enable pulse must be >450ns
|
||||
#endif
|
||||
digitalWrite(_en, LOW);
|
||||
}
|
||||
|
||||
}; // end of class definition
|
||||
#endif
|
||||
293
libraries/hd44780/hd44780ioClass/hd44780_NTCUUserial.h
Normal file
293
libraries/hd44780/hd44780ioClass/hd44780_NTCUUserial.h
Normal file
@@ -0,0 +1,293 @@
|
||||
// vi:ts=4
|
||||
// ---------------------------------------------------------------------------
|
||||
// hd44780_NTCUUserial.h - hd44780_NTCUUserial i/o subclass for hd44780 library
|
||||
// Copyright (c) 2013-2019 Bill Perry
|
||||
//
|
||||
// The API functionality provided by this library class is compatible
|
||||
// with the API functionality of the Arduino LiquidCrystal library.
|
||||
//
|
||||
// ---------------------------------------------------------------------------
|
||||
//
|
||||
// This file is part of the hd44780 library
|
||||
//
|
||||
// hd44780_NTCUUserial is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation version 3 of the License.
|
||||
//
|
||||
// hd44780_NTCUUserial is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with hd44780_NTCUUserial. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
// ---------------------------------------------------------------------------
|
||||
//
|
||||
// It implements all the hd44780 library i/o methods to control a Noritake
|
||||
// CU-U Series VFD, in serial mode. Some CU-U boards are serial-only, some have
|
||||
// a jumper that must be set to enable serial mode, and some do not support
|
||||
// serial communication. See the application note for more information.
|
||||
//
|
||||
// This device has extended function set commands that are not directly
|
||||
// supported by the library but can be used through the command() API
|
||||
//
|
||||
// The device uses a kind of 3-wire SPI for communication.
|
||||
// Pinout:
|
||||
// 1 VCC
|
||||
// 2 SI/SO (DATA)
|
||||
// 3 GND
|
||||
// 4 STB (CS)
|
||||
// 5 SCK (CLK)
|
||||
// 6 NC
|
||||
//
|
||||
// The interface consists of sending 2 bytes serially for each hd44780
|
||||
// data/cmd.
|
||||
// The first byte is a control byte which sets the RS signal
|
||||
// The second byte is the data.
|
||||
//
|
||||
// The application note for CU-U series boards is here:
|
||||
// https://www.noritake-elec.com/includes/documents/brochure/CU-U_Application_Note.pdf
|
||||
// Datasheets for specific boards, code samples, and more can be found here:
|
||||
// https://www.noritake-elec.com/products/vfd-display-module/character-display/cu-u-series
|
||||
//
|
||||
//
|
||||
// @author Bill Perry - bperrybap@opensource.billsworld.billandterrie.com
|
||||
//
|
||||
// ---------------------------------------------------------------------------
|
||||
#ifndef hd44780_NTCUUserial_h
|
||||
#define hd44780_NTCUUserial_h
|
||||
|
||||
|
||||
class hd44780_NTCUUserial : public hd44780
|
||||
{
|
||||
public:
|
||||
// ====================
|
||||
// === constructors ===
|
||||
// ====================
|
||||
|
||||
// no parameters: use h/w spi signals
|
||||
// Note: This doesn't work for Leonardo since SS is not available and only drives an LED
|
||||
hd44780_NTCUUserial() : _cs(SS), _clk(SCK), _data(MOSI) { }
|
||||
|
||||
// supply alternate chip/slave select
|
||||
// will use h/w spi with alternate chip select
|
||||
hd44780_NTCUUserial(int cs) : _cs(cs), _clk(SCK), _data(MOSI) { }
|
||||
|
||||
// supply pins for chip select, clock, and data
|
||||
hd44780_NTCUUserial(uint8_t cs, uint8_t clk, uint8_t data) : _cs(cs), _clk(clk), _data(data) { }
|
||||
|
||||
private:
|
||||
// ====================
|
||||
// === private data ===
|
||||
// ====================
|
||||
|
||||
// Arduino Pin information
|
||||
|
||||
const uint8_t _cs; // arduino pin for chip select
|
||||
const uint8_t _clk; // arduino pin for clock
|
||||
const uint8_t _data; // arduino pin for data i/o
|
||||
|
||||
|
||||
// Control byte values
|
||||
|
||||
static const uint8_t CUU_startByte = 0xf8;
|
||||
static const uint8_t CUU_RS = (1 << 1); // RS bit. set for data, clear for command
|
||||
static const uint8_t CUU_RW = (1 << 2); // RW bit. set for read, clear for write
|
||||
|
||||
|
||||
// ==================================================
|
||||
// === hd44780 i/o subclass virtual i/o functions ===
|
||||
// ==================================================
|
||||
//
|
||||
|
||||
// ioinit() - Returns non zero if initialization failed.
|
||||
int ioinit()
|
||||
{
|
||||
// App note says "Wait at least 260 ms after VCC > 4.75VDC"
|
||||
// See also the delay in hd44780::begin()
|
||||
// In practice little or no delay at all may work fine
|
||||
delay(260);
|
||||
|
||||
// setup pins
|
||||
digitalWrite(_cs, HIGH);
|
||||
digitalWrite(_clk, HIGH);
|
||||
digitalWrite(_data, HIGH);
|
||||
|
||||
pinMode(_cs, OUTPUT);
|
||||
pinMode(_clk, OUTPUT);
|
||||
pinMode(_data, OUTPUT);
|
||||
|
||||
// check to see if SPI has beginTransaction() and endTransaction()
|
||||
// this was added in IDE 1.06 and so if using an IDE older than that,
|
||||
// H/W spi will not be used
|
||||
// This requires that <SPI.h> be included prior to this header
|
||||
#if defined(SPI_HAS_TRANSACTION)
|
||||
// check to see if h/w spi can be used
|
||||
if((_data == MOSI) && (_clk == SCK))
|
||||
SPI.begin();
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Serial interface of this device is always 8 bit
|
||||
*/
|
||||
_displayfunction = HD44780_8BITMODE;
|
||||
|
||||
return(hd44780::RV_ENOERR); // all is good
|
||||
}
|
||||
|
||||
|
||||
// ioread(type) - read a byte from VFD DDRAM
|
||||
//
|
||||
// returns 8 bit value read
|
||||
//
|
||||
int ioread(hd44780::iotype type)
|
||||
{
|
||||
uint8_t data = 0;
|
||||
|
||||
if(type == hd44780::HD44780_IOdata)
|
||||
{
|
||||
data = deviceread(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
data = deviceread(false);
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// iowrite(type, value) - send either a command or data byte to lcd
|
||||
//
|
||||
// returns zero on success, non zero on failure
|
||||
//
|
||||
int iowrite(hd44780::iotype type, uint8_t value)
|
||||
{
|
||||
if(type == hd44780::HD44780_IOdata)
|
||||
{
|
||||
devicewrite(value, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
devicewrite(value, false);
|
||||
}
|
||||
|
||||
return(hd44780::RV_ENOERR);
|
||||
}
|
||||
|
||||
|
||||
// iosetBacklight() - set backlight brightness
|
||||
// Since this display does not use a backlight but can control pixel intensity
|
||||
// use the backlight brightness to set the pixel intensity.
|
||||
//
|
||||
// Note:
|
||||
// The dimmer value on the CU-U Series is a 2 bit value
|
||||
// 00 is 100%
|
||||
// 01 is 75%
|
||||
// 10 is 50%
|
||||
// 11 is 25%
|
||||
//
|
||||
// Because of this, an API dimvalue of 0 does not turn off the display
|
||||
// so the code must check for that and explicitly turn off the display if the
|
||||
// API dimvalue is zero.
|
||||
int iosetBacklight(uint8_t dimvalue)
|
||||
{
|
||||
int status = RV_ENOERR;
|
||||
|
||||
if(dimvalue)
|
||||
{
|
||||
// Data which follows the FunctionSet command is considered as brightness data.
|
||||
command(HD44780_FUNCTIONSET | _displayfunction);
|
||||
// the dim value is 0-255 so divide by 64 to get a value 0-3
|
||||
if (_write(3 - dimvalue / 64) == 0)
|
||||
status = RV_EIO;
|
||||
|
||||
display();
|
||||
}
|
||||
else
|
||||
{
|
||||
noDisplay();
|
||||
}
|
||||
return(status);
|
||||
}
|
||||
|
||||
// ================================
|
||||
// === internal class functions ===
|
||||
// ================================
|
||||
|
||||
// deviceread() - send control and read data byte from the device
|
||||
uint8_t deviceread(bool rs)
|
||||
{
|
||||
uint8_t data = CUU_startByte | CUU_RW | (CUU_RS * rs);
|
||||
|
||||
#if defined(SPI_HAS_TRANSACTION)
|
||||
if((_data == MOSI) && (_clk == SCK))
|
||||
SPI.end();
|
||||
#endif
|
||||
|
||||
digitalWrite(_cs,LOW); // select device
|
||||
|
||||
digitalWrite(_clk, LOW);
|
||||
shiftOut(_data, _clk, MSBFIRST, data);
|
||||
|
||||
pinMode(_data, INPUT);
|
||||
delayMicroseconds(1);
|
||||
|
||||
digitalWrite(_clk, LOW);
|
||||
data = shiftIn(_data, _clk, MSBFIRST);
|
||||
|
||||
digitalWrite(_cs,HIGH); // deselect device
|
||||
|
||||
pinMode(_data, OUTPUT);
|
||||
|
||||
delayMicroseconds(5);
|
||||
|
||||
#if defined(SPI_HAS_TRANSACTION)
|
||||
if((_data == MOSI) && (_clk == SCK))
|
||||
SPI.begin();
|
||||
#endif
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
|
||||
// devicewrite() - send control and data byte to the device
|
||||
void devicewrite(uint8_t data, bool rs)
|
||||
{
|
||||
uint8_t startByte = CUU_startByte | (CUU_RS * rs);
|
||||
|
||||
// use h/w spi if we can
|
||||
#if defined(SPI_HAS_TRANSACTION)
|
||||
if((_data == MOSI) && (_clk == SCK))
|
||||
{
|
||||
// NOTE: App note says min 500ns clock cycle, so 2Mhz is max, 4Mhz seems to work.
|
||||
SPI.beginTransaction(SPISettings(4000000, MSBFIRST, SPI_MODE3));
|
||||
digitalWrite(_cs, LOW); // select device
|
||||
SPI.transfer(startByte);
|
||||
SPI.transfer(data);
|
||||
delayMicroseconds(1); // must delay at least 500ns before de-selecting
|
||||
digitalWrite(_cs, HIGH); // deselect device
|
||||
SPI.endTransaction();
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
digitalWrite(_cs, LOW); // select device
|
||||
|
||||
digitalWrite(_clk, LOW);
|
||||
shiftOut(_data, _clk, MSBFIRST, startByte);
|
||||
|
||||
digitalWrite(_clk, LOW);
|
||||
shiftOut(_data, _clk, MSBFIRST, data);
|
||||
|
||||
delayMicroseconds(1); // must delay at least 500ns before de-selecting
|
||||
digitalWrite(_cs, HIGH); // deselect device
|
||||
|
||||
delayMicroseconds(5);
|
||||
}
|
||||
}
|
||||
|
||||
}; // end of class definition
|
||||
#endif
|
||||
538
libraries/hd44780/hd44780ioClass/hd44780_pinIO.h
Normal file
538
libraries/hd44780/hd44780ioClass/hd44780_pinIO.h
Normal file
@@ -0,0 +1,538 @@
|
||||
// vi:ts=4
|
||||
// ---------------------------------------------------------------------------
|
||||
// hd44780_pinIO.h - hd44780_pinIO i/o subclass for hd44780 library
|
||||
// Copyright (c) 2016-2020 Bill Perry
|
||||
// ---------------------------------------------------------------------------
|
||||
//
|
||||
// This file is part of the hd44780 library
|
||||
//
|
||||
// hd44780_pinIO is free software: you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation version 3 of the License.
|
||||
//
|
||||
// hd44780_pinIO is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with hd44780_pinIO.
|
||||
// If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
// ---------------------------------------------------------------------------
|
||||
//
|
||||
// It implements all the hd44780 library i/o methods to control an LCD based
|
||||
// on the Hitachi HD44780 and compatible chipsets using direct Arduino
|
||||
// pin connections.
|
||||
//
|
||||
// The API functionality provided by this library class is compatible
|
||||
// with the functionality of the Arduino LiquidCrystal library.
|
||||
//
|
||||
//
|
||||
// 2020.08.01 bperrybap - removed calls to analogWrite() on ESP32 core (not supported)
|
||||
// 2019.08.11 bperrybap - fixed bug introduced by broken backlight check tweak
|
||||
// 2016.12.26 bperrybap - tweak to broken backlight check code
|
||||
// 2016.11.12 bperrybap - added code to safely handle broken backlight circuits
|
||||
// 2016.09.08 bperrybap - changed param order of iowrite() to match ioread()
|
||||
// 2016.08.06 bperrybap - added ioread()
|
||||
// 2016.08.06 bperrybap - changed iosend() to iowrite()
|
||||
// 2016.07.27 bperrybap - added return status for iosend()
|
||||
// 2016.07.21 bperrybap - merged all class code into header
|
||||
// 2016.07.20 bperrybap - merged into hd44780 library
|
||||
// 2016.06.03 bperrybap - added smart execution delays
|
||||
// 2016.04.01 bperrybap - initial creation
|
||||
//
|
||||
// @author Bill Perry - bperrybap@opensource.billsworld.billandterrie.com
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
#ifndef hd44780_pinIO_h
|
||||
#define hd44780_pinIO_h
|
||||
|
||||
#include <hd44780.h>
|
||||
// For STUPID versions of gcc that don't hard error on missing header files
|
||||
#ifndef hd44780_h
|
||||
#error Missing hd44780.h header file
|
||||
#endif
|
||||
#include <pins_arduino.h> // to get PWM detection macros
|
||||
|
||||
#define HIGHZ 0xfe // value is not critical but it cannot be the same as LOW or HIGH, or 0xff
|
||||
|
||||
class hd44780_pinIO : public hd44780
|
||||
{
|
||||
public:
|
||||
// ====================
|
||||
// === constructors ===
|
||||
// ====================
|
||||
|
||||
// 4 bit mode constructor without r/w control, without backlight control
|
||||
hd44780_pinIO(uint8_t rs, uint8_t en,
|
||||
uint8_t d4, uint8_t d5, uint8_t d6, uint8_t d7)
|
||||
{
|
||||
_rs = rs;
|
||||
_en = en;
|
||||
_rw = 0xff; // not used
|
||||
_d4 = d4;
|
||||
_d5 = d5;
|
||||
_d6 = d6;
|
||||
_d7 = d7;
|
||||
_bl = 0xff; // not used
|
||||
_blLevel = 0xff; // not used
|
||||
}
|
||||
|
||||
// 4 bit mode constructor without r/w control, with backlight control
|
||||
hd44780_pinIO(uint8_t rs, uint8_t en,
|
||||
uint8_t d4, uint8_t d5, uint8_t d6, uint8_t d7,
|
||||
uint8_t bl, uint8_t blLevel)
|
||||
{
|
||||
_rs = rs;
|
||||
_en = en;
|
||||
_rw = 0xff; // not used
|
||||
_d4 = d4;
|
||||
_d5 = d5;
|
||||
_d6 = d6;
|
||||
_d7 = d7;
|
||||
_bl = bl;
|
||||
_blLevel = blLevel;
|
||||
}
|
||||
|
||||
|
||||
// 4 bit mode constructor with r/w control, without backlight control
|
||||
hd44780_pinIO(uint8_t rs, uint8_t rw, uint8_t en,
|
||||
uint8_t d4, uint8_t d5, uint8_t d6, uint8_t d7)
|
||||
{
|
||||
_rs = rs;
|
||||
_en = en;
|
||||
_rw = rw;
|
||||
_d4 = d4;
|
||||
_d5 = d5;
|
||||
_d6 = d6;
|
||||
_d7 = d7;
|
||||
_bl = 0xff; // not used
|
||||
_blLevel = 0xff; // not used
|
||||
}
|
||||
|
||||
// 4 bit mode constructor with w/2 control, with backlight control
|
||||
hd44780_pinIO(uint8_t rs, uint8_t rw, uint8_t en,
|
||||
uint8_t d4, uint8_t d5, uint8_t d6, uint8_t d7,
|
||||
uint8_t bl, uint8_t blLevel)
|
||||
{
|
||||
_rs = rs;
|
||||
_en = en;
|
||||
_rw = rw;
|
||||
_d4 = d4;
|
||||
_d5 = d5;
|
||||
_d6 = d6;
|
||||
_d7 = d7;
|
||||
_bl = bl;
|
||||
_blLevel = blLevel;
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
// ====================
|
||||
// === private data ===
|
||||
// ====================
|
||||
|
||||
// Arduino Pin information
|
||||
uint8_t _rs; // hd44780 rs arduino pin
|
||||
uint8_t _rw; // hd44780 rw arduino pin
|
||||
uint8_t _en; // hd44780 en arduino pin
|
||||
uint8_t _d4; // hd44780 d4 arduino pin
|
||||
uint8_t _d5; // hd44780 d4 arduino pin
|
||||
uint8_t _d6; // hd44780 d4 arduino pin
|
||||
uint8_t _d7; // hd44780 d4 arduino pin
|
||||
uint8_t _bl; // arduino pin to control backlight
|
||||
uint8_t _blLevel; // backlight active control level HIGH/LOW
|
||||
// (HIGHZ is input mode for ON, LOW for off)
|
||||
|
||||
|
||||
// ==================================================
|
||||
// === hd44780 i/o subclass virtual i/o functions ===
|
||||
// ==================================================
|
||||
|
||||
// ioinit() - initialize the h/w
|
||||
int ioinit()
|
||||
{
|
||||
// initialize Arduino pins used for hd44780 signals
|
||||
// NOTE:
|
||||
// _rw and _en pins are set to low even though they should
|
||||
// default to this from a an initial reset.
|
||||
// the reason is it is possible initilization is called without
|
||||
// without resetting the processor. In that case the state of the
|
||||
// bit in the port register would be unknown, so it is safest to set
|
||||
// to the desired state (LOW).
|
||||
|
||||
pinMode(_rs, OUTPUT);
|
||||
|
||||
if(_rw != 0xff)
|
||||
{
|
||||
pinMode(_rw, OUTPUT);
|
||||
// if r/w is used it be will set to be low,
|
||||
// it will only be turned hi during a read and
|
||||
// then set back to low. This offers a slight boost
|
||||
// for writes since normally reads are not done very often
|
||||
digitalWrite(_rw, LOW);
|
||||
}
|
||||
|
||||
pinMode(_en, OUTPUT);
|
||||
digitalWrite(_en, LOW);
|
||||
|
||||
pinMode(_d4, OUTPUT);
|
||||
pinMode(_d5, OUTPUT);
|
||||
pinMode(_d6, OUTPUT);
|
||||
pinMode(_d7, OUTPUT);
|
||||
|
||||
if(_bl != 0xff)
|
||||
{
|
||||
// check for broken backlight circuit on LCDkeypads
|
||||
// and protect Arduino if it appears to be broken
|
||||
// code will do "safe" backlight control
|
||||
|
||||
if((_blLevel == HIGH) && blPinTest(_bl))
|
||||
_blLevel = HIGHZ;
|
||||
|
||||
pinMode(_bl, OUTPUT);
|
||||
}
|
||||
|
||||
return(hd44780::RV_ENOERR); // all is good
|
||||
}
|
||||
|
||||
// ioread(type) - read a byte from LCD DDRAM
|
||||
//
|
||||
// returns:
|
||||
// success: 8 bit value read
|
||||
// failure: negative value: reading not supported
|
||||
//
|
||||
int ioread(hd44780::iotype type)
|
||||
{
|
||||
uint8_t data = 0;
|
||||
|
||||
// check if r/w control supported
|
||||
if(_rw == 0xff)
|
||||
return(hd44780::RV_ENOTSUP);
|
||||
|
||||
waitReady(); // ensure previous instruction finished
|
||||
|
||||
// put all the LCD data pins into input mode.
|
||||
pinMode(_d4, INPUT);
|
||||
pinMode(_d5, INPUT);
|
||||
pinMode(_d6, INPUT);
|
||||
pinMode(_d7, INPUT);
|
||||
|
||||
// set RS based on type of read (data or status/cmd)
|
||||
if(type == hd44780::HD44780_IOdata)
|
||||
{
|
||||
digitalWrite(_rs, HIGH); // RS high to access data reg
|
||||
}
|
||||
else
|
||||
{
|
||||
digitalWrite(_rs, LOW); // RS LOW to access status/cmd reg
|
||||
}
|
||||
|
||||
// r/w HIGH for reading
|
||||
digitalWrite(_rw, HIGH);
|
||||
|
||||
// raise E to allow reading the data.
|
||||
digitalWrite(_en, HIGH);
|
||||
|
||||
// allow for hd44780 tDDR (Data delay time) before reading data
|
||||
// this could be much shorter but this is portable for all CPUs.
|
||||
// and it will ensure that hd44780 PWEH timing is honored as well.
|
||||
delayMicroseconds(1);
|
||||
|
||||
// read pins for d4-d7 into upper nibble of byte
|
||||
if(digitalRead(_d4) == HIGH)
|
||||
data |= (1 << 4);
|
||||
|
||||
if(digitalRead(_d5) == HIGH)
|
||||
data |= (1 << 5);
|
||||
|
||||
if(digitalRead(_d6) == HIGH)
|
||||
data |= (1 << 6);
|
||||
|
||||
if(digitalRead(_d7) == HIGH)
|
||||
data |= (1 << 7);
|
||||
|
||||
// lower E after reading nibble
|
||||
digitalWrite(_en, LOW);
|
||||
|
||||
// allow for hd44780 1/2 of tcycE (Enable cycle time)
|
||||
// this could be much shorter but this is portable for all CPUs.
|
||||
delayMicroseconds(1);
|
||||
|
||||
// raise E to allow reading the lower nibbly of the byte
|
||||
digitalWrite(_en, HIGH);
|
||||
|
||||
// allow for hd44780 tDDR (Data delay time) before reading data
|
||||
// this could be shorter but this is portable for all CPUs.
|
||||
// and it will ensure that hd44780 PWEH timing is honored as well.
|
||||
delayMicroseconds(1);
|
||||
|
||||
// read pins for d4-d7 into upper nibble of byte
|
||||
if(digitalRead(_d4) == HIGH)
|
||||
data |= (1 << 0);
|
||||
|
||||
if(digitalRead(_d5) == HIGH)
|
||||
data |= (1 << 1);
|
||||
|
||||
if(digitalRead(_d6) == HIGH)
|
||||
data |= (1 << 2);
|
||||
|
||||
if(digitalRead(_d7) == HIGH)
|
||||
data |= (1 << 3);
|
||||
|
||||
|
||||
// lower E after reading nibble
|
||||
digitalWrite(_en, LOW);
|
||||
|
||||
//
|
||||
// put all pins back into state for writing to LCD
|
||||
//
|
||||
|
||||
// put all the LCD data pins into input mode.
|
||||
pinMode(_d4, OUTPUT);
|
||||
pinMode(_d5, OUTPUT);
|
||||
pinMode(_d6, OUTPUT);
|
||||
pinMode(_d7, OUTPUT);
|
||||
|
||||
// r/w LOW for Writing
|
||||
digitalWrite(_rw, LOW);
|
||||
|
||||
return(data);
|
||||
}
|
||||
|
||||
|
||||
// iowrite(type, value) - send either a command or data byte to lcd
|
||||
// returns zero on success, non zero on failure
|
||||
int iowrite(hd44780::iotype type, uint8_t value)
|
||||
{
|
||||
if(type == hd44780::HD44780_IOdata)
|
||||
digitalWrite(_rs, HIGH);
|
||||
else
|
||||
digitalWrite(_rs, LOW);
|
||||
|
||||
// "4 bit commands" are special.
|
||||
// They are used only during initalization and
|
||||
// are used to reliably get the LCD and host in nibble sync
|
||||
// with each other and to get the LCD into 4 bit mode.
|
||||
// 8 bit host interfaces don't have to worry about this,
|
||||
// but 4 bit host interfaces must only send the upper nibble.
|
||||
|
||||
// note:
|
||||
// waitReady() is explicitly called as late as possible *after* the Arduino
|
||||
// pins for the LCD control and data signals are set to allow
|
||||
// overhead of the digitalWrite() calls to be hidden under execution time.
|
||||
|
||||
write4bits(value>>4); // setup uppper nibble d4-d7 lcd pins
|
||||
waitReady(); // ensure previous instruction finished
|
||||
pulseEnable(); // send upper nibble to LCD
|
||||
|
||||
// send lower nibble if not a 4 bit command
|
||||
// (sends nibble for both data and "normal" commands)
|
||||
if (type != hd44780::HD44780_IOcmd4bit )
|
||||
{
|
||||
write4bits((value & 0x0F));// setup lower nibble on d4-d7 lcd pins
|
||||
pulseEnable(); // send lower nibble to LCD
|
||||
}
|
||||
return(hd44780::RV_ENOERR); // it never fails
|
||||
}
|
||||
|
||||
// iosetBacklight() - set backlight brightness
|
||||
// if dimming not supported, any non zero dimvalue turns backlight on
|
||||
int iosetBacklight(uint8_t dimvalue)
|
||||
{
|
||||
if (_bl == 0xff )
|
||||
return(hd44780::RV_ENOTSUP); // no backlight pin so nothing to do
|
||||
|
||||
// Check for HIGHZ active level which is used on LCDkeypads with broken backlight circuits
|
||||
// In HIGHZ active level, the output is is never driven high, instead the pin is put
|
||||
// into input mode to turn on the backlight.
|
||||
// To turn off the backlight, the pin is flipped to output mode.
|
||||
// because the pin is never set to HIGH, when the pin is set to output mode it will be LOW.
|
||||
|
||||
if(_blLevel == HIGHZ)
|
||||
{
|
||||
if(dimvalue)
|
||||
pinMode(_bl, INPUT);
|
||||
else
|
||||
pinMode(_bl, OUTPUT);
|
||||
return(hd44780::RV_ENOERR);
|
||||
}
|
||||
|
||||
// Check if backlight pin has PWM support
|
||||
// The reason this has to be done is that Arduino analogWrite()
|
||||
// sets a pin to LOW if there is no PWM support and the PWM value is
|
||||
// less than half of maximum. This is not desired behavior.
|
||||
// The desired behavior is that if dimming is not supported, then the
|
||||
// output is full on until the PWM value is zero to indicate "off".
|
||||
// So we have to bypass the goofy code in analogWrite()
|
||||
// by detecting if the pin supports PWM and controlling the output manually
|
||||
// when no PWM is available.
|
||||
|
||||
// NOTE: the ESP32 core does not have analogWrite() PWM support !
|
||||
// so on ESP32 core, all you get is on/off
|
||||
#if !defined(ARDUINO_ARCH_ESP32)
|
||||
|
||||
#if defined(digitalPinHasPWM)
|
||||
// Newer 1.5x Arduino has a macro to check for PWM capability on a pin
|
||||
if(digitalPinHasPWM(_bl))
|
||||
#elif defined(digitalPinToTimer)
|
||||
// On 1.x Arduino have to check differently
|
||||
if(digitalPinToTimer(_bl) != NOT_ON_TIMER)
|
||||
#else
|
||||
if(0) // no way to tell so assume no PWM
|
||||
#endif
|
||||
{
|
||||
// set PWM signal appropriately for active level
|
||||
if(_blLevel == HIGH)
|
||||
{
|
||||
analogWrite(_bl, dimvalue);
|
||||
}
|
||||
else
|
||||
{
|
||||
analogWrite(_bl, 255 - dimvalue); // active low is inverse PWM
|
||||
}
|
||||
}
|
||||
|
||||
// No PWM support on pin, so
|
||||
// dimvalue 0 is off, any other value is on
|
||||
else
|
||||
#endif
|
||||
if(((dimvalue) && (_blLevel == HIGH)) ||
|
||||
((dimvalue == 0) && (_blLevel == LOW)))
|
||||
{
|
||||
digitalWrite(_bl, HIGH);
|
||||
}
|
||||
else
|
||||
{
|
||||
digitalWrite(_bl, LOW);
|
||||
}
|
||||
return(hd44780::RV_ENOERR);
|
||||
}
|
||||
|
||||
// ================================
|
||||
// === internal class functions ===
|
||||
// ================================
|
||||
|
||||
// write4bits() - set the 4 hd44780 data lines
|
||||
void write4bits(uint8_t value)
|
||||
{
|
||||
// write the bits on the LCD data lines but don't send the data
|
||||
if(value & 1)
|
||||
digitalWrite(_d4, HIGH);
|
||||
else
|
||||
digitalWrite(_d4, LOW);
|
||||
|
||||
if(value & 2)
|
||||
digitalWrite(_d5, HIGH);
|
||||
else
|
||||
digitalWrite(_d5, LOW);
|
||||
|
||||
if(value & 4)
|
||||
digitalWrite(_d6, HIGH);
|
||||
else
|
||||
digitalWrite(_d6, LOW);
|
||||
|
||||
if(value & 8)
|
||||
digitalWrite(_d7, HIGH);
|
||||
else
|
||||
digitalWrite(_d7, LOW);
|
||||
}
|
||||
|
||||
// pulseEnable() - toggle en to send data to hd44780 module
|
||||
void pulseEnable(void)
|
||||
{
|
||||
digitalWrite(_en, HIGH);
|
||||
#if defined (ARDUINO_ARCH_ESP8266) || defined(ARDUINO_ARCH_ESP32)
|
||||
// the extra delay here is not for the LCD, it is to allow signal lines time
|
||||
// to settle when using 3v esp modules with 5v LCDs.
|
||||
// 3v outputs on 5v inputs is already a bit out of spec and
|
||||
// without this, the slew rate isn't fast enough to get "reliable"
|
||||
// signal levels
|
||||
// while it isn't needed for 3v LCDs, the time penalty isn't much
|
||||
// to always do it.
|
||||
delayMicroseconds(2); // enable pulse must be >450ns
|
||||
#else
|
||||
delayMicroseconds(1); // enable pulse must be >450ns
|
||||
#endif
|
||||
digitalWrite(_en, LOW);
|
||||
}
|
||||
|
||||
//
|
||||
// Function to test a backlight pin
|
||||
// Returns non-zero if test fails (bad circuit design)
|
||||
int blPinTest(int pin)
|
||||
{
|
||||
int val;
|
||||
|
||||
/*
|
||||
* Check to see if there
|
||||
* is a problem in the backlight circuit
|
||||
* So far, the "broken" designs connected D10
|
||||
* directly to the base of a NPN transistor,
|
||||
* this will cause a short when D10 is set to HIGH
|
||||
* as there is no current limiting resistor in the path
|
||||
* between D10 to the base and the emitter to ground.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Set the pin to an input with pullup disabled.
|
||||
* This should be safe on all shields.
|
||||
* The reason for the digitalWrite() first is that
|
||||
* only the newer Arduino cores disable the pullup
|
||||
* when setting the pin to INPUT.
|
||||
* On boards that have a pullup on the transistor base,
|
||||
* this should cause the backlight to be on.
|
||||
*/
|
||||
digitalWrite(pin, LOW);
|
||||
pinMode(pin, INPUT);
|
||||
|
||||
/*
|
||||
* Set the backlight pin to an output.
|
||||
* since the pullup was turned off above by
|
||||
* setting the pin to input mode,
|
||||
* it should drive the pin LOW which should
|
||||
* be safe given the known design flaw.
|
||||
*/
|
||||
pinMode(pin, OUTPUT);
|
||||
|
||||
/*
|
||||
* Set the backlight pin to HIGH
|
||||
* NOTE: This is NOT a safe thing to do
|
||||
* on the broken designs. The code will minimize
|
||||
* the time this is done to prevent any potential damage.
|
||||
*/
|
||||
|
||||
digitalWrite(pin, HIGH);
|
||||
|
||||
|
||||
/*
|
||||
* Now read back the pin value to
|
||||
* See if a short is pulling down the HIGH output.
|
||||
*/
|
||||
|
||||
delayMicroseconds(5); // give some time for the signal to droop
|
||||
|
||||
val = digitalRead(pin); // read the level on the pin
|
||||
|
||||
/*
|
||||
* Restore the pin to a safe state
|
||||
* Input with pullup turned off
|
||||
*/
|
||||
digitalWrite(pin, LOW);
|
||||
pinMode(pin, INPUT);
|
||||
|
||||
/*
|
||||
* If the level read back is not HIGH
|
||||
* Then there is a problem because the pin is
|
||||
* being driven HIGH by the AVR.
|
||||
*/
|
||||
if (val != HIGH)
|
||||
return(-1); // test failed
|
||||
else
|
||||
return(0); // all is ok.
|
||||
}
|
||||
|
||||
|
||||
}; // end of class definition
|
||||
#endif
|
||||
Reference in New Issue
Block a user