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 02 16:51:01 2013 +0000
Revision:
17:652ab113bc2e
Parent:
16:c276b75e6585
Child:
18:bd65dc10f27f
Added support for Display On/Off. Improved 4bit bootprocess.

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