LiquidCrystal440.zip

Leonardo - LCD 40x4,biblioteka LiquidCrystal440 - nie kompiluje kodu, hd44780 x2

Witam, mam wyświetlacz 40x4 LCD , w rzeczywistości to zintegrowane 2 wyświetlacze na sterowniku HD44780 wykorzystując bibliotekę dla Arduino LiquidCrystal440, oto przykładowy kod: #include <LiquidCrystal440.h> // LiquidCrystal lcd(rs,rw,enable1,enable2,d4,d5,d6,d7); // Note: some Forum examples using LiquidCrystal440.h have wrong DB pins, // eg DB0-DB3, or in wrong order. The top 4 work, in this order. LiquidCrystal lcd(2, 3, 4, 5, 9, 10, 11, 12); void setup() { lcd.begin (40, 4); lcd.clear(); for (int j=18; j<129; j++) { lcd.write(j); } // print English chars in rom lower 4 bits, upper 4 bits Japanese } void loop() { } Problem tkwi przy próbie kompilacji, wyskakuje oto taki komunikat: Opcje projektu zmienione, przeładuj całość In file included from lcd40x4v2.ino:1:0: C:\Users\Dell\Documents\Arduino\libraries\Liquidcrystal440/LiquidCrystal440.h:95:16: error: conflicting return type specified for 'virtual void LiquidCrystal::write(uint8_t)' virtual void write(uint8_t); ^ In file included from C:\Users\Dell\Documents\Arduino\libraries\Liquidcrystal440/LiquidCrystal440.h:5:0, from lcd40x4v2.ino:1: C:\arduino-1.6.1\hardware\arduino\avr\cores\arduino/Print.h:48:20: error: overriding 'virtual size_t Print::write(uint8_t)' virtual size_t write(uint8_t) = 0; ^ Błąd kompilacji. nie bardzo wiem o co tu chodzi. Podobno to działa, jest jeszcze wewnątrz biblioteki plik testLCD i też nie mogę go skompilować. TestLCD: #include <LiquidCrystal440.h> // Try to exercise everything in LiquidCrystal for test purposes--: You should be able to modify the first 4 lines // of code to test different options and swap LCD boards (with contrast potentiometers attached directly) by plugging them directly // into the row of digital sockets on the Mega opposite the USB socket. Be careful about current draw on the backlight pins!! //Arduino can only power these if current draw is <= 40 mAmps uint8_t nRows = 4; //number of rows on LCD uint8_t nColumns =20; //number of columns uint8_t rw = 47; //255 if rw is connected vs 47 (or 49 for the 24x2) in the examples below; it should be pulled to GND if not controlled by the interface. LiquidCrystal lcd(49,45, 35,33,31,29); //there are multiple versions of this commented below; paste 'em in //this is kind of interesting: the LIquidCrystal object is created and init/begin is run //out here before setup(); before the board has power on the Mega!!! We need another begin to really //start the board later. //======for an LCD with a single HD44780 type chip and 16 pin interface (eg 16x2 20x2 16x4 20x4) 4 data pinshttp://healthriskappraisal.org/LiquidCrystal440.zip //Alternate interfaces to test for 2x16,4x20,4x16: //LiquidCrystal lcd(49,47,45, 35,33,31,29); // rs,rw,en, 4 data pins remember to set rw = 255 above //LiquidCrystal lcd(49,47,45, 43,41,39,37, 35,33,31,29); // rs,rw,en 8 data pins remember to set rw = 255 above //LiquidCrystal lcd(49,45, 35,33,31,29); // rs,en, 4 data pins remember to set rw = 47 above //LiquidCrystal lcd(49,45, 43,41,39,37, 35,33,31,29); // rs,en 8 data pins remember to set rw = 47 above //alternate interfaces to test for 4x40: //LiquidCrystal lcd(48,47,46,52, 41,40,39,38); rs,rw,en1,en2, 4 data lines set rw to 255 I don't see any way to eliminate rw and include en2 with fcn overloading. //LiquidCrystal lcd(48,255,46,52, 41,40,39,38); rs,rw,en1,en2, 4 data lines set rw to 47 but this trick should let me use a grounded RW and skip the checkLcdBusyFlag if I want. // Connections this assumes we attached a potentiometer across LCD pins 1,2 and 3 with a standard 16 pin straight interface // and then plugged the LCD into the distal row of digital pins on a Mega // with the LCD extending away from the mega board: // this frees up the PWM pins for other uses. // rs (LCD pin 4) to Arduino pin 49 // rw (LCD pin 5) to Arduino pin 47 // enable (LCD pin 6) to Arduino pin 45 // LCD pin 15 to Arduino pin 27 // LCD pins d4, d5, d6, d7 to Arduino pins 35,33,31,29 //Arduino pins 51,43,41,39,37,23 are unused and hard to get at--you could interpose something like a stackable header between // the used pins and the LCD; then you could access the unused pins //=====for a 4x40 LCD with 2 HD44780 type chips and 17 pin interface in 2 rows of 9; the pins are not arranged for // use with a breadboard, although you could solder a female socket onto the LCD board and use wires inserted // female sockets or (as I did) to solder in stackable headers so that you can use the breadboard but // also can plug it into the 2 rows of digital sockets on the Mega. // LCD Mega Signal // 18 Gnd Backlight draws 480 mAmps! // 17 +5V // 16 (53) not used // 15 52 En2 -- enable the 2nd HD44780 chip which controls the bottom 2 rows of the display // 14 51* +5V // 13 50* Gnd // 12 -- Contrast resistor to Gnd // 11 48 RS // 10 47* RW -- could be strapped to Gnd // 9 46 En1 -- enable the 1st HD44780 which controls the top 2 rows // 5-8 42-45* Data 0-3 not used in 4 bit modes // 1-4 38-41 Data 4-7 //This mode for the 4x40 is not working now://LiquidCrystal lcd(48,47,46,52, 45,44,43,42, 41,40,39,38); // rs,rw,en1,en2, 8 data lines remember to set rw =255 //========================================= //alternate versions to test for 2x24: I have not seen this one actually work. //LiquidCrystal lcd(50,49,48, 47,46,45,44, 43,42,41,40); // rs,rw,en 8 data pins remember to set rw = 255 above //LiquidCrystal lcd(50,49,48, 43,42,41,40); // rs,rw,en 4 data pins remember to set rw = 255 above //LiquidCrystal lcd(50,48, 47,46,45,44, 43,42,41,40); // rs,en 8 data pins remember to set rw = 49 above -- these interfaces generally have unreliable initialization //LiquidCrystal lcd(50,48, 43,42,41,40); // rs,en 4 data pins remember to set rw = 49 above -- these interfaces generally have unreliable initialization //====2x24 LCD also has a non standard pinout and pins are numbered in the opposite direction: // 1 53 Gnd // 2 52 +5V // 3 -- Contrast // 4 50 RS // 5 49 RW // 6 48 EN // 7-10 44-47 Data 0-3 not used in 4 bit mode // 11-14 40-43 Data 4-7 // 15 -- Backlight +5v 147 mAmps! // 16 -- Backlight Gnd byte BACKLIGHT, BACKLTGND, POWER5V, GNDMain; void setup(void) { // set some digital pins to high and low to provide LCD with power and gnd: // most of them: 2x16,4x20 4x16 BACKLIGHT = 27; // pin 27 will control the backlight //before I solder pins in, I check current on the backlight BACKLTGND = 25; // PIN 25 will be set LOW to provide a Gnd for the backlight POWER5V = 53; // we will set this HIGH to provide power on pin 2 of the LCD GNDMain = 255; // next to pin 53 (in the pin "55" position) is a GND--pin 1 of the LCD goes there if ((nColumns == 40) && (nRows ==4)) { //4x40 BACKLIGHT = 255; // Digital IO pins cannot control the backlight for the 4x40 double HD44780 LCD draws 480 mAmps !! BACKLTGND = 255; //Arduino is limited to 40 mAmps POWER5V = 51; // we will set this HIGH to provide power on pin 2 of the LCD GNDMain = 50; } if ((nRows ==2) && (nColumns ==24) ) { //2x24 BACKLIGHT = 255; // the 2x24 draws 147 mAmps !! BACKLTGND = 255; // POWER5V = 53; // we will set this HIGH to provide power on pin 2 of the LCD GNDMain = 52; } pinMode(POWER5V, OUTPUT); //We're using a digital out as a 5V power source for the LCD digitalWrite(POWER5V, HIGH); if (BACKLIGHT != 255) { pinMode(BACKLIGHT, OUTPUT); //set 255 if you need to wire backlight to gnd bo high current draw digitalWrite(BACKLIGHT, HIGH); // turn backlight on. Replace 'HIGH' with 'LOW' to turn it off. pinMode(BACKLTGND, OUTPUT); //We're using a digital out as a GND for the backlight digitalWrite(BACKLTGND,LOW); } if (GNDMain != 255) { pinMode (GNDMain, OUTPUT); digitalWrite(GNDMain, LOW); } if (rw != 255) { pinMode(rw,OUTPUT); digitalWrite(rw,LOW); } pinMode(13,OUTPUT); randomSeed(analogRead(0)); //read unconnected pin to seed random number generator lcd.begin(nColumns,nRows); //this is absolutely needed with this arrangement on the Mega--power was not // applied to the LCD when it was initialized as lcd was instantiated above!! } void loop(void) { //this runs the LCD with the interface selected above through a fairly comprehensive series of tests lcd.clear(); lcd.setCursor((nColumns>>1)-2,0); lcd.print( (int)nColumns); lcd.print(","); lcd.print( (int)nRows); delay(1000); //mark the corners lcd.setCursor(0,0); lcd.print('1'); lcd.setCursor(nColumns-1,nRows-1); lcd.print('4'); lcd.setCursor(nColumns-1,0); lcd.print('2'); lcd.setCursor(0,nRows-1); lcd.print('3'); lcd.setCursor((nColumns>>1)-3,0); // lcd.print("corners "); delay(1000); lcd.setCursor((nColumns>>1)-3,0); lcd.print(" scroll "); uint8_t rand=random(150); lcd.setCursor((nColumns>>1)-3,1); lcd.print((int)rand); int i = 0; while (i < rand) { lcd.scrollDisplayLeft(); i++; delay(100); } // now we repeat the corner code to be sure we fixed the behavior of setCursor after scroll delay(1000); //mark the corners lcd.setCursor(0,0); lcd.print('a'); lcd.setCursor(nColumns-1,nRows-1); lcd.print('d'); lcd.setCursor(nColumns-1,0); lcd.print('b'); lcd.setCursor(0,nRows-1); lcd.print('c'); lcd.setCursor((nColumns>>1)-3,0); lcd.print("corners "); delay(1000); lcd.clear(); lcd.setCursor(0,0); lcd.print('1'); lcd.setCursor(nColumns-1,nRows-1); lcd.print('4'); lcd.setCursor(nColumns-1,0); lcd.print('3'); lcd.setCursor(0,nRows-1); lcd.print('2'); lcd.setCursor((nColumns>>1)-3,0); lcd.print("corners"); delay(1000); lcd.setCursor((nColumns>>1)-3,1); lcd.print(" scroll "); rand = random(150); lcd.setCursor((nColumns>>1)-3,2); lcd.print((int) rand); i = 0; while (i < rand) { lcd.scrollDisplayRight(); i++; delay(100); } // now we repeat the corner code to be sure we fixed the behavior of setCursor after scroll delay(1000); //mark the corners -- all of these corner tests are good ways to find off by one errors! lcd.setCursor(nColumns-1,nRows-1); lcd.print('d'); lcd.setCursor(nColumns-1,0); lcd.print('b'); lcd.setCursor(0,nRows-1); lcd.print('c'); lcd.setCursor(0,0); lcd.print('a'); lcd.setCursor((nColumns>>1)-3,0); lcd.print("corners "); delay(1000); //Cursor on/off lcd.clear(); lcd.setCursor (0,0); lcd.print("Cursor off"); lcd.noCursor(); delay(1000); // Turn on the cursor: lcd.setCursor (0,0); lcd.print("Cursor on "); lcd.cursor(); delay(1000); lcd.setCursor (0,nRows-1); lcd.print("Cursor off"); lcd.noCursor(); delay(1000); // Turn on the cursor: lcd.setCursor (0,nRows-1); lcd.print("Cursor on "); lcd.cursor(); delay(1000); //==enumerate lines on the display lcd.clear(); i = 0; while (i < nRows) { lcd.setCursor(nColumns-8,i); lcd.print("ROW "); lcd.print(i+1); i++; } delay(1000); //=====try println lcd.clear(); lcd.setCursor(0,0); i = 0; while (i < nRows) { lcd.print("Println:# "); lcd.println(i+1); i++; } delay(1000); //=====Line wrap demo: lcd.clear(); lcd.setCursor(nColumns-4,0); lcd.print("LINEWRAP01234567890"); delay(200); if (nRows>=2) { lcd.setCursor(nColumns-4,1); lcd.print("linewrap01234567890"); delay(1000); if (nRows >=4) { lcd.setCursor(nColumns-4,3); lcd.print("linewrap01234567890"); delay(200); } } delay(1000); i = 0; while (i < 11) { lcd.scrollDisplayLeft(); i++; delay(100); } delay(1000); lcd.home(); int length = nRows * nColumns; lcd.setCursor(0,0); char text[]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; text[length] = '\0'; lcd.print(text); //here we are printing the entire screen with one long string lets you be sure that linewrap happens exactly as it should delay(2000); uint8_t a =0; if ((nColumns == 8) && (nRows == 2) ) a=1; //This is a trick to make a 'crazy 8' 16x1 LCD work reasonably in a right to left language; I suppose it could be added to the library routine // as a conditional but that seems like too much support. what happens is that we write the 2nd line first; when that fills with (8) characters // it wraps onto the first line. This means that lcd.print("abcdefghijklmno"); will print from right to left as you desire. lcd.clear(); lcd.rightToLeft(); lcd.setCursor(nColumns-1,a); //now we print it in right to left mode to test the same thing lcd.print (text); delay(3000); lcd.leftToRight(); long startTime=millis(); //let's try to benchmark how fast we can go; this will give us an idea about speed of the various interfaces 4/8 bit and checking busy flag or not: uint8_t repetitions = 20; char blanks[]=" "; blanks[length] = '\0'; while (repetitions--) { //fill every screen pixel with text, then fill every pixel with blanks and repeat. lcd.setCursor(0,0); lcd.print(text); lcd.setCursor(0,0); lcd.print(blanks); } long endTime = millis(); lcd.clear(); lcd.setCursor(0,0); lcd.print("Benchmark took "); lcd.setCursor(0,1); lcd.print(endTime - startTime); lcd.print(" millisecs."); delay(5000); //======setCursor=== // loop from ASCII 'a' to ASCII 'z': lcd.home(); int thisLetter = 'a'; // loop over the rows: for (int thisRow = 0; thisRow < nRows; thisRow++) { // loop over the columns: for (int thisCol = 0; thisCol < nColumns; thisCol++) { // set the cursor position: lcd.setCursor(thisCol,thisRow); // print the letter: lcd.print(thisLetter, BYTE); thisLetter++; if (thisLetter > 'z') thisLetter = 'a'; delay(100); } } //========Autoscroll: -- my arch nemesis ! lcd.clear(); // set the cursor to (0,0): lcd.setCursor(0, 0); // print from 0 to 9: lcd.print("Autoscroll"); for (char thisChar = '1'; thisChar < '9'; thisChar++) { lcd.print(thisChar); delay(100); } // set the cursor to (nColumns,1): lcd.setCursor(0,1); lcd.print("Autoscroll"); // set the display to automatically scroll: lcd.autoscroll(); // print from 0 to 9: for (int thisChar = 0; thisChar < 10; thisChar++) { lcd.print(thisChar); delay(100); } // turn off automatic scrolling lcd.noAutoscroll(); if (nRows>2) { //========Autoscroll: -- my arch nemesis ! // set the cursor to (0,0): lcd.setCursor(0, nRows-2); // print from 0 to 9: lcd.print("Autoscroll"); for (char thisChar = '1'; thisChar < '9'; thisChar++) { lcd.print(thisChar); delay(100); } // set the cursor to (nColumns,1): lcd.setCursor(0,nRows-1); lcd.print("Autoscroll"); // set the display to automatically scroll: lcd.autoscroll(); // print from 0 to 9: for (int thisChar = 0; thisChar < 10; thisChar++) { lcd.print(thisChar); delay(200); } // turn off automatic scrolling lcd.noAutoscroll(); } //====== Turn on the blinking cursor: lcd.clear(); lcd.setCursor(0,nRows-1); lcd.print("Blinking Cursor"); lcd.blink(); delay(1000); // Turn off the blinking cursor: lcd.noBlink(); delay(1000); lcd.setCursor(0,0); lcd.print("Blinking Cursor"); lcd.blink(); delay(1000); // Turn off the blinking cursor: lcd.noBlink(); delay(1000); //=====Turn display on and off: lcd.clear(); lcd.setCursor(0,0); lcd.print("turn display off"); delay(1000); // Turn off the display: lcd.noDisplay(); delay(2000); lcd.setCursor(0,0); lcd.print("Turn Display ON "); //sent to the LCD while the display is turned off. // Turn on the display: lcd.display(); delay(1000); lcd.clear(); lcd.home(); lcd.setCursor(0,0); lcd.print(" Shift under program control "); // scroll 27 positions (display length + string length) to the left: for (int positionCounter = 0; positionCounter < 27; positionCounter++) { // scroll one position left: lcd.scrollDisplayLeft(); // wait a bit: delay(100); } // scroll 27 positions (display length + string length) to the right: for (int positionCounter = 0; positionCounter < 27; positionCounter++) { // scroll one position right: lcd.scrollDisplayRight(); // wait a bit: delay(100); } delay(1500); //======Text direction lcd.clear(); lcd.setCursor(0,0); int thisChar ='a'; for (int i = 0;i!=30; i++) { // reverse directions at 'm': if (thisChar == 'm') { // go right for the next letter lcd.rightToLeft(); } // reverse again at 's': if (thisChar == 's') { // go left for the next letter lcd.leftToRight(); } // reset at 'z': if (thisChar > 'z') { // go to (0,0): lcd.home(); // start again at 0 thisChar = 'a'; } // print the character lcd.print(thisChar, BYTE); delay(200); //increment the letter: thisChar++; } lcd.clear(); //======define charset uint8_t bell[8] = {0x4,0xe,0xe,0xe,0x1f,0x0,0x4}; uint8_t note[8] = {0x2,0x3,0x2,0xe,0x1e,0xc,0x0}; uint8_t clock[8] = {0x0,0xe,0x15,0x17,0x11,0xe,0x0}; uint8_t heart[8] = {0x0,0xa,0x1f,0x1f,0xe,0x4,0x0}; uint8_t duck[8] = {0x0,0xc,0x1d,0xf,0xf,0x6,0x0}; uint8_t check[8] = {0x0,0x1,0x3,0x16,0x1c,0x8,0x0}; uint8_t cross[8] = {0x0,0x1b,0xe,0x4,0xe,0x1b,0x0}; uint8_t retarrow[8] = { 0x1,0x1,0x5,0x9,0x1f,0x8,0x4}; lcd.createChar(0, bell); lcd.createChar(1, note); lcd.createChar(2, clock); lcd.createChar(3, heart); lcd.createChar(4, duck); lcd.createChar(5, check); lcd.createChar(6, cross); lcd.createChar(7, retarrow); lcd.home(); i = 0; lcd.clear(); while (i<nRows) { lcd.setCursor(0,i); lcd.print("user:"); for (int j=0; j<7; j++) { lcd.print(j, BYTE); } i++; } delay(2000); } wyświetlacz firmy Optrex Dmc40457 Z biblioteką dla standardowych wyśw. działa jako 40x2 pierwsze 2 linie podając sygnał enable na E1 i pozostałe 2 linie na E2.

  • LiquidCrystal440.zip
    • LiquidCrystal440.h
    • .DS_Store
    • keywords.txt
    • ReadMe.pdf
    • LCDtest.pde
    • LiquidCrystal440.cpp


