Rod Coleman / I2CTextLCD
Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers I2CTextLCD.cpp Source File

I2CTextLCD.cpp

00001 /* mbed I2CTextLCD Library
00002  * Copyright (c) 2007-2009 sford
00003  * Copyright (c) 2010 Wim De Roeve  changed to work with I2C PCF8575
00004  * Released under the MIT License: http://mbed.org/license/mit
00005  */
00006 
00007 #include "I2CTextLCD.h"
00008 #include "mbed.h"
00009 #include "error.h"
00010 
00011 using namespace mbed;
00012 
00013 I2CTextLCD::I2CTextLCD(PinName sda, PinName scl, int i2cAddress , int columns, int rows,
00014                        bool backlight) : _i2c(sda, scl) {
00015 
00016     _i2cAddress = i2cAddress;
00017     _columns = columns;
00018     _rows = rows;
00019     _backlight=backlight;
00020     _i2c.frequency(70000); //  RC:2011-12-1 put this back in
00021 
00022     // Winstar 20x4 WH2004-NYG- needs 40ms after VDD> 4,5V
00023     //RC:2011-11-23: Newhaven 20x4 OLED data sheet method
00024     wait(0.055);
00025     init8574A();         // I2C chip PCF85774A init - E high - E falls with 0x2 on the D-nibble (set 4-bit mode command)
00026     writeCommand(0x2);   // 4-bit mode
00027     wait(0.05);
00028     writeCommand(0x2);   // 4-bit mode
00029     wait(0.05);
00030     writeCommand(0x2A);  // 2012-6-22 RC: Russian font Table. was 0x28. display OFF, "Function Set". Newhaven say 0x08, but this loses 2 rows!
00031     wait(0.05); 
00032     writeCommand(0x1);  // display clear
00033     wait(0.05);
00034     writeCommand(0x6);  // entry mode set
00035     wait(0.05); 
00036     writeCommand(0x2);  // 4-bit mode
00037     wait(0.05);                  
00038     writeCommand(0x0C); // ON-OFF ctrl: turns display ON, no cursor. Use 0x0E for cursor ON.
00039     /* 0x28 also works for Winstar WEH002004ALPP5N00000 OLED display. 0x29= westEuro fon table, 0x2A = UK/Russian*/
00040     wait(0.015);        // Wait 15ms to ensure powered up
00041 }
00042 
00043 int I2CTextLCD::_putc(int value) {
00044     if (value == '\n') {
00045         newline();
00046     } 
00047     else {
00048         writeData(value);
00049     }
00050     return value;
00051 }
00052 
00053 int I2CTextLCD::_getc() {
00054     return 0;
00055 }
00056 
00057 /* void I2CTextLCD::backlight(bool status) {
00058     _backlight=status;
00059     if (_backlight)
00060         writeI2CByte(BACKLIGHT_ON | E1_ON);
00061     else
00062         writeI2CByte(E1_ON);
00063 }
00064 */
00065 
00066 void I2CTextLCD::newline() {
00067     _column = 0;
00068     _row++;
00069     if (_row >= _rows) {
00070         _row = 0;
00071     }
00072     locate(_column, _row);
00073 }
00074 
00075 void I2CTextLCD::locate(int column, int row) {
00076     if (column < 0 || column >= _columns || row < 0 || row >= _rows) {
00077         error("locate(%d,%d) out of range on %dx%d display", column, row, _columns, _rows);
00078         return;
00079     }
00080     _row = row;
00081     _column = column;
00082     int address = 0x80;
00083     if (row==0){
00084     address = 0x80+_column;
00085     }
00086     else if (row==1){
00087     address= 0xc0+_column;
00088     }
00089     else if (row==2){
00090     address=0x94+_column;
00091     }
00092     else if(row==3){
00093     address=0xd4+_column;
00094     }
00095     /*
00096     int address = 0x80 + (_row * 40) + _column; // memory starts at 0x00, and is 40 chars long per row
00097     Set bit 7 also, to signify  ADDRESS SET mode.
00098      // pc_LCD.traceOut("locate %dx%d\r\n", column, row);
00099      */
00100     writeCommand(address);  // must set bit 7 to indicate address SET command
00101     wait(0.004);      // takes 1.5ms on Winstar LCD 20x4
00102 }
00103 
00104 void I2CTextLCD::cls() {
00105     writeCommand(0x01); // Clear Display
00106     wait(0.01f);     // This command takes 1.64 ms (LCD), 6.2ms for Winstar OLED
00107     locate(0, 0);
00108 }
00109 
00110 void I2CTextLCD::reset() {
00111     cls();
00112 }
00113 void I2CTextLCD::init8574A(void) {  // This puts the first command on the bus with E high
00114                                     // to prevent E going LOW at init with undef data lines, WS0010 does not like.
00115         char cmd[2]; 
00116         cmd[0]=(0x2)<<2;                 // lower nibble
00117         cmd[0]=cmd[0] & 0x3c; // 3C = 0011 1100
00118         //RS = 0 for commands - and for init (only), we start with E high
00119         cmd[0]=cmd[0]|0x02; //E=1
00120         _i2c.write( _i2cAddress, cmd,1); 
00121         cmd[0]=cmd[0]&0x3d; //E=0, RS preserved in bit 0
00122         _i2c.write( _i2cAddress, cmd,1); 
00123         wait_us(1);
00124     }
00125 void I2CTextLCD::writeByte(int c, bool rs) {  // This is the actual I2C transfer of the display data:
00126         char cmd[2]; 
00127         cmd[0]=c>>2;                  // upper nibble
00128         cmd[0]=cmd[0] & 0x3c;         // mask out bits other than 5:2 for data (RS and E are enabled separately, below:)
00129         cmd[1]=c<<2;                 // lower nibble
00130         cmd[1]=cmd[1] & 0x3c;        // 3C = 0011 1100
00131         if (rs) {
00132             cmd[0]=cmd[0] | 0x01;        // RS selects display DATA or a COMMAND. It's on bit 0:
00133             cmd[1]=cmd[1] | 0x01;
00134         }
00135         cmd[0]=cmd[0]|0x02; //E=1
00136         _i2c.write( _i2cAddress, cmd,1); 
00137         //wait_us(1); **  delays between nibbles not needed. At 70kHz, the time for the I2C command writes is 114us per byte
00138         cmd[0]=cmd[0]&0x3d; //E=0, RS preserved in bit 0. Data latched on fall of E (tS(d) = 40ns; tH(d) = 20ns)
00139         _i2c.write( _i2cAddress, cmd,1); 
00140         cmd[0]=cmd[1];         // prepare lower nibble
00141         cmd[0]=cmd[0]|0x02;    //E=1
00142         _i2c.write( _i2cAddress, cmd,1); 
00143         cmd[0]=cmd[0]&0x3d;    //E=0, RS preserved in bit 0. this preserves E low beween cycles.
00144         _i2c.write( _i2cAddress, cmd,1);
00145         // ****** RECOVERY TIME:
00146         wait_us(300);         // specified max. recovery time for all operations, except cls(), is 600us
00147     }
00148 
00149 void I2CTextLCD::writeCommand(int command) {
00150     // RS = 0;
00151     writeByte(command,false);
00152 }
00153 
00154 void I2CTextLCD::writeData(int data) {
00155     //RS = 1
00156     writeByte(data,true);
00157 
00158     _column++;
00159     if (_column >= _columns) {
00160         newline();
00161     }
00162 }