mirror of
https://github.com/fmalpartida/New-LiquidCrystal.git
synced 2026-09-15 11:04:31 +00:00
334 lines
10 KiB
C++
334 lines
10 KiB
C++
// ---------------------------------------------------------------------------
|
|
// Created by Francisco Malpartida on 20/08/11.
|
|
// Copyright (C) - 2018
|
|
//
|
|
// This program 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, either version 3 of the License, or
|
|
// any later version.
|
|
//
|
|
// This program 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 v3.0
|
|
// along with this program.
|
|
// If not, see <https://www.gnu.org/licenses/gpl-3.0.en.html>.
|
|
//
|
|
// ---------------------------------------------------------------------------
|
|
//
|
|
// Thread Safe: No
|
|
// Extendable: Yes
|
|
//
|
|
// @file LiquidCrystal.cpp
|
|
// This file implements a basic liquid crystal library that comes as standard
|
|
// in the Arduino SDK.
|
|
//
|
|
// @brief
|
|
// This is a basic implementation of the LiquidCrystal library of the
|
|
// Arduino SDK. The original library has been reworked in such a way that
|
|
// this class implements the all methods to command an LCD based
|
|
// on the Hitachi HD44780 and compatible chipsets using the parallel port of
|
|
// the LCD (4 bit and 8 bit).
|
|
//
|
|
// The functionality provided by this class and its base class is identical
|
|
// to the original functionality of the Arduino LiquidCrystal library.
|
|
//
|
|
//
|
|
// @author F. Malpartida - fmalpartida@gmail.com
|
|
// ---------------------------------------------------------------------------
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <inttypes.h>
|
|
|
|
#if (ARDUINO < 100)
|
|
#include <WProgram.h>
|
|
#else
|
|
#include <Arduino.h>
|
|
#endif
|
|
#include "LiquidCrystal.h"
|
|
|
|
// CONSTANT definitions
|
|
// ---------------------------------------------------------------------------
|
|
#define LCD_NOBACKLIGHT 0xFF
|
|
|
|
// LCD driver configuration (4bit or 8bit driver control)
|
|
#define LCD_4BIT 1
|
|
#define LCD_8BIT 0
|
|
|
|
// STATIC helper functions
|
|
// ---------------------------------------------------------------------------
|
|
|
|
|
|
// CONSTRUCTORS
|
|
// ---------------------------------------------------------------------------
|
|
|
|
LiquidCrystal::LiquidCrystal(uint8_t rs, uint8_t enable,
|
|
uint8_t d0, uint8_t d1, uint8_t d2, uint8_t d3,
|
|
uint8_t d4, uint8_t d5, uint8_t d6, uint8_t d7)
|
|
{
|
|
init(LCD_8BIT, rs, 255, enable, d0, d1, d2, d3, d4, d5, d6, d7);
|
|
}
|
|
|
|
LiquidCrystal::LiquidCrystal(uint8_t rs, uint8_t rw, uint8_t enable,
|
|
uint8_t d0, uint8_t d1, uint8_t d2, uint8_t d3,
|
|
uint8_t d4, uint8_t d5, uint8_t d6, uint8_t d7)
|
|
{
|
|
init(LCD_8BIT, rs, rw, enable, d0, d1, d2, d3, d4, d5, d6, d7);
|
|
}
|
|
|
|
LiquidCrystal::LiquidCrystal(uint8_t rs, uint8_t rw, uint8_t enable,
|
|
uint8_t d0, uint8_t d1, uint8_t d2, uint8_t d3)
|
|
{
|
|
init(LCD_4BIT, rs, rw, enable, d0, d1, d2, d3, 0, 0, 0, 0);
|
|
}
|
|
|
|
LiquidCrystal::LiquidCrystal(uint8_t rs, uint8_t enable,
|
|
uint8_t d0, uint8_t d1, uint8_t d2, uint8_t d3)
|
|
{
|
|
init(LCD_4BIT, rs, 255, enable, d0, d1, d2, d3, 0, 0, 0, 0);
|
|
}
|
|
|
|
// Contructors with backlight control
|
|
LiquidCrystal::LiquidCrystal(uint8_t rs, uint8_t enable,
|
|
uint8_t d0, uint8_t d1, uint8_t d2, uint8_t d3,
|
|
uint8_t d4, uint8_t d5, uint8_t d6, uint8_t d7,
|
|
uint8_t backlightPin, t_backlightPol pol)
|
|
{
|
|
init(LCD_8BIT, rs, 255, enable, d0, d1, d2, d3, d4, d5, d6, d7);
|
|
setBacklightPin ( backlightPin, pol );
|
|
}
|
|
|
|
LiquidCrystal::LiquidCrystal(uint8_t rs, uint8_t rw, uint8_t enable,
|
|
uint8_t d0, uint8_t d1, uint8_t d2, uint8_t d3,
|
|
uint8_t d4, uint8_t d5, uint8_t d6, uint8_t d7,
|
|
uint8_t backlightPin, t_backlightPol pol)
|
|
{
|
|
init(LCD_8BIT, rs, rw, enable, d0, d1, d2, d3, d4, d5, d6, d7);
|
|
setBacklightPin ( backlightPin, pol );
|
|
}
|
|
|
|
LiquidCrystal::LiquidCrystal(uint8_t rs, uint8_t rw, uint8_t enable,
|
|
uint8_t d0, uint8_t d1, uint8_t d2, uint8_t d3,
|
|
uint8_t backlightPin, t_backlightPol pol)
|
|
{
|
|
init(LCD_4BIT, rs, rw, enable, d0, d1, d2, d3, 0, 0, 0, 0);
|
|
setBacklightPin ( backlightPin, pol );
|
|
}
|
|
|
|
LiquidCrystal::LiquidCrystal(uint8_t rs, uint8_t enable,
|
|
uint8_t d0, uint8_t d1, uint8_t d2, uint8_t d3,
|
|
uint8_t backlightPin, t_backlightPol pol)
|
|
{
|
|
init(LCD_4BIT, rs, 255, enable, d0, d1, d2, d3, 0, 0, 0, 0);
|
|
setBacklightPin ( backlightPin, pol );
|
|
}
|
|
|
|
// PUBLIC METHODS
|
|
// ---------------------------------------------------------------------------
|
|
|
|
/************ low level data pushing commands **********/
|
|
//
|
|
// send
|
|
void LiquidCrystal::send(uint8_t value, uint8_t mode)
|
|
{
|
|
// Only interested in COMMAND or DATA
|
|
digitalWrite( _rs_pin, ( mode == LCD_DATA ) );
|
|
|
|
// if there is a RW pin indicated, set it low to Write
|
|
// ---------------------------------------------------
|
|
if (_rw_pin != 255)
|
|
{
|
|
digitalWrite(_rw_pin, LOW);
|
|
}
|
|
|
|
if ( mode != FOUR_BITS )
|
|
{
|
|
if ( (_displayfunction & LCD_8BITMODE ) )
|
|
{
|
|
writeNbits(value, 8);
|
|
}
|
|
else
|
|
{
|
|
writeNbits ( value >> 4, 4 );
|
|
writeNbits ( value, 4 );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
writeNbits ( value, 4 );
|
|
}
|
|
waitUsec ( EXEC_TIME ); // wait for the command to execute by the LCD
|
|
}
|
|
|
|
//
|
|
// setBacklightPin
|
|
void LiquidCrystal::setBacklightPin ( uint8_t pin, t_backlightPol pol )
|
|
{
|
|
pinMode ( pin, OUTPUT ); // Difine the backlight pin as output
|
|
_backlightPin = pin;
|
|
_polarity = pol;
|
|
setBacklight(BACKLIGHT_OFF); // Set the backlight low by default
|
|
}
|
|
|
|
//
|
|
// ESP32 complains if not included
|
|
#if defined(ARDUINO_ARCH_ESP32)
|
|
void LiquidCrystal::analogWrite( uint8_t channel, uint32_t value, uint32_t valueMax = 255 ) {
|
|
// calculate duty, 8191 from 2 ^ 13 - 1
|
|
uint32_t duty = ( 8191 / valueMax) * min(value, valueMax );
|
|
|
|
// write duty to LEDC
|
|
ledcWrite( channel, duty );
|
|
}
|
|
#endif
|
|
|
|
//
|
|
// setBackligh
|
|
void LiquidCrystal::setBacklight ( uint8_t value )
|
|
{
|
|
// Check if there is a pin assigned to the backlight
|
|
// ---------------------------------------------------
|
|
if ( _backlightPin != LCD_NOBACKLIGHT )
|
|
{
|
|
|
|
// Check if the pin is associated to a timer, i.e. PWM
|
|
// We dont need to use != NOT_ON_TIMER hack to detect PWM and
|
|
// 1.5x Arduino and above has a macro to check for PWM capability
|
|
// on a pin.
|
|
// ---------------------------------------------------
|
|
#if digitalPinHasPWM
|
|
if(digitalPinHasPWM(_backlightPin))
|
|
#elif digitalPinToTimer
|
|
// On older 1.x Arduino have to check using hack
|
|
if(digitalPinToTimer(_backlightPin) != NOT_ON_TIMER)
|
|
#else
|
|
if(false) // if neither of the above we assume no PWM
|
|
#endif
|
|
{
|
|
// Check for control polarity inversion
|
|
// ---------------------------------------------------
|
|
if ( _polarity == POSITIVE )
|
|
{
|
|
analogWrite ( _backlightPin, value );
|
|
}
|
|
else
|
|
{
|
|
analogWrite ( _backlightPin, 255 - value );
|
|
}
|
|
}
|
|
// Not a PWM pin, set the backlight pin for POSI or NEG
|
|
// polarity
|
|
// --------------------------------------------------------
|
|
else if (((value > 0) && (_polarity == POSITIVE)) ||
|
|
((value == 0) && (_polarity == NEGATIVE)))
|
|
{
|
|
digitalWrite( _backlightPin, HIGH);
|
|
}
|
|
else
|
|
{
|
|
digitalWrite( _backlightPin, LOW);
|
|
}
|
|
}
|
|
}
|
|
|
|
// PRIVATE METHODS
|
|
// ---------------------------------------------------------------------------
|
|
|
|
|
|
// init
|
|
void LiquidCrystal::init(uint8_t fourbitmode, uint8_t rs, uint8_t rw, uint8_t enable,
|
|
uint8_t d0, uint8_t d1, uint8_t d2, uint8_t d3,
|
|
uint8_t d4, uint8_t d5, uint8_t d6, uint8_t d7)
|
|
{
|
|
uint8_t i;
|
|
|
|
// Initialize the IO pins
|
|
// -----------------------
|
|
|
|
_rs_pin = rs;
|
|
_rw_pin = rw;
|
|
_enable_pin = enable;
|
|
|
|
_data_pins[0] = d0;
|
|
_data_pins[1] = d1;
|
|
_data_pins[2] = d2;
|
|
_data_pins[3] = d3;
|
|
_data_pins[4] = d4;
|
|
_data_pins[5] = d5;
|
|
_data_pins[6] = d6;
|
|
_data_pins[7] = d7;
|
|
|
|
// Initialize the IO port direction to OUTPUT
|
|
// ------------------------------------------
|
|
|
|
for ( i = 0; i < 4; i++ )
|
|
{
|
|
pinMode ( _data_pins[i], OUTPUT );
|
|
}
|
|
|
|
// Initialize the rest of the ports if it is an 8bit controlled LCD
|
|
// ----------------------------------------------------------------
|
|
|
|
if ( !fourbitmode )
|
|
{
|
|
for ( i = 4; i < 8; i++ )
|
|
{
|
|
pinMode ( _data_pins[i], OUTPUT );
|
|
}
|
|
}
|
|
pinMode(_rs_pin, OUTPUT);
|
|
|
|
// we can save 1 pin by not using RW. Indicate by passing 255 instead of pin#
|
|
if (_rw_pin != 255)
|
|
{
|
|
pinMode(_rw_pin, OUTPUT);
|
|
}
|
|
|
|
pinMode(_enable_pin, OUTPUT);
|
|
|
|
// Initialise displaymode functions to defaults: LCD_1LINE and LCD_5x8DOTS
|
|
// -------------------------------------------------------------------------
|
|
if (fourbitmode)
|
|
_displayfunction = LCD_4BITMODE | LCD_1LINE | LCD_5x8DOTS;
|
|
else
|
|
_displayfunction = LCD_8BITMODE | LCD_1LINE | LCD_5x8DOTS;
|
|
|
|
// Now we pull both RS and R/W low to begin commands
|
|
digitalWrite(_rs_pin, LOW);
|
|
digitalWrite(_enable_pin, LOW);
|
|
|
|
if (_rw_pin != 255)
|
|
{
|
|
digitalWrite(_rw_pin, LOW);
|
|
}
|
|
|
|
// Initialise the backlight pin no nothing
|
|
_backlightPin = LCD_NOBACKLIGHT;
|
|
_polarity = POSITIVE;
|
|
}
|
|
|
|
//
|
|
// pulseEnable
|
|
void LiquidCrystal::pulseEnable(void)
|
|
{
|
|
// There is no need for the delays, since the digitalWrite operation
|
|
// takes longer.
|
|
digitalWrite(_enable_pin, HIGH);
|
|
waitUsec(1); // enable pulse must be > 450ns
|
|
digitalWrite(_enable_pin, LOW);
|
|
}
|
|
|
|
//
|
|
// write4bits
|
|
void LiquidCrystal::writeNbits(uint8_t value, uint8_t numBits)
|
|
{
|
|
for (uint8_t i = 0; i < numBits; i++)
|
|
{
|
|
digitalWrite(_data_pins[i], (value >> i) & 0x01);
|
|
}
|
|
pulseEnable();
|
|
}
|
|
|