made some changes in config header file to make this library work with 1602A display and PCF8574AT I2C-bus interface
Fork of TextLCD by
Revision 13:24506ba22480, committed 2013-02-09
- Comitter:
- wim
- Date:
- Sat Feb 09 15:10:36 2013 +0000
- Parent:
- 12:6bf9d9957d31
- Child:
- 14:0c32b66b14b8
- Commit message:
- First version with I2C interface, refactored code
Changed in this revision
| TextLCD.cpp | Show annotated file Show diff for this revision Revisions of this file |
| TextLCD.h | Show annotated file Show diff for this revision Revisions of this file |
--- a/TextLCD.cpp Tue Feb 05 21:50:43 2013 +0000
+++ b/TextLCD.cpp Sat Feb 09 15:10:36 2013 +0000
@@ -24,90 +24,127 @@
#include "TextLCD.h"
#include "mbed.h"
-TextLCD::TextLCD(PinName rs, PinName e, PinName d4, PinName d5,
- PinName d6, PinName d7, LCDType type) : _rs(rs),
- _e(e), _d(d4, d5, d6, d7),
+TextLCD::TextLCD(PinName rs, PinName e,
+ PinName d4, PinName d5, PinName d6, PinName d7,
+ LCDType type): _rs(rs), _e(e),
+ _d(d4, d5, d6, d7),
+ _type(type) {
+
+
+ _busType = _PinBus;
+
+ _init();
+
+}
+
+
+TextLCD::TextLCD(I2C *i2c, char deviceAddress, LCDType type) :
+ _rs(NC), _e(NC), _d(NC),
+ _i2c(i2c),
_type(type) {
+
+ _slaveAddress = deviceAddress;
+ _busType = _I2CBus;
- _e = 1;
- _rs = 0; // command mode
+
+ // Init the portexpander bus
+ _lcd_bus = 0x80;
+
+ // write the new data to the portexpander
+ _i2c->write(_slaveAddress, &_lcd_bus, 1);
+
+ _init();
+
+}
+/** Init the LCD controller
+ * 4-bit mode, number of lines, no cursor etc
+ * Clear display
+ */
+void TextLCD::_init() {
+// _e = 1;
+// _rs = 0; // command mode
+
+ _setEnable(true);
+ _setRS(false); // command mode
+
wait(0.015); // Wait 15ms to ensure powered up
// send "Display Settings" 3 times (Only top nibble of 0x30 as we've got 4-bit bus)
for (int i=0; i<3; i++) {
- writeByte(0x3);
+ _writeByte(0x3);
wait(0.00164); // this command takes 1.64ms, so wait for it
}
- writeByte(0x2); // 4-bit mode
- wait(0.000040f); // most instructions take 40us
+ _writeByte(0x2); // 4-bit mode
+ wait(0.000040f); // most instructions take 40us
// Display is now in 4-bit mode
switch (_type) {
case LCD8x1:
- writeCommand(0x20); // Function set 001 BW N F - -
- // N=0 (1 line)
- // F=0 (5x7 dots font)
+ _writeCommand(0x20); // Function set 001 BW N F - -
+ // N=0 (1 line)
+ // F=0 (5x7 dots font)
break;
case LCD24x4:
// Special mode for KS0078
- writeCommand(0x2A); // Function set 001 BW N RE DH REV
- // N=1 (Dont care for KS0078)
- // RE=0 (Extended Regs, special mode for KS0078)
- // DH=1 (Disp shift, special mode for KS0078)
- // REV=0 (Reverse, special mode for KS0078)
+ _writeCommand(0x2A); // Function set 001 BW N RE DH REV
+ // N=1 (Dont care for KS0078)
+ // RE=0 (Extended Regs, special mode for KS0078)
+ // DH=1 (Disp shift, special mode for KS0078)
+ // REV=0 (Reverse, special mode for KS0078)
- writeCommand(0x2E); // Function set 001 BW N RE DH REV
- // N=1 (Dont care for KS0078)
- // RE=1 (Ena Extended Regs, special mode for KS0078)
- // DH=1 (Disp shift, special mode for KS0078)
- // REV=0 (Reverse, special mode for KS0078)
+ _writeCommand(0x2E); // Function set 001 BW N RE DH REV
+ // N=1 (Dont care for KS0078)
+ // RE=1 (Ena Extended Regs, special mode for KS0078)
+ // DH=1 (Disp shift, special mode for KS0078)
+ // REV=0 (Reverse, special mode for KS0078)
- writeCommand(0x09); // Ext Function set 0000 1 FW BW NW
- // FW=0 (5-dot font, special mode for KS0078)
- // BW=0 (Cur BW invert disable, special mode for KS0078)
- // NW=1 (4 Line, special mode for KS0078)
+ _writeCommand(0x09); // Ext Function set 0000 1 FW BW NW
+ // FW=0 (5-dot font, special mode for KS0078)
+ // BW=0 (Cur BW invert disable, special mode for KS0078)
+ // NW=1 (4 Line, special mode for KS0078)
- writeCommand(0x2A); // Function set 001 BW N RE DH REV
- // N=1 (Dont care for KS0078)
- // RE=0 (Dis. Extended Regs, special mode for KS0078)
- // DH=1 (Disp shift, special mode for KS0078)
- // REV=0 (Reverse, special mode for KS0078)
+ _writeCommand(0x2A); // Function set 001 BW N RE DH REV
+ // N=1 (Dont care for KS0078)
+ // RE=0 (Dis. Extended Regs, special mode for KS0078)
+ // DH=1 (Disp shift, special mode for KS0078)
+ // REV=0 (Reverse, special mode for KS0078)
break;
default:
- writeCommand(0x28); // Function set 001 BW N F - -
- // N=1 (2 lines)
- // F=0 (5x7 dots font)
+ _writeCommand(0x28); // Function set 001 BW N F - -
+ // N=1 (2 lines)
+ // F=0 (5x7 dots font)
+ // - (Don't care)
break;
}
- writeCommand(0x06); // Entry Mode 0000 01 CD S
- // Cursor Direction and Display Shift
- // CD=1 (Cur incr)
- // S=0 (No display shift)
+ _writeCommand(0x06); // Entry Mode 0000 01 CD S
+ // Cursor Direction and Display Shift
+ // CD=1 (Cur incr)
+ // S=0 (No display shift)
-// writeCommand(0x0C); // Display Ctrl 0000 1 D C B
-// // Display On, Cursor Off, Blink Off
- cursor(TextLCD::CurOff_BlkOff);
+// _writeCommand(0x0C); // Display Ctrl 0000 1 D C B
+// // Display On, Cursor Off, Blink Off
+ setCursor(TextLCD::CurOff_BlkOff);
cls();
}
-void TextLCD::character(int column, int row, int c) {
+void TextLCD::_character(int column, int row, int c) {
int addr = getAddress(column, row);
- writeCommand(0x80 | addr);
- writeData(c);
+ _writeCommand(0x80 | addr);
+ _writeData(c);
}
void TextLCD::cls() {
- writeCommand(0x01); // cls, and set cursor to 0
- wait(0.00164f); // This command takes 1.64 ms
+ _writeCommand(0x01); // cls, and set cursor to 0
+ wait(0.00164f); // This command takes 1.64 ms
locate(0, 0);
}
@@ -124,7 +161,7 @@
_row = 0;
}
} else {
- character(_column, _row, value);
+ _character(_column, _row, value);
_column++;
if (_column >= columns()) {
_column = 0;
@@ -141,27 +178,135 @@
return -1;
}
-void TextLCD::writeByte(int value) {
- _d = value >> 4;
+
+void TextLCD::_setEnable(bool value) {
+
+ switch(_busType) {
+ case _PinBus :
+ if (value)
+ _e = 1; // Set E bit
+ else
+ _e = 0; // Reset E bit
+
+ break;
+
+ case _I2CBus :
+ if (value)
+ _lcd_bus |= D_LCD_E; // Set E bit
+ else
+ _lcd_bus &= ~D_LCD_E; // Reset E bit
+
+ // write the new data to the portexpander
+ _i2c->write(_slaveAddress, &_lcd_bus, 1);
+
+ break;
+
+ case _SPIBus :
+ break;
+ }
+}
+
+void TextLCD::_setRS(bool value) {
+
+ switch(_busType) {
+ case _PinBus :
+ if (value)
+ _rs = 1; // Set RS bit
+ else
+ _rs = 0; // Reset RS bit
+
+ break;
+
+ case _I2CBus :
+ if (value)
+ _lcd_bus |= D_LCD_RS; // Set RS bit
+ else
+ _lcd_bus &= ~D_LCD_RS; // Reset RS bit
+
+ // write the new data to the portexpander
+ _i2c->write(_slaveAddress, &_lcd_bus, 1);
+
+ break;
+
+ case _SPIBus :
+ break;
+ }
+
+}
+
+void TextLCD::_setData(int value) {
+ int data;
+
+ switch(_busType) {
+ case _PinBus :
+ _d = value & 0x0F; // Write Databits
+
+ break;
+
+ case _I2CBus :
+ data = value & 0x0F;
+ if (data & 0x01)
+ _lcd_bus |= D_LCD_D4; // Set Databit
+ else
+ _lcd_bus &= ~D_LCD_D4; // Reset Databit
+
+ if (data & 0x02)
+ _lcd_bus |= D_LCD_D5; // Set Databit
+ else
+ _lcd_bus &= ~D_LCD_D5; // Reset Databit
+
+ if (data & 0x04)
+ _lcd_bus |= D_LCD_D6; // Set Databit
+ else
+ _lcd_bus &= ~D_LCD_D6; // Reset Databit
+
+ if (data & 0x08)
+ _lcd_bus |= D_LCD_D7; // Set Databit
+ else
+ _lcd_bus &= ~D_LCD_D7; // Reset Databit
+
+ // write the new data to the portexpander
+ _i2c->write(_slaveAddress, &_lcd_bus, 1);
+
+ break;
+
+ case _SPIBus :
+ break;
+ }
+
+}
+
+
+
+void TextLCD::_writeByte(int value) {
+// _d = value >> 4;
+ _setData(value >> 4);
wait(0.000040f); // most instructions take 40us
- _e = 0;
+// _e = 0;
+ _setEnable(false);
wait(0.000040f);
- _e = 1;
- _d = value >> 0;
+// _e = 1;
+ _setEnable(true);
+// _d = value >> 0;
+ _setData(value >> 0);
wait(0.000040f);
- _e = 0;
+// _e = 0;
+ _setEnable(false);
wait(0.000040f); // most instructions take 40us
- _e = 1;
+// _e = 1;
+ _setEnable(true);
}
-void TextLCD::writeCommand(int command) {
- _rs = 0;
- writeByte(command);
+void TextLCD::_writeCommand(int command) {
+// _rs = 0;
+ _setRS(false);
+ _writeByte(command);
}
-void TextLCD::writeData(int data) {
- _rs = 1;
- writeByte(data);
+void TextLCD::_writeData(int data) {
+// _rs = 1;
+ _setRS(true);
+ _writeByte(data);
}
@@ -170,7 +315,7 @@
// It is confusing since it returns the memoryaddress or-ed with the set memorycommand 0x80.
// Left it in here for compatibility with older code. New applications should use getAddress() instead.
//
-int TextLCD::address(int column, int row) {
+int TextLCD::_address(int column, int row) {
switch (_type) {
case LCD20x4:
switch (row) {
@@ -196,7 +341,7 @@
// This replaces the original method.
// Left it in here for compatibility with older code. New applications should use getAddress() instead.
-int TextLCD::address(int column, int row) {
+int TextLCD::_address(int column, int row) {
return 0x80 | getAddress(column, row);
}
@@ -208,6 +353,13 @@
case LCD8x1:
return 0x00 + column;
+ case LCD16x1:
+ // LCD16x1 is a special layout of LCD8x2
+ if (column<8)
+ return 0x00 + column;
+ else
+ return 0x40 + (column - 8);
+
case LCD16x4:
switch (row) {
case 0:
@@ -263,7 +415,7 @@
}
-// Added for consistency. Set row, colum and update memoryaddress.
+// Added for consistency. Set row, column and update memoryaddress.
//
void TextLCD::setAddress(int column, int row) {
@@ -271,7 +423,7 @@
int addr = getAddress(column, row);
- writeCommand(0x80 | addr);
+ _writeCommand(0x80 | addr);
}
int TextLCD::columns() {
@@ -280,6 +432,7 @@
case LCD8x2:
return 8;
+ case LCD16x1:
case LCD16x2:
case LCD16x2B:
case LCD16x4:
@@ -305,6 +458,7 @@
int TextLCD::rows() {
switch (_type) {
case LCD8x1:
+ case LCD16x1:
return 1;
case LCD8x2:
@@ -327,25 +481,25 @@
}
-void TextLCD::cursor(TextLCD::LCDCursor show) {
+void TextLCD::setCursor(TextLCD::LCDCursor show) {
switch (show) {
- case CurOff_BlkOff : writeCommand(0x0C); // Cursor off and Blink Off
+ case CurOff_BlkOff : _writeCommand(0x0C); // Cursor off and Blink Off
wait_us(40);
_cursor = show;
break;
- case CurOn_BlkOff : writeCommand(0x0E); // Cursor on and Blink Off
+ case CurOn_BlkOff : _writeCommand(0x0E); // Cursor on and Blink Off
wait_us(40);
_cursor = show;
break;
- case CurOff_BlkOn : writeCommand(0x0D); // Cursor off and Blink On
+ case CurOff_BlkOn : _writeCommand(0x0D); // Cursor off and Blink On
wait_us(40);
_cursor = show;
break;
- case CurOn_BlkOn : writeCommand(0x0F); // Cursor on and Blink char
+ case CurOn_BlkOn : _writeCommand(0x0F); // Cursor on and Blink char
wait_us(40);
_cursor = show;
break;
@@ -360,10 +514,10 @@
void TextLCD::setUDC(unsigned char c, char *udc_data) {
- writeCommand(0x40 + ((c & 0x07) << 3)); //Set CG-RAM address
+ _writeCommand(0x40 + ((c & 0x07) << 3)); //Set CG-RAM address
for (int i=0; i<8; i++) {
- writeData(*udc_data++);
+ _writeData(*udc_data++);
}
}
--- a/TextLCD.h Tue Feb 05 21:50:43 2013 +0000
+++ b/TextLCD.h Sat Feb 09 15:10:36 2013 +0000
@@ -1,6 +1,7 @@
/* mbed TextLCD Library, for a 4-bit LCD based on HD44780
* Copyright (c) 2007-2010, sford, http://mbed.org
- * 2013, WH, Added LCD types, fixed LCD address issues, added Cursor and UDCs
+ * 2013, v01: WH, Added LCD types, fixed LCD address issues, added Cursor and UDCs
+ * 2013, v02: WH, Added I2C and SPI bus interfaces
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -42,7 +43,38 @@
* @endcode
*/
-/** User Defined Chars 5x7 dots */
+
+//Pin Defines for I2C PCF8574 and SPI 74595 Bus
+//LCD and serial portexpanders should be wired accordingly
+//Note: LCD RW pin must be connected to GND
+// E2 may be used for future expansion to LCD40x4
+// BL may be used for future expansion to control backlight
+//
+#define D_LCD_PIN_D4 0x00
+#define D_LCD_PIN_D5 0x01
+#define D_LCD_PIN_D6 0x02
+#define D_LCD_PIN_D7 0x03
+#define D_LCD_PIN_RS 0x04
+#define D_LCD_PIN_E 0x05
+#define D_LCD_PIN_E2 0x06
+#define D_LCD_PIN_BL 0x07
+
+#define D_LCD_BUS_MSK 0x0F
+
+//Bitpattern Defines for I2C PCF8574 and SPI 74595 Bus
+//
+#define D_LCD_D4 (1<<D_LCD_PIN_D4)
+#define D_LCD_D5 (1<<D_LCD_PIN_D5)
+#define D_LCD_D6 (1<<D_LCD_PIN_D6)
+#define D_LCD_D7 (1<<D_LCD_PIN_D7)
+#define D_LCD_RS (1<<D_LCD_PIN_RS)
+#define D_LCD_E (1<<D_LCD_PIN_E)
+#define D_LCD_E2 (1<<D_LCD_PIN_E2)
+#define D_LCD_BL (1<<D_LCD_PIN_BL)
+
+
+
+/** Some sample User Defined Chars 5x7 dots */
const char udc_ae[] = {0x00, 0x00, 0x1B, 0x05, 0x1F, 0x14, 0x1F, 0x00}; //æ
const char udc_0e[] = {0x00, 0x00, 0x0E, 0x13, 0x15, 0x19, 0x0E, 0x00}; //ø
const char udc_ao[] = {0x0E, 0x0A, 0x0E, 0x01, 0x0F, 0x11, 0x0F, 0x00}; //å
@@ -59,10 +91,28 @@
const char udc_6[] = {0x15, 0x0a, 0x15, 0x0a, 0x15, 0x0a, 0x15, 0x00}; // checkerboard
const char udc_7[] = {0x10, 0x08, 0x04, 0x02, 0x01, 0x00, 0x10, 0x00}; // \
+const char udc_degr[] = {0x06, 0x09, 0x09, 0x06, 0x00, 0x00, 0x00, 0x00}; // Degree symbol
+
+const char udc_TM_T[] = {0x1F, 0x04, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00}; // Trademark T
+const char udc_TM_M[] = {0x11, 0x1B, 0x15, 0x11, 0x00, 0x00, 0x00, 0x00}; // Trademark M
+
+//const char udc_Bat_Hi[] = {0x0E, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x00}; // Battery Full
+//const char udc_Bat_Ha[] = {0x0E, 0x11, 0x13, 0x17, 0x1F, 0x1F, 0x1F, 0x00}; // Battery Half
+//const char udc_Bat_Lo[] = {0x0E, 0x11, 0x11, 0x11, 0x11, 0x11, 0x1F, 0x00}; // Battery Low
+const char udc_Bat_Hi[] = {0x0E, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x00}; // Battery Full
+const char udc_Bat_Ha[] = {0x0E, 0x11, 0x11, 0x1F, 0x1F, 0x1F, 0x1F, 0x00}; // Battery Half
+const char udc_Bat_Lo[] = {0x0E, 0x11, 0x11, 0x11, 0x11, 0x1F, 0x1F, 0x00}; // Battery Low
+
+const char udc_bar_1[] = {0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00}; // Bar 1
+const char udc_bar_2[] = {0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00}; // Bar 11
+const char udc_bar_3[] = {0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x00}; // Bar 111
+const char udc_bar_4[] = {0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x00}; // Bar 1111
+const char udc_bar_5[] = {0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x00}; // Bar 11111
+
/** A TextLCD interface for driving 4-bit HD44780-based LCDs
*
- * Currently supports 8x1, 8x2, 16x2, 16x4, 20x2, 20x4, 24x2, 24x4 and 40x2 panels
+ * Currently supports 8x1, 8x2, 16x1, 16x2, 16x4, 20x2, 20x4, 24x2, 24x4 and 40x2 panels
*
*/
class TextLCD : public Stream {
@@ -71,7 +121,8 @@
/** LCD panel format */
enum LCDType {
LCD8x1, /**< 8x1 LCD panel */
- LCD8x2, /**< 8x2 LCD panel */
+ LCD8x2, /**< 8x2 LCD panel */
+ LCD16x1, /**< 16x1 LCD panel (actually 8x2) */
LCD16x2, /**< 16x2 LCD panel (default) */
LCD16x2B, /**< 16x2 LCD panel alternate addressing */
LCD16x4, /**< 16x4 LCD panel */
@@ -91,7 +142,7 @@
};
- /** Create a TextLCD interface
+ /** Create a TextLCD interface for using regural mbed pins
*
* @param rs Instruction/data control line
* @param e Enable line (clock)
@@ -99,6 +150,24 @@
* @param type Sets the panel size/addressing mode (default = LCD16x2)
*/
TextLCD(PinName rs, PinName e, PinName d4, PinName d5, PinName d6, PinName d7, LCDType type = LCD16x2);
+
+ /** Create a TextLCD interface using an I2C PC8574 portexpander
+ *
+ * @param i2c I2C Bus
+ * @param deviceAddress I2C slave address (PCF8574)
+ * @param type Sets the panel size/addressing mode (default = LCD16x2)
+ */
+ TextLCD(I2C *i2c, char deviceAddress, LCDType type = LCD16x2);
+
+
+ /** Create a TextLCD interface using an SPI 74595 portexpander
+ *
+ * @param spi SPI Bus
+ * @param cs chip select pin (active low)
+ * @param type Sets the panel size/addressing mode (default = LCD16x2)
+ */
+// TextLCD(SPI *spi, PinName cs, LCDType type = LCD16x2);
+
#if DOXYGEN_ONLY
/** Write a character to the LCD
@@ -159,7 +228,7 @@
*
* @param show The Cursor mode (CurOff_BlkOff, CurOn_BlkOff, CurOff_BlkOn, CurOn_BlkOn)
*/
- void cursor(LCDCursor show);
+ void setCursor(LCDCursor show);
/** Set User Defined Characters
@@ -170,20 +239,56 @@
void setUDC(unsigned char c, char *udc_data);
protected:
+ /** LCD Bus control */
+ enum _LCDBus {
+ _PinBus, /**< Regular mbed pins */
+ _I2CBus, /**< I2C PCF8574 Portexpander */
+ _SPIBus /**< SPI 74595 */
+ };
+
// Stream implementation functions
virtual int _putc(int value);
virtual int _getc();
- int address(int column, int row);
- void character(int column, int row, int c);
- void writeByte(int value);
- void writeCommand(int command);
- void writeData(int data);
+ void _init();
+ int _address(int column, int row);
+ void _character(int column, int row, int c);
+
+//Low level writes to LCD Bus (serial or parallel)
+ void _setEnable(bool value);
+ void _setRS(bool value);
+ void _setData(int value);
+//Low level writes to LCD serial bus only
+ void _writeBus();
+
+//Low level writes to LCD
+ void _writeByte(int value);
+ void _writeCommand(int command);
+ void _writeData(int data);
+
+// Regular mbed pins bus
DigitalOut _rs, _e;
BusOut _d;
+
+// I2C bus
+ I2C *_i2c;
+ unsigned char _slaveAddress;
+
+// SPI bus
+// SPI *_spi;
+// DigitalOut _cs;
+
+//Bus Interface type
+ _LCDBus _busType;
+
+// Internal bus mirror value for serial only
+ char _lcd_bus;
+
+//Display type
LCDType _type;
+// Cursor
int _column;
int _row;
LCDCursor _cursor;
