diff --git a/README.md b/README.md index 318fe7c..f509e10 100644 --- a/README.md +++ b/README.md @@ -12,10 +12,25 @@ The communication is realized by a PCF8574 remote 8 bit I/O Expander for I²c Bu ## LCD Documentation +### Hitatchi HD44780 +The Hitachi HD44780 LCD controller is an alphanumeric dot matrix liquid crystal display (LCD) controller developed by Hitachi in the 1980s. The character set of the controller includes ASCII characters, Japanese Kana characters, and some symbols in two 40 character lines. Using an extension driver, the device can display up to 80 characters. Numerous third-party displays are compatible with its 16-pin interface and instruction set, making it a popular and cheap LCD driver. + +In 8-bit mode, all transfers happen in one cycle of the enable pin (E) with all 8 bits on the data bus and the RS and R/W pins stable. In 4-bit mode, data are transferred as pairs of 4-bit "nibbles" on the upper data pins, D7–D4, with two enable pulses and the RS and R/W pins stable. The four most significant bits (7–4) must be written first, followed by the four least significant bits (3–0). The high/low sequence must be completed each time or the controller will not properly receive further commands. + +### Character Generator ROM (CGROM) +The internal CGROM includes 208 characters in a 5x8 dot matrix, and also 32 characters in a 5x10 dot matrix. +The 5x10 matrix is generally not used. + +### Character Generator RAM (CGRAM) +Additionally to the CGROM there is a CGRAM, in which 8 user-defined characters in 5x8 dot matrix, or 4 characters in a 5x10 dot matrix can be stored. +This enables to store characters which are not available in the CGROM. ## Library Usage # License +This library is licensed under MIT Licence. + +[LCD-I2C licence](https://github.com/hasenradball/LCD-I2C/blob/master/LICENSE) # Helpful Links [Wikipedia - a great description of HD44780 module](https://de.wikipedia.org/wiki/HD44780) diff --git a/examples/Custom_Chars/Custom_Chars.ino b/examples/Custom_Chars/Custom_Chars.ino index c97d580..44dd2a3 100644 --- a/examples/Custom_Chars/Custom_Chars.ino +++ b/examples/Custom_Chars/Custom_Chars.ino @@ -64,6 +64,7 @@ uint8_t snow[8] = void setup() { lcd.begin(); + lcd.display(); lcd.backlight(); lcd.createChar(0, happy); diff --git a/examples/Functions/Functions.ino b/examples/Functions/Functions.ino index e489ff7..6ad3cee 100644 --- a/examples/Functions/Functions.ino +++ b/examples/Functions/Functions.ino @@ -21,9 +21,9 @@ LCD_I2C lcd(0x27, 16, 2); * More info: https://www.arduino.cc/reference/en/language/variables/utilities/progmem/ */ -void setup() -{ +void setup() { lcd.begin(); + lcd.display(); lcd.backlight(); } @@ -41,7 +41,7 @@ void loop() delay(200); } - lcd.noAutoscroll(); + lcd.autoscrollOff(); lcd.clear(); // Scroll left and right @@ -77,9 +77,9 @@ void loop() //Blink without cursor lcd.setCursor(0, 0); - lcd.noCursor(); + lcd.cursorOff(); lcd.print(F("Just blink")); delay(3000); - lcd.noBlink(); + lcd.blinkOff(); lcd.clear(); } diff --git a/examples/Hello_World/Hello_World.ino b/examples/Hello_World/Hello_World.ino index 7dde1fa..b5ab35d 100644 --- a/examples/Hello_World/Hello_World.ino +++ b/examples/Hello_World/Hello_World.ino @@ -12,10 +12,11 @@ LCD_I2C lcd(0x27, 16, 2); // Default address of most PCF8574 modules, change according -void setup() -{ - lcd.begin(); // If you are using more I2C devices using the Wire library use lcd.begin(false) - // this stop the library(LCD-I2C) from calling Wire.begin() +void setup() { + // If you are using more I2C devices using the Wire library use lcd.begin(false) + // this stop the library(LCD-I2C) from calling Wire.begin() + lcd.begin(); + lcd.display(); lcd.backlight(); } @@ -31,7 +32,7 @@ void loop() { lcd.backlight(); delay(50); - lcd.noBacklight(); + lcd.backlightOff(); delay(50); } diff --git a/keywords.txt b/keywords.txt index 778df82..7e34db7 100644 --- a/keywords.txt +++ b/keywords.txt @@ -13,19 +13,19 @@ LCD_I2C KEYWORD1 ################################## begin KEYWORD2 backlight KEYWORD2 -noBacklight KEYWORD2 +backlightOff KEYWORD2 clear KEYWORD2 home KEYWORD2 leftToRight KEYWORD2 rightToLeft KEYWORD2 autoscroll KEYWORD2 -noAutoscroll KEYWORD2 +autoscrollOff KEYWORD2 display KEYWORD2 -noDisplay KEYWORD2 +displayOff KEYWORD2 cursor KEYWORD2 -noCursor KEYWORD2 +cursorOff KEYWORD2 blink KEYWORD2 -noBlink KEYWORD2 +blinkOff KEYWORD2 scrollDisplayLeft KEYWORD2 scrollDisplayRight KEYWORD2 createChar KEYWORD2 @@ -38,12 +38,12 @@ setCursor KEYWORD2 ################################## # Constants (LITERAL1) ################################## -LCD_CLEAR LITERAL1 -LCD_CLEAR LITERAL1 -LCD_HOME LITERAL1 -LCD_ENTRY_MODE_SET LITERAL1 -LCD_DISPLAY_CONTROL LITERAL1 -LCD_CURSOR_OR_DISPLAY_SHIFT LITERAL1 -LCD_FUNCTION_SET LITERAL1 -LCD_SET_CGRAM_ADDR LITERAL1 -LCD_SET_DDRRAM_ADDR LITERAL1 \ No newline at end of file +HD44780_CLEAR LITERAL1 +HD44780_CLEAR LITERAL1 +HD44780_HOME LITERAL1 +HD44780_ENTRY_MODE_SET LITERAL1 +HD44780_DISPLAY_CONTROL LITERAL1 +HD44780_CURSOR_OR_DISPLAY_SHIFT LITERAL1 +HD44780_FUNCTION_SET LITERAL1 +HD44780_SET_CGRAM_ADDR LITERAL1 +HD44780_SET_DDRRAM_ADDR LITERAL1 \ No newline at end of file diff --git a/src/LCD-I2C.cpp b/src/LCD-I2C.cpp index 89f0b60..c8417bf 100644 --- a/src/LCD-I2C.cpp +++ b/src/LCD-I2C.cpp @@ -9,10 +9,11 @@ void LCD_I2C::begin(bool beginWire) { if (beginWire) Wire.begin(); - - I2C_Write(0b00000000); // Clear i2c adapter - delay(50); //Wait more than 40ms after powerOn. - + + // Clear i2c adapter + I2C_Write(0b00000000); + // Wait more than 40 ms after powerOn + delay(50); InitializeLCD(); } @@ -22,16 +23,18 @@ void LCD_I2C::begin(bool beginWire) { */ void LCD_I2C::backlight() { _output.Led = 1; - I2C_Write(0b00000000 | _output.Led << 3); // Led pin is independent from LCD data and control lines. + // Led pin is independent from LCD data and control lines. + I2C_Write(0b00000000 | _output.Led << 3); } /** * @brief switch backlight off * */ -void LCD_I2C::noBacklight() { +void LCD_I2C::backlightOff() { _output.Led = 0; - I2C_Write(0b00000000 | _output.Led << 3); // Led pin is independent from LCD data and control lines. + // Led pin is independent from LCD data and control lines. + I2C_Write(0b00000000 | _output.Led << 3); } /** @@ -42,8 +45,8 @@ void LCD_I2C::clear() { _output.rs = 0; _output.rw = 0; - LCD_Write(LCD_CLEAR); - delayMicroseconds(1600); + LCD_Write(HD44780_CLEAR_DISPLAY); + delayMicroseconds(1550); } /** @@ -54,8 +57,8 @@ void LCD_I2C::home() { _output.rs = 0; _output.rw = 0; - LCD_Write(LCD_HOME); - delayMicroseconds(1600); + LCD_Write(HD44780_CURSOR_HOME); + delayMicroseconds(1550); } @@ -67,9 +70,9 @@ void LCD_I2C::leftToRight() { _output.rs = 0; _output.rw = 0; - _entryState |= 1 << 1; + _entryState |= (1 << 1); - LCD_Write(LCD_ENTRY_MODE_SET | _entryState); + LCD_Write(HD44780_ENTRY_MODE_SET | _entryState); delayMicroseconds(37); } @@ -84,7 +87,7 @@ void LCD_I2C::rightToLeft() { _entryState &= ~(1 << 1); - LCD_Write(LCD_ENTRY_MODE_SET | _entryState); + LCD_Write(HD44780_ENTRY_MODE_SET | _entryState); delayMicroseconds(37); } @@ -99,7 +102,7 @@ void LCD_I2C::autoscroll() { _entryState |= 1; - LCD_Write(LCD_ENTRY_MODE_SET | _entryState); + LCD_Write(HD44780_ENTRY_MODE_SET | _entryState); delayMicroseconds(37); } @@ -108,13 +111,13 @@ void LCD_I2C::autoscroll() { * @brief set no autoscroll * */ -void LCD_I2C::noAutoscroll() { +void LCD_I2C::autoscrollOff() { _output.rs = 0; _output.rw = 0; _entryState &= ~1; - LCD_Write(LCD_ENTRY_MODE_SET | _entryState); + LCD_Write(HD44780_ENTRY_MODE_SET | _entryState); delayMicroseconds(37); } @@ -127,24 +130,24 @@ void LCD_I2C::display() { _output.rs = 0; _output.rw = 0; - _displayState |= 1 << 2; + _displayState |= (1 << 2); - LCD_Write(LCD_DISPLAY_CONTROL | _displayState); + LCD_Write(HD44780_DISPLAY_CONTROL | _displayState); delayMicroseconds(37); } /** - * @brief show no display + * @brief display off * */ -void LCD_I2C::noDisplay() { +void LCD_I2C::displayOff() { _output.rs = 0; _output.rw = 0; _displayState &= ~(1 << 2); - LCD_Write(LCD_DISPLAY_CONTROL | _displayState); + LCD_Write(HD44780_DISPLAY_CONTROL | _displayState); delayMicroseconds(37); } @@ -157,9 +160,9 @@ void LCD_I2C::cursor() { _output.rs = 0; _output.rw = 0; - _displayState |= 1 << 1; + _displayState |= (1 << 1); - LCD_Write(LCD_DISPLAY_CONTROL | _displayState); + LCD_Write(HD44780_DISPLAY_CONTROL | _displayState); delayMicroseconds(37); } @@ -168,19 +171,19 @@ void LCD_I2C::cursor() { * @brief set display => no cursor * */ -void LCD_I2C::noCursor() { +void LCD_I2C::cursorOff() { _output.rs = 0; _output.rw = 0; _displayState &= ~(1 << 1); - LCD_Write(LCD_DISPLAY_CONTROL | _displayState); + LCD_Write(HD44780_DISPLAY_CONTROL | _displayState); delayMicroseconds(37); } /** - * @brief Set Cursor blink + * @brief Set cursor blinkin on * */ void LCD_I2C::blink() { @@ -189,22 +192,22 @@ void LCD_I2C::blink() { _displayState |= 1; - LCD_Write(LCD_DISPLAY_CONTROL | _displayState); + LCD_Write(HD44780_DISPLAY_CONTROL | _displayState); delayMicroseconds(37); } /** - * @brief Set Cursor no blink + * @brief Set cursor blinking off * */ -void LCD_I2C::noBlink() { +void LCD_I2C::blinkOff() { _output.rs = 0; _output.rw = 0; _displayState &= ~1; - LCD_Write(LCD_DISPLAY_CONTROL | _displayState); + LCD_Write(HD44780_DISPLAY_CONTROL | _displayState); delayMicroseconds(37); } @@ -243,9 +246,9 @@ void LCD_I2C::createChar(uint8_t memory_location, uint8_t charmap[]) { _output.rs = 0; _output.rw = 0; - location %= 8; + memory_location %= 8; - LCD_Write(LCD_SET_CGRAM_ADDR | (memory_location << 3)); + LCD_Write(HD44780_SET_CGRAM_ADDR | (memory_location << 3)); delayMicroseconds(37); for (int i = 0; i < 8; i++) @@ -272,7 +275,7 @@ void LCD_I2C::setCursor(uint8_t col, uint8_t row) { uint8_t newAddress = row_offsets[row] + col; - LCD_Write(LCD_SET_DDRRAM_ADDR | newAddress); + LCD_Write(HD44780_SET_DDRRAM_ADDR | newAddress); delayMicroseconds(37); } @@ -293,34 +296,44 @@ size_t LCD_I2C::write(uint8_t character) { } /** - * @brief Funtion to initialize LCD + * @brief Function to initialize LCD * */ void LCD_I2C::InitializeLCD() { // See HD44780U datasheet "Initializing by Instruction" Figure 24 (4-Bit Interface) + // SEE PAGE 45/46 FOR INITIALIZATION SPECIFICATION! + // according to datasheet, we need at least 40 ms after power rises above 2.7 V + // before sending commands. Arduino can turn on way before 4.5 V so we'll wait 50 _output.rs = 0; _output.rw = 0; + // wait more than 40 ms after Vcc = 2.7 V + delay(50); + + // first LCD_Write(0b00110000, true); delayMicroseconds(4200); + // second LCD_Write(0b00110000, true); delayMicroseconds(150); + // third LCD_Write(0b00110000, true); delayMicroseconds(37); + // Function Set - 4 bits mode - LCD_Write(LCD_FUNCTION_SET, true); + LCD_Write(0b00100000, true); delayMicroseconds(37); - // Function Set - 4 bits(Still), 2 lines, 5x8 font + // Function Set - 4 bit Interface, 1 = 2 lines, 0 = 5x8 font LCD_Write(0b00101000); delayMicroseconds(37); - display(); + displayOff(); clear(); leftToRight(); } /** - * @brief I²C write funtion + * @brief I²C write function * * @param output data to write */ @@ -341,7 +354,7 @@ void LCD_I2C::LCD_Write(uint8_t output, bool initialization) { _output.E = true; I2C_Write(_output.GetHighData()); - // High part of enable should be >450 nS + // High part of enable should be > 450 ns delayMicroseconds(1); _output.E = false; @@ -354,7 +367,7 @@ void LCD_I2C::LCD_Write(uint8_t output, bool initialization) { _output.E = true; I2C_Write(_output.GetLowData()); - // High part of enable should be >450 nS + // High part of enable should be > 450 ns delayMicroseconds(1); _output.E = false; diff --git a/src/LCD-I2C.h b/src/LCD-I2C.h index d8ee7d9..f7da8a6 100644 --- a/src/LCD-I2C.h +++ b/src/LCD-I2C.h @@ -43,25 +43,24 @@ class LCD_I2C : public Print { void begin(bool beginWire = true); void backlight(); - void noBacklight(); + void backlightOff(); void clear(); void home(); void leftToRight(); void rightToLeft(); void autoscroll(); - void noAutoscroll(); + void autoscrollOff(); void display(); - void noDisplay(); + void displayOff(); void cursor(); - void noCursor(); + void cursorOff(); void blink(); - void noBlink(); + void blinkOff(); void scrollDisplayLeft(); void scrollDisplayRight(); void createChar(uint8_t location, uint8_t charmap[]); void setCursor(uint8_t col, uint8_t row); - // Method used by the Arduino class "Print" which is the one that provides the .print(string) method virtual size_t write(uint8_t character); diff --git a/src/LCD_Constants.h b/src/LCD_Constants.h index b9d399c..7b3d6f0 100644 --- a/src/LCD_Constants.h +++ b/src/LCD_Constants.h @@ -6,13 +6,15 @@ * @brief Define Instructions Constants of HD44780U * */ -constexpr int LCD_CLEAR {0b00000001}; -constexpr int LCD_HOME {0b00000010}; -constexpr int LCD_ENTRY_MODE_SET {0b00000100}; -constexpr int LCD_DISPLAY_CONTROL {0b00001000}; -constexpr int LCD_CURSOR_OR_DISPLAY_SHIFT {0b00010000}; -constexpr int LCD_FUNCTION_SET {0b00100000}; -constexpr int LCD_SET_CGRAM_ADDR {0b01000000}; -constexpr int LCD_SET_DDRRAM_ADDR {0b10000000}; +constexpr int HD44780_CLEAR_DISPLAY {0b00000001}; +constexpr int HD44780_CURSOR_HOME {0b00000010}; +constexpr int HD44780_ENTRY_MODE_SET {0b00000100}; + +constexpr int HD44780_DISPLAY_CONTROL {0b00001000}; + +constexpr int HD44780_CURSOR_OR_DISPLAY_SHIFT {0b00010000}; +constexpr int HD44780_FUNCTION_SET {0b00100000}; +constexpr int HD44780_SET_CGRAM_ADDR {0b01000000}; +constexpr int HD44780_SET_DDRRAM_ADDR {0b10000000}; #endif \ No newline at end of file