A basic basic basic driver for 2x16 HD44780 based displays using the four wire interface.
Dependents: lcdLibraryTest generado_final
Revision 0:0db835052212, committed 2013-11-08
- Comitter:
- mattegan
- Date:
- Fri Nov 08 07:03:35 2013 +0000
- Commit message:
- [ADMIN] initial commit - everything should be working
Changed in this revision
lcd.cpp | Show annotated file Show diff for this revision Revisions of this file |
lcd.h | Show annotated file Show diff for this revision Revisions of this file |
diff -r 000000000000 -r 0db835052212 lcd.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lcd.cpp Fri Nov 08 07:03:35 2013 +0000 @@ -0,0 +1,215 @@ +#include "lcd.h" + +//Public Methods +////////////////////////////////////////////////////////////////////////////////////////// + +lcd::lcd(PinName _rs, PinName _rw, PinName _e, PinName _db4, PinName _db5, PinName _db6, PinName _db7): + registerSelect(_rs), readWrite(_rw), enable(_e), dataBus(_db4, _db5, _db6, _db7) { + + currentMode = klcdReadMode; + setMode(klcdWriteMode); + + //wait for more than 15ms after Vcc rises to 4.5v + wait_ms(20); + + //function set (interface is 8 bits long) + writeNibble(klcdInstructionRegister, 0x3); + + //wait for more than 4.1ms + wait_ms(4.5); + + //function set(interface is 8 bits long) + writeNibble(klcdInstructionRegister, 0x3); + + //wait for more than 100us + wait_us(150); + + //function set (interface is 8 bits long) + writeNibble(klcdInstructionRegister, 0x3); + wait_us(90); + + //function set (interface is 4 bits long) + writeNibble(klcdInstructionRegister, 0x2); + wait_us(90); + + //function set (interface is 4 bits long) set display lines and character font + // 2 lines, 5x8 character font (1 0 0 0) + writeByte(klcdInstructionRegister, 0x28, false); + wait_us(90); + + //display off + writeByte(klcdInstructionRegister, 0x08, false); + wait_us(90); + + //display clear + writeByte(klcdInstructionRegister, 0x01, false); + wait_ms(2.0); + + //entry mode set + writeByte(klcdInstructionRegister, 0x0C, false); + wait_us(90); + + //clear display, and turn on + writeByte(klcdInstructionRegister, 0x01); + writeByte(klcdInstructionRegister, 0x0C); + + //turn shifting off + writeByte(klcdInstructionRegister, 0x04); + + row = 0; + column = 0; + +} + +void lcd::clear() { + //clear screen -> 0 0 (0 0 0 0 0 0 0 1) + writeByte(klcdInstructionRegister, 0x01); + locate(0, 0); +} + +void lcd::locate(int _row, int _column) { + row = _row; + column = _column; +} + +void lcd::locateCharacter(int _row, int _column, int _char) { + //set DDRAM address -> 0 0 (1 a a a a a a a) + //write DDRAM -> 1 0 (d d d d d d d d); + writeByte(klcdInstructionRegister, 0x80 + (_row * 0x40) + _column); + writeByte(klcdDataRegister, _char); +} + +void lcd::defineCharacter(int _char, int _charData[8]) { + if(_char < 0 || _char > 7) return; + //write CGRAM address 0 0 (0 1 a a a a a a) + // first three bits are character (0-7) + // second three bits are the row in the character + writeByte(klcdInstructionRegister, 0x40 + (_char << 3)); + for(int row = 0; row < 8; row++) { + //write CGRAM data 1 0 (d d d d d d d d) + writeByte(klcdDataRegister, _charData[row]); + } +} + +//Protected Methods +////////////////////////////////////////////////////////////////////////////////////////// +void lcd::setMode(int _mode) { + //since changing the databus mode takes time only do it + // if we're not in the mode already, this might be + // fuzzy science (read, not actually accurate), but it + // can't hurt + if(_mode != currentMode) { + readWrite = _mode; + currentMode = _mode; + switch(_mode) { + case klcdWriteMode: { + dataBus.output(); + break; + } + case klcdReadMode: { + dataBus.input(); + break; + } + } + } +} + +void lcd::waitUntilNotBusy() { + setMode(klcdReadMode); + registerSelect = klcdInstructionRegister; + wait_us(5); + enable = klcdEnableHigh; + wait_us(0.5); + while(dataBus.read() >> 3) {}; + enable = klcdEnableLow; + wait_us(0.6); + readNibble(klcdInstructionRegister); + return; +} + +void lcd::writeByte(int _reg, int _byte, bool _wait) { + //write the most significant four bytes first + writeNibble(_reg, _byte >> 4); + writeNibble(_reg, _byte); + if(_wait) { + waitUntilNotBusy(); + } +} + +//this is useless at the moment, not sure how I want to structure +// reading bytes with the four wire interface, as one read is +// technically reading the busy flag and internal address counter, +// another is actually reading bytes from CGRAM or DDRAM (which isn't +// all that useful actually) +int lcd::readNibble(int _reg) { + setMode(klcdReadMode); + registerSelect = _reg; + + //wait more than 60ns for address set up, then bring enable high + wait_us(0.1); + enable = klcdEnableHigh; + //wait for the enable pulse width to elapse (450ns), by which time the data + // should be present on the bus, then bring enable low, and wait + // till the end of the enable cycle + wait_us(0.5); + int nibble = dataBus.read(); + enable = klcdEnableLow; + wait_us(0.6); + return nibble; +} + +//write a four bit nibble onto the bus with correct delays +void lcd::writeNibble(int _reg, int _nibble) { + setMode(klcdWriteMode); + registerSelect = _reg; + + dataBus = _nibble; + //wait for more than 60ns for address set up, then bring enable high + wait_us(0.1); + enable = klcdEnableHigh; + //wait for more than 450ns for enable pulse width, then bring enable low + wait_us(0.5); + enable = klcdEnableLow; + //wait for more than 550ns for the completion of the enable cycle + wait_us(0.6); +} + + +//Stream Implementation +////////////////////////////////////////////////////////////////////////////////////// +int lcd::_putc(int _char) { + if(_char == '\n') { + column = 0; + row = (++row % 2); + } else { + locateCharacter(row, column, _char); + column++; + } + return _char; +} + +//not respoinding to getc (yet, this would require reading out of the +// DDRAM of the display, or caching +int lcd::_getc() { + return -1; +} + + + + + + + + + + + + + + + + + + + +
diff -r 000000000000 -r 0db835052212 lcd.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lcd.h Fri Nov 08 07:03:35 2013 +0000 @@ -0,0 +1,54 @@ +#ifndef LCD +#define LCD + +#include "mbed.h" + +#define klcdWriteMode 0 +#define klcdReadMode 1 +#define klcdInstructionRegister 0 +#define klcdDataRegister 1 +#define klcdEnableHigh 1 +#define klcdEnableLow 0 + +class lcd : public Stream{ + public: + //uses the four bit interface with a read/write pin in order to read the busy flag + lcd(PinName _rs, PinName _rw, PinName _e, PinName _db4, PinName _db5, PinName _db6, PinName _db7); + + //clear the screen + void clear(); + + //move to a location on the screen, the next printf or putc call + // will locate the character at the location + void locate(int _row, int _column); + + //place a character at a location + void locateCharacter(int _row, int _column, int _char); + + //define a character with a 8 element array of 5 bit wide pixel + // definitions, from top to bottom + void defineCharacter(int _char, int _charData[8]); + + protected: + void setMode(int _mode); + void waitUntilNotBusy(); + int readByte(int _reg); + void writeByte(int _reg, int _byte, bool _wait = true); + int readNibble(int _reg); + void writeNibble(int _reg, int _nibble); + + //stream implementation + virtual int _putc(int _value); + virtual int _getc(); + + BusInOut dataBus; + DigitalOut registerSelect; + DigitalOut readWrite; + DigitalOut enable; + + int currentMode; + int column; + int row; +}; + +#endif \ No newline at end of file