Download file - link to post

LiquidCrystal440.zip > LiquidCrystal440.cpp

#include &quot; LiquidCrystal440.h &quot;

#include &amp; lt; stdio.h &amp; gt;
#include &amp; lt; string.h &amp; gt;
#include &amp; lt; inttypes.h &amp; gt;
#include &quot; WProgram.h &quot;

// 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, //function overloading lets the list of arguments specify if 4 or 8 data lines are used and if rw is used or tied to gnd.
uint8_t d0, uint8_t d1, uint8_t d2, uint8_t d3,
uint8_t d4, uint8_t d5, uint8_t d6, uint8_t d7) // I can't eliminate rw and add en2 and be unique.
{
init(0, rs, rw, enable,255, d0, d1, d2, d3, d4, d5, d6, d7);
}
/* LiquidCrystal::LiquidCrystal(uint8_t rs, uint8_t rw, uint8_t enable, uint8_t en2, //4x40 8 data bits 2 enable pins
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, en2, 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, 255,d0, d1, d2, d3, 0, 0, 0, 0);
}
LiquidCrystal::LiquidCrystal(uint8_t rs, uint8_t rw, uint8_t enable, uint8_t en2,
uint8_t d0, uint8_t d1, uint8_t d2, uint8_t d3) //4x40 4 data pins 2 enable pins
{
init(1, rs, rw, enable,en2, 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,
uint8_t d4, uint8_t d5, uint8_t d6, uint8_t d7)
{
init(0, rs, 255, enable,255,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)
{
init(1, rs, 255, enable,255, 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 en2,
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;
_enable_pin = enable;
_en2 = en2;
_chip = 0;
_scroll_count =0; //to fix the bug if we scroll and then setCursor w/o home() or clear()
_x = 0;
_y = 0;
_numcols = 0;
_setCursFlag = 0;
_direction = LCD_Right;
_data_pins[0] = d0;
_data_pins[1] = d1;
_data_pins[2] = d2;
_data_pins[3] = d3;
_data_pins[4] = d4; //unused in 4 bit mode
_data_pins[5] = d5;
_data_pins[6] = d6;
_data_pins[7] = d7;

pinMode(d0, OUTPUT); //set data pin modes
pinMode(d1, OUTPUT);
pinMode(d2, OUTPUT);
pinMode(d3, OUTPUT);
if (! fourbitmode) {
pinMode(d4, OUTPUT);
pinMode(d5, OUTPUT);
pinMode(d6, OUTPUT);
pinMode(d7, OUTPUT);

}
row_offsets[0] = 00; // DDRAM addresses inside the HD44780 are strange: 0-nColumns-1 on line 0
row_offsets[1] = 0x40; // 64-(63+nColumns) for line 1
row_offsets[2] = 0x14; // 20- (19+nColumns) for line 2 --- NOTHING FROM 40-63 !
row_offsets[3] = 0x54; // 84 - (83+nColumns) for line 3 -- so 80 characters tops out at #103 !

pinMode(_rs_pin, OUTPUT);
// we can save 1 pin by not using RW. Indicate by passing 255 instead of pin#
if (rw != 255) {
pinMode(rw, OUTPUT); //once in init does it
digitalWrite(rw,LOW); //write data to LCD mode
}
pinMode(_enable_pin, OUTPUT);
if( en2 != 0) pinMode(en2,OUTPUT); //4X40 LCD

_displayfunction = LCD_8BITMODE | LCD_1LINE | LCD_5x8DOTS;
if (fourbitmode)
_displayfunction = LCD_4BITMODE | LCD_1LINE | LCD_5x8DOTS;

_rw_pin = rw;
begin(20, 1);
}

void LiquidCrystal::begin(uint8_t cols, uint8_t lines, uint8_t dotsize) {
_numlines = lines;
_numcols = cols;
row_offsets[2] = cols + row_offsets[0]; //should autoadjust for 16/20 or whatever columns now
row_offsets[3] = cols + row_offsets[1];

begin2( cols, lines, dotsize, 0);
if (_en2 != 255) { //if we were called with a 2nd enable line i.e. 4x40 LCD
row_offsets[2] = 0;
row_offsets[3] = 0x40; //each line gets its own little 40 char section of DDRAM--would be fine if there were a 4x32, I suppose.
begin2( cols, lines, dotsize,0x2);//initialize the second HD44780 chip
}
}

void LiquidCrystal::begin2(uint8_t cols, uint8_t lines, uint8_t dotsize, uint8_t chip) {
_chip = chip;

uint8_t en = _enable_pin;
if (chip == 2) en=_en2;
if (lines &amp; gt; 1) {
_displayfunction |= LCD_2LINE;
}

// for some 1 line displays you can select a 10 pixel high font
if ((dotsize != 0) &amp; &amp; (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 before 4.5V so we'll wait 50
delayMicroseconds(60000); //I don't think I can adequately test this number; it will depend a little on which Arduino or clone you have and probably
//could also vary with the power source applied to that board. The way to test is really to load your program, remove power
//and then reapply power so that the program starts up as power is applied. If anyone finds they need a larger number please
//let me know: raine001 at tc dot umn dot edu
// Now we pull both RS and R/W low to begin commands
digitalWrite(_rs_pin, LOW);
digitalWrite(en, LOW);

//put the LCD into 4 bit or 8 bit mode
if (! (_displayfunction &amp; 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
//at this point we are in 8 bit mode but of course in this interface 4 pins are dangling unconnected and the values on them don't matter for these instructions.
write4bits(0x03,LOW);
delayMicroseconds(5000); // I have one LCD for which 4500 here was not long enough.
// second try
write4bits(0x03,LOW);
delayMicroseconds(150); // wait
// third go!
write4bits(0x03,LOW);
delayMicroseconds(150);
// finally, set to 4-bit interface
write4bits(0x02,LOW);
} else {
// this is according to the hitachi HD44780 datasheet
// page 45 figure 23 -- this is 8 bit mode

// Send function set command sequence
command(LCD_FUNCTIONSET | _displayfunction);
delayMicroseconds(5000); // again, one LCD I have needed more than 4500

// 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()
{
if (_en2 != 255) {
_chip=2;
command(LCD_CLEARDISPLAY);
_chip=0;
command(LCD_CLEARDISPLAY);
delayMicroseconds(2000);
setCursor(0,0);
}
else {
command(LCD_CLEARDISPLAY); // clear display, set cursor position to zero
delayMicroseconds(2000); // this command takes a long time!
}
_scroll_count = 0;
}

void LiquidCrystal::home()
{
commandBoth(LCD_RETURNHOME); // set cursor position to zero //both chips.
delayMicroseconds(2000); // this command takes a long time!
_scroll_count = 0;
if (_en2 != 255) setCursor(0,0);
}


// Turn the display on/off (quickly)
void LiquidCrystal::noDisplay() {
_displaycontrol &amp; = ~LCD_DISPLAYON;
commandBoth(LCD_DISPLAYCONTROL | _displaycontrol); //both chips
}
void LiquidCrystal::display() {
_displaycontrol |= LCD_DISPLAYON;
commandBoth(LCD_DISPLAYCONTROL | _displaycontrol); //both chips
}

// Turns the underline cursor on/off
void LiquidCrystal::noCursor() {
_displaycontrol &amp; = ~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 &amp; = ~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) {
commandBoth(LCD_CURSORSHIFT | LCD_DISPLAYMOVE | LCD_MOVELEFT); //both chips
_scroll_count++;
if (_scroll_count &amp; gt; = 40) _scroll_count -= 40; // -39 &amp; lt; scroll_count &amp; lt; 39
}
void LiquidCrystal::scrollDisplayRight(void) {
commandBoth(LCD_CURSORSHIFT | LCD_DISPLAYMOVE | LCD_MOVERIGHT); //both chips
_scroll_count--;
if (_scroll_count &amp; lt; = -40) _scroll_count += 40;
}

// This is for text that flows Left to Right
void LiquidCrystal::leftToRight(void) {
_displaymode |= LCD_ENTRYLEFT;
_direction = LCD_Right;
commandBoth(LCD_ENTRYMODESET | _displaymode); //both chips
}

// This is for text that flows Right to Left
void LiquidCrystal::rightToLeft(void) {
_displaymode &amp; = ~LCD_ENTRYLEFT;
_direction = LCD_Left;
commandBoth(LCD_ENTRYMODESET | _displaymode); //both chips
}


// Allows us to fill the first 8 CGRAM locations
// with custom characters
void LiquidCrystal::createChar(uint8_t location, uint8_t charmap[]) {
location &amp; = 0x7; // we only have 8 locations 0-7
if (_en2 == 255) {
command(LCD_SETCGRAMADDR | (location &amp; lt; &amp; lt; 3));
for (int i=0; i &amp; lt; 8; i++) {
send(charmap[i],HIGH);
}
}
else {
uint8_t chipSave = _chip;
_chip = 0;
command(LCD_SETCGRAMADDR | (location &amp; lt; &amp; lt; 3));
for (uint8_t i=0; i &amp; lt; 8; i++) {
send(charmap[i],HIGH);
}
_chip = 2;
command(LCD_SETCGRAMADDR | (location &amp; lt; &amp; lt; 3));
for (uint8_t i=0; i &amp; lt; 8; i++) {
send(charmap[i],HIGH);
}
_chip = chipSave;
}
}

void LiquidCrystal::setCursor(uint8_t col, uint8_t row) // this can be called by the user but is also called before writing some characters.
{
if ( row &amp; gt; _numlines ) {
row = _numlines-1; // we count rows starting w/0
}
_y = row;
_x = col;
_setCursFlag = 0; //user did a setCursor--clear the flag that may have been set in write()
int8_t high_bit = row_offsets[row] &amp; 0x40; // this keeps coordinates pegged to a spot on the LCD screen even if the user scrolls right or
int8_t offset = col + (row_offsets[row] &amp; 0x3f) + _scroll_count; //left under program control. Previously setCursor was pegged to a location in DDRAM
//the 3 quantities we add are each &amp; lt; 40
if (offset &amp; gt; 39) offset -= 40; // if the display is autoscrolled this method does not work, however.
if (offset &amp; lt; 0) offset += 40;
offset |= high_bit;
if (_chip != (row &amp; 0b10)) noCursor(); //turn off cursor on chip we are leaving
_chip = row &amp; 0b10; //if it is row 0 or 1 this is 0; if it is row 2 or 3 this is 2
command(LCD_SETDDRAMADDR | (byte) offset );
}
// This will 'right justify' text from the cursor
void LiquidCrystal::autoscroll(void) { //to count the number of times we scrolled; here we'd need to keep track of microseconds and divide. I'm not going there.
_displaymode |= LCD_ENTRYSHIFTINCREMENT;
commandBoth(LCD_ENTRYMODESET | _displaymode); //both chips
}

// This will 'left justify' text from the cursor
void LiquidCrystal::noAutoscroll(void) {
_displaymode &amp; = ~LCD_ENTRYSHIFTINCREMENT; //both chips
commandBoth(LCD_ENTRYMODESET | _displaymode);
}


/*********** mid level commands, for sending data/cmds */
inline void LiquidCrystal::command(uint8_t value) {
send(value, LOW);
}

