ESP-IDF and 2x16 LCD display

chuledeco
Posts: 8
Joined: Thu Feb 13, 2020 3:22 pm

ESP-IDF and 2x16 LCD display

Postby chuledeco » Sun Mar 15, 2020 1:36 pm

Hello,

I was looking and looking and I can't find a library to handle a standard 2x16 display using the RS, R/W, E, D4, D5, D6, and D7 pins.

It seems that there are only solutions for the I2C driver.

Arduino has the LiquidCrystal.h library but is written in C++.

It is my last chance before starting to write it myself but I think it is very strange that it does not exist, I'm sure I'm not seeing it.

Can anyone help me guiding my to the resource?

Thanks in advance, Julian.

Sprite
Espressif staff
Espressif staff
Posts: 10593
Joined: Thu Nov 26, 2015 4:08 am

Re: ESP-IDF and 2x16 LCD display

Postby Sprite » Sun Mar 15, 2020 4:29 pm

C++ should not be an issue on esp-idf. You can even import the Arduino base libraries if you want to use Arduino stuff.

Kaisha
Posts: 42
Joined: Thu Mar 05, 2020 8:59 pm

Re: ESP-IDF and 2x16 LCD display

Postby Kaisha » Sun Mar 15, 2020 6:43 pm

The ESP-IDF handles C++ just fine. Here's what I'm using, feel free to copy/paste:

Code: Select all

// **************************************************************************************************************************
//	SumpRelayModule\HD44780U.h
//
//		HD44780U LCD control
//		- the HD44780U internal clock runs at 270kHz (typically) and so timings are all based on 270kHz
//		- HD44780U requires a 37 us delay between commands, and a 41 us delay between character writes
//
//																			Ryan Boghean
//																			August 2017
//																			July 2018
//																			January 2020
//
// **************************************************************************************************************************

# pragma once

# include <cstdint>
# include <cassert>
# include <utility>

# include <freertos/FreeRTOS.h>
# include <freertos/task.h>
# include <esp_err.h>
# include <esp_log.h>
# include <driver/gpio.h>


// -------------------------------------------------------------------------------------------------
//	Display namespace
// -------------------------------------------------------------------------------------------------

