Skovbrynet / Mbed 2 deprecated TankCounter

Dependencies:   EthernetInterface NTPClient SDFileSystem TextLCD WebSocketClient mbed-rtos mbed Socket lwip-eth lwip-sys lwip FATFileSystem

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers TextLCD.cpp Source File

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 /* Create a TextLCD interface for using regular mbed pins
00035  *
00036  * @param rs     Instruction/data control line
00037  * @param e      Enable line (clock)
00038  * @param d4-d7  Data lines for using as a 4-bit interface
00039  * @param type   Sets the panel size/addressing mode (default = LCD16x2)
00040  * @param bl     Backlight control line (optional, default = NC)  
00041  * @param e2     Enable2 line (clock for second controller, LCD40x4 only) 
00042  * @param ctrl   LCD controller (default = HD44780)   
00043  */ 
00044 TextLCD::TextLCD(PinName rs, PinName e,
00045                  PinName d4, PinName d5, PinName d6, PinName d7,
00046                  LCDType type, PinName bl, PinName e2, LCDCtrl ctrl) : _rs(rs), _e(e), _bl(bl), _e2(e2),
00047                                                                        _d(d4, d5, d6, d7),
00048                                                                        _cs(NC), 
00049                                                                        _type(type),
00050                                                                        _ctrl(ctrl) {
00051 
00052   _busType = _PinBus;
00053 
00054   _init();
00055 
00056 }
00057 
00058 /* Create a TextLCD interface using an I2C PC8574 portexpander
00059  *
00060  * @param i2c             I2C Bus
00061  * @param deviceAddress   I2C slave address (PCF8574)
00062  * @param type            Sets the panel size/addressing mode (default = LCD16x2)
00063  * @param ctrl            LCD controller (default = HD44780)    
00064  */
00065 TextLCD::TextLCD(I2C *i2c, char deviceAddress, LCDType type, LCDCtrl ctrl) :
00066         _rs(NC), _e(NC), _bl(NC), _e2(NC),
00067         _d(NC),
00068         _i2c(i2c),        
00069         _cs(NC),
00070         _type(type), 
00071         _ctrl(ctrl) {        
00072          
00073   _slaveAddress = deviceAddress;
00074   _busType = _I2CBus;
00075 
00076   
00077   // Init the portexpander bus
00078   _lcd_bus = D_LCD_BUS_DEF;
00079   
00080   // write the new data to the portexpander
00081   _i2c->write(_slaveAddress, &_lcd_bus, 1);    
00082 
00083   _init();
00084     
00085 }
00086 
00087  /* Create a TextLCD interface using an SPI 74595 portexpander
00088   *
00089   * @param spi             SPI Bus
00090   * @param cs              chip select pin (active low)
00091   * @param type            Sets the panel size/addressing mode (default = LCD16x2)
00092   * @param ctrl            LCD controller (default = HD44780)      
00093   */
00094 TextLCD::TextLCD(SPI *spi, PinName cs, LCDType type, LCDCtrl ctrl) :
00095         _rs(NC), _e(NC), _bl(NC), _e2(NC),
00096         _d(NC),
00097         _spi(spi),        
00098         _cs(cs),
00099         _type(type),
00100         _ctrl(ctrl) {                
00101         
00102   _busType = _SPIBus;
00103 
00104   // Setup the spi for 8 bit data, low steady state clock,
00105   // rising edge capture, with a 500KHz or 1MHz clock rate  
00106   _spi->format(8,0);
00107   _spi->frequency(500000);    
00108   //_spi.frequency(1000000);    
00109 
00110 
00111   // Init the portexpander bus
00112   _lcd_bus = D_LCD_BUS_DEF;
00113   
00114   // write the new data to the portexpander
00115   _setCS(false);  
00116   _spi->write(_lcd_bus);   
00117   _setCS(true);  
00118   
00119   _init();
00120     
00121 }
00122 
00123 
00124 /*  Init the LCD Controller(s)
00125  *  Clear display 
00126  */
00127 void TextLCD::_init() {
00128   
00129   // Select and configure second LCD controller when needed
00130   if(_type==LCD40x4) {
00131     _ctrl_idx=TextLCD::_LCDCtrl_1; // Select 2nd controller
00132     
00133     _initCtrl();                   // Init 2nd controller
00134     
00135     // Secondary LCD controller Clearscreen
00136     _writeCommand(0x01);       // cls, and set cursor to 0    
00137     wait_ms(10);     // The CLS command takes 1.64 ms.
00138                      // Since we are not using the Busy flag, Lets be safe and take 10 ms
00139     
00140   }
00141     
00142   // Select and configure primary LCD controller
00143   _ctrl_idx=TextLCD::_LCDCtrl_0; // Select primary controller  
00144 
00145   _initCtrl();                   // Init primary controller
00146   
00147   // Primary LCD controller Clearscreen
00148   _writeCommand(0x01);       // cls, and set cursor to 0
00149 
00150   wait_ms(10);     // The CLS command takes 1.64 ms.
00151                    // Since we are not using the Busy flag, Lets be safe and take 10 ms
00152     
00153 } 
00154 
00155 /*  Init the LCD controller
00156  *  4-bit mode, number of lines, fonttype, no cursor etc
00157  *  
00158  */
00159 void TextLCD::_initCtrl() {
00160 
00161     _setRS(false);      // command mode
00162     
00163     wait_ms(20);        // Wait 20ms to ensure powered up
00164 
00165     // send "Display Settings" 3 times (Only top nibble of 0x30 as we've got 4-bit bus)    
00166     for (int i=0; i<3; i++) {
00167         _writeNibble(0x3);
00168         wait_ms(15);     // This command takes 1.64ms, so wait for it 
00169     }
00170     _writeNibble(0x2);   // 4-bit mode
00171     wait_us(40);         // most instructions take 40us
00172 
00173     // Display is now in 4-bit mode
00174 
00175     
00176     // Device specific initialisations for DC/DC converter to generate VLCD or VLED
00177     switch (_ctrl) {
00178       case ST7036:
00179           // ST7036 controller: Initialise Voltage booster for VLCD. VDD=5V
00180           // Note: supports 1,2 or 3 lines
00181           _writeByte( 0x29 );    // 4-bit Databus, 2 Lines, Select Instruction table 1
00182           wait_ms(30);           // > 26,3ms 
00183           _writeByte( 0x14 );    // Bias: 1/5, 2-Lines LCD 
00184           wait_ms(30);           // > 26,3ms
00185           _writeByte( 0x55 );    // Icon off, Booster on, Set Contrast C5, C4
00186           wait_ms(30);           // > 26,3ms
00187           _writeByte( 0x6d );    // Voltagefollower On, Ampl ratio Rab2, Rab1, Rab0
00188           wait_ms(200);          // > 200ms!
00189           _writeByte( 0x78 );    // Set Contrast C3, C2, C1, C0
00190           wait_ms(30);           // > 26,3ms
00191           _writeByte( 0x28 );    // Return to Instruction table 0
00192           wait_ms(50);
00193         
00194           break;
00195 
00196       case WS0010:         
00197           // WS0010 OLED controller: Initialise DC/DC Voltage converter for LEDs
00198           // Note: supports 1 or 2 lines (and 16x100 graphics)
00199           //       supports 4 fonts (English/Japanese (default), Western European-I, English/Russian, Western European-II)
00200 
00201                            // Cursor/Disp shift set 0001 SC RL  0 0
00202                            //
00203                            // Mode en Power set     0001 GC PWR 1 1                           
00204                            //  GC  = 0 (Graph Mode=1, Char Mode=0)             
00205                            //  PWR =   (DC/DC On/Off)
00206     
00207           //_writeCommand(0x13);   // DC/DC off            
00208     
00209           _writeCommand(0x17);   // DC/DC on
00210           wait_ms(10);
00211           
00212           break;
00213         
00214         default:
00215           // Devices that do not use DC/DC Voltage converters but external VLCD
00216           break;                  
00217     }
00218     
00219     // Initialise Display configuration
00220     switch (_type) {
00221         case LCD8x1:
00222         case LCD8x2B:        
00223             //8x1 is a regular 1 line display
00224             //8x2B is a special case of 16x1
00225             _writeCommand(0x20); // Function set 001 DL N F - -
00226                                  //  DL=0 (4 bits bus)             
00227                                  //   N=0 (1 line)
00228                                  //   F=0 (5x7 dots font)
00229             break;                                
00230             
00231         case LCD24x4:
00232             // Special mode for KS0078
00233             _writeCommand(0x2A); // Function set 001 DL N RE DH REV
00234                                  //   DL=0  (4 bits bus)             
00235                                  //    N=1  (Dont care for KS0078)
00236                                  //   RE=0  (Extended Regs, special mode for KS0078)
00237                                  //   DH=1  (Disp shift, special mode for KS0078)                                
00238                                  //   REV=0 (Reverse, special mode for KS0078)
00239 
00240             _writeCommand(0x2E); // Function set 001 DL N RE DH REV
00241                                  //   DL=0  (4 bits bus)             
00242                                  //    N=1  (Dont care for KS0078)
00243                                  //   RE=1  (Ena Extended Regs, special mode for KS0078)
00244                                  //   DH=1  (Disp shift, special mode for KS0078)                                
00245                                  //   REV=0 (Reverse, special mode for KS0078)
00246 
00247             _writeCommand(0x09); // Ext Function set 0000 1 FW BW NW
00248                                  //   FW=0  (5-dot font, special mode for KS0078)
00249                                  //   BW=0  (Cur BW invert disable, special mode for KS0078)
00250                                  //   NW=1  (4 Line, special mode for KS0078)                                
00251 
00252             _writeCommand(0x2A); // Function set 001 DL N RE DH REV
00253                                  //   DL=0  (4 bits bus)             
00254                                  //    N=1  (Dont care for KS0078)
00255                                  //   RE=0  (Dis. Extended Regs, special mode for KS0078)
00256                                  //   DH=1  (Disp shift, special mode for KS0078)                                
00257                                  //   REV=0 (Reverse, special mode for KS0078)
00258             break;
00259                                             
00260 // All other LCD types are initialised as 2 Line displays (including LCD40x4)
00261         default:
00262             _writeCommand(0x28); // Function set 001 DL N F - -
00263                                  //  DL=0 (4 bits bus) 
00264                                  //   N=1 (2 lines)
00265                                  //   F=0 (5x7 dots font, only option for 2 line display)
00266                                  //    -  (Don't care)                                
00267             
00268             break;
00269     }
00270 
00271     _writeCommand(0x06); // Entry Mode 0000 01 CD S 
00272                          //   Cursor Direction and Display Shift
00273                          //   CD=1 (Cur incr)
00274                          //   S=0  (No display shift)                        
00275 
00276 //    _writeCommand(0x0C); // Display Ctrl 0000 1 D C B
00277 //                         //   Display On, Cursor Off, Blink Off   
00278     setCursor(TextLCD::CurOff_BlkOff);     
00279     setMode(TextLCD::DispOn);     
00280 }
00281 
00282 
00283 // Clear the screen, Cursor home. 
00284 void TextLCD::cls() {
00285 
00286   // Select and configure second LCD controller when needed
00287   if(_type==LCD40x4) {
00288     _ctrl_idx=TextLCD::_LCDCtrl_1; // Select 2nd controller
00289 
00290     // Second LCD controller Cursor always Off
00291     _setCursorAndDisplayMode(_currentMode, TextLCD::CurOff_BlkOff);
00292 
00293     // Second LCD controller Clearscreen
00294     _writeCommand(0x01); // cls, and set cursor to 0    
00295 
00296     wait_ms(10);     // The CLS command takes 1.64 ms.
00297                      // Since we are not using the Busy flag, Lets be safe and take 10 ms
00298 
00299   
00300     _ctrl_idx=TextLCD::_LCDCtrl_0; // Select primary controller
00301   }
00302   
00303   // Primary LCD controller Clearscreen
00304   _writeCommand(0x01); // cls, and set cursor to 0
00305 
00306   wait_ms(10);     // The CLS command takes 1.64 ms.
00307                    // Since we are not using the Busy flag, Lets be safe and take 10 ms
00308 
00309   // Restore cursormode on primary LCD controller when needed
00310   if(_type==LCD40x4) {
00311     _setCursorAndDisplayMode(_currentMode,_currentCursor);     
00312   }
00313                    
00314   _row=0;          // Reset Cursor location
00315   _column=0;
00316 }
00317 
00318 // Move cursor to selected row and column
00319 void TextLCD::locate(int column, int row) {
00320     
00321    // setAddress() does all the heavy lifting:
00322    //   check column and row sanity, 
00323    //   switch controllers for LCD40x4 if needed
00324    //   switch cursor for LCD40x4 if needed
00325    //   set the new memory address to show cursor at correct location
00326    setAddress(column, row);
00327        
00328 }
00329     
00330 
00331 // Write a single character (Stream implementation)
00332 int TextLCD::_putc(int value) {
00333   int addr;
00334     
00335     if (value == '\n') {
00336       //No character to write
00337       
00338       //Update Cursor      
00339       _column = 0;
00340       _row++;
00341       if (_row >= rows()) {
00342         _row = 0;
00343       }      
00344     }
00345     else {
00346       //Character to write      
00347       _writeData(value); 
00348               
00349       //Update Cursor
00350       _column++;
00351       if (_column >= columns()) {
00352         _column = 0;
00353         _row++;
00354         if (_row >= rows()) {
00355           _row = 0;
00356         }
00357       }          
00358     } //else
00359 
00360     //Set next memoryaddress, make sure cursor blinks at next location
00361     addr = getAddress(_column, _row);
00362     _writeCommand(0x80 | addr);
00363             
00364     return value;
00365 }
00366 
00367 
00368 // get a single character (Stream implementation)
00369 int TextLCD::_getc() {
00370     return -1;
00371 }
00372 
00373 // Set E pin (or E2 pin)
00374 // Used for mbed pins, I2C bus expander or SPI shifregister
00375 void TextLCD::_setEnable(bool value) {
00376 
00377   switch(_busType) {
00378     case _PinBus : 
00379                     if(_ctrl_idx==TextLCD::_LCDCtrl_0) {
00380                       if (value)
00381                         _e  = 1;    // Set E bit 
00382                       else  
00383                         _e  = 0;    // Reset E bit  
00384                     }    
00385                     else {   
00386                       if (value)
00387                         _e2 = 1;    // Set E2 bit 
00388                       else  
00389                         _e2 = 0;    // Reset E2 bit  
00390                     }    
00391 
00392                     break;  
00393     
00394     case _I2CBus : 
00395     
00396                    if(_ctrl_idx==TextLCD::_LCDCtrl_0) {
00397                      if (value)
00398                        _lcd_bus |= D_LCD_E;     // Set E bit 
00399                      else                     
00400                        _lcd_bus &= ~D_LCD_E;    // Reset E bit                     
00401                    }
00402                    else {
00403                      if (value)
00404                        _lcd_bus |= D_LCD_E2;    // Set E2 bit 
00405                      else                     
00406                        _lcd_bus &= ~D_LCD_E2;   // Reset E2bit                     
00407                    }    
00408 
00409                    // write the new data to the I2C portexpander
00410                    _i2c->write(_slaveAddress, &_lcd_bus, 1);    
00411 
00412                    break;  
00413     
00414     case _SPIBus :
00415                    if(_ctrl_idx==TextLCD::_LCDCtrl_0) {
00416                      if (value)
00417                        _lcd_bus |= D_LCD_E;     // Set E bit 
00418                      else                     
00419                        _lcd_bus &= ~D_LCD_E;    // Reset E bit                     
00420                    }
00421                    else {
00422                      if (value)
00423                        _lcd_bus |= D_LCD_E2;    // Set E2 bit 
00424                      else                     
00425                        _lcd_bus &= ~D_LCD_E2;   // Reset E2 bit                     
00426                    }
00427                   
00428                    // write the new data to the SPI portexpander
00429                    _setCS(false);  
00430                    _spi->write(_lcd_bus);   
00431                    _setCS(true);  
00432   
00433                    break;
00434   }
00435 }    
00436 
00437 // Set RS pin
00438 // Used for mbed pins, I2C bus expander or SPI shifregister
00439 void TextLCD::_setRS(bool value) {
00440 
00441   switch(_busType) {
00442     case _PinBus : 
00443                     if (value)
00444                       _rs  = 1;    // Set RS bit 
00445                     else  
00446                       _rs  = 0;    // Reset RS bit 
00447 
00448                     break;  
00449     
00450     case _I2CBus : 
00451                    if (value)
00452                      _lcd_bus |= D_LCD_RS;    // Set RS bit 
00453                    else                     
00454                      _lcd_bus &= ~D_LCD_RS;   // Reset RS bit                     
00455 
00456                    // write the new data to the I2C portexpander
00457                    _i2c->write(_slaveAddress, &_lcd_bus, 1);    
00458                    
00459                    break;
00460                        
00461     case _SPIBus :
00462                    if (value)
00463                      _lcd_bus |= D_LCD_RS;    // Set RS bit 
00464                    else                     
00465                      _lcd_bus &= ~D_LCD_RS;   // Reset RS bit                     
00466       
00467                    // write the new data to the SPI portexpander
00468                    _setCS(false);  
00469                    _spi->write(_lcd_bus);   
00470                    _setCS(true);  
00471      
00472                    break;
00473   }
00474 
00475 }    
00476 
00477 // Set BL pin
00478 // Used for mbed pins, I2C bus expander or SPI shifregister
00479 void TextLCD::_setBL(bool value) {
00480 
00481   switch(_busType) {
00482     case _PinBus : 
00483                     if (value)
00484                       _bl  = 1;    // Set BL bit 
00485                     else  
00486                       _bl  = 0;    // Reset BL bit 
00487 
00488                     break;  
00489     
00490     case _I2CBus : 
00491                    if (value)
00492                      _lcd_bus |= D_LCD_BL;    // Set BL bit 
00493                    else                     
00494                      _lcd_bus &= ~D_LCD_BL;   // Reset BL bit                     
00495 
00496                    // write the new data to the I2C portexpander
00497                    _i2c->write(_slaveAddress, &_lcd_bus, 1);    
00498                    
00499                    break;
00500                        
00501     case _SPIBus :
00502                    if (value)
00503                      _lcd_bus |= D_LCD_BL;    // Set BL bit 
00504                    else                     
00505                      _lcd_bus &= ~D_LCD_BL;   // Reset BL bit                     
00506       
00507                    // write the new data to the SPI portexpander
00508                    _setCS(false);  
00509                    _spi->write(_lcd_bus);   
00510                    _setCS(true);  
00511      
00512                    break;
00513   }
00514 
00515 }    
00516 
00517 
00518 
00519 // Place the 4bit data on the databus
00520 // Used for mbed pins, I2C bus expander or SPI shifregister
00521 void TextLCD::_setData(int value) {
00522   int data;
00523   
00524   switch(_busType) {
00525     case _PinBus : 
00526                     _d = value & 0x0F;   // Write Databits 
00527 
00528                     break;  
00529     
00530     case _I2CBus : 
00531                     data = value & 0x0F;
00532                     if (data & 0x01)
00533                       _lcd_bus |= D_LCD_D4;   // Set Databit 
00534                     else                     
00535                       _lcd_bus &= ~D_LCD_D4;  // Reset Databit                     
00536 
00537                     if (data & 0x02)
00538                       _lcd_bus |= D_LCD_D5;   // Set Databit 
00539                     else                     
00540                       _lcd_bus &= ~D_LCD_D5;  // Reset Databit                     
00541 
00542                     if (data & 0x04)
00543                       _lcd_bus |= D_LCD_D6;   // Set Databit 
00544                     else                     
00545                       _lcd_bus &= ~D_LCD_D6;  // Reset Databit                     
00546 
00547                     if (data & 0x08)
00548                       _lcd_bus |= D_LCD_D7;   // Set Databit 
00549                     else                     
00550                       _lcd_bus &= ~D_LCD_D7;  // Reset Databit                     
00551                     
00552                     // write the new data to the I2C portexpander
00553                     _i2c->write(_slaveAddress, &_lcd_bus, 1);  
00554                    
00555                     break;                    
00556                     
00557     case _SPIBus :
00558     
00559                     data = value & 0x0F;
00560                     if (data & 0x01)
00561                       _lcd_bus |= D_LCD_D4;   // Set Databit 
00562                     else                     
00563                       _lcd_bus &= ~D_LCD_D4;  // Reset Databit                     
00564 
00565                     if (data & 0x02)
00566                       _lcd_bus |= D_LCD_D5;   // Set Databit 
00567                     else                     
00568                       _lcd_bus &= ~D_LCD_D5;  // Reset Databit                     
00569 
00570                     if (data & 0x04)
00571                       _lcd_bus |= D_LCD_D6;   // Set Databit 
00572                     else                     
00573                       _lcd_bus &= ~D_LCD_D6;  // Reset Databit                     
00574 
00575                     if (data & 0x08)
00576                       _lcd_bus |= D_LCD_D7;   // Set Databit 
00577                     else                     
00578                       _lcd_bus &= ~D_LCD_D7;  // Reset Databit                     
00579                     
00580                    // write the new data to the SPI portexpander
00581                    _setCS(false);  
00582                    _spi->write(_lcd_bus);   
00583                    _setCS(true);  
00584         
00585                    break;
00586   }
00587 
00588 }    
00589 
00590 
00591 // Set CS line.
00592 // Only used for SPI bus
00593 void TextLCD::_setCS(bool value) {
00594 
00595   if (value) {   
00596     _cs  = 1;    // Set CS pin 
00597   }  
00598   else  
00599     _cs  = 0;    // Reset CS pin 
00600   
00601 }
00602 
00603 
00604 // Write a nibble using the 4-bit interface
00605 // Used for mbed pins, I2C bus expander or SPI shifregister
00606 void TextLCD::_writeNibble(int value) {
00607 
00608 // Enable is Low
00609     _setEnable(true);        
00610     _setData(value & 0x0F);   // Low nibble
00611     wait_us(1); // Data setup time        
00612     _setEnable(false);    
00613     wait_us(1); // Datahold time
00614 
00615 // Enable is Low
00616 
00617 }
00618 
00619 
00620 // Write a byte using the 4-bit interface
00621 // Used for mbed pins, I2C bus expander or SPI shifregister
00622 void TextLCD::_writeByte(int value) {
00623 
00624 // Enable is Low
00625     _setEnable(true);          
00626     _setData(value >> 4);   // High nibble
00627     wait_us(1); // Data setup time    
00628     _setEnable(false);   
00629     wait_us(1); // Data hold time
00630     
00631     _setEnable(true);        
00632     _setData(value >> 0);   // Low nibble
00633     wait_us(1); // Data setup time        
00634     _setEnable(false);    
00635     wait_us(1); // Datahold time
00636 
00637 // Enable is Low
00638 
00639 }
00640 
00641 void TextLCD::_writeCommand(int command) {
00642 
00643     _setRS(false);        
00644     wait_us(1);  // Data setup time for RS       
00645     
00646     _writeByte(command);   
00647     wait_us(40); // most instructions take 40us            
00648 }
00649 
00650 void TextLCD::_writeData(int data) {
00651 
00652     _setRS(true);            
00653     wait_us(1);  // Data setup time for RS 
00654         
00655     _writeByte(data);
00656     wait_us(40); // data writes take 40us                
00657 }
00658 
00659 
00660 #if (0)
00661 // This is the original _address() method.
00662 // It is confusing since it returns the memoryaddress or-ed with the set memorycommand 0x80.
00663 // Left it in here for compatibility with older code. New applications should use getAddress() instead.
00664 // 
00665 int TextLCD::_address(int column, int row) {
00666     switch (_type) {
00667         case LCD20x4:
00668             switch (row) {
00669                 case 0:
00670                     return 0x80 + column;
00671                 case 1:
00672                     return 0xc0 + column;
00673                 case 2:
00674                     return 0x94 + column;
00675                 case 3:
00676                     return 0xd4 + column;
00677             }
00678         case LCD16x2B:
00679             return 0x80 + (row * 40) + column;
00680         case LCD16x2:
00681         case LCD20x2:
00682         default:
00683             return 0x80 + (row * 0x40) + column;
00684     }
00685 }
00686 #endif
00687 
00688 
00689 // This replaces the original _address() method.
00690 // Left it in here for compatibility with older code. New applications should use getAddress() instead.
00691 int TextLCD::_address(int column, int row) {
00692   return 0x80 | getAddress(column, row);
00693 }
00694 
00695 // This is new method to return the memory address based on row, column and displaytype.
00696 //
00697 int TextLCD::getAddress(int column, int row) {
00698 
00699     switch (_type) {
00700         case LCD8x1:
00701             return 0x00 + column;                        
00702 
00703         case LCD8x2B:
00704             // LCD8x2B is a special layout of LCD16x1
00705             if (row==0) 
00706               return 0x00 + column;                        
00707             else   
00708               return 0x08 + column;                        
00709 
00710 
00711         case LCD16x1:
00712             // LCD16x1 is a special layout of LCD8x2
00713             if (column<8) 
00714               return 0x00 + column;                        
00715             else   
00716               return 0x40 + (column - 8);                        
00717 
00718         case LCD12x4:
00719             switch (row) {
00720                 case 0:
00721                     return 0x00 + column;
00722                 case 1:
00723                     return 0x40 + column;
00724                 case 2:
00725                     return 0x0C + column;
00726                 case 3:
00727                     return 0x4C + column;
00728             }
00729 
00730         case LCD16x4:
00731             switch (row) {
00732                 case 0:
00733                     return 0x00 + column;
00734                 case 1:
00735                     return 0x40 + column;
00736                 case 2:
00737                     return 0x10 + column;
00738                 case 3:
00739                     return 0x50 + column;
00740             }
00741 
00742         case LCD20x4:
00743             switch (row) {
00744                 case 0:
00745                     return 0x00 + column;
00746                 case 1:
00747                     return 0x40 + column;
00748                 case 2:
00749                     return 0x14 + column;
00750                 case 3:
00751                     return 0x54 + column;
00752             }
00753 
00754 // Special mode for KS0078
00755         case LCD24x4:
00756             switch (row) {
00757                 case 0:
00758                     return 0x00 + column;
00759                 case 1:
00760                     return 0x20 + column;
00761                 case 2:
00762                     return 0x40 + column;
00763                 case 3:
00764                     return 0x60 + column;
00765             }
00766 
00767 // Not sure about this one, seems wrong.
00768         case LCD16x2B:      
00769             return 0x00 + (row * 40) + column;
00770       
00771         case LCD8x2:               
00772         case LCD12x2:                
00773         case LCD16x2:
00774         case LCD20x2:
00775         case LCD24x2:        
00776         case LCD40x2:                
00777             return 0x00 + (row * 0x40) + column;
00778 
00779         case LCD40x4:                
00780           // LCD40x4 is a special case since it has 2 controllers
00781           // Each controller is configured as 40x2
00782           if (row<2) { 
00783             // Test to see if we need to switch between controllers  
00784             if (_ctrl_idx != _LCDCtrl_0) {
00785 
00786               // Second LCD controller Cursor Off
00787               _setCursorAndDisplayMode(_currentMode, TextLCD::CurOff_BlkOff);    
00788 
00789               // Select primary controller
00790               _ctrl_idx = _LCDCtrl_0;
00791 
00792               // Restore cursormode on primary LCD controller
00793               _setCursorAndDisplayMode(_currentMode, _currentCursor);    
00794             }           
00795             
00796             return 0x00 + (row * 0x40) + column;          
00797           }
00798           else {
00799 
00800             // Test to see if we need to switch between controllers  
00801             if (_ctrl_idx != _LCDCtrl_1) {
00802               // Primary LCD controller Cursor Off
00803               _setCursorAndDisplayMode(_currentMode, TextLCD::CurOff_BlkOff);    
00804 
00805               // Select secondary controller
00806               _ctrl_idx = _LCDCtrl_1;
00807 
00808               // Restore cursormode on secondary LCD controller
00809               _setCursorAndDisplayMode(_currentMode, _currentCursor);    
00810             }           
00811                                    
00812             return 0x00 + ((row-2) * 0x40) + column;          
00813           } 
00814             
00815 // Should never get here.
00816         default:            
00817             return 0x00;        
00818     }
00819 }
00820 
00821 
00822 // Set row, column and update memoryaddress.
00823 //
00824 void TextLCD::setAddress(int column, int row) {
00825    
00826 // Sanity Check column
00827     if (column < 0) {
00828       _column = 0;
00829     }
00830     else if (column >= columns()) {
00831       _column = columns() - 1;
00832     } else _column = column;
00833     
00834 // Sanity Check row
00835     if (row < 0) {
00836       _row = 0;
00837     }
00838     else if (row >= rows()) {
00839       _row = rows() - 1;
00840     } else _row = row;
00841     
00842     
00843 // Compute the memory address
00844 // For LCD40x4:  switch controllers if needed
00845 //               switch cursor if needed
00846     int addr = getAddress(_column, _row);
00847     
00848     _writeCommand(0x80 | addr);
00849 }
00850 
00851 int TextLCD::columns() {
00852     switch (_type) {
00853         case LCD8x1:
00854         case LCD8x2:
00855         case LCD8x2B:                
00856             return 8;
00857         
00858         case LCD12x2:        
00859         case LCD12x4:        
00860             return 12;        
00861 
00862         case LCD16x1:        
00863         case LCD16x2:
00864         case LCD16x2B:
00865         case LCD16x4:        
00866             return 16;
00867             
00868         case LCD20x2:
00869         case LCD20x4:
00870             return 20;
00871 
00872         case LCD24x2:
00873         case LCD24x4:        
00874             return 24;        
00875 
00876         case LCD40x2:
00877         case LCD40x4:
00878             return 40;        
00879         
00880 // Should never get here.
00881         default:
00882             return 0;
00883     }
00884 }
00885 
00886 int TextLCD::rows() {
00887     switch (_type) {
00888         case LCD8x1: 
00889         case LCD16x1:         
00890             return 1;           
00891 
00892         case LCD8x2:  
00893         case LCD8x2B:                        
00894         case LCD12x2:                      
00895         case LCD16x2:
00896         case LCD16x2B:
00897         case LCD20x2:
00898         case LCD24x2:        
00899         case LCD40x2:                
00900             return 2;
00901                     
00902         case LCD12x4:        
00903         case LCD16x4:
00904         case LCD20x4:
00905         case LCD24x4:        
00906         case LCD40x4:
00907             return 4;
00908 
00909 // Should never get here.      
00910         default:
00911             return 0;        
00912     }
00913 }
00914 
00915 
00916 // Set the Cursor Mode (Cursor Off & Blink Off, Cursor On & Blink Off, Cursor Off & Blink On, Cursor On & Blink On
00917 void TextLCD::setCursor(TextLCD::LCDCursor cursorMode) { 
00918 
00919   // Save new cursor mode, needed when 2 controllers are in use or when display is switched off/on
00920   _currentCursor = cursorMode;
00921     
00922   // Configure only current LCD controller
00923   _setCursorAndDisplayMode(_currentMode, _currentCursor);
00924     
00925 }
00926 
00927 // Set the Displaymode (On/Off)
00928 void TextLCD::setMode(TextLCD::LCDMode displayMode) { 
00929 
00930   // Save new displayMode, needed when 2 controllers are in use or when cursor is changed
00931   _currentMode = displayMode;
00932     
00933   // Select and configure second LCD controller when needed
00934   if(_type==LCD40x4) {
00935     if (_ctrl_idx==TextLCD::_LCDCtrl_0) {
00936       // Configure primary LCD controller
00937       _setCursorAndDisplayMode(_currentMode, _currentCursor);
00938 
00939       // Select 2nd controller
00940       _ctrl_idx=TextLCD::_LCDCtrl_1;
00941   
00942       // Configure secondary LCD controller    
00943       _setCursorAndDisplayMode(_currentMode, TextLCD::CurOff_BlkOff);
00944 
00945       // Restore current controller
00946       _ctrl_idx=TextLCD::_LCDCtrl_0;       
00947     }
00948     else {
00949       // Select primary controller
00950       _ctrl_idx=TextLCD::_LCDCtrl_0;
00951     
00952       // Configure primary LCD controller
00953       _setCursorAndDisplayMode(_currentMode, TextLCD::CurOff_BlkOff);
00954        
00955       // Restore current controller
00956       _ctrl_idx=TextLCD::_LCDCtrl_1;
00957 
00958       // Configure secondary LCD controller    
00959       _setCursorAndDisplayMode(_currentMode, _currentCursor);
00960 
00961     }
00962   }
00963   else {
00964     // Configure primary LCD controller
00965     _setCursorAndDisplayMode(_currentMode, _currentCursor);
00966   }   
00967     
00968 }
00969 
00970 
00971 // Set the Displaymode (On/Off) and Cursortype for current controller
00972 void TextLCD::_setCursorAndDisplayMode(TextLCD::LCDMode displayMode, TextLCD::LCDCursor cursorType) { 
00973     
00974     // Configure current LCD controller       
00975     _writeCommand(0x08 | displayMode | cursorType);
00976 }
00977 
00978 // Set the Backlight mode (Off/On)
00979 void TextLCD::setBacklight(TextLCD::LCDBacklight backlightMode) {
00980 
00981     if (backlightMode == LightOn) {
00982       _setBL(true);
00983     }
00984     else {
00985       _setBL(false);    
00986     }
00987 } 
00988 
00989 
00990 void TextLCD::setUDC(unsigned char c, char *udc_data) {
00991   
00992   // Select and configure second LCD controller when needed
00993   if(_type==LCD40x4) {
00994     _LCDCtrl_Idx current_ctrl_idx = _ctrl_idx; // Temp save current controller
00995    
00996     // Select primary controller     
00997     _ctrl_idx=TextLCD::_LCDCtrl_0;
00998     
00999     // Configure primary LCD controller
01000     _setUDC(c, udc_data);
01001 
01002     // Select 2nd controller
01003     _ctrl_idx=TextLCD::_LCDCtrl_1;
01004   
01005     // Configure secondary LCD controller    
01006     _setUDC(c, udc_data);
01007 
01008     // Restore current controller
01009     _ctrl_idx=current_ctrl_idx;       
01010   }
01011   else {
01012     // Configure primary LCD controller
01013     _setUDC(c, udc_data); 
01014   }
01015     
01016 }
01017 
01018 void TextLCD::_setUDC(unsigned char c, char *udc_data) {
01019   
01020   // Select CG RAM for current LCD controller
01021   _writeCommand(0x40 + ((c & 0x07) << 3)); //Set CG-RAM address,
01022                                            //8 sequential locations needed per UDC
01023   // Store UDC pattern 
01024   for (int i=0; i<8; i++) {
01025     _writeData(*udc_data++);
01026   }
01027    
01028   //Select DD RAM again for current LCD controller
01029   int addr = getAddress(_column, _row);
01030   _writeCommand(0x80 | addr);
01031   
01032 }