void LiquidCrystal::commandBoth(uint8_t value) { //for many of the commands that need to be sent twice if 2 controller chips
if (_en2 == 255) {
send(value, LOW); //not 40x4
}
else {
uint8_t chipSave = _chip;
_chip = 0;
send(value,LOW); //send command to first HD44780
_chip = 2;
send(value,LOW); //send to 2nd HD44780
_chip=chipSave;
}
}

void LiquidCrystal::write(uint8_t value) { //print calls this to send characters to the LCD
if ((_scroll_count != 0) || (_setCursFlag != 0) ) setCursor(_x,_y); //first we call setCursor and send the character
if ((value != '\r') &amp; &amp; (value != '\n') )send(value, HIGH);

_setCursFlag = 0;
if (_direction == LCD_Right) { // then we update the x &amp; y location for the NEXT character
_x++;
if ((value == '\r') ||(_x &amp; gt; = _numcols) ) { //romance languages go left to right

_x = 0;
_y++;
_setCursFlag = 1; //we'll need a setCursor() before the next char to move to begin of next line
}
}
else {
_x--;
if ( (value == '\n') || (_x &amp; lt; 0)) { //emulate right to left text mode which is built in but would be defeated by my code above
_x = _numcols-1;
_y++;
_setCursFlag = 1;
}
}
if (_y &amp; gt; = _numlines) _y = 0; //wrap last line up to line 0
}