namespace Display {


// -------------------------------------------------------------------------------------------------
//	HD44780U_4bit
//		- uses a 4 bit data interface (which means 6 lines in total required)
// -------------------------------------------------------------------------------------------------

// ----- HD44780U_4bit -----
template <
	gpio_num_t rs_, gpio_num_t e_, gpio_num_t d4_, gpio_num_t d5_, gpio_num_t d6_, gpio_num_t d7_, 
	uint8_t cols_, uint8_t rows_, bool font_mode_
	> class HD44780U_4bit {

	static_assert(cols_ > 0, "Error: display cannot have 0 columns.");
	static_assert(rows_ == 1 || rows_ == 2 || rows_ == 4, "Error: only supports 1, 2, or 4 row displays.");

	private:
		// pin constants
		static constexpr gpio_num_t pin_rs = rs_;
		static constexpr gpio_num_t pin_e = e_;

		static constexpr gpio_num_t d4 = d4_;
		static constexpr gpio_num_t d5 = d5_;
		static constexpr gpio_num_t d6 = d6_;
		static constexpr gpio_num_t d7 = d7_;

		// display constants
		static constexpr bool font_mode = font_mode_;							// false = 5x8 font, true = 5x10 font
		static constexpr bool display_lines = (rows_ == 4) ? true : false;		// false = 1 and 2 display lines, true = 4 display lines
		static constexpr bool data_length = false;								// false = 4 bits, true = 8 bits

		static constexpr uint8_t cols = cols_;
		static constexpr uint8_t rows = rows_;
	
		// internal helpers
		static void SendInit(uint8_t cmd);				// sends an initialization command
		static void SendCommand(uint8_t cmd);			// sends a command
		static void SendChar(char);						// sends a character

	public:
		HD44780U_4bit();

		// info
		static constexpr uint8_t RowCount() { return rows; }
		static constexpr uint8_t ColumnCount() { return cols; }

		// access
		void Init();																				// must be called prior to using 
		void Clear();																				// clears whole display
		void ClearLn(uint8_t row);																	// clears a single line
		void SetCursor(uint8_t row, uint8_t col);													// set the cursor position
		void PrintChar(char c);																		// print a single character at current cursor position, increments cursor
		void PrintLn(uint8_t row, const char*);														// prints the string to the line
		template<class... TArgs> void PrintLn(uint8_t row, const char* fmt, TArgs&& ... args);		// prints a full line using printf formatting, any character off the edge will be truncated, control characters (/n /t etc...) should not be used
	};


// ----- convenience macros -----
# define HD_TEMPLATE template<gpio_num_t rs_, gpio_num_t e_, gpio_num_t d4_, gpio_num_t d5_, gpio_num_t d6_, gpio_num_t d7_, uint8_t cols_, uint8_t rows_, bool font_mode_>
# define HD_CLASS HD44780U_4bit<rs_, e_, d4_, d5_, d6_, d7_, cols_, rows_, font_mode_>


// ----- standard member functions -----
HD_TEMPLATE HD_CLASS::HD44780U_4bit() {}


// ----- internal helpers -----
HD_TEMPLATE void HD_CLASS::SendInit(uint8_t cmd) {

	gpio_set_level(pin_rs, 0);
	gpio_set_level(pin_e, 1);

	// 4-bit init commands only send the high nibble
	gpio_set_level(d4, (cmd & 0b00010000) != 0);
	gpio_set_level(d5, (cmd & 0b00100000) != 0);
	gpio_set_level(d6, (cmd & 0b01000000) != 0);
	gpio_set_level(d7, (cmd & 0b10000000) != 0);

	ets_delay_us(37);
	gpio_set_level(pin_e, 0);
	ets_delay_us(37);
	gpio_set_level(pin_e, 1);
	}

HD_TEMPLATE void HD_CLASS::SendCommand(uint8_t cmd) {

	gpio_set_level(pin_rs, 0);

	// send high nibble
	gpio_set_level(d4, (cmd & 0b00010000) != 0);
	gpio_set_level(d5, (cmd & 0b00100000) != 0);
	gpio_set_level(d6, (cmd & 0b01000000) != 0);
	gpio_set_level(d7, (cmd & 0b10000000) != 0);

	ets_delay_us(37);
	gpio_set_level(pin_e, 0);
	ets_delay_us(37);
	gpio_set_level(pin_e, 1);

	// send low nibble
	gpio_set_level(d4, (cmd & 0b00000001) != 0);
	gpio_set_level(d5, (cmd & 0b00000010) != 0);
	gpio_set_level(d6, (cmd & 0b00000100) != 0);
	gpio_set_level(d7, (cmd & 0b00001000) != 0);

	ets_delay_us(37);
	gpio_set_level(pin_e, 0);
	ets_delay_us(37);
	gpio_set_level(pin_e, 1);
	}

HD_TEMPLATE void HD_CLASS::SendChar(char c) {

	gpio_set_level(pin_rs, 1);

	// send high nibble
	gpio_set_level(d4, (c & 0b00010000) != 0);
	gpio_set_level(d5, (c & 0b00100000) != 0);
	gpio_set_level(d6, (c & 0b01000000) != 0);
	gpio_set_level(d7, (c & 0b10000000) != 0);

	ets_delay_us(41);
	gpio_set_level(pin_e, 0);
	ets_delay_us(41);
	gpio_set_level(pin_e, 1);

	// send low nibble
	gpio_set_level(d4, (c & 0b00000001) != 0);
	gpio_set_level(d5, (c & 0b00000010) != 0);
	gpio_set_level(d6, (c & 0b00000100) != 0);
	gpio_set_level(d7, (c & 0b00001000) != 0);

	ets_delay_us(41);
	gpio_set_level(pin_e, 0);
	ets_delay_us(41);
	gpio_set_level(pin_e, 1);
	}


// ----- access -----
HD_TEMPLATE void HD_CLASS::Init() {

	constexpr uint8_t cmd_por = 0x30;
	constexpr uint8_t cmd_4bit_mode = 0x20;
	constexpr uint8_t cmd_8bit_mode = 0x30;

	// config GPIO pins
	gpio_config_t io_conf = {};
	io_conf.pin_bit_mask =
		(1ULL << static_cast<uint64_t>(pin_rs)) |
		(1ULL << static_cast<uint64_t>(pin_e)) |
		(1ULL << static_cast<uint64_t>(d4)) |
		(1ULL << static_cast<uint64_t>(d5)) |
		(1ULL << static_cast<uint64_t>(d6)) |
		(1ULL << static_cast<uint64_t>(d7));
	io_conf.mode = GPIO_MODE_OUTPUT;
	io_conf.pull_up_en = GPIO_PULLUP_DISABLE;
	io_conf.pull_down_en = GPIO_PULLDOWN_DISABLE;
	io_conf.intr_type = GPIO_INTR_DISABLE;

	ESP_ERROR_CHECK(gpio_config(&io_conf));

	gpio_set_level(pin_rs, 0);
	gpio_set_level(pin_e, 1);
	gpio_set_level(d4, 0);
	gpio_set_level(d5, 0);
	gpio_set_level(d6, 0);
	gpio_set_level(d7, 0);

	// power on reset
	ets_delay_us(100000);							// wait 15ms (other docs claim 40ms, some as high as 100) after Vcc rises past 4.5v (2.7v)
	SendInit(cmd_por);
	ets_delay_us(5000);								// wait more than 4.1ms
	SendInit(cmd_por);
	ets_delay_us(1000);								// wait more than 100us
	SendInit(cmd_por);
	ets_delay_us(1000);								// no delay specified here in docs, but other libraries have it
	if (data_length) SendInit(cmd_8bit_mode);
	else SendInit(cmd_4bit_mode);

	// initialize
	uint8_t cmd_fs = 0x20;					// 'function set' command
	if (font_mode) cmd_fs |= 0x04;
	if (display_lines) cmd_fs |= 0x08;
	if (data_length) cmd_fs |= 0x10;
	SendCommand(cmd_fs);
	SendCommand(0x0C);					// turn display on, cursor/blink off
	SendCommand(0x01);					// clear display
	ets_delay_us(20000);						// clear display requires a long wait before new commands

	// ready to go
	Clear();
	}

HD_TEMPLATE void HD_CLASS::Clear() {
	for (uint8_t i = 0; i < rows; ++i) {
		ClearLn(i);
		}
	}

HD_TEMPLATE void HD_CLASS::ClearLn(uint8_t row) {
	SetCursor(row, 0);
	for (uint8_t i = 0; i < cols; ++i) {
		SendChar(32);
		}
	}

HD_TEMPLATE void HD_CLASS::SetCursor(uint8_t row, uint8_t col) {
	static constexpr uint8_t row_offsets[4] = { 0x00, 0x40, 0x14, 0x54 };
	assert(row < rows);
	assert(col < cols);

	SendCommand(0x80 + row_offsets[row] + col);
	}

HD_TEMPLATE void HD_CLASS::PrintChar(char c) {
	SendChar(c);
	}

void HD_CLASS::PrintLn(uint8_t row, const char* s) {
	if (row > rows) return;				// sanity check

	// set cursor
	SetCursor(row, 0);

	// print string
	size_t n = 0;
	while (n < cols && *s) {
		SendChar(*s++);
		++n;
		}

	while (n < cols) {
		SendChar(' ');
		++n;
		}
	}

HD_TEMPLATE template<class... TArgs> void HD_CLASS::PrintLn(uint8_t row, const char* fmt, TArgs&& ... args) {
	if (row > rows) return;				// sanity check

	// print to buffer
	char bfr[cols + 1];
	int n = vsnprintf(bfr, cols + 1, fmt, std::forward<TArgs>(args)...);
	while (n < cols) {
		bfr[n] = 32;
		++n;
		}

	// set cursor
	SetCursor(row, 0);

	// send data
	for (uint8_t i = 0; i < cols; ++i) SendChar(bfr[i]);
	}


// ----- clean up macros -----
# undef HD_CLASS
# undef HD_TEMPLATE


// -------------------------------------------------------------------------------------------------
//	End 
// -------------------------------------------------------------------------------------------------

}			// end of Display namespace

Who is online

Users browsing this forum: Baidu [Spider], Bing [Bot], ChatGPT-User and 4 guests