Updated for more display types. Fixed memoryaddress confusion in address() method. Added new getAddress() method. Added support for UDCs, Backlight control and other features such as control through I2C and SPI port expanders and controllers with native I2C and SPI interfaces. Refactored to fix issue with pins that are default declared as NC.

Dependents:   GPSDevice TestTextLCD SD to Flash Data Transfer DrumMachine ... more

Fork of TextLCD by Simon Ford

Example

Hello World! for the TextLCD

#include "mbed.h"
#include "TextLCD.h"
 
// Host PC Communication channels
Serial pc(USBTX, USBRX); // tx, rx
 
// I2C Communication
I2C i2c_lcd(p28,p27); // SDA, SCL
 
// SPI Communication
SPI spi_lcd(p5, NC, p7); // MOSI, MISO, SCLK

//TextLCD lcd(p15, p16, p17, p18, p19, p20);                // RS, E, D4-D7, LCDType=LCD16x2, BL=NC, E2=NC, LCDTCtrl=HD44780
//TextLCD_SPI lcd(&spi_lcd, p8, TextLCD::LCD40x4);   // SPI bus, 74595 expander, CS pin, LCD Type  
TextLCD_I2C lcd(&i2c_lcd, 0x42, TextLCD::LCD20x4);  // I2C bus, PCF8574 Slaveaddress, LCD Type
//TextLCD_I2C lcd(&i2c_lcd, 0x42, TextLCD::LCD16x2, TextLCD::WS0010); // I2C bus, PCF8574 Slaveaddress, LCD Type, Device Type
//TextLCD_SPI_N lcd(&spi_lcd, p8, p9);               // SPI bus, CS pin, RS pin, LCDType=LCD16x2, BL=NC, LCDTCtrl=ST7032_3V3   
//TextLCD_I2C_N lcd(&i2c_lcd, ST7032_SA, TextLCD::LCD16x2, NC, TextLCD::ST7032_3V3); // I2C bus, Slaveaddress, LCD Type, BL=NC, LCDTCtrl=ST7032_3V3  

int main() {
    pc.printf("LCD Test. Columns=%d, Rows=%d\n\r", lcd.columns(), lcd.rows());
    
    for (int row=0; row<lcd.rows(); row++) {
      int col=0;
      
      pc.printf("MemAddr(Col=%d, Row=%d)=0x%02X\n\r", col, row, lcd.getAddress(col, row));      
//      lcd.putc('-');
      lcd.putc('0' + row);      
      
      for (col=1; col<lcd.columns()-1; col++) {    
        lcd.putc('*');
      }
 
      pc.printf("MemAddr(Col=%d, Row=%d)=0x%02X\n\r", col, row, lcd.getAddress(col, row));      
      lcd.putc('+');
        
    }    
    
// Show cursor as blinking character
    lcd.setCursor(TextLCD::CurOff_BlkOn);
 
// Set and show user defined characters. A maximum of 8 UDCs are supported by the HD44780.
// They are defined by a 5x7 bitpattern. 
    lcd.setUDC(0, (char *) udc_0);  // Show |>
    lcd.putc(0);    
    lcd.setUDC(1, (char *) udc_1);  // Show <|
    lcd.putc(1);    

}

Handbook page

More info is here

Committer:
wim
Date:
Mon May 13 19:29:13 2013 +0000
Revision:
20:e0da005a777f
Parent:
19:c747b9e2e7b8
Child:
21:9eb628d9e164
Added support for Backlight control; Added portdefinitions for I2C/TWI LCD2004 Module from DFROBOT

Who changed what in which revision?

