UNPKG

pxt-common-packages

Version:
317 lines (285 loc) 11.4 kB
namespace lcd { //% shim=lcd::__write8 function __write8(value: number, char_mode: boolean): void { } // Commands const _LCD_CLEARDISPLAY = 0x01 const _LCD_RETURNHOME = 0x02 const _LCD_ENTRYMODESET = 0x04 const _LCD_DISPLAYCONTROL = 0x08 const _LCD_CURSORSHIFT = 0x10 const _LCD_FUNCTIONSET = 0x20 const _LCD_SETCGRAMADDR = 0x40 const _LCD_SETDDRAMADDR = 0x80 // Entry flags const _LCD_ENTRYLEFT = 0x02 const _LCD_ENTRYSHIFTDECREMENT = 0x00 // Control flags const _LCD_DISPLAYON = 0x04 const _LCD_CURSORON = 0x02 const _LCD_CURSOROFF = 0x00 const _LCD_BLINKON = 0x01 const _LCD_BLINKOFF = 0x00 // Move flags const _LCD_DISPLAYMOVE = 0x08 const _LCD_MOVERIGHT = 0x04 const _LCD_MOVELEFT = 0x00 // Function set flags const _LCD_4BITMODE = 0x00 const _LCD_2LINE = 0x08 const _LCD_1LINE = 0x00 const _LCD_5X8DOTS = 0x00 // Offset for up to 4 rows. const _LCD_ROW_OFFSETS = [0x00, 0x40, 0x14, 0x54] export class CharacterLCD { columns: number lines: number reset: DigitalInOutPin; enable: DigitalInOutPin; dl4: DigitalInOutPin; dl5: DigitalInOutPin; dl6: DigitalInOutPin; dl7: DigitalInOutPin; displaycontrol: number displayfunction: number displaymode: number _message: string; _enable: boolean; _rtl: boolean; // pylint: disable-msg=too-many-arguments constructor(rs: DigitalInOutPin, en: DigitalInOutPin, d4: DigitalInOutPin, d5: DigitalInOutPin, d6: DigitalInOutPin, d7: DigitalInOutPin, columns: number, lines: number) { this._rtl = false; this.columns = columns; this.lines = lines; // save pin numbers this.reset = rs; this.enable = en; this.dl4 = d4; this.dl5 = d5; this.dl6 = d6; this.dl7 = d7; // set all pins as outputs for (const pin of [rs, en, d4, d5, d6, d7]) { pin.digitalWrite(false); } // Initialise the display this._write8(0x33) this._write8(0x32) // Initialise display control this.displaycontrol = _LCD_DISPLAYON | _LCD_CURSOROFF | _LCD_BLINKOFF // Initialise display function this.displayfunction = _LCD_4BITMODE | _LCD_1LINE | _LCD_2LINE | _LCD_5X8DOTS // Initialise display mode this.displaymode = _LCD_ENTRYLEFT | _LCD_ENTRYSHIFTDECREMENT // Write to displaycontrol this._write8(_LCD_DISPLAYCONTROL | this.displaycontrol) // Write to displayfunction this._write8(_LCD_FUNCTIONSET | this.displayfunction) // Set entry mode this._write8(_LCD_ENTRYMODESET | this.displaymode) this.clear() this._message = "" this._enable = null } /** * Moves the cursor "home" to position (1, 1). **/ public home(): void { this._write8(_LCD_RETURNHOME) pause(3) } /** Clears everything displayed on the LCD. * The following example displays, "Hello, world!", then clears the LCD. **/ public clear(): void { this._write8(_LCD_CLEARDISPLAY) this._message = ""; pause(3) } /** * True if cursor is visible. False to stop displaying the cursor. */ get cursor(): boolean { return (this.displaycontrol & _LCD_CURSORON) == _LCD_CURSORON; } set cursor(show: boolean) { const dc = this.displaycontrol; if (show) this.displaycontrol |= _LCD_CURSORON else this.displaycontrol &= ~_LCD_CURSORON if (dc != this.displaycontrol) this._write8(_LCD_DISPLAYCONTROL | this.displaycontrol) } /** * Move the cursor to position ``column``, ``row`` **/ public setCursorPosition(column: number, row: number): void { column = Math.max(0, Math.min(this.columns - 1, column | 0)); row = Math.max(0, Math.min(this.lines - 1, row | 0)); //console.log(`cursor ${_LCD_SETDDRAMADDR | column + _LCD_ROW_OFFSETS[row]}`) this._write8(_LCD_SETDDRAMADDR | column + _LCD_ROW_OFFSETS[row]) } /** * Blink the cursor. True to blink the cursor. False to stop blinking. */ get blink(): boolean { return (this.displaycontrol & _LCD_BLINKON) == _LCD_BLINKON } set blink(value: boolean) { const dc = this.displaycontrol; if (value) this.displaycontrol |= _LCD_BLINKON else this.displaycontrol &= ~_LCD_BLINKON if (dc != this.displaycontrol) this._write8(_LCD_DISPLAYCONTROL | this.displaycontrol) } /** * Enable or disable the display. True to enable the display. False to disable the display. */ get display(): boolean { return (this.displaycontrol & _LCD_DISPLAYON) == _LCD_DISPLAYON } set display(enable: boolean) { const dc = this.displaycontrol; if (enable) this.displaycontrol |= _LCD_DISPLAYON else this.displaycontrol &= ~_LCD_DISPLAYON if (dc != this.displaycontrol) this._write8(_LCD_DISPLAYCONTROL | this.displaycontrol) } /** * Display a string of text on the character LCD. */ get message(): string { return this._message } set message(message: string) { if (message === undefined || message === null) message = ""; if (this._message === message) return; // nothing to do here const oldMessage = this._message; this._message = message; //console.log(`'${oldMessage}' => '${message}'`); const ltr = !!(this.displaymode & _LCD_ENTRYLEFT); const oldLines = oldMessage.split('\n'); const lines = this._message.split('\n'); const rn = Math.min(this.lines, Math.max(oldLines.length, lines.length)); let cursorrow = -1; let cursorcol = -1; for (let row = 0; row < rn; ++row) { let oldLine = oldLines[row]; if (oldLine === undefined) oldLine = ""; let line = lines[row]; if (line === undefined) line = ""; const cn = Math.min(this.columns, Math.max(oldLine.length, line.length)); for (let column = 0; column < cn; ++column) { const oc = oldLine.charCodeAt(column); const c = line.charCodeAt(column); if (oc !== c) { // letter is already shown, skip // move cursor if needed if (row != cursorrow || column != cursorcol) { //console.log(`set cursor pos ${column}, ${row}`); this.setCursorPosition(ltr ? column : this.columns - 1 - column, row); cursorrow = row; cursorcol = column; } //console.log(`write ${String.fromCharCode(c)} (${String.fromCharCode(oc)}) at ${cursorcol}, ${cursorrow}`); if (column >= line.length) this._write8(32 /* space */, true); else this._write8(c, true); cursorcol++; } } } } /** * Moves displayed text left one column. **/ public moveLeft(): void { this._write8(_LCD_CURSORSHIFT | _LCD_DISPLAYMOVE | _LCD_MOVELEFT) } /** * Moves displayed text right one column. **/ public moveRight(): void { this._write8(_LCD_CURSORSHIFT | _LCD_DISPLAYMOVE | _LCD_MOVERIGHT) } get rightToLeft(): boolean { return this._rtl; } set rightToLeft(direction: boolean) { if (this._rtl != direction) { this._rtl = direction; if (this._rtl) this._right_to_left(); else this._left_to_right(); } } private _left_to_right(): void { // Displays text from left to right on the LCD. this.displaymode |= _LCD_ENTRYLEFT this._write8(_LCD_ENTRYMODESET | this.displaymode) } private _right_to_left(): void { // Displays text from right to left on the LCD. this.displaymode &= ~_LCD_ENTRYLEFT this._write8(_LCD_ENTRYMODESET | this.displaymode) } /** * Fill one of the first 8 CGRAM locations with custom characters. * The location parameter should be between 0 and 7 and pattern should * provide an array of 8 bytes containing the pattern. E.g. you can easily * design your custom character at http://www.quinapalus.com/hd44780udg.html * To show your custom character use, for example, ``lcd.message = ""`` */ public create_char(location: number, pattern: Buffer): void { // only position 0..7 are allowed location &= 0x7 this._write8(_LCD_SETCGRAMADDR | location << 3) for (let i = 0; i < 8; ++i) { this._write8(pattern[i], true) } } /** * Sends 8b ``value`` in ``char_mode``. * @param value bytes * @param char_mode character/data mode selector. False (default) for data only, True for character bits. */ private _write8(value: number, char_mode = false): void { __write8(value, char_mode); // one ms delay to prevent writing too quickly. pause(1) // set character/data bit. (charmode = False) this.reset.digitalWrite(char_mode) // WRITE upper 4 bits this.dl4.digitalWrite(!!(value >> 4 & 1)); this.dl5.digitalWrite(!!(value >> 5 & 1)); this.dl6.digitalWrite(!!(value >> 6 & 1)); this.dl7.digitalWrite(!!(value >> 7 & 1)); // send command this._pulse_enable() // WRITE lower 4 bits this.dl4.digitalWrite(!!(value & 1)); this.dl5.digitalWrite(!!(value >> 1 & 1)); this.dl6.digitalWrite(!!(value >> 2 & 1)); this.dl7.digitalWrite(!!(value >> 3 & 1)); this._pulse_enable() } private _pulse_enable(): void { // Pulses (lo->hi->lo) to send commands. this.enable.digitalWrite(false); control.waitMicros(1); this.enable.digitalWrite(true); control.waitMicros(1); this.enable.digitalWrite(false); control.waitMicros(1); } } }