CaryCoders / AdaFruit_RGBLCDShield

Dependents:  

Fork of AdaFruit_RGBLCDShield by Justin Howard

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers AdaFruit_RGBLCDShield.cpp Source File

AdaFruit_RGBLCDShield.cpp

00001 /*************************************************** 
00002   This is a library for the Adafruit RGB 16x2 LCD Shield 
00003   Pick one up at the Adafruit shop!
00004   ---------> http://http://www.adafruit.com/products/714
00005 
00006   The shield uses I2C to communicate, 2 pins are required to  
00007   interface
00008   Adafruit invests time and resources providing this open source code, 
00009   please support Adafruit and open-source hardware by purchasing 
00010   products from Adafruit!
00011 
00012   Written by Limor Fried/Ladyada for Adafruit Industries.  
00013   BSD license, all text above must be included in any redistribution
00014  ****************************************************/
00015 
00016 #include "Adafruit_RGBLCDShield.h"
00017 
00018 #include <stdio.h>
00019 #include <string.h>
00020 #include <inttypes.h>
00021 
00022 // New MBED code to handle porting
00023 #define OUTPUT DIR_OUTPUT
00024 #define INPUT DIR_INPUT
00025 
00026 #define LOW 0
00027 #define HIGH 1
00028 
00029 #define delayMicroseconds(a) wait(a / 1000000)
00030 
00031 /* MBED TURNED OFF
00032 
00033 Arduino i2c (wire) interface
00034 
00035 #include <Wire.h>
00036 #ifdef __AVR__
00037  #define WIRE Wire
00038 #else // Arduino Due
00039  #define WIRE Wire1
00040 #endif
00041 
00042 #if ARDUINO >= 100
00043  #include "Arduino.h"
00044 #else
00045  #include "WProgram.h"
00046 #endif
00047 */
00048 
00049 // When the display powers up, it is configured as follows:
00050 //
00051 // 1. Display clear
00052 // 2. Function set: 
00053 //    DL = 1; 8-bit interface data 
00054 //    N = 0; 1-line display 
00055 //    F = 0; 5x8 dot character font 
00056 // 3. Display on/off control: 
00057 //    D = 0; Display off 
00058 //    C = 0; Cursor off 
00059 //    B = 0; Blinking off 
00060 // 4. Entry mode set: 
00061 //    I/D = 1; Increment by 1 
00062 //    S = 0; No shift 
00063 //
00064 // Note, however, that resetting the Arduino doesn't reset the LCD, so we
00065 // can't assume that its in that state when a sketch starts (and the
00066 // RGBLCDShield constructor is called).
00067 
00068 // MBED - wired in serial
00069 // MBED - wired in _i2c
00070 Adafruit_RGBLCDShield::Adafruit_RGBLCDShield(MCP23017 & inMCP)
00071     : Serial(USBTX, USBRX)
00072     , _i2c(inMCP)
00073 {
00074   _i2cAddr = 0;
00075 
00076   _displayfunction = LCD_4BITMODE | LCD_1LINE | LCD_5x8DOTS;
00077   
00078   // the I/O expander pinout
00079   _rs_pin = 15;
00080   _rw_pin = 14;
00081   _enable_pin = 13;
00082   _data_pins[0] = 12;  // really d4
00083   _data_pins[1] = 11;  // really d5
00084   _data_pins[2] = 10;  // really d6
00085   _data_pins[3] = 9;  // really d7
00086   
00087   _button_pins[0] = 0;
00088   _button_pins[1] = 1;
00089   _button_pins[2] = 2;
00090   _button_pins[3] = 3;
00091   _button_pins[4] = 4;
00092   // we can't begin() yet :(
00093 }
00094 
00095 Adafruit_RGBLCDShield::Adafruit_RGBLCDShield
00096 (
00097     MCP23017 &  inMCP,
00098     uint8_t     inRs,
00099     uint8_t     inRw,
00100     uint8_t     inEn,
00101     uint8_t     inD4,
00102     uint8_t     inD5,
00103     uint8_t     inD6,
00104     uint8_t     inD7
00105 )
00106     : Serial(USBTX, USBRX)
00107     , _i2c(inMCP)
00108 {
00109   _i2cAddr = 0;
00110 
00111   _displayfunction = LCD_4BITMODE | LCD_1LINE | LCD_5x8DOTS;
00112   
00113   // the I/O expander pinout
00114   _rs_pin = inRs;
00115   _rw_pin = inRw;
00116   _enable_pin = inEn;
00117   _data_pins[0] = inD4;  // really d4
00118   _data_pins[1] = inD5;  // really d5
00119   _data_pins[2] = inD6;  // really d6
00120   _data_pins[3] = inD7;  // really d7
00121   
00122   // we can't begin() yet :(
00123 }
00124 
00125 void Adafruit_RGBLCDShield::init(uint8_t fourbitmode, uint8_t rs, uint8_t rw, uint8_t enable,
00126              uint8_t d0, uint8_t d1, uint8_t d2, uint8_t d3,
00127              uint8_t d4, uint8_t d5, uint8_t d6, uint8_t d7)
00128 {
00129   _rs_pin = rs;
00130   _rw_pin = rw;
00131   _enable_pin = enable;
00132   
00133   _data_pins[0] = d0;
00134   _data_pins[1] = d1;
00135   _data_pins[2] = d2;
00136   _data_pins[3] = d3; 
00137   _data_pins[4] = d4;
00138   _data_pins[5] = d5;
00139   _data_pins[6] = d6;
00140   _data_pins[7] = d7; 
00141 
00142   _i2cAddr = 255;
00143 
00144   _pinMode(_rs_pin, OUTPUT);
00145   // we can save 1 pin by not using RW. Indicate by passing 255 instead of pin#
00146   if (_rw_pin != 255) { 
00147     _pinMode(_rw_pin, OUTPUT);
00148   }
00149   _pinMode(_enable_pin, OUTPUT);
00150   
00151 
00152   if (fourbitmode)
00153     _displayfunction = LCD_4BITMODE | LCD_1LINE | LCD_5x8DOTS;
00154   else 
00155     _displayfunction = LCD_8BITMODE | LCD_1LINE | LCD_5x8DOTS;
00156   
00157   begin(16, 1);  
00158 }
00159 
00160 void Adafruit_RGBLCDShield::begin(uint8_t cols, uint8_t lines, uint8_t dotsize) {    
00161   // check if i2c
00162   if (_i2cAddr != 255) {    
00163     //_i2c.begin(_i2cAddr);
00164     //WIRE.begin();
00165     
00166     _i2c.reset();
00167     
00168     _i2c.pinMode(8, OUTPUT);
00169     _i2c.pinMode(6, OUTPUT);
00170     _i2c.pinMode(7, OUTPUT);
00171 
00172 //    setBacklight(0x7);
00173     setBacklight(0x2);
00174 
00175 
00176     if (_rw_pin)
00177       _i2c.pinMode(_rw_pin, OUTPUT);
00178 
00179     _i2c.pinMode(_rs_pin, OUTPUT);
00180     _i2c.pinMode(_enable_pin, OUTPUT);
00181     for (uint8_t i=0; i<4; i++) 
00182       _i2c.pinMode(_data_pins[i], OUTPUT);
00183 
00184     unsigned short nPullups = 0;
00185     for (uint8_t i=0; i<5; i++) {
00186       _i2c.pinMode(_button_pins[i], INPUT);
00187       nPullups |= (1 << _button_pins[i]);
00188       //_i2c.pullUp(_button_pins[i], 1);
00189     }
00190     
00191     _i2c.internalPullupMask(nPullups);
00192   }
00193 
00194   if (lines > 1) {
00195     _displayfunction |= LCD_2LINE;
00196   }
00197   _numlines = lines;
00198   _currline = 0;
00199 
00200   // for some 1 line displays you can select a 10 pixel high font
00201   if ((dotsize != 0) && (lines == 1)) {
00202     _displayfunction |= LCD_5x10DOTS;
00203   }
00204 
00205   // SEE PAGE 45/46 FOR INITIALIZATION SPECIFICATION!
00206   // according to datasheet, we need at least 40ms after power rises above 2.7V
00207   // before sending commands. Arduino can turn on way befer 4.5V so we'll wait 50
00208   delayMicroseconds(50000); 
00209   // Now we pull both RS and R/W low to begin commands
00210   _digitalWrite(_rs_pin, LOW);
00211   _digitalWrite(_enable_pin, LOW);
00212   if (_rw_pin != 255) { 
00213     _digitalWrite(_rw_pin, LOW);
00214   }
00215   
00216   //put the LCD into 4 bit or 8 bit mode
00217   if (! (_displayfunction & LCD_8BITMODE)) {
00218     // this is according to the hitachi HD44780 datasheet
00219     // figure 24, pg 46
00220 
00221     // we start in 8bit mode, try to set 4 bit mode
00222     write4bits(0x03);
00223     delayMicroseconds(4500); // wait min 4.1ms
00224 
00225     // second try
00226     write4bits(0x03);
00227     delayMicroseconds(4500); // wait min 4.1ms
00228     
00229     // third go!
00230     write4bits(0x03); 
00231     delayMicroseconds(150);
00232 
00233     // finally, set to 8-bit interface
00234     write4bits(0x02);
00235   } else {
00236     // this is according to the hitachi HD44780 datasheet
00237     // page 45 figure 23
00238 
00239     // Send function set command sequence
00240     command(LCD_FUNCTIONSET | _displayfunction);
00241     delayMicroseconds(4500);  // wait more than 4.1ms
00242 
00243     // second try
00244     command(LCD_FUNCTIONSET | _displayfunction);
00245     delayMicroseconds(150);
00246 
00247     // third go
00248     command(LCD_FUNCTIONSET | _displayfunction);
00249   }
00250 
00251   // finally, set # lines, font size, etc.
00252   command(LCD_FUNCTIONSET | _displayfunction);
00253   
00254   // turn the display on with no cursor or blinking default
00255   _displaycontrol = LCD_DISPLAYON | LCD_CURSOROFF | LCD_BLINKOFF;
00256   display();
00257 
00258   // clear it off
00259   clear();
00260 
00261   // Initialize to default text direction (for romance languages)
00262   _displaymode = LCD_ENTRYLEFT | LCD_ENTRYSHIFTDECREMENT;
00263   // set the entry mode
00264   command(LCD_ENTRYMODESET | _displaymode);
00265 }
00266 
00267 /********** high level commands, for the user! */
00268 void Adafruit_RGBLCDShield::clear()
00269 {
00270   command(LCD_CLEARDISPLAY);  // clear display, set cursor position to zero
00271   delayMicroseconds(2000);  // this command takes a long time!
00272 }
00273 
00274 void Adafruit_RGBLCDShield::home()
00275 {
00276   command(LCD_RETURNHOME);  // set cursor position to zero
00277   delayMicroseconds(2000);  // this command takes a long time!
00278 }
00279 
00280 uint8_t Adafruit_RGBLCDShield::lines()
00281 {
00282     return _numlines;
00283 }
00284 
00285 void Adafruit_RGBLCDShield::setCursor(uint8_t col, uint8_t row)
00286 {
00287   int row_offsets[] = { 0x00, 0x40, 0x14, 0x54 };
00288   if ( row > _numlines ) {
00289     row = _numlines-1;    // we count rows starting w/0
00290   }
00291   
00292   command(LCD_SETDDRAMADDR | (col + row_offsets[row]));
00293 }
00294 
00295 // Turn the display on/off (quickly)
00296 void Adafruit_RGBLCDShield::noDisplay() {
00297   _displaycontrol &= ~LCD_DISPLAYON;
00298   command(LCD_DISPLAYCONTROL | _displaycontrol);
00299 }
00300 void Adafruit_RGBLCDShield::display() {
00301   _displaycontrol |= LCD_DISPLAYON;
00302   command(LCD_DISPLAYCONTROL | _displaycontrol);
00303 }
00304 
00305 // Turns the underline cursor on/off
00306 void Adafruit_RGBLCDShield::noCursor() {
00307   _displaycontrol &= ~LCD_CURSORON;
00308   command(LCD_DISPLAYCONTROL | _displaycontrol);
00309 }
00310 void Adafruit_RGBLCDShield::cursor() {
00311   _displaycontrol |= LCD_CURSORON;
00312   command(LCD_DISPLAYCONTROL | _displaycontrol);
00313 }
00314 
00315 // Turn on and off the blinking cursor
00316 void Adafruit_RGBLCDShield::noBlink() {
00317   _displaycontrol &= ~LCD_BLINKON;
00318   command(LCD_DISPLAYCONTROL | _displaycontrol);
00319 }
00320 void Adafruit_RGBLCDShield::blink() {
00321   _displaycontrol |= LCD_BLINKON;
00322   command(LCD_DISPLAYCONTROL | _displaycontrol);
00323 }
00324 
00325 // These commands scroll the display without changing the RAM
00326 void Adafruit_RGBLCDShield::scrollDisplayLeft(void) {
00327   command(LCD_CURSORSHIFT | LCD_DISPLAYMOVE | LCD_MOVELEFT);
00328 }
00329 void Adafruit_RGBLCDShield::scrollDisplayRight(void) {
00330   command(LCD_CURSORSHIFT | LCD_DISPLAYMOVE | LCD_MOVERIGHT);
00331 }
00332 
00333 // This is for text that flows Left to Right
00334 void Adafruit_RGBLCDShield::leftToRight(void) {
00335   _displaymode |= LCD_ENTRYLEFT;
00336   command(LCD_ENTRYMODESET | _displaymode);
00337 }
00338 
00339 // This is for text that flows Right to Left
00340 void Adafruit_RGBLCDShield::rightToLeft(void) {
00341   _displaymode &= ~LCD_ENTRYLEFT;
00342   command(LCD_ENTRYMODESET | _displaymode);
00343 }
00344 
00345 // This will 'right justify' text from the cursor
00346 void Adafruit_RGBLCDShield::autoscroll(void) {
00347   _displaymode |= LCD_ENTRYSHIFTINCREMENT;
00348   command(LCD_ENTRYMODESET | _displaymode);
00349 }
00350 
00351 // This will 'left justify' text from the cursor
00352 void Adafruit_RGBLCDShield::noAutoscroll(void) {
00353   _displaymode &= ~LCD_ENTRYSHIFTINCREMENT;
00354   command(LCD_ENTRYMODESET | _displaymode);
00355 }
00356 
00357 // Allows us to fill the first 8 CGRAM locations
00358 // with custom characters
00359 void Adafruit_RGBLCDShield::createChar(uint8_t location, uint8_t charmap[]) {
00360   location &= 0x7; // we only have 8 locations 0-7
00361   command(LCD_SETCGRAMADDR | (location << 3));
00362   for (int i=0; i<8; i++) {
00363     _putc(charmap[i]);
00364   }
00365   command(LCD_SETDDRAMADDR);  // unfortunately resets the location to 0,0
00366 }
00367 
00368 /*********** mid level commands, for sending data/cmds */
00369 
00370 inline void Adafruit_RGBLCDShield::command(uint8_t value) {
00371   send(value, LOW);
00372 }
00373 
00374 #if ARDUINO >= 100
00375 inline size_t Adafruit_RGBLCDShield::write(uint8_t value) {
00376   send(value, HIGH);
00377   return 1;
00378 }
00379 #else
00380 //inline void Adafruit_RGBLCDShield::write(uint8_t value) {
00381 int Adafruit_RGBLCDShield::_putc(int value) {
00382   send(value, HIGH);
00383   return 1;
00384 }
00385 #endif
00386 
00387 /************ low level data pushing commands **********/
00388 
00389 // little wrapper for i/o writes
00390 void  Adafruit_RGBLCDShield::_digitalWrite(uint8_t p, uint8_t d) {
00391   if (_i2cAddr != 255) {
00392     // an i2c command
00393     _i2c.digitalWrite(p, d);
00394   } else {
00395     // straightup IO
00396     // MBED TURNED OFF
00397     //digitalWrite(p, d);
00398   }
00399 }
00400 
00401 // Allows to set the backlight, if the LCD backpack is used
00402 void Adafruit_RGBLCDShield::setBacklight(uint8_t status) {
00403   // check if i2c or SPI
00404   _i2c.digitalWrite(8, ~(status >> 2) & 0x1);
00405   _i2c.digitalWrite(7, ~(status >> 1) & 0x1);
00406   _i2c.digitalWrite(6, ~status & 0x1);
00407 }
00408 
00409 // little wrapper for i/o directions
00410 void  Adafruit_RGBLCDShield::_pinMode(uint8_t p, uint8_t d) {
00411   if (_i2cAddr != 255) {
00412     // an i2c command
00413     _i2c.pinMode(p, d);
00414   } else {
00415     // straightup IO
00416     // MBED TURNED OFF
00417     //pinMode(p, d);
00418   }
00419 }
00420 
00421 // write either command or data, with automatic 4/8-bit selection
00422 void Adafruit_RGBLCDShield::send(uint8_t value, uint8_t mode) {
00423   _digitalWrite(_rs_pin, mode);
00424 
00425   // if there is a RW pin indicated, set it low to Write
00426   if (_rw_pin != 255) { 
00427     _digitalWrite(_rw_pin, LOW);
00428   }
00429   
00430   if (_displayfunction & LCD_8BITMODE) {
00431     write8bits(value); 
00432   } else {
00433     write4bits(value>>4);
00434     write4bits(value);
00435   }
00436 }
00437 
00438 void Adafruit_RGBLCDShield::pulseEnable(void) {
00439   _digitalWrite(_enable_pin, LOW);
00440   delayMicroseconds(1);    
00441   _digitalWrite(_enable_pin, HIGH);
00442   delayMicroseconds(1);    // enable pulse must be >450ns
00443   _digitalWrite(_enable_pin, LOW);
00444   delayMicroseconds(100);   // commands need > 37us to settle
00445 }
00446 
00447 void Adafruit_RGBLCDShield::write4bits(uint8_t value) {
00448   if (_i2cAddr != 255) {
00449     uint16_t out = 0;
00450 
00451     //out = _i2c.readGPIOAB();
00452     out = _i2c.digitalWordRead();
00453 
00454     // speed up for i2c since its sluggish
00455     for (int i = 0; i < 4; i++) {
00456       out &= ~(1 << _data_pins[i]);
00457       out |= ((value >> i) & 0x1) << _data_pins[i];
00458     }
00459 
00460     // make sure enable is low
00461     out &= ~(1 << _enable_pin);
00462 
00463     //_i2c.writeGPIOAB(out);
00464     _i2c.digitalWordWrite(out);
00465 
00466     // pulse enable
00467     delayMicroseconds(1);
00468     out |= (1 << _enable_pin);
00469     //_i2c.writeGPIOAB(out);
00470     _i2c.digitalWordWrite(out);
00471     
00472     delayMicroseconds(1);
00473     out &= ~(1 << _enable_pin);
00474     
00475     //_i2c.writeGPIOAB(out);   
00476     _i2c.digitalWordWrite(out);
00477     
00478     delayMicroseconds(100);
00479 
00480   } else {
00481     for (int i = 0; i < 4; i++) {
00482      _pinMode(_data_pins[i], OUTPUT);
00483      _digitalWrite(_data_pins[i], (value >> i) & 0x01);
00484     }
00485     pulseEnable();
00486   }
00487 }
00488 
00489 void Adafruit_RGBLCDShield::write8bits(uint8_t value) {
00490   for (int i = 0; i < 8; i++) {
00491     _pinMode(_data_pins[i], OUTPUT);
00492     _digitalWrite(_data_pins[i], (value >> i) & 0x01);
00493   }
00494   
00495   pulseEnable();
00496 }
00497 
00498 uint8_t Adafruit_RGBLCDShield::readButtons(void) {
00499   uint8_t reply = 0x1F;
00500 
00501   for (uint8_t i=0; i<5; i++) {
00502     reply &= ~((_i2c.digitalRead(_button_pins[i])) << i);
00503   }
00504   return reply;
00505 }