UserRevisionLine numberNew contents of line
simon 1:ac48b187213c 1 /* mbed TextLCD Library, for a 4-bit LCD based on HD44780
simon 6:e4cb7ddee0d3 2 * Copyright (c) 2007-2010, sford, http://mbed.org
wim 14:0c32b66b14b8 3 * 2013, v01: WH, Added LCD types, fixed LCD address issues, added Cursor and UDCs
wim 14:0c32b66b14b8 4 * 2013, v02: WH, Added I2C and SPI bus interfaces
wim 15:b70ebfffb258 5 * 2013, v03: WH, Added support for LCD40x4 which uses 2 controllers
wim 18:bd65dc10f27f 6 * 2013, v04: WH, Added support for Display On/Off, improved 4bit bootprocess
wim 18:bd65dc10f27f 7 * 2013, v05: WH, Added support for 8x2B, added some UDCs
wim 19:c747b9e2e7b8 8 * 2013, v06: WH, Added support for devices that use internal DC/DC converters
wim 20:e0da005a777f 9 * 2013, v07: WH, Added support for backlight and include portdefinitions for LCD2004 Module from DFROBOT
simon 1:ac48b187213c 10 *
simon 1:ac48b187213c 11 * Permission is hereby granted, free of charge, to any person obtaining a copy
simon 1:ac48b187213c 12 * of this software and associated documentation files (the "Software"), to deal
simon 1:ac48b187213c 13 * in the Software without restriction, including without limitation the rights
simon 1:ac48b187213c 14 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
simon 1:ac48b187213c 15 * copies of the Software, and to permit persons to whom the Software is
simon 1:ac48b187213c 16 * furnished to do so, subject to the following conditions:
simon 1:ac48b187213c 17 *
simon 1:ac48b187213c 18 * The above copyright notice and this permission notice shall be included in
simon 1:ac48b187213c 19 * all copies or substantial portions of the Software.
simon 1:ac48b187213c 20 *
simon 1:ac48b187213c 21 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
simon 1:ac48b187213c 22 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
simon 1:ac48b187213c 23 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
simon 1:ac48b187213c 24 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
simon 1:ac48b187213c 25 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
simon 1:ac48b187213c 26 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
simon 1:ac48b187213c 27 * THE SOFTWARE.
simon 1:ac48b187213c 28 */
simon 1:ac48b187213c 29
simon 1:ac48b187213c 30 #include "TextLCD.h"
simon 1:ac48b187213c 31 #include "mbed.h"
simon 1:ac48b187213c 32
wim 15:b70ebfffb258 33
wim 15:b70ebfffb258 34 /* Create a TextLCD interface for using regular mbed pins
wim 15:b70ebfffb258 35 *
wim 19:c747b9e2e7b8 36 * @param rs Instruction/data control line
wim 19:c747b9e2e7b8 37 * @param e Enable line (clock)
wim 19:c747b9e2e7b8 38 * @param d4-d7 Data lines for using as a 4-bit interface
wim 19:c747b9e2e7b8 39 * @param type Sets the panel size/addressing mode (default = LCD16x2)
wim 20:e0da005a777f 40 * @param bl Backlight control line (optional, default = NC)
wim 19:c747b9e2e7b8 41 * @param e2 Enable2 line (clock for second controller, LCD40x4 only)
wim 19:c747b9e2e7b8 42 * @param ctrl LCD controller (default = HD44780)
wim 15:b70ebfffb258 43 */
wim 13:24506ba22480 44 TextLCD::TextLCD(PinName rs, PinName e,
wim 13:24506ba22480 45 PinName d4, PinName d5, PinName d6, PinName d7,
wim 20:e0da005a777f 46 LCDType type, PinName bl, PinName e2, LCDCtrl ctrl) : _rs(rs), _e(e), _bl(bl), _e2(e2),
wim 20:e0da005a777f 47 _d(d4, d5, d6, d7),
wim 20:e0da005a777f 48 _cs(NC),
wim 20:e0da005a777f 49 _type(type),
wim 20:e0da005a777f 50 _ctrl(ctrl) {
wim 13:24506ba22480 51
wim 13:24506ba22480 52 _busType = _PinBus;
wim 13:24506ba22480 53
wim 13:24506ba22480 54 _init();
wim 13:24506ba22480 55
wim 13:24506ba22480 56 }
wim 13:24506ba22480 57
wim 15:b70ebfffb258 58 /* Create a TextLCD interface using an I2C PC8574 portexpander
wim 15:b70ebfffb258 59 *
wim 15:b70ebfffb258 60 * @param i2c I2C Bus
wim 15:b70ebfffb258 61 * @param deviceAddress I2C slave address (PCF8574)
wim 15:b70ebfffb258 62 * @param type Sets the panel size/addressing mode (default = LCD16x2)
wim 19:c747b9e2e7b8 63 * @param ctrl LCD controller (default = HD44780)
wim 15:b70ebfffb258 64 */
wim 19:c747b9e2e7b8 65 TextLCD::TextLCD(I2C *i2c, char deviceAddress, LCDType type, LCDCtrl ctrl) :
wim 20:e0da005a777f 66 _rs(NC), _e(NC), _bl(NC), _e2(NC),
wim 15:b70ebfffb258 67 _d(NC),
wim 15:b70ebfffb258 68 _i2c(i2c),
wim 15:b70ebfffb258 69 _cs(NC),
wim 19:c747b9e2e7b8 70 _type(type),
wim 19:c747b9e2e7b8 71 _ctrl(ctrl) {
wim 15:b70ebfffb258 72
wim 13:24506ba22480 73 _slaveAddress = deviceAddress;
wim 13:24506ba22480 74 _busType = _I2CBus;
simon 1:ac48b187213c 75
wim 13:24506ba22480 76
wim 13:24506ba22480 77 // Init the portexpander bus
wim 15:b70ebfffb258 78 _lcd_bus = D_LCD_BUS_DEF;
wim 13:24506ba22480 79
wim 13:24506ba22480 80 // write the new data to the portexpander
wim 13:24506ba22480 81 _i2c->write(_slaveAddress, &_lcd_bus, 1);
wim 13:24506ba22480 82
wim 13:24506ba22480 83 _init();
wim 13:24506ba22480 84
wim 13:24506ba22480 85 }
simon 1:ac48b187213c 86
wim 15:b70ebfffb258 87 /* Create a TextLCD interface using an SPI 74595 portexpander
wim 15:b70ebfffb258 88 *
wim 15:b70ebfffb258 89 * @param spi SPI Bus
wim 15:b70ebfffb258 90 * @param cs chip select pin (active low)
wim 15:b70ebfffb258 91 * @param type Sets the panel size/addressing mode (default = LCD16x2)
wim 19:c747b9e2e7b8 92 * @param ctrl LCD controller (default = HD44780)
wim 15:b70ebfffb258 93 */
wim 19:c747b9e2e7b8 94 TextLCD::TextLCD(SPI *spi, PinName cs, LCDType type, LCDCtrl ctrl) :
wim 20:e0da005a777f 95 _rs(NC), _e(NC), _bl(NC), _e2(NC),
wim 15:b70ebfffb258 96 _d(NC),
wim 15:b70ebfffb258 97 _spi(spi),
wim 15:b70ebfffb258 98 _cs(cs),
wim 19:c747b9e2e7b8 99 _type(type),
wim 19:c747b9e2e7b8 100 _ctrl(ctrl) {
wim 14:0c32b66b14b8 101
wim 14:0c32b66b14b8 102 _busType = _SPIBus;
wim 14:0c32b66b14b8 103
wim 14:0c32b66b14b8 104 // Setup the spi for 8 bit data, low steady state clock,
wim 14:0c32b66b14b8 105 // rising edge capture, with a 500KHz or 1MHz clock rate
wim 14:0c32b66b14b8 106 _spi->format(8,0);
wim 14:0c32b66b14b8 107 _spi->frequency(500000);
wim 14:0c32b66b14b8 108 //_spi.frequency(1000000);
wim 14:0c32b66b14b8 109
wim 14:0c32b66b14b8 110
wim 14:0c32b66b14b8 111 // Init the portexpander bus
wim 15:b70ebfffb258 112 _lcd_bus = D_LCD_BUS_DEF;
wim 14:0c32b66b14b8 113
wim 14:0c32b66b14b8 114 // write the new data to the portexpander
wim 14:0c32b66b14b8 115 _setCS(false);
wim 14:0c32b66b14b8 116 _spi->write(_lcd_bus);
wim 14:0c32b66b14b8 117 _setCS(true);
wim 14:0c32b66b14b8 118
wim 14:0c32b66b14b8 119 _init();
wim 14:0c32b66b14b8 120
wim 14:0c32b66b14b8 121 }
wim 14:0c32b66b14b8 122
wim 14:0c32b66b14b8 123
wim 15:b70ebfffb258 124 /* Init the LCD Controller(s)
wim 13:24506ba22480 125 * Clear display
wim 13:24506ba22480 126 */
wim 13:24506ba22480 127 void TextLCD::_init() {
wim 15:b70ebfffb258 128
wim 15:b70ebfffb258 129 // Select and configure second LCD controller when needed
wim 15:b70ebfffb258 130 if(_type==LCD40x4) {
wim 19:c747b9e2e7b8 131 _ctrl_idx=TextLCD::_LCDCtrl_1; // Select 2nd controller
wim 15:b70ebfffb258 132
wim 19:c747b9e2e7b8 133 _initCtrl(); // Init 2nd controller
wim 15:b70ebfffb258 134
wim 15:b70ebfffb258 135 // Secondary LCD controller Clearscreen
wim 15:b70ebfffb258 136 _writeCommand(0x01); // cls, and set cursor to 0
wim 15:b70ebfffb258 137 wait_ms(10); // The CLS command takes 1.64 ms.
wim 15:b70ebfffb258 138 // Since we are not using the Busy flag, Lets be safe and take 10 ms
wim 15:b70ebfffb258 139
wim 15:b70ebfffb258 140 }
wim 15:b70ebfffb258 141
wim 15:b70ebfffb258 142 // Select and configure primary LCD controller
wim 19:c747b9e2e7b8 143 _ctrl_idx=TextLCD::_LCDCtrl_0; // Select primary controller
wim 13:24506ba22480 144
wim 19:c747b9e2e7b8 145 _initCtrl(); // Init primary controller
wim 15:b70ebfffb258 146
wim 15:b70ebfffb258 147 // Primary LCD controller Clearscreen
wim 15:b70ebfffb258 148 _writeCommand(0x01); // cls, and set cursor to 0
wim 15:b70ebfffb258 149
wim 15:b70ebfffb258 150 wait_ms(10); // The CLS command takes 1.64 ms.
wim 15:b70ebfffb258 151 // Since we are not using the Busy flag, Lets be safe and take 10 ms
wim 15:b70ebfffb258 152
wim 15:b70ebfffb258 153 }
wim 15:b70ebfffb258 154
wim 15:b70ebfffb258 155 /* Init the LCD controller
wim 15:b70ebfffb258 156 * 4-bit mode, number of lines, fonttype, no cursor etc
wim 15:b70ebfffb258 157 *
wim 15:b70ebfffb258 158 */
wim 15:b70ebfffb258 159 void TextLCD::_initCtrl() {
wim 15:b70ebfffb258 160
wim 13:24506ba22480 161 _setRS(false); // command mode
wim 13:24506ba22480 162
wim 15:b70ebfffb258 163 wait_ms(20); // Wait 20ms to ensure powered up
simon 1:ac48b187213c 164
wim 17:652ab113bc2e 165 // send "Display Settings" 3 times (Only top nibble of 0x30 as we've got 4-bit bus)
wim 17:652ab113bc2e 166 for (int i=0; i<3; i++) {
wim 17:652ab113bc2e 167 _writeNibble(0x3);
wim 20:e0da005a777f 168 wait_ms(15); // This command takes 1.64ms, so wait for it
wim 17:652ab113bc2e 169 }
wim 17:652ab113bc2e 170 _writeNibble(0x2); // 4-bit mode
wim 17:652ab113bc2e 171 wait_us(40); // most instructions take 40us
wim 18:bd65dc10f27f 172
wim 18:bd65dc10f27f 173 // Display is now in 4-bit mode
wim 18:bd65dc10f27f 174
wim 19:c747b9e2e7b8 175
wim 19:c747b9e2e7b8 176 // Device specific initialisations for DC/DC converter to generate VLCD or VLED
wim 19:c747b9e2e7b8 177 switch (_ctrl) {
wim 20:e0da005a777f 178 case ST7036:
wim 19:c747b9e2e7b8 179 // ST7036 controller: Initialise Voltage booster for VLCD. VDD=5V
wim 19:c747b9e2e7b8 180 // Note: supports 1,2 or 3 lines
wim 19:c747b9e2e7b8 181 _writeByte( 0x29 ); // 4-bit Databus, 2 Lines, Select Instruction table 1
wim 20:e0da005a777f 182 wait_ms(30); // > 26,3ms
wim 19:c747b9e2e7b8 183 _writeByte( 0x14 ); // Bias: 1/5, 2-Lines LCD
wim 20:e0da005a777f 184 wait_ms(30); // > 26,3ms
wim 19:c747b9e2e7b8 185 _writeByte( 0x55 ); // Icon off, Booster on, Set Contrast C5, C4
wim 20:e0da005a777f 186 wait_ms(30); // > 26,3ms
wim 19:c747b9e2e7b8 187 _writeByte( 0x6d ); // Voltagefollower On, Ampl ratio Rab2, Rab1, Rab0
wim 19:c747b9e2e7b8 188 wait_ms(200); // > 200ms!
wim 19:c747b9e2e7b8 189 _writeByte( 0x78 ); // Set Contrast C3, C2, C1, C0
wim 20:e0da005a777f 190 wait_ms(30); // > 26,3ms
wim 19:c747b9e2e7b8 191 _writeByte( 0x28 ); // Return to Instruction table 0
wim 19:c747b9e2e7b8 192 wait_ms(50);
wim 19:c747b9e2e7b8 193
wim 19:c747b9e2e7b8 194 break;
wim 19:c747b9e2e7b8 195
wim 19:c747b9e2e7b8 196 case WS0010:
wim 19:c747b9e2e7b8 197 // WS0010 OLED controller: Initialise DC/DC Voltage converter for LEDs
wim 19:c747b9e2e7b8 198 // Note: supports 1 or 2 lines (and 16x100 graphics)
wim 19:c747b9e2e7b8 199 // supports 4 fonts (English/Japanese (default), Western European-I, English/Russian, Western European-II)
wim 19:c747b9e2e7b8 200
wim 19:c747b9e2e7b8 201 // Cursor/Disp shift set 0001 SC RL 0 0
wim 19:c747b9e2e7b8 202 //
wim 19:c747b9e2e7b8 203 // Mode en Power set 0001 GC PWR 1 1
wim 19:c747b9e2e7b8 204 // GC = 0 (Graph Mode=1, Char Mode=0)
wim 19:c747b9e2e7b8 205 // PWR = (DC/DC On/Off)
wim 19:c747b9e2e7b8 206
wim 19:c747b9e2e7b8 207 //_writeCommand(0x13); // DC/DC off
wim 19:c747b9e2e7b8 208
wim 19:c747b9e2e7b8 209 _writeCommand(0x17); // DC/DC on
wim 19:c747b9e2e7b8 210 wait_ms(10);
wim 19:c747b9e2e7b8 211
wim 19:c747b9e2e7b8 212 break;
wim 19:c747b9e2e7b8 213
wim 19:c747b9e2e7b8 214 default:
wim 19:c747b9e2e7b8 215 // Devices that do not use DC/DC Voltage converters but external VLCD
wim 19:c747b9e2e7b8 216 break;
wim 19:c747b9e2e7b8 217 }
wim 14:0c32b66b14b8 218
wim 18:bd65dc10f27f 219 // Initialise Display configuration
wim 10:dd9b3a696acd 220 switch (_type) {
wim 10:dd9b3a696acd 221 case LCD8x1:
wim 18:bd65dc10f27f 222 case LCD8x2B:
wim 18:bd65dc10f27f 223 //8x1 is a regular 1 line display
wim 18:bd65dc10f27f 224 //8x2B is a special case of 16x1
wim 15:b70ebfffb258 225 _writeCommand(0x20); // Function set 001 DL N F - -
wim 15:b70ebfffb258 226 // DL=0 (4 bits bus)
wim 13:24506ba22480 227 // N=0 (1 line)
wim 13:24506ba22480 228 // F=0 (5x7 dots font)
wim 10:dd9b3a696acd 229 break;
wim 10:dd9b3a696acd 230
wim 10:dd9b3a696acd 231 case LCD24x4:
wim 10:dd9b3a696acd 232 // Special mode for KS0078
wim 15:b70ebfffb258 233 _writeCommand(0x2A); // Function set 001 DL N RE DH REV
wim 15:b70ebfffb258 234 // DL=0 (4 bits bus)
wim 13:24506ba22480 235 // N=1 (Dont care for KS0078)
wim 13:24506ba22480 236 // RE=0 (Extended Regs, special mode for KS0078)
wim 13:24506ba22480 237 // DH=1 (Disp shift, special mode for KS0078)
wim 13:24506ba22480 238 // REV=0 (Reverse, special mode for KS0078)
wim 10:dd9b3a696acd 239
wim 15:b70ebfffb258 240 _writeCommand(0x2E); // Function set 001 DL N RE DH REV
wim 15:b70ebfffb258 241 // DL=0 (4 bits bus)
wim 13:24506ba22480 242 // N=1 (Dont care for KS0078)
wim 13:24506ba22480 243 // RE=1 (Ena Extended Regs, special mode for KS0078)
wim 13:24506ba22480 244 // DH=1 (Disp shift, special mode for KS0078)
wim 13:24506ba22480 245 // REV=0 (Reverse, special mode for KS0078)
wim 10:dd9b3a696acd 246
wim 13:24506ba22480 247 _writeCommand(0x09); // Ext Function set 0000 1 FW BW NW
wim 13:24506ba22480 248 // FW=0 (5-dot font, special mode for KS0078)
wim 13:24506ba22480 249 // BW=0 (Cur BW invert disable, special mode for KS0078)
wim 13:24506ba22480 250 // NW=1 (4 Line, special mode for KS0078)
wim 10:dd9b3a696acd 251
wim 15:b70ebfffb258 252 _writeCommand(0x2A); // Function set 001 DL N RE DH REV
wim 15:b70ebfffb258 253 // DL=0 (4 bits bus)
wim 13:24506ba22480 254 // N=1 (Dont care for KS0078)
wim 13:24506ba22480 255 // RE=0 (Dis. Extended Regs, special mode for KS0078)
wim 13:24506ba22480 256 // DH=1 (Disp shift, special mode for KS0078)
wim 13:24506ba22480 257 // REV=0 (Reverse, special mode for KS0078)
wim 10:dd9b3a696acd 258 break;
wim 10:dd9b3a696acd 259
wim 15:b70ebfffb258 260 // All other LCD types are initialised as 2 Line displays (including LCD40x4)
wim 10:dd9b3a696acd 261 default:
wim 15:b70ebfffb258 262 _writeCommand(0x28); // Function set 001 DL N F - -
wim 15:b70ebfffb258 263 // DL=0 (4 bits bus)
wim 13:24506ba22480 264 // N=1 (2 lines)
wim 15:b70ebfffb258 265 // F=0 (5x7 dots font, only option for 2 line display)
wim 13:24506ba22480 266 // - (Don't care)
wim 10:dd9b3a696acd 267
wim 10:dd9b3a696acd 268 break;
wim 10:dd9b3a696acd 269 }
wim 10:dd9b3a696acd 270
wim 13:24506ba22480 271 _writeCommand(0x06); // Entry Mode 0000 01 CD S
wim 13:24506ba22480 272 // Cursor Direction and Display Shift
wim 13:24506ba22480 273 // CD=1 (Cur incr)
wim 13:24506ba22480 274 // S=0 (No display shift)
wim 10:dd9b3a696acd 275
wim 13:24506ba22480 276 // _writeCommand(0x0C); // Display Ctrl 0000 1 D C B
wim 17:652ab113bc2e 277 // // Display On, Cursor Off, Blink Off
wim 15:b70ebfffb258 278 setCursor(TextLCD::CurOff_BlkOff);
wim 17:652ab113bc2e 279 setMode(TextLCD::DispOn);
simon 1:ac48b187213c 280 }
simon 1:ac48b187213c 281
wim 8:03116f75b66e 282
wim 16:c276b75e6585 283 // Clear the screen, Cursor home.
wim 15:b70ebfffb258 284 void TextLCD::cls() {
wim 15:b70ebfffb258 285
wim 15:b70ebfffb258 286 // Select and configure second LCD controller when needed
wim 15:b70ebfffb258 287 if(_type==LCD40x4) {
wim 19:c747b9e2e7b8 288 _ctrl_idx=TextLCD::_LCDCtrl_1; // Select 2nd controller
wim 15:b70ebfffb258 289
wim 15:b70ebfffb258 290 // Second LCD controller Cursor always Off
wim 17:652ab113bc2e 291 _setCursorAndDisplayMode(_currentMode, TextLCD::CurOff_BlkOff);
wim 15:b70ebfffb258 292
wim 15:b70ebfffb258 293 // Second LCD controller Clearscreen
wim 15:b70ebfffb258 294 _writeCommand(0x01); // cls, and set cursor to 0
wim 15:b70ebfffb258 295
wim 15:b70ebfffb258 296 wait_ms(10); // The CLS command takes 1.64 ms.
wim 15:b70ebfffb258 297 // Since we are not using the Busy flag, Lets be safe and take 10 ms
wim 15:b70ebfffb258 298
wim 15:b70ebfffb258 299
wim 19:c747b9e2e7b8 300 _ctrl_idx=TextLCD::_LCDCtrl_0; // Select primary controller
wim 15:b70ebfffb258 301 }
wim 15:b70ebfffb258 302
wim 15:b70ebfffb258 303 // Primary LCD controller Clearscreen
wim 15:b70ebfffb258 304 _writeCommand(0x01); // cls, and set cursor to 0
wim 15:b70ebfffb258 305
wim 15:b70ebfffb258 306 wait_ms(10); // The CLS command takes 1.64 ms.
wim 15:b70ebfffb258 307 // Since we are not using the Busy flag, Lets be safe and take 10 ms
wim 15:b70ebfffb258 308
wim 15:b70ebfffb258 309 // Restore cursormode on primary LCD controller when needed
wim 15:b70ebfffb258 310 if(_type==LCD40x4) {
wim 17:652ab113bc2e 311 _setCursorAndDisplayMode(_currentMode,_currentCursor);
wim 15:b70ebfffb258 312 }
wim 15:b70ebfffb258 313
wim 15:b70ebfffb258 314 _row=0; // Reset Cursor location
wim 15:b70ebfffb258 315 _column=0;
simon 1:ac48b187213c 316 }
simon 1:ac48b187213c 317
wim 16:c276b75e6585 318 // Move cursor to selected row and column
simon 1:ac48b187213c 319 void TextLCD::locate(int column, int row) {
wim 15:b70ebfffb258 320
wim 15:b70ebfffb258 321 // setAddress() does all the heavy lifting:
wim 15:b70ebfffb258 322 // check column and row sanity,
wim 15:b70ebfffb258 323 // switch controllers for LCD40x4 if needed
wim 15:b70ebfffb258 324 // switch cursor for LCD40x4 if needed
wim 15:b70ebfffb258 325 // set the new memory address to show cursor at correct location
wim 15:b70ebfffb258 326 setAddress(column, row);
wim 15:b70ebfffb258 327
wim 15:b70ebfffb258 328 }
wim 15:b70ebfffb258 329
wim 15:b70ebfffb258 330
wim 16:c276b75e6585 331 // Write a single character (Stream implementation)
wim 15:b70ebfffb258 332 int TextLCD::_putc(int value) {
wim 15:b70ebfffb258 333 int addr;
wim 15:b70ebfffb258 334
wim 15:b70ebfffb258 335 if (value == '\n') {
wim 15:b70ebfffb258 336 //No character to write
wim 15:b70ebfffb258 337
wim 15:b70ebfffb258 338 //Update Cursor
wim 15:b70ebfffb258 339 _column = 0;
wim 15:b70ebfffb258 340 _row++;
wim 15:b70ebfffb258 341 if (_row >= rows()) {
wim 15:b70ebfffb258 342 _row = 0;
wim 15:b70ebfffb258 343 }
wim 15:b70ebfffb258 344 }
wim 15:b70ebfffb258 345 else {
wim 15:b70ebfffb258 346 //Character to write
wim 15:b70ebfffb258 347 _writeData(value);
wim 15:b70ebfffb258 348
wim 15:b70ebfffb258 349 //Update Cursor
wim 15:b70ebfffb258 350 _column++;
wim 15:b70ebfffb258 351 if (_column >= columns()) {
wim 15:b70ebfffb258 352 _column = 0;
wim 15:b70ebfffb258 353 _row++;
wim 15:b70ebfffb258 354 if (_row >= rows()) {
wim 15:b70ebfffb258 355 _row = 0;
wim 15:b70ebfffb258 356 }
wim 15:b70ebfffb258 357 }
wim 15:b70ebfffb258 358 } //else
wim 15:b70ebfffb258 359
wim 15:b70ebfffb258 360 //Set next memoryaddress, make sure cursor blinks at next location
wim 15:b70ebfffb258 361 addr = getAddress(_column, _row);
wim 15:b70ebfffb258 362 _writeCommand(0x80 | addr);
wim 15:b70ebfffb258 363
wim 15:b70ebfffb258 364 return value;
wim 15:b70ebfffb258 365 }
wim 15:b70ebfffb258 366
wim 15:b70ebfffb258 367
wim 16:c276b75e6585 368 // get a single character (Stream implementation)
simon 1:ac48b187213c 369 int TextLCD::_getc() {
simon 1:ac48b187213c 370 return -1;
simon 1:ac48b187213c 371 }
simon 1:ac48b187213c 372
wim 16:c276b75e6585 373 // Set E pin (or E2 pin)
wim 16:c276b75e6585 374 // Used for mbed pins, I2C bus expander or SPI shifregister
wim 13:24506ba22480 375 void TextLCD::_setEnable(bool value) {
wim 13:24506ba22480 376
wim 13:24506ba22480 377 switch(_busType) {
wim 13:24506ba22480 378 case _PinBus :
wim 19:c747b9e2e7b8 379 if(_ctrl_idx==TextLCD::_LCDCtrl_0) {
wim 15:b70ebfffb258 380 if (value)
wim 15:b70ebfffb258 381 _e = 1; // Set E bit
wim 15:b70ebfffb258 382 else
wim 15:b70ebfffb258 383 _e = 0; // Reset E bit
wim 15:b70ebfffb258 384 }
wim 15:b70ebfffb258 385 else {
wim 15:b70ebfffb258 386 if (value)
wim 15:b70ebfffb258 387 _e2 = 1; // Set E2 bit
wim 15:b70ebfffb258 388 else
wim 15:b70ebfffb258 389 _e2 = 0; // Reset E2 bit
wim 15:b70ebfffb258 390 }
wim 15:b70ebfffb258 391
wim 13:24506ba22480 392 break;
wim 13:24506ba22480 393
wim 13:24506ba22480 394 case _I2CBus :
wim 15:b70ebfffb258 395
wim 19:c747b9e2e7b8 396 if(_ctrl_idx==TextLCD::_LCDCtrl_0) {
wim 15:b70ebfffb258 397 if (value)
wim 15:b70ebfffb258 398 _lcd_bus |= D_LCD_E; // Set E bit
wim 15:b70ebfffb258 399 else
wim 15:b70ebfffb258 400 _lcd_bus &= ~D_LCD_E; // Reset E bit
wim 15:b70ebfffb258 401 }
wim 15:b70ebfffb258 402 else {
wim 15:b70ebfffb258 403 if (value)
wim 15:b70ebfffb258 404 _lcd_bus |= D_LCD_E2; // Set E2 bit
wim 15:b70ebfffb258 405 else
wim 15:b70ebfffb258 406 _lcd_bus &= ~D_LCD_E2; // Reset E2bit
wim 15:b70ebfffb258 407 }
wim 15:b70ebfffb258 408
wim 15:b70ebfffb258 409 // write the new data to the I2C portexpander
wim 14:0c32b66b14b8 410 _i2c->write(_slaveAddress, &_lcd_bus, 1);
wim 15:b70ebfffb258 411
wim 13:24506ba22480 412 break;
wim 13:24506ba22480 413
wim 13:24506ba22480 414 case _SPIBus :
wim 19:c747b9e2e7b8 415 if(_ctrl_idx==TextLCD::_LCDCtrl_0) {
wim 15:b70ebfffb258 416 if (value)
wim 15:b70ebfffb258 417 _lcd_bus |= D_LCD_E; // Set E bit
wim 15:b70ebfffb258 418 else
wim 15:b70ebfffb258 419 _lcd_bus &= ~D_LCD_E; // Reset E bit
wim 15:b70ebfffb258 420 }
wim 15:b70ebfffb258 421 else {
wim 15:b70ebfffb258 422 if (value)
wim 15:b70ebfffb258 423 _lcd_bus |= D_LCD_E2; // Set E2 bit
wim 15:b70ebfffb258 424 else
wim 15:b70ebfffb258 425 _lcd_bus &= ~D_LCD_E2; // Reset E2 bit
wim 15:b70ebfffb258 426 }
wim 15:b70ebfffb258 427
wim 15:b70ebfffb258 428 // write the new data to the SPI portexpander
wim 14:0c32b66b14b8 429 _setCS(false);
wim 14:0c32b66b14b8 430 _spi->write(_lcd_bus);
wim 14:0c32b66b14b8 431 _setCS(true);
wim 14:0c32b66b14b8 432
wim 13:24506ba22480 433 break;
wim 13:24506ba22480 434 }
wim 13:24506ba22480 435 }
wim 13:24506ba22480 436
wim 16:c276b75e6585 437 // Set RS pin
wim 16:c276b75e6585 438 // Used for mbed pins, I2C bus expander or SPI shifregister
wim 13:24506ba22480 439 void TextLCD::_setRS(bool value) {
wim 13:24506ba22480 440
wim 13:24506ba22480 441 switch(_busType) {
wim 13:24506ba22480 442 case _PinBus :
wim 13:24506ba22480 443 if (value)
wim 13:24506ba22480 444 _rs = 1; // Set RS bit
wim 13:24506ba22480 445 else
wim 13:24506ba22480 446 _rs = 0; // Reset RS bit
wim 13:24506ba22480 447
wim 13:24506ba22480 448 break;
wim 13:24506ba22480 449
wim 13:24506ba22480 450 case _I2CBus :
wim 14:0c32b66b14b8 451 if (value)
wim 14:0c32b66b14b8 452 _lcd_bus |= D_LCD_RS; // Set RS bit
wim 14:0c32b66b14b8 453 else
wim 14:0c32b66b14b8 454 _lcd_bus &= ~D_LCD_RS; // Reset RS bit
wim 13:24506ba22480 455
wim 15:b70ebfffb258 456 // write the new data to the I2C portexpander
wim 14:0c32b66b14b8 457 _i2c->write(_slaveAddress, &_lcd_bus, 1);
wim 13:24506ba22480 458
wim 13:24506ba22480 459 break;
wim 13:24506ba22480 460
wim 13:24506ba22480 461 case _SPIBus :
wim 14:0c32b66b14b8 462 if (value)
wim 14:0c32b66b14b8 463 _lcd_bus |= D_LCD_RS; // Set RS bit
wim 14:0c32b66b14b8 464 else
wim 14:0c32b66b14b8 465 _lcd_bus &= ~D_LCD_RS; // Reset RS bit
wim 14:0c32b66b14b8 466
wim 15:b70ebfffb258 467 // write the new data to the SPI portexpander
wim 14:0c32b66b14b8 468 _setCS(false);
wim 14:0c32b66b14b8 469 _spi->write(_lcd_bus);
wim 14:0c32b66b14b8 470 _setCS(true);
wim 14:0c32b66b14b8 471
wim 13:24506ba22480 472 break;
wim 13:24506ba22480 473 }
wim 13:24506ba22480 474
wim 13:24506ba22480 475 }
wim 13:24506ba22480 476
wim 20:e0da005a777f 477 // Set BL pin
wim 20:e0da005a777f 478 // Used for mbed pins, I2C bus expander or SPI shifregister
wim 20:e0da005a777f 479 void TextLCD::_setBL(bool value) {
wim 20:e0da005a777f 480
wim 20:e0da005a777f 481 switch(_busType) {
wim 20:e0da005a777f 482 case _PinBus :
wim 20:e0da005a777f 483 if (value)
wim 20:e0da005a777f 484 _bl = 1; // Set BL bit
wim 20:e0da005a777f 485 else
wim 20:e0da005a777f 486 _bl = 0; // Reset BL bit
wim 20:e0da005a777f 487
wim 20:e0da005a777f 488 break;
wim 20:e0da005a777f 489
wim 20:e0da005a777f 490 case _I2CBus :
wim 20:e0da005a777f 491 if (value)
wim 20:e0da005a777f 492 _lcd_bus |= D_LCD_BL; // Set BL bit
wim 20:e0da005a777f 493 else
wim 20:e0da005a777f 494 _lcd_bus &= ~D_LCD_BL; // Reset BL bit
wim 20:e0da005a777f 495
wim 20:e0da005a777f 496 // write the new data to the I2C portexpander
wim 20:e0da005a777f 497 _i2c->write(_slaveAddress, &_lcd_bus, 1);
wim 20:e0da005a777f 498
wim 20:e0da005a777f 499 break;
wim 20:e0da005a777f 500
wim 20:e0da005a777f 501 case _SPIBus :
wim 20:e0da005a777f 502 if (value)
wim 20:e0da005a777f 503 _lcd_bus |= D_LCD_BL; // Set BL bit
wim 20:e0da005a777f 504 else
wim 20:e0da005a777f 505 _lcd_bus &= ~D_LCD_BL; // Reset BL bit
wim 20:e0da005a777f 506
wim 20:e0da005a777f 507 // write the new data to the SPI portexpander
wim 20:e0da005a777f 508 _setCS(false);
wim 20:e0da005a777f 509 _spi->write(_lcd_bus);
wim 20:e0da005a777f 510 _setCS(true);
wim 20:e0da005a777f 511
wim 20:e0da005a777f 512 break;
wim 20:e0da005a777f 513 }
wim 20:e0da005a777f 514
wim 20:e0da005a777f 515 }
wim 20:e0da005a777f 516
wim 20:e0da005a777f 517
wim 20:e0da005a777f 518
wim 16:c276b75e6585 519 // Place the 4bit data on the databus
wim 16:c276b75e6585 520 // Used for mbed pins, I2C bus expander or SPI shifregister
wim 13:24506ba22480 521 void TextLCD::_setData(int value) {
wim 13:24506ba22480 522 int data;
wim 13:24506ba22480 523
wim 13:24506ba22480 524 switch(_busType) {
wim 13:24506ba22480 525 case _PinBus :
wim 13:24506ba22480 526 _d = value & 0x0F; // Write Databits
wim 13:24506ba22480 527
wim 13:24506ba22480 528 break;
wim 13:24506ba22480 529
wim 13:24506ba22480 530 case _I2CBus :
wim 13:24506ba22480 531 data = value & 0x0F;
wim 13:24506ba22480 532 if (data & 0x01)
wim 13:24506ba22480 533 _lcd_bus |= D_LCD_D4; // Set Databit
wim 13:24506ba22480 534 else
wim 13:24506ba22480 535 _lcd_bus &= ~D_LCD_D4; // Reset Databit
wim 13:24506ba22480 536
wim 13:24506ba22480 537 if (data & 0x02)
wim 13:24506ba22480 538 _lcd_bus |= D_LCD_D5; // Set Databit
wim 13:24506ba22480 539 else
wim 13:24506ba22480 540 _lcd_bus &= ~D_LCD_D5; // Reset Databit
wim 13:24506ba22480 541
wim 13:24506ba22480 542 if (data & 0x04)
wim 13:24506ba22480 543 _lcd_bus |= D_LCD_D6; // Set Databit
wim 13:24506ba22480 544 else
wim 13:24506ba22480 545 _lcd_bus &= ~D_LCD_D6; // Reset Databit
wim 13:24506ba22480 546
wim 13:24506ba22480 547 if (data & 0x08)
wim 13:24506ba22480 548 _lcd_bus |= D_LCD_D7; // Set Databit
wim 13:24506ba22480 549 else
wim 13:24506ba22480 550 _lcd_bus &= ~D_LCD_D7; // Reset Databit
wim 13:24506ba22480 551
wim 15:b70ebfffb258 552 // write the new data to the I2C portexpander
wim 13:24506ba22480 553 _i2c->write(_slaveAddress, &_lcd_bus, 1);
wim 13:24506ba22480 554
wim 13:24506ba22480 555 break;
wim 13:24506ba22480 556
wim 13:24506ba22480 557 case _SPIBus :
wim 14:0c32b66b14b8 558
wim 14:0c32b66b14b8 559 data = value & 0x0F;
wim 14:0c32b66b14b8 560 if (data & 0x01)
wim 14:0c32b66b14b8 561 _lcd_bus |= D_LCD_D4; // Set Databit
wim 14:0c32b66b14b8 562 else
wim 14:0c32b66b14b8 563 _lcd_bus &= ~D_LCD_D4; // Reset Databit
wim 14:0c32b66b14b8 564
wim 14:0c32b66b14b8 565 if (data & 0x02)
wim 14:0c32b66b14b8 566 _lcd_bus |= D_LCD_D5; // Set Databit
wim 14:0c32b66b14b8 567 else
wim 14:0c32b66b14b8 568 _lcd_bus &= ~D_LCD_D5; // Reset Databit
wim 14:0c32b66b14b8 569
wim 14:0c32b66b14b8 570 if (data & 0x04)
wim 14:0c32b66b14b8 571 _lcd_bus |= D_LCD_D6; // Set Databit
wim 14:0c32b66b14b8 572 else
wim 14:0c32b66b14b8 573 _lcd_bus &= ~D_LCD_D6; // Reset Databit
wim 14:0c32b66b14b8 574
wim 14:0c32b66b14b8 575 if (data & 0x08)
wim 14:0c32b66b14b8 576 _lcd_bus |= D_LCD_D7; // Set Databit
wim 14:0c32b66b14b8 577 else
wim 14:0c32b66b14b8 578 _lcd_bus &= ~D_LCD_D7; // Reset Databit
wim 14:0c32b66b14b8 579
wim 15:b70ebfffb258 580 // write the new data to the SPI portexpander
wim 14:0c32b66b14b8 581 _setCS(false);
wim 14:0c32b66b14b8 582 _spi->write(_lcd_bus);
wim 14:0c32b66b14b8 583 _setCS(true);
wim 14:0c32b66b14b8 584
wim 14:0c32b66b14b8 585 break;
wim 13:24506ba22480 586 }
wim 13:24506ba22480 587
wim 13:24506ba22480 588 }
wim 13:24506ba22480 589
wim 13:24506ba22480 590
wim 16:c276b75e6585 591 // Set CS line.
wim 16:c276b75e6585 592 // Only used for SPI bus
wim 14:0c32b66b14b8 593 void TextLCD::_setCS(bool value) {
wim 14:0c32b66b14b8 594
wim 15:b70ebfffb258 595 if (value) {
wim 14:0c32b66b14b8 596 _cs = 1; // Set CS pin
wim 15:b70ebfffb258 597 }
wim 14:0c32b66b14b8 598 else
wim 14:0c32b66b14b8 599 _cs = 0; // Reset CS pin
wim 15:b70ebfffb258 600
wim 14:0c32b66b14b8 601 }
wim 14:0c32b66b14b8 602
wim 14:0c32b66b14b8 603
wim 17:652ab113bc2e 604 // Write a nibble using the 4-bit interface
wim 17:652ab113bc2e 605 // Used for mbed pins, I2C bus expander or SPI shifregister
wim 17:652ab113bc2e 606 void TextLCD::_writeNibble(int value) {
wim 17:652ab113bc2e 607
wim 17:652ab113bc2e 608 // Enable is Low
wim 17:652ab113bc2e 609 _setEnable(true);
wim 17:652ab113bc2e 610 _setData(value & 0x0F); // Low nibble
wim 17:652ab113bc2e 611 wait_us(1); // Data setup time
wim 17:652ab113bc2e 612 _setEnable(false);
wim 17:652ab113bc2e 613 wait_us(1); // Datahold time
wim 17:652ab113bc2e 614
wim 17:652ab113bc2e 615 // Enable is Low
wim 17:652ab113bc2e 616
wim 17:652ab113bc2e 617 }
wim 17:652ab113bc2e 618
wim 17:652ab113bc2e 619
wim 16:c276b75e6585 620 // Write a byte using the 4-bit interface
wim 16:c276b75e6585 621 // Used for mbed pins, I2C bus expander or SPI shifregister
wim 13:24506ba22480 622 void TextLCD::_writeByte(int value) {
wim 15:b70ebfffb258 623
wim 15:b70ebfffb258 624 // Enable is Low
wim 15:b70ebfffb258 625 _setEnable(true);
wim 16:c276b75e6585 626 _setData(value >> 4); // High nibble
wim 15:b70ebfffb258 627 wait_us(1); // Data setup time
wim 15:b70ebfffb258 628 _setEnable(false);
wim 15:b70ebfffb258 629 wait_us(1); // Data hold time
wim 15:b70ebfffb258 630
wim 13:24506ba22480 631 _setEnable(true);
wim 16:c276b75e6585 632 _setData(value >> 0); // Low nibble
wim 15:b70ebfffb258 633 wait_us(1); // Data setup time
wim 13:24506ba22480 634 _setEnable(false);
wim 15:b70ebfffb258 635 wait_us(1); // Datahold time
wim 15:b70ebfffb258 636
wim 15:b70ebfffb258 637 // Enable is Low
wim 15:b70ebfffb258 638
simon 1:ac48b187213c 639 }
simon 1:ac48b187213c 640
wim 13:24506ba22480 641 void TextLCD::_writeCommand(int command) {
wim 15:b70ebfffb258 642
wim 13:24506ba22480 643 _setRS(false);
wim 16:c276b75e6585 644 wait_us(1); // Data setup time for RS
wim 15:b70ebfffb258 645
wim 15:b70ebfffb258 646 _writeByte(command);
wim 15:b70ebfffb258 647 wait_us(40); // most instructions take 40us
simon 1:ac48b187213c 648 }
simon 1:ac48b187213c 649
wim 13:24506ba22480 650 void TextLCD::_writeData(int data) {
wim 15:b70ebfffb258 651
wim 13:24506ba22480 652 _setRS(true);
wim 16:c276b75e6585 653 wait_us(1); // Data setup time for RS
wim 15:b70ebfffb258 654
wim 13:24506ba22480 655 _writeByte(data);
wim 15:b70ebfffb258 656 wait_us(40); // data writes take 40us
simon 1:ac48b187213c 657 }
simon 1:ac48b187213c 658
wim 8:03116f75b66e 659
wim 8:03116f75b66e 660 #if (0)
wim 16:c276b75e6585 661 // This is the original _address() method.
wim 8:03116f75b66e 662 // It is confusing since it returns the memoryaddress or-ed with the set memorycommand 0x80.
wim 8:03116f75b66e 663 // Left it in here for compatibility with older code. New applications should use getAddress() instead.
wim 8:03116f75b66e 664 //
wim 13:24506ba22480 665 int TextLCD::_address(int column, int row) {
simon 1:ac48b187213c 666 switch (_type) {
simon 1:ac48b187213c 667 case LCD20x4:
simon 1:ac48b187213c 668 switch (row) {
simon 1:ac48b187213c 669 case 0:
simon 1:ac48b187213c 670 return 0x80 + column;
simon 1:ac48b187213c 671 case 1:
simon 1:ac48b187213c 672 return 0xc0 + column;
simon 1:ac48b187213c 673 case 2:
simon 1:ac48b187213c 674 return 0x94 + column;
simon 1:ac48b187213c 675 case 3:
simon 1:ac48b187213c 676 return 0xd4 + column;
simon 1:ac48b187213c 677 }
simon 1:ac48b187213c 678 case LCD16x2B:
simon 4:bf5b706f8d32 679 return 0x80 + (row * 40) + column;
simon 1:ac48b187213c 680 case LCD16x2:
simon 1:ac48b187213c 681 case LCD20x2:
simon 1:ac48b187213c 682 default:
simon 4:bf5b706f8d32 683 return 0x80 + (row * 0x40) + column;
simon 1:ac48b187213c 684 }
simon 1:ac48b187213c 685 }
wim 8:03116f75b66e 686 #endif
wim 8:03116f75b66e 687
wim 8:03116f75b66e 688
wim 16:c276b75e6585 689 // This replaces the original _address() method.
wim 8:03116f75b66e 690 // Left it in here for compatibility with older code. New applications should use getAddress() instead.
wim 13:24506ba22480 691 int TextLCD::_address(int column, int row) {
wim 8:03116f75b66e 692 return 0x80 | getAddress(column, row);
wim 8:03116f75b66e 693 }
wim 8:03116f75b66e 694
wim 8:03116f75b66e 695 // This is new method to return the memory address based on row, column and displaytype.
wim 8:03116f75b66e 696 //
wim 8:03116f75b66e 697 int TextLCD::getAddress(int column, int row) {
wim 8:03116f75b66e 698
wim 8:03116f75b66e 699 switch (_type) {
wim 8:03116f75b66e 700 case LCD8x1:
wim 8:03116f75b66e 701 return 0x00 + column;
wim 18:bd65dc10f27f 702
wim 18:bd65dc10f27f 703 case LCD8x2B:
wim 18:bd65dc10f27f 704 // LCD8x2B is a special layout of LCD16x1
wim 18:bd65dc10f27f 705 if (row==0)
wim 18:bd65dc10f27f 706 return 0x00 + column;
wim 18:bd65dc10f27f 707 else
wim 18:bd65dc10f27f 708 return 0x08 + column;
wim 18:bd65dc10f27f 709
wim 18:bd65dc10f27f 710
wim 13:24506ba22480 711 case LCD16x1:
wim 13:24506ba22480 712 // LCD16x1 is a special layout of LCD8x2
wim 13:24506ba22480 713 if (column<8)
wim 13:24506ba22480 714 return 0x00 + column;
wim 13:24506ba22480 715 else
wim 13:24506ba22480 716 return 0x40 + (column - 8);
wim 13:24506ba22480 717
wim 15:b70ebfffb258 718 case LCD12x4:
wim 15:b70ebfffb258 719 switch (row) {
wim 15:b70ebfffb258 720 case 0:
wim 15:b70ebfffb258 721 return 0x00 + column;
wim 15:b70ebfffb258 722 case 1:
wim 15:b70ebfffb258 723 return 0x40 + column;
wim 15:b70ebfffb258 724 case 2:
wim 15:b70ebfffb258 725 return 0x0C + column;
wim 15:b70ebfffb258 726 case 3:
wim 15:b70ebfffb258 727 return 0x4C + column;
wim 15:b70ebfffb258 728 }
wim 15:b70ebfffb258 729
wim 8:03116f75b66e 730 case LCD16x4:
wim 8:03116f75b66e 731 switch (row) {
wim 8:03116f75b66e 732 case 0:
wim 8:03116f75b66e 733 return 0x00 + column;
wim 8:03116f75b66e 734 case 1:
wim 8:03116f75b66e 735 return 0x40 + column;
wim 8:03116f75b66e 736 case 2:
wim 8:03116f75b66e 737 return 0x10 + column;
wim 8:03116f75b66e 738 case 3:
wim 8:03116f75b66e 739 return 0x50 + column;
wim 8:03116f75b66e 740 }
wim 8:03116f75b66e 741
wim 8:03116f75b66e 742 case LCD20x4:
wim 8:03116f75b66e 743 switch (row) {
wim 8:03116f75b66e 744 case 0:
wim 8:03116f75b66e 745 return 0x00 + column;
wim 8:03116f75b66e 746 case 1:
wim 8:03116f75b66e 747 return 0x40 + column;
wim 8:03116f75b66e 748 case 2:
wim 8:03116f75b66e 749 return 0x14 + column;
wim 8:03116f75b66e 750 case 3:
wim 8:03116f75b66e 751 return 0x54 + column;
wim 8:03116f75b66e 752 }
wim 8:03116f75b66e 753
wim 10:dd9b3a696acd 754 // Special mode for KS0078
wim 10:dd9b3a696acd 755 case LCD24x4:
wim 10:dd9b3a696acd 756 switch (row) {
wim 10:dd9b3a696acd 757 case 0:
wim 10:dd9b3a696acd 758 return 0x00 + column;
wim 10:dd9b3a696acd 759 case 1:
wim 10:dd9b3a696acd 760 return 0x20 + column;
wim 10:dd9b3a696acd 761 case 2:
wim 10:dd9b3a696acd 762 return 0x40 + column;
wim 10:dd9b3a696acd 763 case 3:
wim 10:dd9b3a696acd 764 return 0x60 + column;
wim 10:dd9b3a696acd 765 }
wim 10:dd9b3a696acd 766
wim 8:03116f75b66e 767 // Not sure about this one, seems wrong.
wim 8:03116f75b66e 768 case LCD16x2B:
wim 8:03116f75b66e 769 return 0x00 + (row * 40) + column;
wim 8:03116f75b66e 770
wim 18:bd65dc10f27f 771 case LCD8x2:
wim 15:b70ebfffb258 772 case LCD12x2:
wim 8:03116f75b66e 773 case LCD16x2:
wim 8:03116f75b66e 774 case LCD20x2:
wim 8:03116f75b66e 775 case LCD24x2:
wim 9:0893d986e717 776 case LCD40x2:
wim 8:03116f75b66e 777 return 0x00 + (row * 0x40) + column;
wim 15:b70ebfffb258 778
wim 15:b70ebfffb258 779 case LCD40x4:
wim 15:b70ebfffb258 780 // LCD40x4 is a special case since it has 2 controllers
wim 15:b70ebfffb258 781 // Each controller is configured as 40x2
wim 15:b70ebfffb258 782 if (row<2) {
wim 15:b70ebfffb258 783 // Test to see if we need to switch between controllers
wim 19:c747b9e2e7b8 784 if (_ctrl_idx != _LCDCtrl_0) {
wim 17:652ab113bc2e 785
wim 15:b70ebfffb258 786 // Second LCD controller Cursor Off
wim 17:652ab113bc2e 787 _setCursorAndDisplayMode(_currentMode, TextLCD::CurOff_BlkOff);
wim 15:b70ebfffb258 788
wim 15:b70ebfffb258 789 // Select primary controller
wim 19:c747b9e2e7b8 790 _ctrl_idx = _LCDCtrl_0;
wim 15:b70ebfffb258 791
wim 15:b70ebfffb258 792 // Restore cursormode on primary LCD controller
wim 17:652ab113bc2e 793 _setCursorAndDisplayMode(_currentMode, _currentCursor);
wim 15:b70ebfffb258 794 }
wim 15:b70ebfffb258 795
wim 15:b70ebfffb258 796 return 0x00 + (row * 0x40) + column;
wim 15:b70ebfffb258 797 }
wim 15:b70ebfffb258 798 else {
wim 15:b70ebfffb258 799
wim 15:b70ebfffb258 800 // Test to see if we need to switch between controllers
wim 19:c747b9e2e7b8 801 if (_ctrl_idx != _LCDCtrl_1) {
wim 15:b70ebfffb258 802 // Primary LCD controller Cursor Off
wim 17:652ab113bc2e 803 _setCursorAndDisplayMode(_currentMode, TextLCD::CurOff_BlkOff);
wim 15:b70ebfffb258 804
wim 15:b70ebfffb258 805 // Select secondary controller
wim 19:c747b9e2e7b8 806 _ctrl_idx = _LCDCtrl_1;
wim 15:b70ebfffb258 807
wim 15:b70ebfffb258 808 // Restore cursormode on secondary LCD controller
wim 17:652ab113bc2e 809 _setCursorAndDisplayMode(_currentMode, _currentCursor);
wim 15:b70ebfffb258 810 }
wim 15:b70ebfffb258 811
wim 15:b70ebfffb258 812 return 0x00 + ((row-2) * 0x40) + column;
wim 15:b70ebfffb258 813 }
wim 8:03116f75b66e 814
wim 8:03116f75b66e 815 // Should never get here.
wim 8:03116f75b66e 816 default:
wim 8:03116f75b66e 817 return 0x00;
wim 8:03116f75b66e 818 }
wim 8:03116f75b66e 819 }
wim 8:03116f75b66e 820
wim 8:03116f75b66e 821
wim 15:b70ebfffb258 822 // Set row, column and update memoryaddress.
wim 8:03116f75b66e 823 //
wim 8:03116f75b66e 824 void TextLCD::setAddress(int column, int row) {
wim 15:b70ebfffb258 825
wim 15:b70ebfffb258 826 // Sanity Check column
wim 15:b70ebfffb258 827 if (column < 0) {
wim 15:b70ebfffb258 828 _column = 0;
wim 15:b70ebfffb258 829 }
wim 15:b70ebfffb258 830 else if (column >= columns()) {
wim 15:b70ebfffb258 831 _column = columns() - 1;
wim 15:b70ebfffb258 832 } else _column = column;
wim 8:03116f75b66e 833
wim 15:b70ebfffb258 834 // Sanity Check row
wim 15:b70ebfffb258 835 if (row < 0) {
wim 15:b70ebfffb258 836 _row = 0;
wim 15:b70ebfffb258 837 }
wim 15:b70ebfffb258 838 else if (row >= rows()) {
wim 15:b70ebfffb258 839 _row = rows() - 1;
wim 15:b70ebfffb258 840 } else _row = row;
wim 15:b70ebfffb258 841
wim 15:b70ebfffb258 842
wim 15:b70ebfffb258 843 // Compute the memory address
wim 15:b70ebfffb258 844 // For LCD40x4: switch controllers if needed
wim 15:b70ebfffb258 845 // switch cursor if needed
wim 15:b70ebfffb258 846 int addr = getAddress(_column, _row);
wim 8:03116f75b66e 847
wim 13:24506ba22480 848 _writeCommand(0x80 | addr);
wim 8:03116f75b66e 849 }
simon 1:ac48b187213c 850
simon 1:ac48b187213c 851 int TextLCD::columns() {
simon 1:ac48b187213c 852 switch (_type) {
wim 8:03116f75b66e 853 case LCD8x1:
wim 8:03116f75b66e 854 case LCD8x2:
wim 18:bd65dc10f27f 855 case LCD8x2B:
wim 8:03116f75b66e 856 return 8;
wim 15:b70ebfffb258 857
wim 15:b70ebfffb258 858 case LCD12x2:
wim 15:b70ebfffb258 859 case LCD12x4:
wim 15:b70ebfffb258 860 return 12;
wim 8:03116f75b66e 861
wim 13:24506ba22480 862 case LCD16x1:
simon 1:ac48b187213c 863 case LCD16x2:
simon 1:ac48b187213c 864 case LCD16x2B:
wim 8:03116f75b66e 865 case LCD16x4:
wim 8:03116f75b66e 866 return 16;
wim 8:03116f75b66e 867
wim 8:03116f75b66e 868 case LCD20x2:
wim 8:03116f75b66e 869 case LCD20x4:
wim 8:03116f75b66e 870 return 20;
wim 8:03116f75b66e 871
wim 8:03116f75b66e 872 case LCD24x2:
wim 10:dd9b3a696acd 873 case LCD24x4:
wim 8:03116f75b66e 874 return 24;
wim 9:0893d986e717 875
wim 9:0893d986e717 876 case LCD40x2:
wim 15:b70ebfffb258 877 case LCD40x4:
wim 9:0893d986e717 878 return 40;
wim 8:03116f75b66e 879
wim 8:03116f75b66e 880 // Should never get here.
simon 1:ac48b187213c 881 default:
wim 8:03116f75b66e 882 return 0;
simon 1:ac48b187213c 883 }
simon 1:ac48b187213c 884 }
simon 1:ac48b187213c 885
simon 1:ac48b187213c 886 int TextLCD::rows() {
simon 1:ac48b187213c 887 switch (_type) {
wim 8:03116f75b66e 888 case LCD8x1:
wim 13:24506ba22480 889 case LCD16x1:
wim 8:03116f75b66e 890 return 1;
wim 8:03116f75b66e 891
wim 15:b70ebfffb258 892 case LCD8x2:
wim 18:bd65dc10f27f 893 case LCD8x2B:
wim 15:b70ebfffb258 894 case LCD12x2:
simon 1:ac48b187213c 895 case LCD16x2:
simon 1:ac48b187213c 896 case LCD16x2B:
simon 1:ac48b187213c 897 case LCD20x2:
wim 8:03116f75b66e 898 case LCD24x2:
wim 9:0893d986e717 899 case LCD40x2:
wim 8:03116f75b66e 900 return 2;
wim 8:03116f75b66e 901
wim 15:b70ebfffb258 902 case LCD12x4:
wim 8:03116f75b66e 903 case LCD16x4:
wim 8:03116f75b66e 904 case LCD20x4:
wim 10:dd9b3a696acd 905 case LCD24x4:
wim 15:b70ebfffb258 906 case LCD40x4:
wim 8:03116f75b66e 907 return 4;
wim 12:6bf9d9957d31 908
wim 12:6bf9d9957d31 909 // Should never get here.
simon 1:ac48b187213c 910 default:
wim 8:03116f75b66e 911 return 0;
simon 1:ac48b187213c 912 }
simon 1:ac48b187213c 913 }
wim 10:dd9b3a696acd 914
wim 10:dd9b3a696acd 915
wim 17:652ab113bc2e 916 // Set the Cursor Mode (Cursor Off & Blink Off, Cursor On & Blink Off, Cursor Off & Blink On, Cursor On & Blink On
wim 17:652ab113bc2e 917 void TextLCD::setCursor(TextLCD::LCDCursor cursorMode) {
wim 15:b70ebfffb258 918
wim 17:652ab113bc2e 919 // Save new cursor mode, needed when 2 controllers are in use or when display is switched off/on
wim 17:652ab113bc2e 920 _currentCursor = cursorMode;
wim 10:dd9b3a696acd 921
wim 17:652ab113bc2e 922 // Configure only current LCD controller
wim 17:652ab113bc2e 923 _setCursorAndDisplayMode(_currentMode, _currentCursor);
wim 15:b70ebfffb258 924
wim 15:b70ebfffb258 925 }
wim 15:b70ebfffb258 926
wim 17:652ab113bc2e 927 // Set the Displaymode (On/Off)
wim 17:652ab113bc2e 928 void TextLCD::setMode(TextLCD::LCDMode displayMode) {
wim 17:652ab113bc2e 929
wim 17:652ab113bc2e 930 // Save new displayMode, needed when 2 controllers are in use or when cursor is changed
wim 17:652ab113bc2e 931 _currentMode = displayMode;
wim 15:b70ebfffb258 932
wim 17:652ab113bc2e 933 // Select and configure second LCD controller when needed
wim 17:652ab113bc2e 934 if(_type==LCD40x4) {
wim 19:c747b9e2e7b8 935 if (_ctrl_idx==TextLCD::_LCDCtrl_0) {
wim 17:652ab113bc2e 936 // Configure primary LCD controller
wim 17:652ab113bc2e 937 _setCursorAndDisplayMode(_currentMode, _currentCursor);
wim 11:9ec02df863a1 938
wim 17:652ab113bc2e 939 // Select 2nd controller
wim 19:c747b9e2e7b8 940 _ctrl_idx=TextLCD::_LCDCtrl_1;
wim 17:652ab113bc2e 941
wim 17:652ab113bc2e 942 // Configure secondary LCD controller
wim 17:652ab113bc2e 943 _setCursorAndDisplayMode(_currentMode, TextLCD::CurOff_BlkOff);
wim 11:9ec02df863a1 944
wim 17:652ab113bc2e 945 // Restore current controller
wim 19:c747b9e2e7b8 946 _ctrl_idx=TextLCD::_LCDCtrl_0;
wim 17:652ab113bc2e 947 }
wim 17:652ab113bc2e 948 else {
wim 17:652ab113bc2e 949 // Select primary controller
wim 19:c747b9e2e7b8 950 _ctrl_idx=TextLCD::_LCDCtrl_0;
wim 17:652ab113bc2e 951
wim 17:652ab113bc2e 952 // Configure primary LCD controller
wim 17:652ab113bc2e 953 _setCursorAndDisplayMode(_currentMode, TextLCD::CurOff_BlkOff);
wim 17:652ab113bc2e 954
wim 17:652ab113bc2e 955 // Restore current controller
wim 19:c747b9e2e7b8 956 _ctrl_idx=TextLCD::_LCDCtrl_1;
wim 11:9ec02df863a1 957
wim 17:652ab113bc2e 958 // Configure secondary LCD controller
wim 17:652ab113bc2e 959 _setCursorAndDisplayMode(_currentMode, _currentCursor);
wim 11:9ec02df863a1 960
wim 10:dd9b3a696acd 961 }
wim 17:652ab113bc2e 962 }
wim 17:652ab113bc2e 963 else {
wim 17:652ab113bc2e 964 // Configure primary LCD controller
wim 17:652ab113bc2e 965 _setCursorAndDisplayMode(_currentMode, _currentCursor);
wim 17:652ab113bc2e 966 }
wim 17:652ab113bc2e 967
wim 17:652ab113bc2e 968 }
wim 17:652ab113bc2e 969
wim 17:652ab113bc2e 970
wim 17:652ab113bc2e 971 // Set the Displaymode (On/Off) and Cursortype for current controller
wim 17:652ab113bc2e 972 void TextLCD::_setCursorAndDisplayMode(TextLCD::LCDMode displayMode, TextLCD::LCDCursor cursorType) {
wim 17:652ab113bc2e 973
wim 17:652ab113bc2e 974 // Configure current LCD controller
wim 17:652ab113bc2e 975 _writeCommand(0x08 | displayMode | cursorType);
wim 10:dd9b3a696acd 976 }
wim 10:dd9b3a696acd 977
wim 20:e0da005a777f 978 // Set the Backlight mode (Off/On)
wim 20:e0da005a777f 979 void TextLCD::setBacklight(TextLCD::LCDBacklight backlightMode) {
wim 20:e0da005a777f 980
wim 20:e0da005a777f 981 if (backlightMode == LightOn) {
wim 20:e0da005a777f 982 _setBL(true);
wim 20:e0da005a777f 983 }
wim 20:e0da005a777f 984 else {
wim 20:e0da005a777f 985 _setBL(false);
wim 20:e0da005a777f 986 }
wim 20:e0da005a777f 987 }
wim 20:e0da005a777f 988
wim 10:dd9b3a696acd 989
wim 11:9ec02df863a1 990 void TextLCD::setUDC(unsigned char c, char *udc_data) {
wim 15:b70ebfffb258 991
wim 15:b70ebfffb258 992 // Select and configure second LCD controller when needed
wim 15:b70ebfffb258 993 if(_type==LCD40x4) {
wim 19:c747b9e2e7b8 994 _LCDCtrl_Idx current_ctrl_idx = _ctrl_idx; // Temp save current controller
wim 15:b70ebfffb258 995
wim 15:b70ebfffb258 996 // Select primary controller
wim 19:c747b9e2e7b8 997 _ctrl_idx=TextLCD::_LCDCtrl_0;
wim 15:b70ebfffb258 998
wim 15:b70ebfffb258 999 // Configure primary LCD controller
wim 15:b70ebfffb258 1000 _setUDC(c, udc_data);
wim 15:b70ebfffb258 1001
wim 15:b70ebfffb258 1002 // Select 2nd controller
wim 19:c747b9e2e7b8 1003 _ctrl_idx=TextLCD::_LCDCtrl_1;
wim 15:b70ebfffb258 1004
wim 15:b70ebfffb258 1005 // Configure secondary LCD controller
wim 15:b70ebfffb258 1006 _setUDC(c, udc_data);
wim 11:9ec02df863a1 1007
wim 15:b70ebfffb258 1008 // Restore current controller
wim 19:c747b9e2e7b8 1009 _ctrl_idx=current_ctrl_idx;
wim 15:b70ebfffb258 1010 }
wim 15:b70ebfffb258 1011 else {
wim 15:b70ebfffb258 1012 // Configure primary LCD controller
wim 15:b70ebfffb258 1013 _setUDC(c, udc_data);
wim 15:b70ebfffb258 1014 }
wim 15:b70ebfffb258 1015
wim 15:b70ebfffb258 1016 }
wim 15:b70ebfffb258 1017
wim 15:b70ebfffb258 1018 void TextLCD::_setUDC(unsigned char c, char *udc_data) {
wim 15:b70ebfffb258 1019
wim 15:b70ebfffb258 1020 // Select CG RAM for current LCD controller
wim 15:b70ebfffb258 1021 _writeCommand(0x40 + ((c & 0x07) << 3)); //Set CG-RAM address,
wim 15:b70ebfffb258 1022 //8 sequential locations needed per UDC
wim 15:b70ebfffb258 1023 // Store UDC pattern
wim 11:9ec02df863a1 1024 for (int i=0; i<8; i++) {
wim 13:24506ba22480 1025 _writeData(*udc_data++);
wim 11:9ec02df863a1 1026 }
wim 15:b70ebfffb258 1027
wim 15:b70ebfffb258 1028 //Select DD RAM again for current LCD controller
wim 15:b70ebfffb258 1029 int addr = getAddress(_column, _row);
wim 15:b70ebfffb258 1030 _writeCommand(0x80 | addr);
wim 15:b70ebfffb258 1031
wim 11:9ec02df863a1 1032 }