Demo of LCD modified to use interrupts not delays.
Fork of LCD_nonblocking_demo by
This is an experiment in controlling an LCD from callbacks independently of the main program loop. As it runs from callbacks it is necessary to check if the library is "busy", which is currently indicated by an integer called "busy".
Busy checking should be converted into a method so that the criteria for being "busy" can be changed without changing the API.
As this is rough I have not issued it as a library ... yet.
Also due to my inexperience using the repository manager this is currently listed as a fork of itself. Sorry.
LCD_nonblocking/LCD_nonblocking.cpp
- Committer:
- oliverb
- Date:
- 2013-11-20
- Revision:
- 3:f18aa98bc9a8
File content as of revision 3:f18aa98bc9a8:
/* mbed TextLCD Library, for a 4-bit LCD based on HD44780 * Copyright (c) 2007-2010, sford, http://mbed.org * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include "LCD_nonblocking.h" #include "mbed.h" TextLCD::TextLCD(PinName rs, PinName e, PinName d4, PinName d5, PinName d6, PinName d7, LCDType type) : busy(0),_rs(rs), _e(e), _d(d4, d5, d6, d7), _type(type) , _column(0),_row(0), _head(0), _tail(0) {} void TextLCD::init() { busy=1; _rs = 1; _d = 0; wait_us(1); _e = 0; _rs = 0; // command mode timer.attach_us(this,&TextLCD::init2,15000); } void TextLCD::init2() { _rs = 0; _d = 0x3; _e = 1; wait_us(1); _e = 0; timer.attach_us(this,&TextLCD::init2b,4100); } void TextLCD::init2b() { _d = 0x3; _e = 1; wait_us(1); _e = 0; timer.attach_us(this,&TextLCD::init3,4100); } void TextLCD::init3() { _d = 0x3; _e = 1; wait_us(1); _e = 0; timer.attach_us(this,&TextLCD::init4,1000); } void TextLCD::init4() { _d = 0x2; _e = 1; wait_us(1); _e = 0; timer.attach_us(this,&TextLCD::init5,60); } void TextLCD::init5() { writeByte(0x28); // Function set 001 BW N F - - timer.attach_us(this,&TextLCD::init6,60); } void TextLCD::init6() { writeByte(0x0C); timer.attach_us(this,&TextLCD::init7,60); } void TextLCD::init7() { writeByte(0x6); // Cursor Direction and Display Shift : 0000 01 CD S (CD 0-left, 1-right S(hift) 0-no, 1-yes timer.attach_us(this,&TextLCD::init8,60); } void TextLCD::init8() { writeByte(0x01); // cls, and set cursor to 0 // This command takes 1.64 ms locate(0, 0); timer.attach_us(this,&TextLCD::locate_cb,1640); } /* void TextLCD::character(int column, int row, int c) { int a = address(column, row); writeCommand(a); writeData(c); } */ void TextLCD::cls() { busy=1; writeByte(0x01); // cls, and set cursor to 0 // This command takes 1.64 ms locate(0, 0); timer.attach_us(this,&TextLCD::locate_cb,1640); } void TextLCD::locate(int column, int row) { _column = column; _row = row; } /* this is the general buffered-write callback for writing text to the display * it normally chains to itself unless a newline occurs in which case it chains to * locate_cb * or the buffer runs out in which case it clears busy and does not chain */ void TextLCD::callback() { if (_tail<_head) { int value=_queue[_tail++]; if (value == '\n') { _column = 0; _row++; if (_row >= rows()) { _row = 0; } locate_cb(); // newline isn't printed so go straight to "locate" code } else { _rs = 1; // data mode writeByte(value); _column++; if (_column >= columns()) { //if we've reached the end of line then chain to "locate" //otherwise go back to callback _column = 0; _row++; if (_row >= rows()) { _row = 0; } timer.attach_us(this,&TextLCD::locate_cb,60); } else { timer.attach_us(this,&TextLCD::callback,60); } } } else { //if we've run out of text then clear flag _head=_tail=0; busy=0; } } void TextLCD::locate_cb() { int a = address(_column, _row); _rs=0; writeByte(a); timer.attach_us(this,&TextLCD::callback,60); } int TextLCD::_putc(int value) { if (_head<40) { _queue[_head++]=value; }; if (busy==0) { busy=1; locate_cb(); // set cursor position before text /* int a = address(_column, _row); _rs=0; writeByte(a); timer.attach_us(this,&TextLCD::callback,60); */ }; return value; } /*{ if (value == '\n') { _column = 0; _row++; if (_row >= rows()) { _row = 0; } } else { character(_column, _row, value); _column++; if (_column >= columns()) { _column = 0; _row++; if (_row >= rows()) { _row = 0; } } } return value; } */ int TextLCD::_getc() { return -1; } void TextLCD::writeByte(int value) { _d = value >> 4; _e = 1; wait_us(1); _e = 0; _d = value >> 0; wait_us(2); _e = 1; wait_us(1); // most instructions take 40us _e = 0; } void TextLCD::writeCommand(int command) { _rs = 0; //command mode wait_us(50); // most instructions take 40us writeByte(command); } void TextLCD::writeData(int data) { _rs = 1; // data mode wait_us(50); // most instructions take 40us writeByte(data); } int TextLCD::address(int column, int row) { switch (_type) { case LCD20x4: switch (row) { case 0: return 0x80 + column; case 1: return 0xc0 + column; case 2: return 0x94 + column; case 3: return 0xd4 + column; } case LCD16x2B: return 0x80 + (row * 40) + column; case LCD16x2: case LCD20x2: default: return 0x80 + (row * 0x40) + column; } } int TextLCD::columns() { switch (_type) { case LCD20x4: case LCD20x2: return 20; case LCD16x2: case LCD16x2B: default: return 16; } } int TextLCD::rows() { switch (_type) { case LCD20x4: return 4; case LCD16x2: case LCD16x2B: case LCD20x2: default: return 2; } }