TextLCD
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;