├── .gitignore ├── README.md ├── i2c_clock.js ├── index.html ├── index.js ├── lcdi2c.js ├── package-lock.json ├── package.json └── test2.js /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | 6 | # Runtime data 7 | pids 8 | *.pid 9 | *.seed 10 | 11 | # Directory for instrumented libs generated by jscoverage/JSCover 12 | lib-cov 13 | 14 | # Coverage directory used by tools like istanbul 15 | coverage 16 | 17 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 18 | .grunt 19 | 20 | # node-waf configuration 21 | .lock-wscript 22 | 23 | # Compiled binary addons (http://nodejs.org/api/addons.html) 24 | build/Release 25 | 26 | # Dependency directories 27 | node_modules 28 | jspm_packages 29 | 30 | # Optional npm cache directory 31 | .npm 32 | 33 | # Optional REPL history 34 | .node_repl_history 35 | 36 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # lcdi2c 2 | 3 | ## Overview 4 | For use on a Raspberry Pi, lcdi2c is a node.js library for accessing LCD character displays using I2C via a PCF8574 port expander, typically found on inexpensive LCD I2C "backpacks." This work is based upon the following repository: 5 | 6 | https://github.com/wilberforce/lcd-pcf8574 7 | 8 | lcdi2c supports 16x2 and 20x4 LCD character displays based on the Hitachi HD44780 LCD controller ( https://en.wikipedia.org/wiki/Hitachi_HD44780_LCD_controller ). lcdi2c uses the i2c-bus library ( https://github.com/fivdi/i2c-bus ) instead of the i2c library since the former supports more recent versions of node (e.g. 4.2.1). 9 | 10 | lcdi2c also provides new functions to facilitate output on a multiline character display based on the Hitachi HD44780 LCD controller. These include: 11 | 12 | println( string, line ): Sends output to a specified line. Automatically truncates output to number of columns specified on startup. 13 | 14 | ## Installation 15 | 16 | ```bash 17 | npm install lcdi2c 18 | 19 | ``` 20 | 21 | 22 | ## Usage 23 | 24 | First, set up I2C on your Raspberry Pi. More information about this can be found here: 25 | 26 | https://learn.adafruit.com/adafruits-raspberry-pi-lesson-4-gpio-setup/configuring-i2c 27 | 28 | Now, check for the address of the LCD on the I2C bus: 29 | 30 | For a rev. 1 board, use the following: 31 | 32 | ```bash 33 | sudo i2cdetect -y 0 34 | 35 | ``` 36 | 37 | For a rev. 2+ board, use the following: 38 | 39 | 40 | ```bash 41 | sudo i2cdetect -y 1 42 | 43 | ``` 44 | 45 | This will print out the devices on the I2C bus, such as: 46 | 47 | 48 | ```bash 49 | root@raspberrypi:/home/pi/lcdi2c# sudo i2cdetect -y 1 50 | 0 1 2 3 4 5 6 7 8 9 a b c d e f 51 | 00: -- -- -- -- -- -- -- -- -- -- -- -- -- 52 | 10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 53 | 20: -- -- -- -- -- -- -- 27 -- -- -- -- -- -- -- -- 54 | 30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 55 | 40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 56 | 50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 57 | 60: -- -- -- -- -- -- -- -- 68 -- -- -- -- -- -- -- 58 | 70: -- -- -- -- -- -- -- -- 59 | 60 | ``` 61 | 62 | Here, we see two devices, 0x27 (our LCD display) and 0x68 (a realtime clock board). So, the device address is 0x27. 63 | 64 | To use lcdi2c, add the following code to your node.js application to set up the lcd object: 65 | 66 | ```bash 67 | var LCD = require('lcdi2c'); 68 | var lcd = new LCD( 1, 0x27, 20, 4 ); 69 | 70 | ``` 71 | 72 | Note that this will set up an I2C LCD panel on I2C bus 1, address 0x27, with 20 columns and 4 rows. 73 | 74 | To print out strings to the LCD panel, see the following code: 75 | 76 | ```bash 77 | lcd.clear(); 78 | lcd.print( 'This is line 1... ' ); 79 | lcd.print( 'This is line 2... ' ); 80 | lcd.print( 'This is line 3... ' ); 81 | lcd.print( 'plThis is line 4... ' ); 82 | ``` 83 | 84 | 85 | To print out a string to the LCD panel using specified line numbers, see the following example code: 86 | 87 | ```bash 88 | lcd.clear(); 89 | lcd.println( 'plThis is line 1...', 1 ); 90 | lcd.println( 'plThis is line 2...', 2 ); 91 | lcd.println( 'plThis is line 3...', 3 ); 92 | lcd.println( 'plThis is line 4...', 4 ); 93 | ``` 94 | 95 | To turn on the backlight: 96 | 97 | ```bash 98 | lcd.on(); 99 | ``` 100 | 101 | To turn off the backlight: 102 | 103 | ```bash 104 | lcd.off(); 105 | ``` 106 | 107 | To create custom characters: 108 | 109 | ```bash 110 | lcd.createChar( 0,[ 0x1B,0x15,0x0E,0x1B,0x15,0x1B,0x15,0x0E] ).createChar( 1,[ 0x0C,0x12,0x12,0x0C,0x00,0x00,0x00,0x00] ); 111 | ``` 112 | 113 | More information about creating such custom characters can be found here: 114 | 115 | http://www.quinapalus.com/hd44780udg.html 116 | 117 | ## Error Checking 118 | 119 | i2clcd checks for errors and implements a simple try/catch method to catch errors sent by the I2C driver. Such errors will occur if the bus has not been set up properly, if the device ID is wrong, or if the device is not operational. To prevent crashes, it is recommended that error checking be implemented in the calling code. 120 | 121 | If an error is encountered, this will be stored in the variable lcd.error. The calling code should test lcd.error is null/false before calling the i2clcd routine again. Failure to check for such errors will result in a crash of the node.js application. 122 | 123 | Example code: 124 | 125 | ```bash 126 | var LCD = require('lcdi2c'); 127 | var lcd = new LCD( 1, 0x27, 20, 4 ); 128 | 129 | lcd.println( 'This is line 1...', 1 ); 130 | if ( lcd.error ) { 131 | lcdErrorHandler( lcd.error ); 132 | } else { 133 | lcd.println( 'This is line 2...', 2 ); 134 | if ( lcd.error ) { 135 | lcdErrorHandler( lcd.error ); 136 | } else { 137 | lcd.println( 'This is line 3...', 3 ); 138 | if ( lcd.error ) { 139 | lcdErrorHandler( lcd.error ); 140 | } else { 141 | lcd.println( 'This is line 4...', 4 ); 142 | if ( lcd.error ) { 143 | lcdErrorHandler( lcd.error ); 144 | }; 145 | }; 146 | }; 147 | }; 148 | 149 | function lcdErrorHandler( err ) { 150 | console.log( 'Unable to print to LCD display on bus 1 at address 0x27' ); 151 | //Disable further processing if application calls this recursively. 152 | }; 153 | 154 | ``` 155 | 156 | This code is rather ugly, but it will prevent any calls to the underlying I2C driver from causing a program crash if the I2C bus or LCD display is not configured properly, or if the LCD is not plugged in. This recursive error checking will prevent the application from crashing even if the LCD device is unplugged during application processing. 157 | 158 | A sample application called i2c_clock is provided in this library (and can be found in ../node_modules/lcdi2c) that provides an example of such error checking. 159 | 160 | -------------------------------------------------------------------------------- /i2c_clock.js: -------------------------------------------------------------------------------- 1 | //i2c_clock.js - Tests i2c lcd display clock function. Uses 20x4 LCD character display 2 | // over I2C bus 1 using PCF8574-based LCD "backpack" with device address 0x27. 3 | 4 | var LCD = require('./lcdi2c.js'); 5 | var sleep = require('sleep'); 6 | 7 | 8 | var lcd = new LCD( 1, 0x27, 20, 4 ); 9 | 10 | var now = 0; 11 | lcd.on(); 12 | //lcd.setBacklight(1); 13 | lcd.clear(); 14 | lcd.home(); 15 | 16 | 17 | 18 | var int1 = setInterval( function() { 19 | now = new Date(); 20 | var time1 = now.toTimeString(); 21 | var date1 = now.toDateString(); 22 | 23 | //Print and check for errors. If errors found, shut down gently. 24 | lcd.println( date1, 1 ); 25 | if ( lcd.error ) { 26 | lcdError( lcd.error ); 27 | } else { 28 | lcd.println( time1, 2 ); 29 | if ( lcd.error ) { 30 | lcdError( lcd.error ); 31 | }; 32 | }; 33 | }, 500 ); 34 | lcd.off; 35 | 36 | function lcdError( err ) { 37 | clearInterval( int1 ); 38 | console.log( 'Unable to print to LCD on bus 1 at address 0x27. Error: ' + JSON.stringify( err ) ); 39 | 40 | }; -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | module.exports = require('./lcdi2c.js'); -------------------------------------------------------------------------------- /lcdi2c.js: -------------------------------------------------------------------------------- 1 | /** 2 | * lcdi2c.js - Add I2C LCD character display using PCF8574 I2C port expander. 3 | * https://github.com/wilberforce/lcd-pcf8574 but replaced calls to i2c library with 4 | * calls to i2c-bus. Currently, only works in synchronous output mode. Asynch mode does not work. 5 | * LCD i2c interface via PCF8574P 6 | * http://dx.com/p/lcd1602-adapter-board-w-iic-i2c-interface-black-works-with-official-arduino-boards-216865 7 | 8 | * https://gist.github.com/chrisnew/6725633 9 | * http://www.espruino.com/HD44780 10 | * http://www.espruino.com/LCD1602 11 | */ 12 | const i2c = require('i2c-bus'); 13 | const sleep = require('sleep'); 14 | 15 | let LCD = class LCD { 16 | constructor(device, address, cols, rows) { 17 | this.displayPorts = { 18 | RS: 0x01, 19 | E: 0x04, 20 | D4: 0x10, 21 | D5: 0x20, 22 | D6: 0x40, 23 | D7: 0x80, 24 | 25 | CHR: 1, 26 | CMD: 0, 27 | 28 | backlight: 0x08, 29 | RW: 0x20 // not used 30 | }; 31 | 32 | // <<<<<<< alexfederlin-patch-1 33 | var buffer = new Buffer(3); //Required for printlnBuffer. 34 | 35 | //LCD() - Initialize LCD object. 36 | // device: I2C bus number; 0 for rev. 1 boards, 1 for rev. 2+ boards. 37 | // address: Address of device (use i2cdetect to determine this) 38 | // cols: columns supported by display (e.g. 16 or 20) 39 | // rows: rows supported by display (e.g. 2 or 4 ) 40 | var LCD = function (device, address, cols, rows ) { 41 | //this.i2c = new i2c(address, { 42 | // device : device 43 | // }); 44 | this.device = device; 45 | this.address = address; 46 | this.cols = cols; 47 | this.rows = rows; 48 | this.error = null; 49 | this.i2c = i2c.open( device, function( err ) { 50 | if ( err ) { 51 | console.log( 'Unable to open I2C port on device ' + device + ' ERROR: ' + err ); 52 | console.log( this ); 53 | this.error = err; 54 | return this 55 | }; 56 | }); 57 | //console.log( 'Opened I2C port on bus ' + device + ' for LCD at address 0x' + address.toString( 16 ) + '.' ); 58 | this._sleep(1000); 59 | 60 | this.init(); 61 | 62 | return this; 63 | }; 64 | 65 | // commands 66 | LCD.CLEARDISPLAY = 0x01; 67 | LCD.RETURNHOME = 0x02; 68 | LCD.ENTRYMODESET = 0x04; 69 | LCD.DISPLAYCONTROL = 0x08; 70 | LCD.CURSORSHIFT = 0x10; 71 | LCD.FUNCTIONSET = 0x20; 72 | LCD.SETCGRAMADDR = 0x40; 73 | LCD.SETDDRAMADDR = 0x80; 74 | 75 | //# flags for display entry mode 76 | LCD.ENTRYRIGHT = 0x00; 77 | LCD.ENTRYLEFT = 0x02; 78 | LCD.ENTRYSHIFTINCREMENT = 0x01; 79 | LCD.ENTRYSHIFTDECREMENT = 0x00; 80 | 81 | //# flags for display on/off control 82 | LCD.DISPLAYON = 0x04; 83 | LCD.DISPLAYOFF = 0x00; 84 | LCD.CURSORON = 0x02; 85 | LCD.CURSOROFF = 0x00; 86 | LCD.BLINKON = 0x01; 87 | LCD.BLINKOFF = 0x00; 88 | 89 | //# flags for display/cursor shift 90 | LCD.DISPLAYMOVE = 0x08; 91 | LCD.CURSORMOVE = 0x00; 92 | LCD.MOVERIGHT = 0x04; 93 | LCD.MOVELEFT = 0x00; 94 | 95 | //# flags for function set 96 | LCD._8BITMODE = 0x10; 97 | LCD._4BITMODE = 0x00; 98 | LCD._2LINE = 0x08; 99 | LCD._1LINE = 0x00; 100 | LCD._5x10DOTS = 0x04; 101 | LCD._5x8DOTS = 0x00; 102 | 103 | //Line addresses. 104 | LCD.LINEADDRESS = []; 105 | LCD.LINEADDRESS[1] = 0x80; 106 | LCD.LINEADDRESS[2] = 0xC0; 107 | LCD.LINEADDRESS[3] = 0x94; 108 | LCD.LINEADDRESS[4] = 0xD4; 109 | 110 | LCD.prototype.init = function (){ 111 | this.write4( 0x33, displayPorts.CMD); //initialization 112 | this._sleep(200); 113 | this.write4(0x32, displayPorts.CMD); //initialization 114 | this._sleep(100); 115 | this.write4( 0x06, displayPorts.CMD); //initialization 116 | this._sleep(100); 117 | this.write4( 0x28, displayPorts.CMD); //initialization 118 | this._sleep(100); 119 | this.write4( 0x01, displayPorts.CMD); //initialization 120 | this._sleep(100); 121 | 122 | 123 | this.write4(LCD.FUNCTIONSET | LCD._4BITMODE | LCD._2LINE | LCD._5x10DOTS, displayPorts.CMD); //4 bit - 2 line 5x7 matrix 124 | 125 | this._sleep(10); 126 | this.write( LCD.DISPLAYCONTROL | LCD.DISPLAYON, displayPorts.CMD); //turn cursor off 0x0E to enable cursor 127 | this._sleep(10); 128 | this.write( LCD.ENTRYMODESET | LCD.ENTRYLEFT, displayPorts.CMD); //shift cursor right 129 | this._sleep(10); 130 | this.write( LCD.CLEARDISPLAY, displayPorts.CMD); // LCD clear 131 | this.write( displayPorts.backlight, displayPorts.CHR ); //Turn on backlight. 132 | } 133 | 134 | LCD.prototype._sleep = function (milli) { 135 | sleep.usleep(milli * 1000); 136 | }; 137 | // ======= 138 | this.buffer = new Buffer(3); //Required for printlnBuffer. 139 | 140 | // commands 141 | this.CLEARDISPLAY = 0x01; 142 | this.RETURNHOME = 0x02; 143 | this.ENTRYMODESET = 0x04; 144 | this.DISPLAYCONTROL = 0x08; 145 | this.CURSORSHIFT = 0x10; 146 | this.FUNCTIONSET = 0x20; 147 | this.SETCGRAMADDR = 0x40; 148 | this.SETDDRAMADDR = 0x80; 149 | 150 | //# flags for display entry mode 151 | this.ENTRYRIGHT = 0x00; 152 | this.ENTRYLEFT = 0x02; 153 | this.ENTRYSHIFTINCREMENT = 0x01; 154 | this.ENTRYSHIFTDECREMENT = 0x00; 155 | 156 | //# flags for display on/off control 157 | this.DISPLAYON = 0x04; 158 | this.DISPLAYOFF = 0x00; 159 | this.CURSORON = 0x02; 160 | this.CURSOROFF = 0x00; 161 | this.BLINKON = 0x01; 162 | this.BLINKOFF = 0x00; 163 | 164 | //# flags for display/cursor shift 165 | this.DISPLAYMOVE = 0x08; 166 | this.CURSORMOVE = 0x00; 167 | this.MOVERIGHT = 0x04; 168 | this.MOVELEFT = 0x00; 169 | 170 | //# flags for function set 171 | this._8BITMODE = 0x10; 172 | this._4BITMODE = 0x00; 173 | this._2LINE = 0x08; 174 | this._1LINE = 0x00; 175 | this._5x10DOTS = 0x04; 176 | this._5x8DOTS = 0x00; 177 | 178 | //Line addresses. 179 | this.LINEADDRESS = [0x80, 0xC0, 0x94, 0xD4]; 180 | 181 | this.device = device; 182 | this.address = address; 183 | this.cols = cols; 184 | this.rows = rows; 185 | this.error = null; 186 | this.i2c = null; 187 | 188 | this._init(); 189 | }; 190 | 191 | _init() { 192 | this.i2c = i2c.open(this.device, function (err) { 193 | if (err) { 194 | console.log('Unable to open I2C port on device ' + device + ' ERROR: ' + err); 195 | console.log(this); 196 | this.error = err; 197 | return this 198 | } 199 | }); 200 | 201 | this._sleep(1000); 202 | 203 | this.write4(0x33, this.displayPorts.CMD); //initialization 204 | this._sleep(200); 205 | this.write4(0x32, this.displayPorts.CMD); //initialization 206 | this._sleep(100); 207 | this.write4(0x06, this.displayPorts.CMD); //initialization 208 | this._sleep(100); 209 | this.write4(0x28, this.displayPorts.CMD); //initialization 210 | this._sleep(100); 211 | this.write4(0x01, this.displayPorts.CMD); //initialization 212 | this._sleep(100); 213 | 214 | this.write4(this.FUNCTIONSET | this._4BITMODE | this._2LINE | this._5x10DOTS, this.displayPorts.CMD); //4 bit - 2 line 5x7 matrix 215 | 216 | this._sleep(10); 217 | this.write(this.DISPLAYCONTROL | this.DISPLAYON, this.displayPorts.CMD); //turn cursor off 0x0E to enable cursor 218 | this._sleep(10); 219 | this.write(this.ENTRYMODESET | this.ENTRYLEFT, this.displayPorts.CMD); //shift cursor right 220 | this._sleep(10); 221 | this.write(this.CLEARDISPLAY, this.displayPorts.CMD); // LCD clear 222 | this.write(this.displayPorts.backlight, this.displayPorts.CHR); //Turn on backlight. 223 | 224 | return this; 225 | }; 226 | // >>>>>>> master 227 | 228 | _sleep(milli) { 229 | sleep.usleep(milli * 1000); 230 | }; 231 | 232 | write4(x, c) { 233 | try { 234 | let a = (x & 0xF0); // Use upper 4 bit nibble 235 | this.i2c.sendByteSync(this.address, a | this.displayPorts.backlight | c); 236 | this.i2c.sendByteSync(this.address, a | this.displayPorts.E | this.displayPorts.backlight | c); 237 | this.i2c.sendByteSync(this.address, a | this.displayPorts.backlight | c); 238 | } catch (err) { 239 | this.error = err; 240 | } 241 | this._sleep(2); 242 | }; 243 | 244 | write4Async(x, c) { 245 | let a = (x & 0xF0); // Use upper 4 bit nibble 246 | this.i2c.sendByte(this.address, a | this.displayPorts.backlight | c, (err) => { 247 | if (err) { 248 | this.error = err; 249 | } 250 | }); 251 | this.i2c.sendByte(this.address, a | this.displayPorts.E | this.displayPorts.backlight | c, (err) => { 252 | if (err) { 253 | this.error = err; 254 | } 255 | }); 256 | this.i2c.sendByte(this.address, a | this.displayPorts.backlight | c, (err) => { 257 | if (err) { 258 | this.error = err; 259 | } 260 | }); 261 | 262 | //Had to add this as it fixes a weird bug where the display was showing garbled text after a few minutes 263 | //Found this solution by accident though... 264 | this.i2c.sendByte(this.address, a | this.displayPorts.backlight | c, (err) => { 265 | if (err) { 266 | this.error = err; 267 | } 268 | }); 269 | }; 270 | 271 | write4Block(x, c) { 272 | let a = (x & 0xF0 ); 273 | this.buffer[0] = a | this.displayPorts.backlight | c; 274 | this.buffer[1] = a | this.displayPorts.E | this.displayPorts.backlight | c; 275 | this.buffer[2] = a | this.displayPorts.backlight | c; 276 | 277 | this.i2c.writeI2cBlockSync(this.address, 1, this.buffer.length, this.buffer); 278 | this._sleep(2); 279 | }; 280 | 281 | write(x, c) { 282 | this.write4(x, c); 283 | this.write4(x << 4, c); 284 | return this; 285 | }; 286 | 287 | writeAsync(x, c) { 288 | this.write4Async(x, c); 289 | this.write4Async(x << 4, c); 290 | return this; 291 | }; 292 | 293 | // <<<<<<< alexfederlin-patch-1 294 | //Set cursor to correct line. 295 | if ( line > 0 && line <= this.rows ) { 296 | this.write( LCD.LINEADDRESS[line], displayPorts.CMD ); 297 | this._sleep(2); 298 | }; 299 | // ======= 300 | writeBlock(x, c) { 301 | this.write4Block(x, c); 302 | this.write4Block(x << 4, c); 303 | return this; 304 | }; 305 | //>>>>>>> master 306 | 307 | clear() { 308 | return this.write(this.CLEARDISPLAY, this.displayPorts.CMD); 309 | }; 310 | 311 | print(str) { 312 | if (typeof str === 'string') { 313 | for (let i = 0; i < str.length; i++) { 314 | let c = str[i].charCodeAt(0); 315 | this.write(c, this.displayPorts.CHR); 316 | this._sleep(2); 317 | } 318 | } 319 | return this; 320 | }; 321 | 322 | printAsync(str) { 323 | if (typeof str === 'string') { 324 | for (let i = 0; i < str.length; i++) { 325 | let c = str[i].charCodeAt(0); 326 | this.writeAsync(c, this.displayPorts.CHR); 327 | //this._sleep(2); 328 | } 329 | } 330 | return this; 331 | }; 332 | 333 | printBlock(str) { 334 | if (typeof str === 'string') { 335 | for (let i = 0; i < str.length; i++) { 336 | let c = str[i].charCodeAt(0); 337 | this.writeBlock(c, this.displayPorts.CHR); 338 | this._sleep(2); 339 | } 340 | } 341 | }; 342 | 343 | println(str, line) { 344 | if (typeof str === 'string') { 345 | //Set cursor to correct line. 346 | if (line > 0 && line <= this.rows) { 347 | this.write(this.LINEADDRESS[line - 1], this.displayPorts.CMD); 348 | } 349 | this.print(str.substring(0, this.cols)); 350 | } 351 | return this; 352 | }; 353 | 354 | printlnAsync(str, line) { 355 | if (typeof str === 'string') { 356 | //Set cursor to correct line. 357 | if (line > 0 && line <= this.rows) { 358 | this.writeAsync(this.LINEADDRESS[line - 1], this.displayPorts.CMD); 359 | } 360 | this.printAsync(str.substring(0, this.cols)); 361 | } 362 | return this; 363 | 364 | }; 365 | 366 | printlnBlock(str, line) { 367 | if (typeof str === 'string') { 368 | if (line > 0) { 369 | this.write(this.LINEADDRESS[line - 1], this.displayPorts.CMD); 370 | } 371 | 372 | //Now, write block to i2c. 373 | this.printBlock(str.substring(0, this.cols)); 374 | } 375 | return this; 376 | }; 377 | 378 | /** flashing block for the current cursor */ 379 | cursorFull() { 380 | return this.write(this.DISPLAYCONTROL | this.DISPLAYON | this.CURSORON | this.BLINKON, this.displayPorts.CMD); 381 | }; 382 | 383 | /** small line under the current cursor */ 384 | cursorUnder() { 385 | return this.write(this.DISPLAYCONTROL | this.DISPLAYON | this.CURSORON | this.BLINKOFF, this.displayPorts.CMD); 386 | } 387 | 388 | /** set cursor pos, top left = 0,0 */ 389 | setCursor(x, y) { 390 | let l = [0x00, 0x40, 0x14, 0x54]; 391 | return this.write(this.SETDDRAMADDR | (l[y] + x), this.displayPorts.CMD); 392 | } 393 | 394 | /** set cursor to 0,0 */ 395 | home() { 396 | return this.write(this.SETDDRAMADDR | 0x00, this.displayPorts.CMD); 397 | } 398 | 399 | /** Turn underline cursor off */ 400 | blinkOff() { 401 | return this.write(this.DISPLAYCONTROL | this.DISPLAYON | this.CURSOROFF | this.BLINKOFF, this.displayPorts.CMD); 402 | } 403 | 404 | /** Turn underline cursor on */ 405 | blinkOn() { 406 | return this.write(this.DISPLAYCONTROL | this.DISPLAYON | this.CURSORON | this.BLINKOFF, this.displayPorts.CMD); 407 | } 408 | 409 | /** Turn block cursor off */ 410 | cursorOff() { 411 | return this.write(this.DISPLAYCONTROL | this.DISPLAYON | this.CURSOROFF | this.BLINKON, this.displayPorts.CMD); 412 | } 413 | 414 | /** Turn block cursor on */ 415 | cursorOn() { 416 | return this.write(this.DISPLAYCONTROL | this.DISPLAYON | this.CURSORON | this.BLINKON, this.displayPorts.CMD); 417 | } 418 | 419 | /** setBacklight */ 420 | setBacklight(val) { 421 | if (val > 0) { 422 | this.displayPorts.backlight = 0x08; 423 | } else { 424 | this.displayPorts.backlight = 0x00; 425 | } 426 | return this.write(this.DISPLAYCONTROL, this.displayPorts.CMD); 427 | } 428 | 429 | /** setContrast stub */ 430 | // setContrast(val) { 431 | // return this.write(this.DISPLAYCONTROL, this.displayPorts.CMD); 432 | // } 433 | /** Turn display off */ 434 | off() { 435 | this.displayPorts.backlight = 0x00; 436 | return this.write(this.DISPLAYCONTROL | this.DISPLAYOFF, this.displayPorts.CMD); 437 | } 438 | 439 | /** Turn display on */ 440 | on() { 441 | this.displayPorts.backlight = 0x08; 442 | return this.write(this.DISPLAYCONTROL | this.DISPLAYON, this.displayPorts.CMD); 443 | } 444 | 445 | /** set special character 0..7, data is an array(8) of bytes, and then return to home addr */ 446 | createChar(ch, data) { 447 | this.write(this.SETCGRAMADDR | ((ch & 7) << 3), this.displayPorts.CMD); 448 | for (let i = 0; i < 8; i++) 449 | this.write(data[i], this.displayPorts.CHR); 450 | return this.write(this.SETDDRAMADDR, this.displayPorts.CMD); 451 | } 452 | }; 453 | 454 | module.exports = LCD; 455 | -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "lcdi2c", 3 | "version": "1.0.6", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "bindings": { 8 | "version": "1.5.0", 9 | "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", 10 | "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", 11 | "requires": { 12 | "file-uri-to-path": "1.0.0" 13 | } 14 | }, 15 | "file-uri-to-path": { 16 | "version": "1.0.0", 17 | "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", 18 | "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==" 19 | }, 20 | "i2c-bus": { 21 | "version": "5.1.0", 22 | "resolved": "https://registry.npmjs.org/i2c-bus/-/i2c-bus-5.1.0.tgz", 23 | "integrity": "sha512-u/q1fuZ5xrG77y3uo1rAANycboXsRNjneN+6jXRNMT2yRNpanVkbAP+IArwgsPRCHaY/zKxw7x5G8Y2fSPNseA==", 24 | "requires": { 25 | "bindings": "^1.5.0", 26 | "nan": "^2.14.0" 27 | } 28 | }, 29 | "nan": { 30 | "version": "2.14.0", 31 | "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.0.tgz", 32 | "integrity": "sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg==" 33 | }, 34 | "sleep": { 35 | "version": "6.1.0", 36 | "resolved": "https://registry.npmjs.org/sleep/-/sleep-6.1.0.tgz", 37 | "integrity": "sha512-Z1x4JjJxsru75Tqn8F4tnOFeEu3HjtITTsumYUiuz54sGKdISgLCek9AUlXlVVrkhltRFhNUsJDJE76SFHTDIQ==", 38 | "requires": { 39 | "nan": "^2.13.2" 40 | }, 41 | "dependencies": { 42 | "nan": { 43 | "version": "2.14.0", 44 | "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.0.tgz", 45 | "integrity": "sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg==" 46 | } 47 | } 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "lcdi2c", 3 | "version": "1.0.6", 4 | "description": "I2C LCD character display driver for Raspberry Pi using PCF8574 port expander.", 5 | "main": "index.js", 6 | "dependencies": { 7 | "i2c-bus": "^5.1.0", 8 | "sleep": "^6.1.0" 9 | }, 10 | "devDependencies": {}, 11 | "scripts": { 12 | "test": "echo \"Error: no test specified\" && exit 1" 13 | }, 14 | "repository": { 15 | "type": "git", 16 | "url": "git+https://github.com/craigmw/lcdi2c.git" 17 | }, 18 | "keywords": [ 19 | "LCD", 20 | "I2C", 21 | "Raspberry", 22 | "Pi", 23 | "PCF8574", 24 | "i2c-bus" 25 | ], 26 | "author": "craigmw", 27 | "license": "ISC", 28 | "bugs": { 29 | "url": "https://github.com/craigmw/lcdi2c/issues" 30 | }, 31 | "homepage": "https://github.com/craigmw/lcdi2c#readme" 32 | } 33 | -------------------------------------------------------------------------------- /test2.js: -------------------------------------------------------------------------------- 1 | //test2.js - Test lcdi2c.js using a 20x4 LCD display over i2c bus 1 (device 0x27). 2 | 3 | var LCD = require('./lcdi2c.js'); 4 | var sleep = require('sleep'); 5 | 6 | 7 | var lcd = new LCD( 1, 0x27, 20, 4 ); 8 | 9 | lcd.createChar( 0,[ 0x1B,0x15,0x0E,0x1B,0x15,0x1B,0x15,0x0E] ).createChar( 1,[ 0x0C,0x12,0x12,0x0C,0x00,0x00,0x00,0x00] ); 10 | 11 | //Turning on LCD. 12 | //lcd.on(); 13 | //_sleep(200); 14 | 15 | var toggle = false; 16 | var count = 0; 17 | var intV = setInterval( function() { 18 | if (count > 10 ) { 19 | clearInterval( intV ); 20 | }; 21 | if (toggle ) { 22 | toggle = false; 23 | lcd.on(); 24 | } else { 25 | toggle = true; 26 | lcd.off(); 27 | }; 28 | //lcd.print('1'); 29 | count++; 30 | }, 500 ); 31 | 32 | _sleep(1000); 33 | 34 | //Printing 35 | console.log( 'Printing on LCD...'); 36 | lcd.home(); 37 | _sleep( 200 ); 38 | lcd.print( 'This is line 1'); 39 | //lcd.print('Raspberry Pi ').setCursor(0,1).cursorUnder(); 40 | 41 | function _sleep( milli ) { 42 | sleep.usleep(milli * 1000); 43 | }; 44 | 45 | for (i=0; i < 80; i++ ) { 46 | lcd.print('X'); 47 | //console.log( i ); 48 | }; 49 | 50 | //Try print function. 51 | for (var i = 0; i < 10; i++ ) { 52 | lcd.clear(); 53 | lcd.print( '01234567890123456789' ); 54 | lcd.print( 'p This is line 2....' ); 55 | lcd.print( 'p This is line 3....' ); 56 | lcd.print( 'p This is line 4....' ); 57 | }; 58 | 59 | //Now, try println function. 60 | for (var i = 0; i < 10; i++ ) { 61 | lcd.clear(); 62 | lcd.println( '01234567890123456789', 1 ); 63 | lcd.println( 'plThis is line 2...', 2 ); 64 | lcd.println( 'plThis is line 3...', 3 ); 65 | lcd.println( 'plThis is line 4...', 4 ); 66 | }; 67 | 68 | //Now, try printlnBlock function. 69 | for (var i = 0; i < 10; i++ ) { 70 | lcd.clear(); 71 | lcd.printlnBlock( '01234567890123456789', 1 ); 72 | lcd.printlnBlock( 'plbThis is line 2...', 2 ); 73 | lcd.printlnBlock( 'plbThis is line 3...', 3 ); 74 | lcd.printlnBlock( 'plbThis is line 4...', 4 ); 75 | }; 76 | 77 | 78 | _sleep( 2000 ); 79 | lcd.off(); --------------------------------------------------------------------------------