From 500c6d69319e5a860e9169ab0e5acb8a3d3fed01 Mon Sep 17 00:00:00 2001 From: Rhys Weatherley Date: Wed, 4 Apr 2012 08:15:21 +1000 Subject: [PATCH] Improved library for Freetronics LCD shield --- HelloWorld/HelloWorld.pde | 52 +++ libraries/FreetronicsLCD/FreetronicsLCD.cpp | 112 +++++++ libraries/FreetronicsLCD/FreetronicsLCD.h | 69 ++++ .../examples/HelloWorld/HelloWorld.pde | 52 +++ libraries/FreetronicsLCD/keywords.txt | 5 + .../FreetronicsLCD/utility/LiquidCrystal.cpp | 309 ++++++++++++++++++ .../FreetronicsLCD/utility/LiquidCrystal.h | 104 ++++++ 7 files changed, 703 insertions(+) create mode 100644 HelloWorld/HelloWorld.pde create mode 100644 libraries/FreetronicsLCD/FreetronicsLCD.cpp create mode 100644 libraries/FreetronicsLCD/FreetronicsLCD.h create mode 100644 libraries/FreetronicsLCD/examples/HelloWorld/HelloWorld.pde create mode 100644 libraries/FreetronicsLCD/keywords.txt create mode 100644 libraries/FreetronicsLCD/utility/LiquidCrystal.cpp create mode 100644 libraries/FreetronicsLCD/utility/LiquidCrystal.h diff --git a/HelloWorld/HelloWorld.pde b/HelloWorld/HelloWorld.pde new file mode 100644 index 00000000..d2e00fe9 --- /dev/null +++ b/HelloWorld/HelloWorld.pde @@ -0,0 +1,52 @@ +/* +This example demonstrates how to use the FreetronicsLCD library, which extends the +standard LiquidCrystal library to provide support for the Freetronics back light +and Up/Down/Left/Right/Select buttons. More information on the shield here: + +http://www.freetronics.com/pages/16x2-lcd-shield-quickstart-guide +*/ + +// include the library code: +#include + +// initialize the library +FreetronicsLCD lcd; + +// Note: if you are using the USBDroid and have reassigned pin D9 on the LCD shield to some +// other pin (e.g. A1), then you will need to initialize the shield with something like: +// FreetronicsLCD lcd(A1); +// See also: http://www.freetronics.com/pages/combining-the-lcd-keypad-shield-and-the-usbdroid + +void setup() { + // Enable the screen saver, which will automatically blank the screen after 10 seconds. + // The screen will wake up again when a button is pressed or lcd.display() is called. + lcd.enableScreenSaver(); + + // Print a message to the LCD. + lcd.print("hello, world!"); +} + +void loop() { + // set the cursor to column 0, line 1 + // (note: line 1 is the second row, since counting begins with 0): + lcd.setCursor(0, 1); + // print the number of seconds since reset: + lcd.print(millis()/1000); + + // print the name of the button that is currently pressed + lcd.setCursor(8, 1); + int button = lcd.getButton(); + if (button == LCD_BUTTON_LEFT) + lcd.print("LEFT"); + else if (button == LCD_BUTTON_RIGHT) + lcd.print("RIGHT"); + else if (button == LCD_BUTTON_UP) + lcd.print("UP"); + else if (button == LCD_BUTTON_DOWN) + lcd.print("DOWN"); + else if (button == LCD_BUTTON_SELECT) + lcd.print("SELECT"); + else if (button < 0) // button release + lcd.print(" "); +} + diff --git a/libraries/FreetronicsLCD/FreetronicsLCD.cpp b/libraries/FreetronicsLCD/FreetronicsLCD.cpp new file mode 100644 index 00000000..9a1412d8 --- /dev/null +++ b/libraries/FreetronicsLCD/FreetronicsLCD.cpp @@ -0,0 +1,112 @@ +#include "FreetronicsLCD.h" +#include + +#define LCD_BACK_LIGHT 3 // LCD backlight is on D3 +#define LCD_BUTTON_PIN A0 // Button state is on A0 + +#define LCD_BUTTON_VALUE_GAP 10 +#define LCD_BUTTON_RIGHT_VALUE 0 +#define LCD_BUTTON_UP_VALUE 145 +#define LCD_BUTTON_DOWN_VALUE 329 +#define LCD_BUTTON_LEFT_VALUE 505 +#define LCD_BUTTON_SELECT_VALUE 741 + +void FreetronicsLCD::init() +{ + // The Freetronics display is 16x2. + begin(16, 2); + + // Set the LCD back light to be initially on. + pinMode(LCD_BACK_LIGHT, OUTPUT); + digitalWrite(LCD_BACK_LIGHT, HIGH); + + // Initialise button input. + pinMode(LCD_BUTTON_PIN, INPUT); + digitalWrite(LCD_BUTTON_PIN, LOW); + prevButton = LCD_BUTTON_NONE; + eatRelease = false; + + // Initialize screen saver. + timeout = 0; + lastRestore = millis(); + screenSaved = false; +} + +void FreetronicsLCD::display() +{ + LiquidCrystal::display(); + digitalWrite(LCD_BACK_LIGHT, HIGH); + + screenSaved = false; + lastRestore = millis(); +} + +void FreetronicsLCD::noDisplay() +{ + LiquidCrystal::noDisplay(); + digitalWrite(LCD_BACK_LIGHT, LOW); + screenSaved = true; +} + +void FreetronicsLCD::enableScreenSaver(int timeoutSecs) +{ + if (timeoutSecs < 0) + timeout = 0; + else + timeout = ((unsigned long)timeoutSecs) * 1000; + display(); +} + +void FreetronicsLCD::disableScreenSaver() +{ + timeout = 0; + display(); +} + +int FreetronicsLCD::getButton() +{ + int value = analogRead(LCD_BUTTON_PIN); + int button; + if (value < (LCD_BUTTON_RIGHT_VALUE + LCD_BUTTON_VALUE_GAP)) + button = LCD_BUTTON_RIGHT; + else if (value >= (LCD_BUTTON_UP_VALUE - LCD_BUTTON_VALUE_GAP) && + value <= (LCD_BUTTON_UP_VALUE + LCD_BUTTON_VALUE_GAP)) + button = LCD_BUTTON_UP; + else if (value >= (LCD_BUTTON_DOWN_VALUE - LCD_BUTTON_VALUE_GAP) && + value <= (LCD_BUTTON_DOWN_VALUE + LCD_BUTTON_VALUE_GAP)) + button = LCD_BUTTON_DOWN; + else if (value >= (LCD_BUTTON_LEFT_VALUE - LCD_BUTTON_VALUE_GAP) && + value <= (LCD_BUTTON_LEFT_VALUE + LCD_BUTTON_VALUE_GAP)) + button = LCD_BUTTON_LEFT; + else if (value >= (LCD_BUTTON_SELECT_VALUE - LCD_BUTTON_VALUE_GAP) && + value <= (LCD_BUTTON_SELECT_VALUE + LCD_BUTTON_VALUE_GAP)) + button = LCD_BUTTON_SELECT; + else + button = LCD_BUTTON_NONE; + if (prevButton == LCD_BUTTON_NONE && button != LCD_BUTTON_NONE) { + prevButton = button; + if (screenSaved) { + // Button pressed when screen saver active. + display(); + eatRelease = true; + return LCD_BUTTON_NONE; + } + eatRelease = false; + lastRestore = millis(); + return button; + } else if (prevButton != LCD_BUTTON_NONE && button == LCD_BUTTON_NONE) { + button = -prevButton; + prevButton = LCD_BUTTON_NONE; + lastRestore = millis(); + if (eatRelease) { + eatRelease = false; + return LCD_BUTTON_NONE; + } + return button; + } else { + if (!screenSaved && prevButton == LCD_BUTTON_NONE && + timeout != 0 && (millis() - lastRestore) >= timeout) + noDisplay(); // Activate screen saver. + return LCD_BUTTON_NONE; + } +} diff --git a/libraries/FreetronicsLCD/FreetronicsLCD.h b/libraries/FreetronicsLCD/FreetronicsLCD.h new file mode 100644 index 00000000..be9e7031 --- /dev/null +++ b/libraries/FreetronicsLCD/FreetronicsLCD.h @@ -0,0 +1,69 @@ +#ifndef FreetronicsLCD_h +#define FreetronicsLCD_h + +// Extended version of the LiquidCrystal library that works specifically +// with Freetronics' 16x2 LCD display, including support for the back +// light and the Up/Down/Left/Right/Select buttons. More info: +// +// http://www.freetronics.com/pages/16x2-lcd-shield-quickstart-guide + +// Include a copy of the standard LiquidCrystal library so we can extend it. +#include "utility/LiquidCrystal.h" + +// Button event codes. +#define LCD_BUTTON_NONE 0 +#define LCD_BUTTON_LEFT 1 +#define LCD_BUTTON_RIGHT 2 +#define LCD_BUTTON_UP 3 +#define LCD_BUTTON_DOWN 4 +#define LCD_BUTTON_SELECT 5 +#define LCD_BUTTON_LEFT_RELEASED -1 +#define LCD_BUTTON_RIGHT_RELEASED -2 +#define LCD_BUTTON_UP_RELEASED -3 +#define LCD_BUTTON_DOWN_RELEASED -4 +#define LCD_BUTTON_SELECT_RELEASED -5 + +class FreetronicsLCD : public LiquidCrystal { +public: + FreetronicsLCD() : LiquidCrystal(8, 9, 4, 5, 6, 7) { init(); } + + // For USBDroid where D9 needs to be reassigned to some other pin. + FreetronicsLCD(uint8_t pin9) : LiquidCrystal(8, pin9, 4, 5, 6, 7) { init(); } + + // Turn on the display, including the back light and the text. + // This will also reset the screen saver timeout. + void display(); + + // Turn off the display, including the back light and the text, + // effectively forcing the screen saver to activate immediately. + void noDisplay(); + + // Enable the screen saver and activate it after timeout seconds + // of inactivity on the buttons. Note: the screen saver is activated + // during the call to getButton() so it must be polled regularly. + void enableScreenSaver(int timeoutSecs = 10); + + // Disable the screen saver and turn the screen back on. + void disableScreenSaver(); + + // Determine if the screen saver is active. + bool isScreenSaved() const { return screenSaved; } + + // Get the next button event, or LCD_BUTTON_NONE if no change + // since the last event. If the screen saver is active, then + // pressing a button will disable the screen saver and return + // LCD_BUTTON_NONE as the button code. Thus, any button can + // be used to wake up the screen. + int getButton(); + +private: + int prevButton; + unsigned long timeout; + unsigned long lastRestore; + bool screenSaved; + bool eatRelease; + + void init(); +}; + +#endif diff --git a/libraries/FreetronicsLCD/examples/HelloWorld/HelloWorld.pde b/libraries/FreetronicsLCD/examples/HelloWorld/HelloWorld.pde new file mode 100644 index 00000000..d2e00fe9 --- /dev/null +++ b/libraries/FreetronicsLCD/examples/HelloWorld/HelloWorld.pde @@ -0,0 +1,52 @@ +/* +This example demonstrates how to use the FreetronicsLCD library, which extends the +standard LiquidCrystal library to provide support for the Freetronics back light +and Up/Down/Left/Right/Select buttons. More information on the shield here: + +http://www.freetronics.com/pages/16x2-lcd-shield-quickstart-guide +*/ + +// include the library code: +#include + +// initialize the library +FreetronicsLCD lcd; + +// Note: if you are using the USBDroid and have reassigned pin D9 on the LCD shield to some +// other pin (e.g. A1), then you will need to initialize the shield with something like: +// FreetronicsLCD lcd(A1); +// See also: http://www.freetronics.com/pages/combining-the-lcd-keypad-shield-and-the-usbdroid + +void setup() { + // Enable the screen saver, which will automatically blank the screen after 10 seconds. + // The screen will wake up again when a button is pressed or lcd.display() is called. + lcd.enableScreenSaver(); + + // Print a message to the LCD. + lcd.print("hello, world!"); +} + +void loop() { + // set the cursor to column 0, line 1 + // (note: line 1 is the second row, since counting begins with 0): + lcd.setCursor(0, 1); + // print the number of seconds since reset: + lcd.print(millis()/1000); + + // print the name of the button that is currently pressed + lcd.setCursor(8, 1); + int button = lcd.getButton(); + if (button == LCD_BUTTON_LEFT) + lcd.print("LEFT"); + else if (button == LCD_BUTTON_RIGHT) + lcd.print("RIGHT"); + else if (button == LCD_BUTTON_UP) + lcd.print("UP"); + else if (button == LCD_BUTTON_DOWN) + lcd.print("DOWN"); + else if (button == LCD_BUTTON_SELECT) + lcd.print("SELECT"); + else if (button < 0) // button release + lcd.print(" "); +} + diff --git a/libraries/FreetronicsLCD/keywords.txt b/libraries/FreetronicsLCD/keywords.txt new file mode 100644 index 00000000..49217427 --- /dev/null +++ b/libraries/FreetronicsLCD/keywords.txt @@ -0,0 +1,5 @@ +FreetronicsLCD KEYWORD1 +getButton KEYWORD2 +enableScreenSaver KEYWORD2 +disableScreenSaver KEYWORD2 +isScreenSaved KEYWORD2 diff --git a/libraries/FreetronicsLCD/utility/LiquidCrystal.cpp b/libraries/FreetronicsLCD/utility/LiquidCrystal.cpp new file mode 100644 index 00000000..23713f47 --- /dev/null +++ b/libraries/FreetronicsLCD/utility/LiquidCrystal.cpp @@ -0,0 +1,309 @@ +#include "LiquidCrystal.h" + +#include +#include +#include +#include "WProgram.h" + +// 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(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(0, rs, rw, enable, d0, d1, d2, d3, d4, d5, d6, d7); +} + +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(0, 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) +{ + init(1, 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(1, rs, 255, enable, d0, d1, d2, d3, 0, 0, 0, 0); +} + +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) +{ + _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; + + 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); + + if (fourbitmode) + _displayfunction = LCD_4BITMODE | LCD_1LINE | LCD_5x8DOTS; + else + _displayfunction = LCD_8BITMODE | LCD_1LINE | LCD_5x8DOTS; + + begin(16, 1); +} + +void LiquidCrystal::begin(uint8_t cols, uint8_t lines, uint8_t dotsize) { + 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 + digitalWrite(_rs_pin, LOW); + digitalWrite(_enable_pin, LOW); + if (_rw_pin != 255) { + digitalWrite(_rw_pin, LOW); + } + + //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::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 void LiquidCrystal::write(uint8_t value) { + send(value, HIGH); +} + +/************ low level data pushing commands **********/ + +// write either command or data, with automatic 4/8-bit selection +void LiquidCrystal::send(uint8_t value, uint8_t mode) { + digitalWrite(_rs_pin, mode); + + // if there is a RW pin indicated, set it low to Write + if (_rw_pin != 255) { + digitalWrite(_rw_pin, LOW); + } + + if (_displayfunction & LCD_8BITMODE) { + write8bits(value); + } else { + write4bits(value>>4); + write4bits(value); + } +} + +void LiquidCrystal::pulseEnable(void) { + digitalWrite(_enable_pin, LOW); + delayMicroseconds(1); + digitalWrite(_enable_pin, HIGH); + delayMicroseconds(1); // enable pulse must be >450ns + digitalWrite(_enable_pin, LOW); + delayMicroseconds(100); // commands need > 37us to settle +} + +void LiquidCrystal::write4bits(uint8_t value) { + for (int i = 0; i < 4; i++) { + pinMode(_data_pins[i], OUTPUT); + digitalWrite(_data_pins[i], (value >> i) & 0x01); + } + + pulseEnable(); +} + +void LiquidCrystal::write8bits(uint8_t value) { + for (int i = 0; i < 8; i++) { + pinMode(_data_pins[i], OUTPUT); + digitalWrite(_data_pins[i], (value >> i) & 0x01); + } + + pulseEnable(); +} diff --git a/libraries/FreetronicsLCD/utility/LiquidCrystal.h b/libraries/FreetronicsLCD/utility/LiquidCrystal.h new file mode 100644 index 00000000..f66ec1b4 --- /dev/null +++ b/libraries/FreetronicsLCD/utility/LiquidCrystal.h @@ -0,0 +1,104 @@ +#ifndef LiquidCrystal_h +#define LiquidCrystal_h + +#include +#include "Print.h" + +// commands +#define LCD_CLEARDISPLAY 0x01 +#define LCD_RETURNHOME 0x02 +#define LCD_ENTRYMODESET 0x04 +#define LCD_DISPLAYCONTROL 0x08 +#define LCD_CURSORSHIFT 0x10 +#define LCD_FUNCTIONSET 0x20 +#define LCD_SETCGRAMADDR 0x40 +#define LCD_SETDDRAMADDR 0x80 + +// flags for display entry mode +#define LCD_ENTRYRIGHT 0x00 +#define LCD_ENTRYLEFT 0x02 +#define LCD_ENTRYSHIFTINCREMENT 0x01 +#define LCD_ENTRYSHIFTDECREMENT 0x00 + +// flags for display on/off control +#define LCD_DISPLAYON 0x04 +#define LCD_DISPLAYOFF 0x00 +#define LCD_CURSORON 0x02 +#define LCD_CURSOROFF 0x00 +#define LCD_BLINKON 0x01 +#define LCD_BLINKOFF 0x00 + +// flags for display/cursor shift +#define LCD_DISPLAYMOVE 0x08 +#define LCD_CURSORMOVE 0x00 +#define LCD_MOVERIGHT 0x04 +#define LCD_MOVELEFT 0x00 + +// flags for function set +#define LCD_8BITMODE 0x10 +#define LCD_4BITMODE 0x00 +#define LCD_2LINE 0x08 +#define LCD_1LINE 0x00 +#define LCD_5x10DOTS 0x04 +#define LCD_5x8DOTS 0x00 + +class LiquidCrystal : public Print { +public: + 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); + 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); + LiquidCrystal(uint8_t rs, uint8_t rw, uint8_t enable, + uint8_t d0, uint8_t d1, uint8_t d2, uint8_t d3); + LiquidCrystal(uint8_t rs, uint8_t enable, + uint8_t d0, uint8_t d1, uint8_t d2, uint8_t d3); + + void 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); + + void begin(uint8_t cols, uint8_t rows, uint8_t charsize = LCD_5x8DOTS); + + void clear(); + void home(); + + void noDisplay(); + void display(); + void noBlink(); + void blink(); + void noCursor(); + void cursor(); + void scrollDisplayLeft(); + void scrollDisplayRight(); + void leftToRight(); + void rightToLeft(); + void autoscroll(); + void noAutoscroll(); + + void createChar(uint8_t, uint8_t[]); + void setCursor(uint8_t, uint8_t); + virtual void write(uint8_t); + void command(uint8_t); +private: + void send(uint8_t, uint8_t); + void write4bits(uint8_t); + void write8bits(uint8_t); + void pulseEnable(); + + uint8_t _rs_pin; // LOW: command. HIGH: character. + uint8_t _rw_pin; // LOW: write to LCD. HIGH: read from LCD. + uint8_t _enable_pin; // activated by a HIGH pulse. + uint8_t _data_pins[8]; + + uint8_t _displayfunction; + uint8_t _displaycontrol; + uint8_t _displaymode; + + uint8_t _initialized; + + uint8_t _numlines,_currline; +}; + +#endif