/************ 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 (_displayfunction &amp; LCD_8BITMODE) {
write8bits(value,mode);
delayMicroseconds(100);
} else {
write4bits(value &amp; gt; &amp; gt; 4, mode);
write4bits(value, mode);
delayMicroseconds(100);
}
}

void LiquidCrystal::pulseEnable(void) {
byte en = _enable_pin;
if ((_en2 != 255) &amp; &amp; (_chip)) en = _en2; //I have a 4x40 LCD with 2 controller chips with separate enable lines if we called w 2 enable pins and are on lines 2 or 3 enable chip 2
digitalWrite(en,LOW);
digitalWrite(en, HIGH); // enable pulse must be &amp; gt; 450ns
// delayMicroseconds(1); // but this is unnecessary see:
digitalWrite(en, LOW); //http://billgrundmann.wordpress.com/2009/03/03/to-use-or-not-use-writedigital/
}


void LiquidCrystal::write4bits(uint8_t value, uint8_t mode) {

digitalWrite(_rs_pin,mode);
for (uint8_t i = 0; i &amp; lt; 4; i++) {
digitalWrite(_data_pins[i], (value &amp; gt; &amp; gt; i) &amp; 0x01);
}
pulseEnable();
}

void LiquidCrystal::write8bits(uint8_t value, uint8_t mode) {
digitalWrite(_rs_pin,mode);
for (uint8_t i = 0; i &amp; lt; 8; i++) {
digitalWrite(_data_pins[i], (value &amp; gt; &amp; gt; i) &amp; 0x01);
}
pulseEnable();
}


LiquidCrystal440.zip > LiquidCrystal440.h

#ifndef LiquidCrystal_h
#define LiquidCrystal_h

#include &amp; lt; inttypes.h &amp; gt;
#include &quot; Print.h &quot;

// 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
#define LCD_Right 0
#define LCD_Left 1

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 en2,
uint8_t d0, uint8_t d1, uint8_t d2, uint8_t d3,
uint8_t d4, uint8_t d5, uint8_t d6, uint8_t d7); 4x40 LCD 8 data pins, 2 enable lines not working now
*/

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 rw, uint8_t enable, uint8_t en2,
uint8_t d0, uint8_t d1, uint8_t d2, uint8_t d3); //4x40 LCD w 2x HD44780 controller chips, 2 enable lines to select between them 4 data pins
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 en2,
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);
void commandBoth(uint8_t);
private:
void send(uint8_t, uint8_t);
void write4bits(uint8_t, uint8_t);
void write8bits(uint8_t, uint8_t);
void pulseEnable();
void checkLcdBusyFlag(void);
void begin2(uint8_t cols, uint8_t rows, uint8_t charsize, uint8_t chip);
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 _en2; //4x40 LCD
uint8_t _chip; //4x40
int8_t _scroll_count;
int8_t _x, _y,_setCursFlag;
uint8_t _direction;
uint8_t _numcols;
uint8_t _busyPin; // for reading the busy flag on the LCD synonmymous w _data_pins[0]
uint8_t _data_pins[8];
uint8_t row_offsets[4];

