Jan Cumps
Published © LGPL

C++ LCD Display Driver for IOT2020

Hitachi LCD displays are used in many designs. If you're building a C++ project, this driver class can help.

BeginnerProtip1 hour3,945
C++ LCD Display Driver for IOT2020

Things used in this project

Story

Read more

Code

Lcd driver header file

C/C++
/*
 * Lcd.h
 *
 *  Created on: 20 mrt. 2017
 *      Author: jancu
 */

#ifndef LCD_H_
#define LCD_H_

#include "mraa.hpp"

namespace lcd_hitachi {


/**
 *
 * This code ported from:
 *
 * = Liquid Crystal Library for Arduino =

This library allows an Arduino board to control LiquidCrystal displays (LCDs) based on the Hitachi HD44780 (or a compatible) chipset, which is found on most text-based LCDs.

For more information about this library please visit us at
http://www.arduino.cc/en/Reference/LiquidCrystal

== License ==

Copyright (C) 2006-2008 Hans-Christoph Steiner. All rights reserved.
Copyright (c) 2010 Arduino LLC. All right reserved.

This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
 *
 */





class Lcd {
public:
	Lcd();

	~Lcd();

	void init( uint32_t u_rs,  uint32_t u_enable,  uint32_t u_d0,
			uint32_t u_d1,  uint32_t u_d2,
			uint32_t u_d3);

	void begin(uint32_t cols, uint32_t lines, uint32_t dotsize);

	void setCursor(uint32_t col, uint32_t row);

	void print(const std::string& input);

private:
	mraa::Gpio* _rs = NULL;
	mraa::Gpio* _enable = NULL;
	mraa::Gpio* _d0 = NULL;
	mraa::Gpio* _d1 = NULL;
	mraa::Gpio* _d2 = NULL;
	mraa::Gpio* _d3 = NULL;
	uint32_t _lcd_bitmode;
	uint32_t _numlines;
	uint32_t _currline;
	uint32_t _displayfunction;
	uint32_t _displaycontrol;
	uint32_t _displaymode;
	mraa::Gpio* _data_pins[8];

	void write4bits(uint32_t value);

	void write8bits(uint32_t value);

	void clear();

	void display();

	void lcdSetCursor(uint32_t col, uint32_t row);

	void lcdPrint(const char *str);

	/**
	 * set the direction of a given pin without altering other pins
	 * on the same port
	 *
	 */
	void command(uint32_t value);

	void send(uint32_t value, uint32_t mode);

	uint32_t lcdWrite(uint32_t value);

	void pulseEnable(void);

	/**
	 * delay for the given number of microseconds, for 80MHz processor
	 */
	void lcdDelayMicroSeconds(uint32_t us);

};

}

#endif /* LCD_H_ */

Lcd driver source file

C/C++
/*
 * Lcd.cpp
 *
 *  Created on: 20 mrt. 2017
 *      Author: jancu
 */

#include "Lcd.h"
using namespace mraa;

