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:
Fri Apr 19 19:36:37 2013 +0000
Revision:
19:c747b9e2e7b8
Parent:
18:bd65dc10f27f
Child:
20:e0da005a777f
Beta version supporting WS0010 and ST7036 DC/DC converters

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