uint8_t _displayfunction; // 4/8 bit mode, 1/2'lines', dotsize
uint8_t _displaycontrol; //display on/off, cursor on/off, blink on/off
uint8_t _displaymode; //text direction

// uint8_t _initialized;

uint8_t _numlines;
};

#endif


LiquidCrystal440.zip > keywords.txt

#######################################
# Syntax Coloring Map For LiquidCrystal
#######################################

#######################################
# Datatypes (KEYWORD1)
#######################################

LiquidCrystal KEYWORD1

#######################################
# Methods and Functions (KEYWORD2)
#######################################

begin KEYWORD2
clear KEYWORD2
home KEYWORD2
print KEYWORD2
setCursor KEYWORD2
cursor KEYWORD2
noCursor KEYWORD2
blink KEYWORD2
noBlink KEYWORD2
display KEYWORD2
noDisplay KEYWORD2
autoscroll KEYWORD2
noAutoscroll KEYWORD2
leftToRight KEYWORD2
rightToLeft KEYWORD2
scrollDisplayLeft KEYWORD2
scrollDisplayRight KEYWORD2
createChar KEYWORD2

#######################################
# Constants (LITERAL1)
#######################################


LiquidCrystal440.zip > ReadMe.pdf

Modifications to LiquidCrystal for the Arduino
I made several modifications to the LiquidCrystal library module from Arduino17:
40x4 LCDs
I added support for an LCD of 4 LInes and 40 characters. I think that if 24x4, 32x4
LCDs exist, they would also work with the software as I have modified it although I
have not had the opportunity to test that. The 40x4 LCD (and any HD44780 based
LCD with between 81 and 160 characters) will have 2 enable lines. To use an LCD
with 4 lines and 40 columns you would declare your LiquidCrystal object as:
LiquidCrystal lcd(RS,RW,Enable1,Enable2, data3,data2,data1,data0); at this time I
don't support 8 data lines. nor do I support eliminating the RW line in this option,
although it may be possible to pass 255 as the RW item and get that behavior.
Then in the setup function you would call:
lcd.begin(40,4);
Linewrap
When you declare the dimensions of the LCD in your begin call, the LiquidCrystal
library remembers how long the lines are. Now when it reaches the end of line 1, text
wraps onto line 2 (not line 3 as previously).
16x4 LCDs
The begin statement also correctly positions text at the beginning of the line on 16x4
(and 40x4) LCDs, which were not correctly handled before.
setCursor
In the past setCursor selected a location in the HD44780's RAM not actually a
screen location. If you use any of the commands that shift the display left or right with
the previous routines, then setCursor and print, text appears in an unexpected
location on the screen. With the new software, if you call either scrollDisplayLeft() or
scrollDisplayRight(), the LiquidCrystal package keeps track of the relationship
between RAM and the LCD so that setCursor coordinates are pegged to a specific
spot on the screen, rather than a spot in RAM. The sotware does not handle
autoScroll, however. Call home() after autoScroll to restore the expected relationship
between setCursor and the LCD screen.
Testing the LCD Busy Flag
Previous versions of LiquidCrystal always used timed delays on the Arduino side of
the interface to give the LCD module enough time to complete its operation. This
version still does that if you tie the RW pin to ground and do not tell LiquidCrystal
what that pin number is. If you do specify RW now, however, the software will poll the
busy flag on the LCD module. Arduino operations may thus overlap LCD operations.

