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:
Sat Mar 09 19:39:53 2013 +0000
Revision:
18:bd65dc10f27f
Parent:
17:652ab113bc2e
Child:
19:c747b9e2e7b8
Added some UDCs, Updated documentation.

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