ESP-Ventilation/LiquidCrystal/src/LiquidCrystal.cpp
2022-10-16 11:27:26 +03:00

350 lines
8.7 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "LiquidCrystal.h"
#include "chip.h"
#include <cstring>
#define LOW 0
#define HIGH 1
void
delayMicroseconds (unsigned int us)
{
uint32_t reg;
// calculate compare value
uint64_t cmp = (Chip_Clock_GetSystemClockRate () / 1000000)
* us; // One cycle equals ~72 us, thus cycle * us
// disable RIT compare value may only be changed when RIT is disabled
reg = LPC_RITIMER->CTRL & 0xF;
LPC_RITIMER->CTRL = reg & ~RIT_CTRL_TEN;
// set compare value to RIT
LPC_RITIMER->COMPVAL = (uint32_t)cmp;
LPC_RITIMER->COMPVAL_H = (uint32_t) (cmp >> 32);
// clear RIT counter (so that counting starts from zero)
LPC_RITIMER->COUNTER = (uint32_t)0;
LPC_RITIMER->COUNTER_H = (uint32_t) (0 >> 32);
// enable RIT
reg = LPC_RITIMER->CTRL & 0xF;
LPC_RITIMER->CTRL = reg | RIT_CTRL_TEN;
// wait until RIT Int flag is set
while (!(LPC_RITIMER->CTRL & RIT_CTRL_INT))
;
// disable RIT
reg = LPC_RITIMER->CTRL & 0xF;
LPC_RITIMER->CTRL = reg & ~RIT_CTRL_TEN;
// clear RIT Int flag
reg = LPC_RITIMER->CTRL & 0xF;
LPC_RITIMER->CTRL = reg | RIT_CTRL_INT;
}
// When the display powers up, it is configured as follows:
//
// 1. Display clear
// 2. Function set:
// DL = 1; 8-bit interface data
// N = 0; 1-line display
// F = 0; 5x8 dot character font
// 3. Display on/off control:
// D = 0; Display off
// C = 0; Cursor off
// B = 0; Blinking off
// 4. Entry mode set:
// I/D = 1; Increment by 1
// S = 0; No shift
//
// Note, however, that resetting the Arduino doesn't reset the LCD, so we
// can't assume that its in that state when a sketch starts (and the
// LiquidCrystal constructor is called).
LiquidCrystal::LiquidCrystal (DigitalIoPin *rs, DigitalIoPin *enable,
DigitalIoPin *d0, DigitalIoPin *d1,
DigitalIoPin *d2, DigitalIoPin *d3)
{
rs_pin = rs;
enable_pin = enable;
data_pins[0] = d0;
data_pins[1] = d1;
data_pins[2] = d2;
data_pins[3] = d3;
_displayfunction = LCD_4BITMODE | LCD_1LINE | LCD_5x8DOTS;
begin (16, 2); // default to 16x2 display
}
void
LiquidCrystal::begin (uint8_t cols, uint8_t lines, uint8_t dotsize)
{
this->rows = lines;
this->col = cols;
if (lines > 1)
{
_displayfunction |= LCD_2LINE;
}
_numlines = lines;
_currline = 0;
// for some 1 line displays you can select a 10 pixel high font
if ((dotsize != 0) && (lines == 1))
{
_displayfunction |= LCD_5x10DOTS;
}
// SEE PAGE 45/46 FOR INITIALIZATION SPECIFICATION!
// according to datasheet, we need at least 40ms after power rises above 2.7V
// before sending commands. Arduino can turn on way befer 4.5V so we'll wait
// 50
delayMicroseconds (50000);
// Now we pull both RS and R/W low to begin commands
rs_pin->write (false); // digitalWrite(_rs_pin, LOW);
enable_pin->write (false); // digitalWrite(_enable_pin, LOW);
// note: this port supports only 4 bit mode
// put the LCD into 4 bit or 8 bit mode
if (!(_displayfunction & LCD_8BITMODE))
{
// this is according to the hitachi HD44780 datasheet
// figure 24, pg 46
// we start in 8bit mode, try to set 4 bit mode
write4bits (0x03);
delayMicroseconds (4500); // wait min 4.1ms
// second try
write4bits (0x03);
delayMicroseconds (4500); // wait min 4.1ms
// third go!
write4bits (0x03);
delayMicroseconds (150);
// finally, set to 4-bit interface
write4bits (0x02);
}
else
{
// this is according to the hitachi HD44780 datasheet
// page 45 figure 23
// Send function set command sequence
command (LCD_FUNCTIONSET | _displayfunction);
delayMicroseconds (4500); // wait more than 4.1ms
// second try
command (LCD_FUNCTIONSET | _displayfunction);
delayMicroseconds (150);
// third go
command (LCD_FUNCTIONSET | _displayfunction);
}
// finally, set # lines, font size, etc.
command (LCD_FUNCTIONSET | _displayfunction);
// turn the display on with no cursor or blinking default
_displaycontrol = LCD_DISPLAYON | LCD_CURSOROFF | LCD_BLINKOFF;
display ();
// clear it off
clear ();
// Initialize to default text direction (for romance languages)
_displaymode = LCD_ENTRYLEFT | LCD_ENTRYSHIFTDECREMENT;
// set the entry mode
command (LCD_ENTRYMODESET | _displaymode);
}
/********** high level commands, for the user! */
void
LiquidCrystal::clear ()
{
command (LCD_CLEARDISPLAY); // clear display, set cursor position to zero
delayMicroseconds (2000); // this command takes a long time!
}
void
LiquidCrystal::home ()
{
command (LCD_RETURNHOME); // set cursor position to zero
delayMicroseconds (2000); // this command takes a long time!
}
void
LiquidCrystal::print (std::string const &s)
{
this->print (s.c_str ());
}
void
LiquidCrystal::print (const char *s)
{
int char_counter = 0;
while (*s && char_counter < this->col)
{
send (*s, HIGH);
char_counter++;
s++;
}
}
void
LiquidCrystal::setCursor (uint8_t col, uint8_t row)
{
int row_offsets[] = { 0x00, 0x40, 0x14, 0x54 };
if (row >= _numlines)
{
row = _numlines - 1; // we count rows starting w/0
}
command (LCD_SETDDRAMADDR | (col + row_offsets[row]));
}
// Turn the display on/off (quickly)
void
LiquidCrystal::noDisplay ()
{
_displaycontrol &= ~LCD_DISPLAYON;
command (LCD_DISPLAYCONTROL | _displaycontrol);
}
void
LiquidCrystal::display ()
{
_displaycontrol |= LCD_DISPLAYON;
command (LCD_DISPLAYCONTROL | _displaycontrol);
}
// Turns the underline cursor on/off
void
LiquidCrystal::noCursor ()
{
_displaycontrol &= ~LCD_CURSORON;
command (LCD_DISPLAYCONTROL | _displaycontrol);
}
void
LiquidCrystal::cursor ()
{
_displaycontrol |= LCD_CURSORON;
command (LCD_DISPLAYCONTROL | _displaycontrol);
}
// Turn on and off the blinking cursor
void
LiquidCrystal::noBlink ()
{
_displaycontrol &= ~LCD_BLINKON;
command (LCD_DISPLAYCONTROL | _displaycontrol);
}
void
LiquidCrystal::blink ()
{
_displaycontrol |= LCD_BLINKON;
command (LCD_DISPLAYCONTROL | _displaycontrol);
}
// These commands scroll the display without changing the RAM
void
LiquidCrystal::scrollDisplayLeft (void)
{
command (LCD_CURSORSHIFT | LCD_DISPLAYMOVE | LCD_MOVELEFT);
}
void
LiquidCrystal::scrollDisplayRight (void)
{
command (LCD_CURSORSHIFT | LCD_DISPLAYMOVE | LCD_MOVERIGHT);
}
// This is for text that flows Left to Right
void
LiquidCrystal::leftToRight (void)
{
_displaymode |= LCD_ENTRYLEFT;
command (LCD_ENTRYMODESET | _displaymode);
}
// This is for text that flows Right to Left
void
LiquidCrystal::rightToLeft (void)
{
_displaymode &= ~LCD_ENTRYLEFT;
command (LCD_ENTRYMODESET | _displaymode);
}
// This will 'right justify' text from the cursor
void
LiquidCrystal::autoscroll (void)
{
_displaymode |= LCD_ENTRYSHIFTINCREMENT;
command (LCD_ENTRYMODESET | _displaymode);
}
// This will 'left justify' text from the cursor
void
LiquidCrystal::noAutoscroll (void)
{
_displaymode &= ~LCD_ENTRYSHIFTINCREMENT;
command (LCD_ENTRYMODESET | _displaymode);
}
// Allows us to fill the first 8 CGRAM locations
// with custom characters
void
LiquidCrystal::createChar (uint8_t location, uint8_t charmap[])
{
location &= 0x7; // we only have 8 locations 0-7
command (LCD_SETCGRAMADDR | (location << 3));
for (int i = 0; i < 8; i++)
{
write (charmap[i]);
}
}
/*********** mid level commands, for sending data/cmds */
inline void
LiquidCrystal::command (uint8_t value)
{
send (value, LOW);
}
inline size_t
LiquidCrystal::write (uint8_t value)
{
send (value, HIGH);
return 1; // assume sucess
}
/************ low level data pushing commands **********/
// write either command or data
void
LiquidCrystal::send (uint8_t value, uint8_t mode)
{
rs_pin->write (mode); // digitalWrite(_rs_pin, mode);
write4bits (value >> 4);
write4bits (value);
}
void
LiquidCrystal::pulseEnable (void)
{
enable_pin->write (false); // digitalWrite(_enable_pin, LOW);
delayMicroseconds (1);
enable_pin->write (true); // digitalWrite(_enable_pin, HIGH);
delayMicroseconds (1); // enable pulse must be >450ns
enable_pin->write (false); // digitalWrite(_enable_pin, LOW);
delayMicroseconds (100); // commands need > 37us to settle
}
void
LiquidCrystal::write4bits (uint8_t value)
{
for (int i = 0; i < 4; i++)
{
data_pins[i]->write (
(value >> i)
& 0x01); // digitalWrite(_data_pins[i], (value >> i) & 0x01);
}
pulseEnable ();
}