Speed testing
All of the interface modes go faster than the eye can follow. I compared the speeds
of the different interfaces--writing 80 characters to the screen then 80 blanks and
looping through that 20 times. The results are:
8 data pins + RW 431 milliseconds
4 data pins + RW 532 milliseconds
8 data pins - RW 641 milliseconds
4 data pins - RW 687 milliseconds
Crazy 8 Addressing
16x1 LCDs often have an unusual address layout; these modules often have two 8
character halves and work best with this software if you declare them as
lcd.begin(8,2); if you do that, then you can print("abcdefghilklmno"); and have all the
characters appear as you would like across the screen. If you use any of the scrolling
commands, the bizarre addressing of these modules will manifest itself. For details
follow the _LCD Addressing_ link at web.alfredstate.edu/weimandn
Disadvantages
The two real disadvantages I can see to the changes I have made are:
1. The code is longer than before. Much of the increase is in checkLcdBusyFlag()
and this could be fairly easily replaced with delayMicroseconds(100);
2. The possibility that someone with a little 16x2 LCD is using the scrollDisplayLeft()
or scrollDisplayRight() instructions to move data across the screen, but wants to
write the data 40 characters at a time with a print statement. This version really does
not let the user write data to the HD44780 DDRAM which is not visible. To
accomplish a scrolling display with 40 characters per line, you would now need to
write 16 characters, scroll the display, write a little more and so on.
There are going to be some incompatibilities between code that assumed that line 1
wrapped onto line 3, etc.
Directions for the future
I see little purpose to retaining the 8 pin interface options. Even in the slowest
situation output to the LCD goes faster than the eye can follow. The slowest situation
would be using the 40x4 LCD, doing a scrollDisplayLeft() or scrollDisplayRight() and
then printing 160 characters. When the display has been scrolled, the software
actually calls setCursor internally with every character sent to the LCD, so you would
be communicating 480 items to the LCD in that instance. As I have tested the various
interfaces with the various shapes of LCDs, I have reflected many times on the
likelihood that no one else has tried the 8 bit interfaces for some time. Don Weiman
argues that inclusion of both 4 and 8 bit interfaces makes the code harder to read. I
am more motivated by the idea that the 8 bit interface takes up Arduino RAM and
pins but contributes little additional function.

Thanks
Certainly my efforts would not have been possible without the help and prior efforts
of David Mellis, Limor Friede, and Donald Weiman. Don was particularly patient in
guiding me through the idiosyncracies of the HD44780 based LCDs and especially in
supplying an example of how the busy flag could be tested.


LiquidCrystal440.zip > LiquidCrystal440.cpp

#include &quot; LiquidCrystal440.h &quot;

#include &amp; lt; stdio.h &amp; gt;
#include &amp; lt; string.h &amp; gt;
#include &amp; lt; inttypes.h &amp; gt;
#include &quot; WProgram.h &quot;

// 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, //function overloading lets the list of arguments specify if 4 or 8 data lines are used and if rw is used or tied to gnd.
uint8_t d0, uint8_t d1, uint8_t d2, uint8_t d3,
uint8_t d4, uint8_t d5, uint8_t d6, uint8_t d7) // I can't eliminate rw and add en2 and be unique.
{
init(0, rs, rw, enable,0, d0, d1, d2, d3, d4, d5, d6, d7);
}
/* LiquidCrystal::LiquidCrystal(uint8_t rs, uint8_t rw, uint8_t enable, uint8_t en2, //4x40 8 data bits 2 enable pins
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, en2, 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, 0,d0, d1, d2, d3, 0, 0, 0, 0);
}
LiquidCrystal::LiquidCrystal(uint8_t rs, uint8_t rw, uint8_t enable, uint8_t en2,
uint8_t d0, uint8_t d1, uint8_t d2, uint8_t d3) //4x40 4 data pins 2 enable pins
{
init(1, rs, rw, enable,en2, 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,
uint8_t d4, uint8_t d5, uint8_t d6, uint8_t d7)
{
init(0, rs, 255, enable, 0,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)
{
init(1, rs, 255, enable,0, 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 en2,
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;
_enable_pin = enable;
_en2 = en2;
_chip = 0;
_scroll_count =0; //to fix the bug if we scroll and then setCursor w/o home() or clear()
_x = 0;
_y = 0;
_numcols = 0;
_setCursFlag = 0;
_direction = LCD_Right;
_busyPin = d3; // for reading the busy flag on the LCD
if (! fourbitmode) _busyPin = d7;
_data_pins[0] = d0;
_data_pins[1] = d1;
_data_pins[2] = d2;
_data_pins[3] = d3;
_data_pins[4] = d4; //unused in 4 bit mode
_data_pins[5] = d5;
_data_pins[6] = d6;
_data_pins[7] = d7;
pinMode(d0, OUTPUT); //set data pin modes
pinMode(d1, OUTPUT);
pinMode(d2, OUTPUT);
pinMode(d3, OUTPUT);
if (! fourbitmode) {
pinMode(d4, OUTPUT);
pinMode(d5, OUTPUT);
pinMode(d6, OUTPUT);
pinMode(d7, OUTPUT);
}
row_offsets[0] = 00; // DDRAM addresses inside the HD44780 are strange: 0-nColumns-1 on line 0
row_offsets[1] = 0x40; // 64-(63+nColumns) for line 1
row_offsets[2] = 0x14; // 20- (19+nColumns) for line 2 --- NOTHING FROM 40-63 !
row_offsets[3] = 0x54; // 84 - (83+nColumns) for line 3 -- so 80 characters tops out at #103 !

pinMode(_rs_pin, OUTPUT);
// we can save 1 pin by not using RW. Indicate by passing 255 instead of pin#
if (rw != 255) {
pinMode(rw, OUTPUT); //once in init does it
digitalWrite(rw,LOW); //write data to LCD mode
}
pinMode(_enable_pin, OUTPUT);
if( en2 != 0) pinMode(en2,OUTPUT); //4X40 LCD

_displayfunction = LCD_8BITMODE | LCD_1LINE | LCD_5x8DOTS;
if (fourbitmode)
_displayfunction = LCD_4BITMODE | LCD_1LINE | LCD_5x8DOTS;

_rw_pin = rw;
begin(20, 1);
}

void LiquidCrystal::begin(uint8_t cols, uint8_t lines, uint8_t dotsize) {
_numlines = lines;
_numcols = cols;
row_offsets[2] = cols + row_offsets[0]; //should autoadjust for 16/20 or whatever columns now
row_offsets[3] = cols + row_offsets[1];

begin2( cols, lines, dotsize, 0);
if (_en2 != 0) { //if we were called with a 2nd enable line i.e. 4x40 LCD
row_offsets[2] = 0;
row_offsets[3] = 0x40; //each line gets its own little 40 char section of DDRAM--would be fine if there were a 4x32, I suppose.
begin2( cols, lines, dotsize,0x2);//initialize the second HD44780 chip
}
}

void LiquidCrystal::begin2(uint8_t cols, uint8_t lines, uint8_t dotsize, uint8_t chip) {
_chip = chip;
uint8_t rwSave = _rw_pin;
_rw_pin = 255; //idea is to play a game with timing vs busy as we start up this tells checkLcdBusyFlag to time 100 microseconds rather thanwatch busy.
uint8_t en = _enable_pin;
if (chip == 2) en=_en2;
if (lines &amp; gt; 1) {
_displayfunction |= LCD_2LINE;
}

// for some 1 line displays you can select a 10 pixel high font
if ((dotsize != 0) &amp; &amp; (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 before 4.5V so we'll wait 50
delayMicroseconds(60000); //I don't think I can adequately test this number; it will depend a little on which Arduino or clone you have and probably
//could also vary with the power source applied to that board. The way to test is really to load your program, remove power
//and then reapply power so that the program starts up as power is applied. If anyone finds they need a larger number please
//let me know: raine001 at tc dot umn dot edu
// Now we pull both RS and R/W low to begin commands
digitalWrite(_rs_pin, LOW);
digitalWrite(en, LOW);

//put the LCD into 4 bit or 8 bit mode
if (! (_displayfunction &amp; 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
//at this point we are in 8 bit mode but of course in this interface 4 pins are dangling unconnected and the values on them don't matter for these instructions.
write4bits(0x03,LOW);
delayMicroseconds(5000); // I have one LCD for which 4500 here was not long enough.
// second try
write4bits(0x03,LOW);
delayMicroseconds(150); // wait
// third go!
write4bits(0x03,LOW);
delayMicroseconds(150);
// finally, set to 4-bit interface
write4bits(0x02,LOW);
} else {
// this is according to the hitachi HD44780 datasheet
// page 45 figure 23 -- this is 8 bit mode

// Send function set command sequence
command(LCD_FUNCTIONSET | _displayfunction);
delayMicroseconds(5000); // again, one LCD I have needed more than 4500

// 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);
_rw_pin = rwSave; //game w checkLcdBusyFlag is over.


}

/********** high level commands, for the user! */
void LiquidCrystal::clear()
{
if (_en2 != 0) {
_chip=2;
command(LCD_CLEARDISPLAY);
_chip=0;
command(LCD_CLEARDISPLAY);
delayMicroseconds(2000);
setCursor(0,0);
}
else {
command(LCD_CLEARDISPLAY); // clear display, set cursor position to zero
delayMicroseconds(2000); // this command takes a long time!
}
_scroll_count = 0;
}