namespace lcd_hitachi {

// commands
#define LCD_CLEARDISPLAY 0x01
#define LCD_RETURNHOME 0x02
#define LCD_ENTRYMODESET 0x04
#define LCD_DISPLAYCONTROL 0x08
#define LCD_CURSORSHIFT 0x10
#define LCD_FUNCTIONSET 0x20
#define LCD_SETCGRAMADDR 0x40
#define LCD_SETDDRAMADDR 0x80

// flags for display entry mode
#define LCD_ENTRYRIGHT 0x00
#define LCD_ENTRYLEFT 0x02
#define LCD_ENTRYSHIFTINCREMENT 0x01
#define LCD_ENTRYSHIFTDECREMENT 0x00

// flags for display on/off control
#define LCD_DISPLAYON 0x04
#define LCD_DISPLAYOFF 0x00
#define LCD_CURSORON 0x02
#define LCD_CURSOROFF 0x00
#define LCD_BLINKON 0x01
#define LCD_BLINKOFF 0x00

// flags for display/cursor shift
#define LCD_DISPLAYMOVE 0x08
#define LCD_CURSORMOVE 0x00
#define LCD_MOVERIGHT 0x04
#define LCD_MOVELEFT 0x00

// flags for function set
#define LCD_8BITMODE 0x10
#define LCD_4BITMODE 0x00
#define LCD_2LINE 0x08
#define LCD_1LINE 0x00
#define LCD_5x10DOTS 0x04
#define LCD_5x8DOTS 0x00


Lcd::Lcd() {
	_lcd_bitmode = 0;
	_numlines=0;
	_currline=0;
	_displaycontrol = 0;
	_displaymode = 0;
	_displayfunction = 0;
}


Lcd::~Lcd()  {
	if (_rs) {
		delete _rs;
		_rs = NULL;
	}
	if (_enable) {
		delete _enable;
		_enable = NULL;
	}
	if (_d0) {
		delete _d0;
		_d0 = NULL;
	}
	if (_d1) {
		delete _d1;
		_d1 = NULL;
	}
	if (_d2) {
		delete _d2;
		_d2 = NULL;
	}
	if (_d3) {
		delete _d3;
		_d3 = NULL;
	}

}

void Lcd::init( uint32_t u_rs,  uint32_t u_enable,  uint32_t u_d0,
		uint32_t u_d1,  uint32_t u_d2,
		uint32_t u_d3) {
	_rs = 	new Gpio(u_rs, true, false),
			_rs->dir(mraa::DIR_OUT);
	_enable = new Gpio(u_enable, true, false);
	_enable->dir(mraa::DIR_OUT);
	_d0 = new Gpio(u_d0, true, false);
	_d0->dir(mraa::DIR_OUT);
	_d1 = new Gpio(u_d1, true, false);
	_d1->dir(mraa::DIR_OUT);
	_d2 = new Gpio(u_d2, true, false);
	_d2->dir(mraa::DIR_OUT);
	_d3 = new Gpio(u_d3, true, false);
	_d3->dir(mraa::DIR_OUT);
	_data_pins[0] = _d0;
	_data_pins[1] = _d1;
	_data_pins[2] = _d2;
	_data_pins[3] = _d3;

	// if we call this version of lcdInit, we're in 4 bit mode
	_lcd_bitmode = LCD_4BITMODE;

	// the mode is set to fixed character matrix, rows and bitmode(4/8)
	_displayfunction = LCD_4BITMODE | LCD_1LINE | LCD_5x8DOTS;




}
void Lcd::begin(uint32_t cols, uint32_t lines, uint32_t dotsize) {
	if (lines > 1) {
		_displayfunction |= LCD_2LINE;
	}
	_numlines = lines;
	_currline = 0;

	// for some 1 line displays you can select a 10 pixel high font
	if ((dotsize != 0) && (lines == 1)) {
		_displayfunction |= LCD_5x10DOTS;
	}

	// 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
	lcdDelayMicroSeconds(50000);

	// Now we pull both RS and R/W low to begin commands
	_rs->write(0);
	_enable->write(0);
	// no rw pin unless needed

	//put the LCD into 4 bit or 8 bit mode
	if (! (_displayfunction & LCD_8BITMODE)) {
		// this is according to the hitachi HD44780 datasheet
		// figure 24, pg 46

		// we start in 8bit mode, try to set 4 bit mode
		write4bits(0x03);
		lcdDelayMicroSeconds(4500); // wait min 4.1ms

		// second try
		write4bits(0x03);
		lcdDelayMicroSeconds(4500); // wait min 4.1ms

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

		// finally, set to 4-bit interface
		write4bits(0x02);
	} else {
		// this is according to the hitachi HD44780 datasheet
		// page 45 figure 23

		// Send function set command sequence
		command(LCD_FUNCTIONSET | _displayfunction);
		lcdDelayMicroSeconds(4500);  // wait more than 4.1ms

		// second try
		command(LCD_FUNCTIONSET | _displayfunction);
		lcdDelayMicroSeconds(150);

		// third go
		command(LCD_FUNCTIONSET | _displayfunction);
	}

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

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

	// clear it off
	clear();

	// Initialize to default text direction (for romance languages)
	_displaymode = LCD_ENTRYLEFT | LCD_ENTRYSHIFTDECREMENT;
	// set the entry mode
	command(LCD_ENTRYMODESET | _displaymode);



}
void Lcd::setCursor(uint32_t col, uint32_t row) {

	uint32_t row_offsets[] = { 0x00, 0x40, 0x14, 0x54 };
	if ( row >= _numlines ) {
		row = _numlines-1;    // we count rows starting w/0
	}

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

}

void Lcd::print(const std::string& input) {

	for(std::string::size_type i = 0; i < input.size(); ++i) {
	    lcdWrite(input[i]);
	}
}

void Lcd::write4bits(uint32_t value) {
	uint32_t i;
	for (i = 0; i < 4; i++) {
		_data_pins[i]->dir(mraa::DIR_OUT);
		_data_pins[i]->write((value >> i) & 0x01);
	}

	pulseEnable();
}

void Lcd::write8bits(uint32_t value) {
	int i;
	for (i = 0; i < 8; i++) {
		_data_pins[i]->dir(mraa::DIR_OUT);
		_data_pins[i]->write((value >> i) & 0x01);
	}

	pulseEnable();
}

void Lcd::clear() {
	command(LCD_CLEARDISPLAY);  // clear display, set cursor position to zero
	lcdDelayMicroSeconds(2000);  // this command takes a long time!
}

void Lcd::display() {
	_displaycontrol |= LCD_DISPLAYON;
	command(LCD_DISPLAYCONTROL | _displaycontrol);
}

void Lcd::lcdSetCursor(uint32_t col, uint32_t row) {
	int row_offsets[] = { 0x00, 0x40, 0x14, 0x54 };
	if ( row >= _numlines ) {
		row = _numlines-1;    // we count rows starting w/0
	}

	command(LCD_SETDDRAMADDR | (col + row_offsets[row]));
/*	// TODO implement lcdSetCursor()
	printf("\n*** start lcdSetCursor()");
	printf("\nThe cursor moves to row %u and column %u", row, col);
	printf("\n*** stop lcdSetCursor()");*/
}

void Lcd::lcdPrint(const char *str) {
	  while (*str)
		  lcdWrite(*str++);
/*	// TODO implement lcdPrint()
	printf("\n*** start lcdPrint()");
	printf("\nlcd print: %s", str);
	printf("\n*** stop lcdPrint()");*/
}

/**
 * set the direction of a given pin without altering other pins
 * on the same port
 *
 */
void Lcd::command(uint32_t value) {
	send(value, 0);
}

void Lcd::send(uint32_t value, uint32_t mode) {
	_rs->write(mode);

  // rw pin removed, add later if needed

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

uint32_t Lcd::lcdWrite(uint32_t value) {
	send(value, 1);
	return 1; // assume sucess
}

void Lcd::pulseEnable(void) {
	_enable->write(0);
	lcdDelayMicroSeconds(1);
	_enable->write(1);
	lcdDelayMicroSeconds(1);    // enable pulse must be >450ns
	_enable->write(0);
	lcdDelayMicroSeconds(100);   // commands need > 37us to settle
}

/**
 * delay for the given number of microseconds, for 80MHz processor
 */
void Lcd::lcdDelayMicroSeconds(uint32_t us) {
	usleep(us);
}



} /* namespace lcd_hitachi */

Lcd driver Example code

C/C++
#include <iostream>
using namespace std;
#include "mraa.hpp"
#include "Lcd.h"

using namespace mraa;
using namespace lcd_hitachi;

int main(void) {
	cout << "Hello IOT2000." << endl;


	Lcd* lcd = new Lcd();

	lcd->init(8, 9, 4, 5, 6, 7);
	lcd->begin(16,2, 0);

	lcd->setCursor(0,0); // move to the beginning of the first line
	lcd->print("Hello, world!");


	delete lcd;


	return MRAA_SUCCESS;
}

Linux Command Line Utility

C/C++
call with 0, 1 or 2 arguments.
0: clear display
1: clear and print argument on line 1
2: clear and print 1st argument on line 1, 2nd arguent on line 2
#include <iostream>
using namespace std;
#include "mraa.hpp"
#include "Lcd.h"

using namespace mraa;
using namespace lcd_hitachi;

int main(int argc, char* argv[]) {

	std::string *sText= NULL;
	std::string sEmpty("                ");

	cout << "Hello IOT2000." << endl;


	Lcd* lcd = new Lcd();

	lcd->init(8, 9, 4, 5, 6, 7);
	lcd->begin(16,2, 0);

	if (argc > 1) {
		lcd->setCursor(0,0); // move to the beginning of the first line
		sText = new std::string(argv[1]);
		lcd->print(*sText);
		delete sText;
		if (argc > 2) {
			lcd->setCursor(0,1); // move to the beginning of the second line
			sText = new std::string(argv[2]);
			lcd->print(*sText);
			delete sText;
		}
//	}else { // clean screen
//
//			lcd->setCursor(0,0); // move to the beginning of the first line
//			lcd->print(sEmpty);
//			lcd->setCursor(0,0); // move to the beginning of the first line
//			lcd->print(sEmpty);
//
	}




	delete lcd;


	return MRAA_SUCCESS;
}

Credits

Jan Cumps

Jan Cumps

22 projects • 23 followers

Comments