A basic basic basic driver for 2x16 HD44780 based displays using the four wire interface.
Dependents: lcdLibraryTest generado_final
lcd.cpp
- Committer:
- mattegan
- Date:
- 2013-11-08
- Revision:
- 0:0db835052212
File content as of revision 0:0db835052212:
#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; }