void LiquidCrystal::home()
{
commandBoth(LCD_RETURNHOME); // set cursor position to zero //both chips.
delayMicroseconds(2000); // this command takes a long time!
_scroll_count = 0;
if (_en2 != 0) setCursor(0,0);
}


// Turn the display on/off (quickly)
void LiquidCrystal::noDisplay() {
_displaycontrol &amp; = ~LCD_DISPLAYON;
commandBoth(LCD_DISPLAYCONTROL | _displaycontrol); //both chips
}
void LiquidCrystal::display() {
_displaycontrol |= LCD_DISPLAYON;
commandBoth(LCD_DISPLAYCONTROL | _displaycontrol); //both chips
}

// Turns the underline cursor on/off
void LiquidCrystal::noCursor() {
_displaycontrol &amp; = ~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 &amp; = ~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) {
commandBoth(LCD_CURSORSHIFT | LCD_DISPLAYMOVE | LCD_MOVELEFT); //both chips
_scroll_count++;
if (_scroll_count &amp; gt; = 40) _scroll_count -= 40; // -39 &amp; lt; scroll_count &amp; lt; 39
}
void LiquidCrystal::scrollDisplayRight(void) {
commandBoth(LCD_CURSORSHIFT | LCD_DISPLAYMOVE | LCD_MOVERIGHT); //both chips
_scroll_count--;
if (_scroll_count &amp; lt; = -40) _scroll_count += 40;
}

// This is for text that flows Left to Right
void LiquidCrystal::leftToRight(void) {
_displaymode |= LCD_ENTRYLEFT;
_direction = LCD_Right;
commandBoth(LCD_ENTRYMODESET | _displaymode); //both chips
}

// This is for text that flows Right to Left
void LiquidCrystal::rightToLeft(void) {
_displaymode &amp; = ~LCD_ENTRYLEFT;
_direction = LCD_Left;
commandBoth(LCD_ENTRYMODESET | _displaymode); //both chips
}

// This will 'right justify' text from the cursor
void LiquidCrystal::autoscroll(void) { //to count the number of times we scrolled; here we'd need to keep track of microseconds and divide. I'm not going there.
_displaymode |= LCD_ENTRYSHIFTINCREMENT;
commandBoth(LCD_ENTRYMODESET | _displaymode); //both chips
}

// This will 'left justify' text from the cursor
void LiquidCrystal::noAutoscroll(void) {
_displaymode &amp; = ~LCD_ENTRYSHIFTINCREMENT; //both chips
commandBoth(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 &amp; = 0x7; // we only have 8 locations 0-7
if (_en2 == 0) {
command(LCD_SETCGRAMADDR | (location &amp; lt; &amp; lt; 3));
for (int i=0; i &amp; lt; 8; i++) {
send(charmap[i],HIGH);
}
}
else {
uint8_t chipSave = _chip;
_chip = 0;
command(LCD_SETCGRAMADDR | (location &amp; lt; &amp; lt; 3));
for (uint8_t i=0; i &amp; lt; 8; i++) {
send(charmap[i],HIGH);
}
_chip = 2;
command(LCD_SETCGRAMADDR | (location &amp; lt; &amp; lt; 3));
for (uint8_t i=0; i &amp; lt; 8; i++) {
send(charmap[i],HIGH);
}
_chip = chipSave;
}
}

void LiquidCrystal::setCursor(uint8_t col, uint8_t row) // this can be called by the user but is also called before writing some characters.
{
if ( row &amp; gt; _numlines ) {
row = _numlines-1; // we count rows starting w/0
}
_y = row;
_x = col;
_setCursFlag = 0; //user did a setCursor--clear the flag that may have been set in write()
int8_t high_bit = row_offsets[row] &amp; 0x40; // this keeps coordinates pegged to a spot on the LCD screen even if the user scrolls right or
int8_t offset = col + (row_offsets[row] &amp; 0x3f) + _scroll_count; //left under program control. Previously setCursor was pegged to a location in DDRAM
//the 3 quantities we add are each &amp; lt; 40
if (offset &amp; gt; 39) offset -= 40; // if the display is autoscrolled this method does not work, however.
if (offset &amp; lt; 0) offset += 40;
offset |= high_bit;
if (_chip != (row &amp; 0b10)) noCursor(); //turn off cursor on chip we are leaving
_chip = row &amp; 0b10; //if it is row 0 or 1 this is 0; if it is row 2 or 3 this is 2
command(LCD_SETDDRAMADDR | (byte) offset );
}

/*********** mid level commands, for sending data/cmds */

void LiquidCrystal::write(uint8_t value) { //print calls this to send characters to the LCD
if ((_scroll_count != 0) || (_setCursFlag != 0) ) setCursor(_x,_y); //first we call setCursor and send the character
send(value, HIGH);
_setCursFlag = 0;
if (_direction == LCD_Right) { // then we update the x &amp; y location for the NEXT character
_x++;
if ((value == '\r') ||(_x &amp; gt; = _numcols) ) { //romance languages go left to right
_x = 0;
_y++;
_setCursFlag = 1; //we'll need a setCursor() before the next char to move to begin of next line
}
}
else {
_x--;
if ( (value == '\n') || (_x &amp; lt; 0)) { //emulate right to left text mode which is built in but would be defeated by my code above
_x = _numcols-1;
_y++;
_setCursFlag = 1;
}
}
if (_y &amp; gt; = _numlines) _y = 0; //wrap last line up to line 0
}


inline void LiquidCrystal::command(uint8_t value) {
send(value, LOW);
}
void LiquidCrystal::commandBoth(uint8_t value) { //for many of the commands that need to be sent twice if 2 controller chips
if (_en2 == 0) {
send(value, LOW); //not 40x4
}
else {
uint8_t chipSave = _chip;
_chip =0;
send(value,LOW); //send command to first HD44780
_chip = 2;
send(value,LOW); //send to 2nd HD44780
_chip=chipSave;
}
}

/************ 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 (_displayfunction &amp; LCD_8BITMODE) {
if (mode == HIGH) digitalWrite(13,LOW);
write8bits(value,mode);
} else {
checkLcdBusyFlag();
write4bits(value &amp; gt; &amp; gt; 4, mode);
write4bits(value, mode);
}
}

void LiquidCrystal::pulseEnable(void) {
byte en = _enable_pin;
if ((_en2 != 0) &amp; &amp; (_chip)) en = _en2; //I have a 4x40 LCD with 2 controller chips with separate enable lines if we called w 2 enable pins and are on lines 2 or 3 enable chip 2
digitalWrite(en, HIGH); // enable pulse must be &amp; gt; 450ns
// delayMicroseconds(1); // but this is unnecessary see:
digitalWrite(en, LOW); //http://billgrundmann.wordpress.com/2009/03/03/to-use-or-not-use-writedigital/
// delayMicroseconds(100); // commands need &amp; gt; 37us to settle not needed if using checkLcdBusyFlag
}
void LiquidCrystal::checkLcdBusyFlag(void) {
if (_rw_pin != 255) {
uint8_t busy = HIGH;
digitalWrite(_rw_pin,HIGH); //read data from LCD
digitalWrite(_rs_pin,LOW);
pinMode(_busyPin,INPUT); //set the high order data pin to read the busy flag
uint8_t en = _enable_pin;
if ((_en2 != 0) &amp; &amp; (_chip)) en = _en2; //if we have a 2nd enable line interface and are on lines 2 or 3 use the 2nd enable line
do {
// digitalWrite(en,LOW);
// delayMicroseconds(1);
digitalWrite(en,HIGH); //pulse appropriate enable pin high
// delayMicroseconds(1);
busy = digitalRead(_busyPin);
digitalWrite(en,LOW); //busy+address
// delayMicroseconds(1);
if (! (_displayfunction &amp; LCD_8BITMODE) ) pulseEnable(); //we are in 4 bit mode and need to get rid of the 2nd nibble
} while (busy == HIGH);
pinMode(_busyPin,OUTPUT); // set data pin back to 'Write'
digitalWrite(_rw_pin,LOW); //set RW back to 'Write'
digitalWrite(_rs_pin,HIGH);
}
else delayMicroseconds(100); //no RW line just blow 100 microsec
}

void LiquidCrystal::write4bits(uint8_t value, uint8_t mode) {

digitalWrite(_rs_pin,mode);
for (uint8_t i = 0; i &amp; lt; 4; i++) {
digitalWrite(_data_pins[i], (value &amp; gt; &amp; gt; i) &amp; 0x01);
}
pulseEnable();
}

void LiquidCrystal::write8bits(uint8_t value, uint8_t mode) {
checkLcdBusyFlag();
digitalWrite(_rs_pin,mode);
for (uint8_t i = 0; i &amp; lt; 8; i++) {
digitalWrite(_data_pins[i], (value &amp; gt; &amp; gt; i) &amp; 0x01);
}
pulseEnable();
}


LiquidCrystal440.zip > keywords.txt

#######################################
# Syntax Coloring Map For LiquidCrystal
#######################################

#######################################
# Datatypes (KEYWORD1)
#######################################

LiquidCrystal KEYWORD1

#######################################
# Methods and Functions (KEYWORD2)
#######################################

begin KEYWORD2
clear KEYWORD2
home KEYWORD2
print KEYWORD2
setCursor KEYWORD2
cursor KEYWORD2
noCursor KEYWORD2
blink KEYWORD2
noBlink KEYWORD2
display KEYWORD2
noDisplay KEYWORD2
autoscroll KEYWORD2
noAutoscroll KEYWORD2
leftToRight KEYWORD2
rightToLeft KEYWORD2
scrollDisplayLeft KEYWORD2
scrollDisplayRight KEYWORD2
createChar KEYWORD2

#######################################
# Constants (LITERAL1)
#######################################


LiquidCrystal440.zip > LiquidCrystal440.h

#ifndef LiquidCrystal_h
#define LiquidCrystal_h

#include &amp; lt; inttypes.h &amp; gt;
#include &quot; Print.h &quot;

// 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
#define LCD_Right 0
#define LCD_Left 1

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 en2,
uint8_t d0, uint8_t d1, uint8_t d2, uint8_t d3,
uint8_t d4, uint8_t d5, uint8_t d6, uint8_t d7); 4x40 LCD 8 data pins, 2 enable lines not working now
*/

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 rw, uint8_t enable, uint8_t en2,
uint8_t d0, uint8_t d1, uint8_t d2, uint8_t d3); //4x40 LCD w 2x HD44780 controller chips, 2 enable lines to select between them 4 data pins

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 en2,
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);
void commandBoth(uint8_t);
private:
void send(uint8_t, uint8_t);
void write4bits(uint8_t, uint8_t);
void write8bits(uint8_t, uint8_t);
void pulseEnable();
void checkLcdBusyFlag(void);
void begin2(uint8_t cols, uint8_t rows, uint8_t charsize, uint8_t chip);
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 _en2; //4x40 LCD
uint8_t _chip; //4x40
int8_t _scroll_count;
int8_t _x, _y,_setCursFlag;
uint8_t _direction;
uint8_t _numcols;
uint8_t _data_pins[8];
uint8_t row_offsets[4];

