Skip to content

Added read functions to the LiquidCrystal library #1517

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
274 changes: 240 additions & 34 deletions libraries/LiquidCrystal/LiquidCrystal.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,17 @@
// When the display powers up, it is configured as follows:
//
// 1. Display clear
// 2. Function set:
// DL = 1; 8-bit interface data
// N = 0; 1-line display
// F = 0; 5x8 dot character font
// 3. Display on/off control:
// D = 0; Display off
// C = 0; Cursor off
// B = 0; Blinking off
// 4. Entry mode set:
// I/D = 1; Increment by 1
// S = 0; No shift
// 2. Function set:
// DL = 1; 8-bit interface data
// N = 0; 1-line display
// F = 0; 5x8 dot character font
// 3. Display on/off control:
// D = 0; Display off
// C = 0; Cursor off
// B = 0; Blinking off
// 4. Entry mode set:
// I/D = 1; Increment by 1
// S = 0; No shift
//
// Note, however, that resetting the Arduino doesn't reset the LCD, so we
// can't assume that its in that state when a sketch starts (and the
Expand Down Expand Up @@ -57,29 +57,29 @@ void LiquidCrystal::init(uint8_t fourbitmode, uint8_t rs, uint8_t rw, uint8_t en
_rs_pin = rs;
_rw_pin = rw;
_enable_pin = enable;

_data_pins[0] = d0;
_data_pins[1] = d1;
_data_pins[2] = d2;
_data_pins[3] = d3;
_data_pins[3] = d3;
_data_pins[4] = d4;
_data_pins[5] = d5;
_data_pins[6] = d6;
_data_pins[7] = d7;
_data_pins[7] = d7;

pinMode(_rs_pin, OUTPUT);
// we can save 1 pin by not using RW. Indicate by passing 255 instead of pin#
if (_rw_pin != 255) {
if (_rw_pin != 255) {
pinMode(_rw_pin, OUTPUT);
}
pinMode(_enable_pin, OUTPUT);

if (fourbitmode)
_displayfunction = LCD_4BITMODE | LCD_1LINE | LCD_5x8DOTS;
else
else
_displayfunction = LCD_8BITMODE | LCD_1LINE | LCD_5x8DOTS;
begin(16, 1);

begin(16, 1);
}

void LiquidCrystal::begin(uint8_t cols, uint8_t lines, uint8_t dotsize) {
Expand All @@ -97,14 +97,14 @@ void LiquidCrystal::begin(uint8_t cols, uint8_t lines, uint8_t dotsize) {
// SEE PAGE 45/46 FOR INITIALIZATION SPECIFICATION!
// according to datasheet, we need at least 40ms after power rises above 2.7V
// before sending commands. Arduino can turn on way befer 4.5V so we'll wait 50
delayMicroseconds(50000);
delayMicroseconds(50000);
// Now we pull both RS and R/W low to begin commands
digitalWrite(_rs_pin, LOW);
digitalWrite(_enable_pin, LOW);
if (_rw_pin != 255) {
if (_rw_pin != 255) {
digitalWrite(_rw_pin, LOW);
}

//put the LCD into 4 bit or 8 bit mode
if (! (_displayfunction & LCD_8BITMODE)) {
// this is according to the hitachi HD44780 datasheet
Expand All @@ -117,13 +117,13 @@ void LiquidCrystal::begin(uint8_t cols, uint8_t lines, uint8_t dotsize) {
// second try
write4bits(0x03);
delayMicroseconds(4500); // wait min 4.1ms

// third go!
write4bits(0x03);
write4bits(0x03);
delayMicroseconds(150);

// finally, set to 4-bit interface
write4bits(0x02);
write4bits(0x02);
} else {
// this is according to the hitachi HD44780 datasheet
// page 45 figure 23
Expand All @@ -141,10 +141,10 @@ void LiquidCrystal::begin(uint8_t cols, uint8_t lines, uint8_t dotsize) {
}

// finally, set # lines, font size, etc.
command(LCD_FUNCTIONSET | _displayfunction);
command(LCD_FUNCTIONSET | _displayfunction);

// turn the display on with no cursor or blinking default
_displaycontrol = LCD_DISPLAYON | LCD_CURSOROFF | LCD_BLINKOFF;
_displaycontrol = LCD_DISPLAYON | LCD_CURSOROFF | LCD_BLINKOFF;
display();

// clear it off
Expand Down Expand Up @@ -176,7 +176,7 @@ void LiquidCrystal::setCursor(uint8_t col, uint8_t row)
if ( row >= _numlines ) {
row = _numlines-1; // we count rows starting w/0
}

command(LCD_SETDDRAMADDR | (col + row_offsets[row]));
}

Expand Down Expand Up @@ -252,6 +252,126 @@ void LiquidCrystal::createChar(uint8_t location, uint8_t charmap[]) {
}
}

// Get the current cursor position and put the information in the passed values
void LiquidCrystal::getCursorPos(int &col, int &row) {
uint8_t value = readBusyFlagAndAddress();
value &= 0x7f; //get rid of the busy flag if it is set

row=0;
if(_numlines > 1)
{
//if there are 2 rows
if(value >= 64 )//it means it is on line 2
{
value-=64;
row=1;
}
}
col = value;
}

// Retrieves a number of characters starting from the specified position
// and puts them into the buffer, the buffer is NOT null terminated.
// Returns 0 if it could not read or returns the length if it was successful.
// Much faster with more characters than calling getCharAt for each character.
uint8_t LiquidCrystal::getChars(uint8_t col, uint8_t row, char* buffer, uint8_t length)
{

if (_rw_pin == 255)
{//if there is no rw pin just return 0
return 0;
}

//save the last position to return to it when the function is finished
int prev_col, prev_row;
getCursorPos(prev_col, prev_row);

setCursor(col, row);

for(int i=0; i<length; i++) // no need to increment position...
{
buffer[i]= receive(HIGH);
}

//return to the initial position of the cursor
setCursor(prev_col, prev_row);

return length;
}

// Retrieves a character from the specified position
char LiquidCrystal::getCharAt(uint8_t col, uint8_t row)
{
return getCharAt(col, row, 0); //calls the getCharAt without
//it to return to the current position, so it saves a little bit of time
}

// Retrieves a character from the specified position with the possibility of returning to the original position
char LiquidCrystal::getCharAt(uint8_t col, uint8_t row, uint8_t ret)
{
if (_rw_pin == 255)
{//if there is no rw pin just return 0
return (char) 0;
}

int x,y;
if(ret) //if it needs to return, save the current position
{
getCursorPos(x,y);
}

setCursor(col, row); //set the position to the one from which to read

char value = 0 ;
value = receive(HIGH);

if(ret) //return to the old position
{
setCursor(x,y);
}
return value;
}

// Deletes the character from the specified position
void LiquidCrystal::deleteAt(uint8_t col, uint8_t row)
{
//get to the specified pos, write whitespace and move the cursor back
setCursor(col, row);
print(' ');
if(_displaymode & LCD_ENTRYLEFT) // which direction is it writing?
{
//decrement
command(LCD_CURSORSHIFT | LCD_MOVELEFT);
}
else
{
//increment
command(LCD_CURSORSHIFT | LCD_MOVERIGHT);
}
}

// Deletes the character from the current position -1
void LiquidCrystal::deleteLast()
{
// which direction is it writing?
uint8_t cmd = 0;
if(_displaymode & LCD_ENTRYLEFT)
{
//decrement
cmd=LCD_CURSORSHIFT | LCD_MOVELEFT;
}
else
{
//increment
cmd=LCD_CURSORSHIFT | LCD_MOVERIGHT;
}

// move the cursor, write whitespace and move the cursor back...
command(cmd);
print(' ');
command(cmd);
}

/*********** mid level commands, for sending data/cmds */

inline void LiquidCrystal::command(uint8_t value) {
Expand All @@ -263,28 +383,66 @@ inline size_t LiquidCrystal::write(uint8_t value) {
return 1; // assume sucess
}

/************ low level data pushing commands **********/
// Reads the busy flag and the address
uint8_t LiquidCrystal::readBusyFlagAndAddress()
{
if (_rw_pin == 255)
{ //if there is no rw pin just return 0
return (uint8_t) 0;
}

uint8_t value = 0 ;
value = receive(LOW);

return value;
}

/************ low level data pushing/reading commands **********/

// write either command or data, with automatic 4/8-bit selection
void LiquidCrystal::send(uint8_t value, uint8_t mode) {
digitalWrite(_rs_pin, mode);

// if there is a RW pin indicated, set it low to Write
if (_rw_pin != 255) {
if (_rw_pin != 255) {
digitalWrite(_rw_pin, LOW);
}

if (_displayfunction & LCD_8BITMODE) {
write8bits(value);
write8bits(value);
} else {
write4bits(value>>4);
write4bits(value);
}
}

// reads busy flag and address if rs_pin_mode is LOW or reads characters if rs_pin_mode is HIGH,
// it is analogous to the send function
uint8_t LiquidCrystal::receive(int rs_pin_mode){
digitalWrite(_rs_pin, rs_pin_mode);
digitalWrite(_rw_pin, HIGH); //it is up to the higher function to check if there is a rw pin,
// this is done to avoid using a code for error returning

delayMicroseconds(1); // tAS time

uint8_t value;
if (_displayfunction & LCD_8BITMODE) //is it 4/8 bit mode?
{
value = read8bits();
}
else
{
value = read4bits();
value = value << 4;
value |= read4bits();
}

return value;
}

void LiquidCrystal::pulseEnable(void) {
digitalWrite(_enable_pin, LOW);
delayMicroseconds(1);
delayMicroseconds(1);
digitalWrite(_enable_pin, HIGH);
delayMicroseconds(1); // enable pulse must be >450ns
digitalWrite(_enable_pin, LOW);
Expand All @@ -305,6 +463,54 @@ void LiquidCrystal::write8bits(uint8_t value) {
pinMode(_data_pins[i], OUTPUT);
digitalWrite(_data_pins[i], (value >> i) & 0x01);
}

pulseEnable();
}

// Reads data from the LCD in 4Bit Mode
uint8_t LiquidCrystal::read4bits()
{

digitalWrite(_enable_pin, HIGH);
delayMicroseconds(1); // tDDR time

uint8_t value =0;
for(int i=3; i>=0; i--)
{
value= value<< 1;

pinMode(_data_pins[i], INPUT);
if(digitalRead(_data_pins[i]) == HIGH)
{
value+=1;
}

}
digitalWrite(_enable_pin, LOW);
delayMicroseconds(1); //tDHR time

return value;
}

// Reads data from the LCD in 8Bit Mode
uint8_t LiquidCrystal::read8bits()
{
digitalWrite(_enable_pin, HIGH);
delayMicroseconds(1); // tDDR time
uint8_t value =0;
for(int i=7; i>=0; i--)
{
value= value<< 1;

pinMode(_data_pins[i], INPUT);
if(digitalRead(_data_pins[i]) == HIGH)
{
value+=1;
}

}
digitalWrite(_enable_pin, LOW);
delayMicroseconds(1); //tDHR time
return value;
}

Loading