Initial commit
Fork of TextLCD by
Embed:
(wiki syntax)
Show/hide line numbers
TextLCD.cpp
00001 /* mbed TextLCD Library, for a 4-bit LCD based on HD44780 00002 * Copyright (c) 2007-2010, sford, http://mbed.org 00003 * 2013, v01: WH, Added LCD types, fixed LCD address issues, added Cursor and UDCs 00004 * 2013, v02: WH, Added I2C and SPI bus interfaces 00005 * 2013, v03: WH, Added support for LCD40x4 which uses 2 controllers 00006 * 2013, v04: WH, Added support for Display On/Off, improved 4bit bootprocess 00007 * 2013, v05: WH, Added support for 8x2B, added some UDCs 00008 * 2013, v06: WH, Added support for devices that use internal DC/DC converters 00009 * 2013, v07: WH, Added support for backlight and include portdefinitions for LCD2004 Module from DFROBOT 00010 * 00011 * Permission is hereby granted, free of charge, to any person obtaining a copy 00012 * of this software and associated documentation files (the "Software"), to deal 00013 * in the Software without restriction, including without limitation the rights 00014 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 00015 * copies of the Software, and to permit persons to whom the Software is 00016 * furnished to do so, subject to the following conditions: 00017 * 00018 * The above copyright notice and this permission notice shall be included in 00019 * all copies or substantial portions of the Software. 00020 * 00021 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 00022 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 00023 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 00024 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 00025 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 00026 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 00027 * THE SOFTWARE. 00028 */ 00029 00030 #include "TextLCD.h" 00031 #include "mbed.h" 00032 00033 00034 00035 /* Create a TextLCD interface using SPI 00036 * 00037 * @param spi SPI Bus 00038 * @param cs chip select pin (active low) 00039 * @param type Sets the panel size/addressing mode (default = LCD16x2) 00040 * @param ctrl LCD controller (default = HD44780) 00041 */ 00042 TextLCD::TextLCD(SPI *spi, PinName cs, PinName rs, LCDType type, LCDCtrl ctrl) : 00043 _e(NC), _bl(NC), _e2(NC), 00044 _d(NC), 00045 _spi(spi), 00046 _cs(cs), 00047 _rs(rs), 00048 _type(type), 00049 _ctrl(ctrl) { 00050 00051 _busType = _SPIBus; 00052 00053 // Setup the spi for 8 bit data, low steady state clock, 00054 // rising edge capture, with a 500KHz or 1MHz clock rate 00055 _spi->format(8,0); 00056 _spi->frequency(500000); 00057 //_spi.frequency(1000000); 00058 00059 00060 // Init the portexpander bus 00061 _lcd_bus = D_LCD_BUS_DEF; 00062 00063 // write the new data to the portexpander 00064 _setCS(false); 00065 _spi->write(_lcd_bus); 00066 _setCS(true); 00067 00068 _init(); 00069 00070 } 00071 00072 00073 /* Init the LCD Controller(s) 00074 * Clear display 00075 */ 00076 void TextLCD::_init() { 00077 00078 // Select and configure second LCD controller when needed 00079 if(_type==LCD40x4) { 00080 _ctrl_idx=TextLCD::_LCDCtrl_1; // Select 2nd controller 00081 00082 _initCtrl(); // Init 2nd controller 00083 00084 // Secondary LCD controller Clearscreen 00085 _writeCommand(0x01); // cls, and set cursor to 0 00086 wait_ms(10); // The CLS command takes 1.64 ms. 00087 // Since we are not using the Busy flag, Lets be safe and take 10 ms 00088 00089 } 00090 00091 // Select and configure primary LCD controller 00092 _ctrl_idx=TextLCD::_LCDCtrl_0; // Select primary controller 00093 00094 _initCtrl(); // Init primary controller 00095 00096 // Primary LCD controller Clearscreen 00097 _writeCommand(0x01); // cls, and set cursor to 0 00098 00099 wait_ms(10); // The CLS command takes 1.64 ms. 00100 // Since we are not using the Busy flag, Lets be safe and take 10 ms 00101 00102 } 00103 00104 /* Init the LCD controller 00105 * 4-bit mode, number of lines, fonttype, no cursor etc 00106 * 00107 */ 00108 void TextLCD::_initCtrl() { 00109 00110 _setRS(false); // command mode 00111 00112 wait_ms(20); // Wait 20ms to ensure powered up 00113 00114 /* // send "Display Settings" 3 times (Only top nibble of 0x30 as we've got 4-bit bus) 00115 for (int i=0; i<3; i++) { 00116 _writeNibble(0x3); 00117 wait_ms(15); // This command takes 1.64ms, so wait for it 00118 } 00119 _writeNibble(0x2); // 4-bit mode 00120 wait_us(40); // most instructions take 40us 00121 */ 00122 // Display is now in 4-bit mode 00123 00124 00125 // ST7036 controller: Initialise Voltage booster for VLCD. VDD=3.3V 00126 // Note: supports 1,2 or 3 lines 00127 _writeByte( 0x39 ); // 8-bit Databus, 2 Lines, Select Instruction table 1 00128 wait_ms(30); // > 26,3ms 00129 _writeByte( 0x14 ); // Bias: 1/5, 2-Lines LCD 00130 wait_ms(30); // > 26,3ms 00131 _writeByte( 0x55 ); // Icon off, Booster on, Set Contrast C5, C4 00132 wait_ms(30); // > 26,3ms 00133 _writeByte( 0x6d ); // Voltagefollower On, Ampl ratio Rab2, Rab1, Rab0 00134 wait_ms(200); // > 200ms! 00135 _writeByte( 0x78 ); // Set Contrast C3, C2, C1, C0 00136 wait_ms(30); // > 26,3ms 00137 _writeByte( 0x38 ); // Return to Instruction table 0 00138 wait_ms(50); 00139 _writeByte( 0x0f ); // Return to Instruction table 0 00140 wait_ms(50); 00141 _writeByte( 0x01 ); // Return to Instruction table 0 00142 wait_ms(50); 00143 _writeByte( 0x06 ); // Return to Instruction table 0 00144 wait_ms(50); 00145 00146 00147 00148 // Initialise Display configuration 00149 switch (_type) { 00150 case LCD8x1: 00151 case LCD8x2B: 00152 //8x1 is a regular 1 line display 00153 //8x2B is a special case of 16x1 00154 _writeCommand(0x20); // Function set 001 DL N F - - 00155 // DL=0 (4 bits bus) 00156 // N=0 (1 line) 00157 // F=0 (5x7 dots font) 00158 break; 00159 00160 case LCD24x4: 00161 // Special mode for KS0078 00162 _writeCommand(0x2A); // Function set 001 DL N RE DH REV 00163 // DL=0 (4 bits bus) 00164 // N=1 (Dont care for KS0078) 00165 // RE=0 (Extended Regs, special mode for KS0078) 00166 // DH=1 (Disp shift, special mode for KS0078) 00167 // REV=0 (Reverse, special mode for KS0078) 00168 00169 _writeCommand(0x2E); // Function set 001 DL N RE DH REV 00170 // DL=0 (4 bits bus) 00171 // N=1 (Dont care for KS0078) 00172 // RE=1 (Ena Extended Regs, special mode for KS0078) 00173 // DH=1 (Disp shift, special mode for KS0078) 00174 // REV=0 (Reverse, special mode for KS0078) 00175 00176 _writeCommand(0x09); // Ext Function set 0000 1 FW BW NW 00177 // FW=0 (5-dot font, special mode for KS0078) 00178 // BW=0 (Cur BW invert disable, special mode for KS0078) 00179 // NW=1 (4 Line, special mode for KS0078) 00180 00181 _writeCommand(0x2A); // Function set 001 DL N RE DH REV 00182 // DL=0 (4 bits bus) 00183 // N=1 (Dont care for KS0078) 00184 // RE=0 (Dis. Extended Regs, special mode for KS0078) 00185 // DH=1 (Disp shift, special mode for KS0078) 00186 // REV=0 (Reverse, special mode for KS0078) 00187 break; 00188 00189 // All other LCD types are initialised as 2 Line displays (including LCD40x4) 00190 default: 00191 _writeCommand(0x39); // Function set 001 DL N F - - 00192 // DL=0 (4 bits bus) 00193 // N=1 (2 lines) 00194 // F=0 (5x7 dots font, only option for 2 line display) 00195 // - (Don't care) 00196 00197 break; 00198 } 00199 00200 _writeCommand(0x06); // Entry Mode 0000 01 CD S 00201 // Cursor Direction and Display Shift 00202 // CD=1 (Cur incr) 00203 // S=0 (No display shift) 00204 00205 // _writeCommand(0x0C); // Display Ctrl 0000 1 D C B 00206 // // Display On, Cursor Off, Blink Off 00207 setCursor(TextLCD::CurOff_BlkOff); 00208 setMode(TextLCD::DispOn); 00209 } 00210 00211 00212 // Clear the screen, Cursor home. 00213 void TextLCD::cls() { 00214 00215 // Select and configure second LCD controller when needed 00216 if(_type==LCD40x4) { 00217 _ctrl_idx=TextLCD::_LCDCtrl_1; // Select 2nd controller 00218 00219 // Second LCD controller Cursor always Off 00220 _setCursorAndDisplayMode(_currentMode, TextLCD::CurOff_BlkOff); 00221 00222 // Second LCD controller Clearscreen 00223 _writeCommand(0x01); // cls, and set cursor to 0 00224 00225 wait_ms(10); // The CLS command takes 1.64 ms. 00226 // Since we are not using the Busy flag, Lets be safe and take 10 ms 00227 00228 00229 _ctrl_idx=TextLCD::_LCDCtrl_0; // Select primary controller 00230 } 00231 00232 // Primary LCD controller Clearscreen 00233 _writeCommand(0x01); // cls, and set cursor to 0 00234 00235 wait_ms(10); // The CLS command takes 1.64 ms. 00236 // Since we are not using the Busy flag, Lets be safe and take 10 ms 00237 00238 // Restore cursormode on primary LCD controller when needed 00239 if(_type==LCD40x4) { 00240 _setCursorAndDisplayMode(_currentMode,_currentCursor); 00241 } 00242 00243 _row=0; // Reset Cursor location 00244 _column=0; 00245 } 00246 00247 // Move cursor to selected row and column 00248 void TextLCD::locate(int column, int row) { 00249 00250 // setAddress() does all the heavy lifting: 00251 // check column and row sanity, 00252 // switch controllers for LCD40x4 if needed 00253 // switch cursor for LCD40x4 if needed 00254 // set the new memory address to show cursor at correct location 00255 setAddress(column, row); 00256 00257 } 00258 00259 00260 // Write a single character (Stream implementation) 00261 int TextLCD::_putc(int value) { 00262 int addr; 00263 00264 if (value == '\n') { 00265 //No character to write 00266 00267 //Update Cursor 00268 _column = 0; 00269 _row++; 00270 if (_row >= rows()) { 00271 _row = 0; 00272 } 00273 } 00274 else { 00275 //Character to write 00276 _writeData(value); 00277 00278 //Update Cursor 00279 _column++; 00280 if (_column >= columns()) { 00281 _column = 0; 00282 _row++; 00283 if (_row >= rows()) { 00284 _row = 0; 00285 } 00286 } 00287 } //else 00288 00289 //Set next memoryaddress, make sure cursor blinks at next location 00290 addr = getAddress(_column, _row); 00291 _writeCommand(0x80 | addr); 00292 00293 return value; 00294 } 00295 00296 00297 // get a single character (Stream implementation) 00298 int TextLCD::_getc() { 00299 return -1; 00300 } 00301 00302 00303 // Set RS pin 00304 // Used for mbed pins, I2C bus expander or SPI shifregister 00305 void TextLCD::_setRS(bool value) 00306 { 00307 if (value) 00308 _rs = 1; // Set RS bit 00309 else 00310 _rs = 0; // Reset RS bit 00311 } 00312 00313 // Place the 4bit data on the databus 00314 // Used for mbed pins, I2C bus expander or SPI shifregister 00315 void TextLCD::_setData(int value) 00316 { 00317 // write the new data to the SPI portexpander 00318 _setCS(false); 00319 _spi->write(value); 00320 _setCS(true); 00321 } 00322 00323 00324 // Set CS line. 00325 // Only used for SPI bus 00326 void TextLCD::_setCS(bool value) 00327 { 00328 if (value) { 00329 _cs = 1; // Set CS pin 00330 } 00331 else 00332 _cs = 0; // Reset CS pin 00333 00334 } 00335 00336 00337 00338 // Write a byte using the 4-bit interface 00339 // Used for mbed pins, I2C bus expander or SPI shifregister 00340 void TextLCD::_writeByte(int value) { 00341 00342 _setData(value); // High nibble 00343 wait_us(1); // Data setup time 00344 } 00345 00346 void TextLCD::_writeCommand(int command) { 00347 00348 _setRS(false); 00349 wait_us(1); // Data setup time for RS 00350 00351 _writeByte(command); 00352 wait_us(40); // most instructions take 40us 00353 } 00354 00355 void TextLCD::_writeData(int data) { 00356 00357 _setRS(true); 00358 wait_us(1); // Data setup time for RS 00359 00360 _writeByte(data); 00361 wait_us(40); // data writes take 40us 00362 } 00363 00364 00365 00366 00367 // This replaces the original _address() method. 00368 // Left it in here for compatibility with older code. New applications should use getAddress() instead. 00369 int TextLCD::_address(int column, int row) { 00370 return 0x80 | getAddress(column, row); 00371 } 00372 00373 // This is new method to return the memory address based on row, column and displaytype. 00374 // 00375 int TextLCD::getAddress(int column, int row) { 00376 00377 switch (_type) { 00378 case LCD8x1: 00379 return 0x00 + column; 00380 00381 case LCD8x2B: 00382 // LCD8x2B is a special layout of LCD16x1 00383 if (row==0) 00384 return 0x00 + column; 00385 else 00386 return 0x08 + column; 00387 00388 00389 case LCD16x1: 00390 // LCD16x1 is a special layout of LCD8x2 00391 if (column<8) 00392 return 0x00 + column; 00393 else 00394 return 0x40 + (column - 8); 00395 00396 case LCD12x4: 00397 switch (row) { 00398 case 0: 00399 return 0x00 + column; 00400 case 1: 00401 return 0x40 + column; 00402 case 2: 00403 return 0x0C + column; 00404 case 3: 00405 return 0x4C + column; 00406 } 00407 00408 case LCD16x4: 00409 switch (row) { 00410 case 0: 00411 return 0x00 + column; 00412 case 1: 00413 return 0x40 + column; 00414 case 2: 00415 return 0x10 + column; 00416 case 3: 00417 return 0x50 + column; 00418 } 00419 00420 case LCD20x4: 00421 switch (row) { 00422 case 0: 00423 return 0x00 + column; 00424 case 1: 00425 return 0x40 + column; 00426 case 2: 00427 return 0x14 + column; 00428 case 3: 00429 return 0x54 + column; 00430 } 00431 00432 // Special mode for KS0078 00433 case LCD24x4: 00434 switch (row) { 00435 case 0: 00436 return 0x00 + column; 00437 case 1: 00438 return 0x20 + column; 00439 case 2: 00440 return 0x40 + column; 00441 case 3: 00442 return 0x60 + column; 00443 } 00444 00445 // Not sure about this one, seems wrong. 00446 case LCD16x2B: 00447 return 0x00 + (row * 40) + column; 00448 00449 case LCD8x2: 00450 case LCD12x2: 00451 case LCD16x2: 00452 case LCD20x2: 00453 case LCD24x2: 00454 case LCD40x2: 00455 return 0x00 + (row * 0x40) + column; 00456 00457 case LCD40x4: 00458 // LCD40x4 is a special case since it has 2 controllers 00459 // Each controller is configured as 40x2 00460 if (row<2) { 00461 // Test to see if we need to switch between controllers 00462 if (_ctrl_idx != _LCDCtrl_0) { 00463 00464 // Second LCD controller Cursor Off 00465 _setCursorAndDisplayMode(_currentMode, TextLCD::CurOff_BlkOff); 00466 00467 // Select primary controller 00468 _ctrl_idx = _LCDCtrl_0; 00469 00470 // Restore cursormode on primary LCD controller 00471 _setCursorAndDisplayMode(_currentMode, _currentCursor); 00472 } 00473 00474 return 0x00 + (row * 0x40) + column; 00475 } 00476 else { 00477 00478 // Test to see if we need to switch between controllers 00479 if (_ctrl_idx != _LCDCtrl_1) { 00480 // Primary LCD controller Cursor Off 00481 _setCursorAndDisplayMode(_currentMode, TextLCD::CurOff_BlkOff); 00482 00483 // Select secondary controller 00484 _ctrl_idx = _LCDCtrl_1; 00485 00486 // Restore cursormode on secondary LCD controller 00487 _setCursorAndDisplayMode(_currentMode, _currentCursor); 00488 } 00489 00490 return 0x00 + ((row-2) * 0x40) + column; 00491 } 00492 00493 // Should never get here. 00494 default: 00495 return 0x00; 00496 } 00497 } 00498 00499 00500 // Set row, column and update memoryaddress. 00501 // 00502 void TextLCD::setAddress(int column, int row) { 00503 00504 // Sanity Check column 00505 if (column < 0) { 00506 _column = 0; 00507 } 00508 else if (column >= columns()) { 00509 _column = columns() - 1; 00510 } else _column = column; 00511 00512 // Sanity Check row 00513 if (row < 0) { 00514 _row = 0; 00515 } 00516 else if (row >= rows()) { 00517 _row = rows() - 1; 00518 } else _row = row; 00519 00520 00521 // Compute the memory address 00522 // For LCD40x4: switch controllers if needed 00523 // switch cursor if needed 00524 int addr = getAddress(_column, _row); 00525 00526 _writeCommand(0x80 | addr); 00527 } 00528 00529 int TextLCD::columns() { 00530 switch (_type) { 00531 case LCD8x1: 00532 case LCD8x2: 00533 case LCD8x2B: 00534 return 8; 00535 00536 case LCD12x2: 00537 case LCD12x4: 00538 return 12; 00539 00540 case LCD16x1: 00541 case LCD16x2: 00542 case LCD16x2B: 00543 case LCD16x4: 00544 return 16; 00545 00546 case LCD20x2: 00547 case LCD20x4: 00548 return 20; 00549 00550 case LCD24x2: 00551 case LCD24x4: 00552 return 24; 00553 00554 case LCD40x2: 00555 case LCD40x4: 00556 return 40; 00557 00558 // Should never get here. 00559 default: 00560 return 0; 00561 } 00562 } 00563 00564 int TextLCD::rows() { 00565 switch (_type) { 00566 case LCD8x1: 00567 case LCD16x1: 00568 return 1; 00569 00570 case LCD8x2: 00571 case LCD8x2B: 00572 case LCD12x2: 00573 case LCD16x2: 00574 case LCD16x2B: 00575 case LCD20x2: 00576 case LCD24x2: 00577 case LCD40x2: 00578 return 2; 00579 00580 case LCD12x4: 00581 case LCD16x4: 00582 case LCD20x4: 00583 case LCD24x4: 00584 case LCD40x4: 00585 return 4; 00586 00587 // Should never get here. 00588 default: 00589 return 0; 00590 } 00591 } 00592 00593 00594 // Set the Cursor Mode (Cursor Off & Blink Off, Cursor On & Blink Off, Cursor Off & Blink On, Cursor On & Blink On 00595 void TextLCD::setCursor(TextLCD::LCDCursor cursorMode) { 00596 00597 // Save new cursor mode, needed when 2 controllers are in use or when display is switched off/on 00598 _currentCursor = cursorMode; 00599 00600 // Configure only current LCD controller 00601 _setCursorAndDisplayMode(_currentMode, _currentCursor); 00602 00603 } 00604 00605 // Set the Displaymode (On/Off) 00606 void TextLCD::setMode(TextLCD::LCDMode displayMode) { 00607 00608 // Save new displayMode, needed when 2 controllers are in use or when cursor is changed 00609 _currentMode = displayMode; 00610 00611 // Select and configure second LCD controller when needed 00612 if(_type==LCD40x4) { 00613 if (_ctrl_idx==TextLCD::_LCDCtrl_0) { 00614 // Configure primary LCD controller 00615 _setCursorAndDisplayMode(_currentMode, _currentCursor); 00616 00617 // Select 2nd controller 00618 _ctrl_idx=TextLCD::_LCDCtrl_1; 00619 00620 // Configure secondary LCD controller 00621 _setCursorAndDisplayMode(_currentMode, TextLCD::CurOff_BlkOff); 00622 00623 // Restore current controller 00624 _ctrl_idx=TextLCD::_LCDCtrl_0; 00625 } 00626 else { 00627 // Select primary controller 00628 _ctrl_idx=TextLCD::_LCDCtrl_0; 00629 00630 // Configure primary LCD controller 00631 _setCursorAndDisplayMode(_currentMode, TextLCD::CurOff_BlkOff); 00632 00633 // Restore current controller 00634 _ctrl_idx=TextLCD::_LCDCtrl_1; 00635 00636 // Configure secondary LCD controller 00637 _setCursorAndDisplayMode(_currentMode, _currentCursor); 00638 00639 } 00640 } 00641 else { 00642 // Configure primary LCD controller 00643 _setCursorAndDisplayMode(_currentMode, _currentCursor); 00644 } 00645 00646 } 00647 00648 00649 // Set the Displaymode (On/Off) and Cursortype for current controller 00650 void TextLCD::_setCursorAndDisplayMode(TextLCD::LCDMode displayMode, TextLCD::LCDCursor cursorType) { 00651 00652 // Configure current LCD controller 00653 _writeCommand(0x08 | displayMode | cursorType); 00654 } 00655 00656 00657 00658 void TextLCD::setUDC(unsigned char c, char *udc_data) { 00659 00660 // Select and configure second LCD controller when needed 00661 if(_type==LCD40x4) { 00662 _LCDCtrl_Idx current_ctrl_idx = _ctrl_idx; // Temp save current controller 00663 00664 // Select primary controller 00665 _ctrl_idx=TextLCD::_LCDCtrl_0; 00666 00667 // Configure primary LCD controller 00668 _setUDC(c, udc_data); 00669 00670 // Select 2nd controller 00671 _ctrl_idx=TextLCD::_LCDCtrl_1; 00672 00673 // Configure secondary LCD controller 00674 _setUDC(c, udc_data); 00675 00676 // Restore current controller 00677 _ctrl_idx=current_ctrl_idx; 00678 } 00679 else { 00680 // Configure primary LCD controller 00681 _setUDC(c, udc_data); 00682 } 00683 00684 } 00685 00686 void TextLCD::_setUDC(unsigned char c, char *udc_data) { 00687 00688 // Select CG RAM for current LCD controller 00689 _writeCommand(0x40 + ((c & 0x07) << 3)); //Set CG-RAM address, 00690 //8 sequential locations needed per UDC 00691 // Store UDC pattern 00692 for (int i=0; i<8; i++) { 00693 _writeData(*udc_data++); 00694 } 00695 00696 //Select DD RAM again for current LCD controller 00697 int addr = getAddress(_column, _row); 00698 _writeCommand(0x80 | addr); 00699 00700 }
Generated on Sun Jul 17 2022 18:32:24 by 1.7.2