uint8_t _displayfunction; // 4/8 bit mode, 1/2'lines', dotsize
uint8_t _displaycontrol; //display on/off, cursor on/off, blink on/off
uint8_t _displaymode; //text direction

uint8_t _numlines;
};

#endif


LiquidCrystal440.zip > ReadMe.pdf

Modifications to LiquidCrystal for the Arduino
I made several modifications to the LiquidCrystal library module from Arduino17:
40x4 LCDs
I added support for an LCD of 4 LInes and 40 characters. I think that if 24x4, 32x4
LCDs exist, they would also work with the software as I have modified it although I
have not had the opportunity to test that. The 40x4 LCD (and any HD44780 based
LCD with between 81 and 160 characters) will have 2 enable lines. To use an LCD
with 4 lines and 40 columns you would declare your LiquidCrystal object as:
LiquidCrystal lcd(RS,RW,Enable1,Enable2, data3,data2,data1,data0); at this time I
don't support 8 data lines. (You can pass 255 as the RW item, ground RW and save
an Arduino pin.)
Then in the setup function you would call:
lcd.begin(40,4);
Linewrap
When you declare the dimensions of the LCD in your begin call, the LiquidCrystal
library remembers how long the lines are. Now when it reaches the end of line 1, text
wraps onto line 2 (not line 3 as previously).
println
Although print has worked properly in the past, println has not. Now the ?\r' and ?\n'
characters are not sent to the screen as though they were visible characters and the
?\r' resets the character position to the top of the next line.
16x4 LCDs
The begin statement also correctly positions text at the beginning of the line on 16x4
(and 40x4) LCDs, which were not correctly handled before.
setCursor
In the past setCursor selected a location in the HD44780's RAM not actually a
screen location. If you use any of the commands that shift the display left or right with
the previous routines, then setCursor and print, text appears in an unexpected
location on the screen. With the new software, if you call either scrollDisplayLeft() or
scrollDisplayRight(), the LiquidCrystal package keeps track of the relationship
between RAM and the LCD so that setCursor coordinates are pegged to a specific
spot on the screen, rather than a spot in RAM. The sotware does not handle
autoScroll, however. Call home() after autoScroll to restore the expected relationship
between setCursor and the LCD screen.
Speed testing
All of the interface modes go faster than the eye can follow. I compared the speeds
of the different interfaces--writing 80 characters to the screen then 80 blanks and
looping through that 20 times. The results are:

4 data pins 727 milliseconds
8 data pins 644 milliseconds
The 4 data pin option is significantly faster than the previous LIquidCrystal which
takes 1076 milliseconds because of an unnecessary delay between sending the high
and low data nibbles.
Crazy 8 Addressing
16x1 LCDs often have an unusual address layout; these modules often have two 8
character halves and work best with this software if you declare them as
lcd.begin(8,2); if you do that, then you can print("abcdefghilklmno"); and have all the
characters appear as you would like across the screen. If you use any of the scrolling
commands, the bizarre addressing of these modules will manifest itself. For details
follow the _LCD Addressing_ link at web.alfredstate.edu/weimandn
Disadvantages
The two real disadvantages I can see to the changes I have made are:
1. The code is a little longer than before.
2. The possibility that someone with a little 16x2 LCD is using the scrollDisplayLeft()
or scrollDisplayRight() instructions to move data across the screen, but wants to
write the data 40 characters at a time with a print statement. This version really does
not let the user write data to the HD44780 DDRAM which is not visible. To
accomplish a scrolling display with 40 characters per line, you would now need to
write 16 characters, scroll the display, write a little more and so on.
There are going to be some incompatibilities between code that assumed that line 1
wrapped onto line 3, etc.
Directions for the future
I see little purpose to retaining the 8 pin interface or RW pin options. Even in the
slowest situation output to the LCD goes faster than the eye can follow. The slowest
situation would be using the 40x4 LCD, doing a scrollDisplayLeft() or
scrollDisplayRight() and then printing 160 characters. When the display has been
scrolled, the software actually calls setCursor internally with every character sent to
the LCD, so you would be communicating 480 items to the LCD in that instance. As I
have tested the various interfaces with the various shapes of LCDs, I have reflected
many times on the likelihood that no one else has tried the 8 bit interfaces for some
time. Don Weiman argues that inclusion of both 4 and 8 bit interfaces makes the
code harder to read. I am more motivated by the idea that the 8 bit interface takes up
Arduino RAM and pins but contributes little additional function.
Bug
The one bug I am aware of is that autoscroll() on a 40x4 LCD only scrolls 2 lines
despite my best efforts.

Thanks
Certainly my efforts would not have been possible without the help and prior efforts
of David Mellis, Limor Friede, and Donald Weiman. Don was particularly patient in
guiding me through the idiosyncracies of the HD44780 based LCDs and especially in
supplying an example of how the busy flag could be tested.

  Search 5 million + Products