From 574f944fbb01c926033566cc90159a52fb0e6075 Mon Sep 17 00:00:00 2001 From: "Ruslan V. Uss" Date: Wed, 26 Oct 2016 19:21:55 +0600 Subject: [PATCH] Driver for HD44780 LCDs (#246) Driver for HD44780 LCDs connected directly to GPIO / to I2C by PCF8574-like GPIO expanders (#246) --- examples/hd44780_lcd/Makefile | 6 + examples/hd44780_lcd/main.c | 62 +++++++++ examples/hd44780_lcd/schematics.png | Bin 0 -> 31131 bytes examples/i2c_lcd_test/Makefile | 6 + examples/i2c_lcd_test/i2c_lcd.png | Bin 0 -> 14468 bytes examples/i2c_lcd_test/main.c | 71 +++++++++++ extras/hd44780/component.mk | 8 ++ extras/hd44780/hd44780.c | 189 ++++++++++++++++++++++++++++ extras/hd44780/hd44780.h | 115 +++++++++++++++++ 9 files changed, 457 insertions(+) create mode 100644 examples/hd44780_lcd/Makefile create mode 100644 examples/hd44780_lcd/main.c create mode 100644 examples/hd44780_lcd/schematics.png create mode 100644 examples/i2c_lcd_test/Makefile create mode 100644 examples/i2c_lcd_test/i2c_lcd.png create mode 100644 examples/i2c_lcd_test/main.c create mode 100644 extras/hd44780/component.mk create mode 100644 extras/hd44780/hd44780.c create mode 100644 extras/hd44780/hd44780.h diff --git a/examples/hd44780_lcd/Makefile b/examples/hd44780_lcd/Makefile new file mode 100644 index 0000000..02a868d --- /dev/null +++ b/examples/hd44780_lcd/Makefile @@ -0,0 +1,6 @@ +PROGRAM = hd44780_lcd +EXTRA_COMPONENTS = extras/hd44780 + +HD44780_I2C = 0 + +include ../../common.mk diff --git a/examples/hd44780_lcd/main.c b/examples/hd44780_lcd/main.c new file mode 100644 index 0000000..00ea8ad --- /dev/null +++ b/examples/hd44780_lcd/main.c @@ -0,0 +1,62 @@ +/* + * Example of using HD44780 driver with LCD + * connected directly to GPIO pins + * + * Part of esp-open-rtos + * Copyright (C) 2016 Ruslan V. Uss + * BSD Licensed as described in the file LICENSE + */ +#include +#include +#include + +#include + +static const uint8_t char_data[] = { + 0x04, 0x0e, 0x0e, 0x0e, 0x1f, 0x00, 0x04, 0x00, + 0x1f, 0x11, 0x0a, 0x04, 0x0a, 0x11, 0x1f, 0x00 +}; + +void user_init(void) +{ + uart_set_baud(0, 115200); + printf("SDK version:%s\n", sdk_system_get_sdk_version()); + + hd44780_t lcd = { + .font = HD44780_FONT_5X8, + .lines = 2, + .pins = { + .rs = 5, + .e = 4, + .d4 = 0, + .d5 = 2, + .d6 = 14, + .d7 = 12, + .bl = HD44780_NOT_USED + } + }; + + hd44780_init(&lcd); + hd44780_upload_character(&lcd, 0, char_data); + hd44780_upload_character(&lcd, 1, char_data + 8); + + hd44780_gotoxy(&lcd, 0, 0); + hd44780_puts(&lcd, "\x08 Hello world!"); + hd44780_gotoxy(&lcd, 0, 1); + hd44780_puts(&lcd, "\x09 "); + + char time[16]; + + while (true) + { + hd44780_gotoxy(&lcd, 2, 1); + + snprintf(time, 7, "%u ", sdk_system_get_time() / 1000000); + time[sizeof(time) - 1] = 0; + + hd44780_puts(&lcd, time); + + for (uint32_t i = 0; i < 1000; i++) + sdk_os_delay_us(1000); + } +} diff --git a/examples/hd44780_lcd/schematics.png b/examples/hd44780_lcd/schematics.png new file mode 100644 index 0000000000000000000000000000000000000000..d3145cd4d951c829635e396543efeb6e5715f0ae GIT binary patch literal 31131 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 literal 0 HcmV?d00001 diff --git a/examples/i2c_lcd_test/Makefile b/examples/i2c_lcd_test/Makefile new file mode 100644 index 0000000..4e03494 --- /dev/null +++ b/examples/i2c_lcd_test/Makefile @@ -0,0 +1,6 @@ +PROGRAM = i2c_lcd_test +EXTRA_COMPONENTS = extras/i2c extras/pcf8574 extras/hd44780 + +HD44780_I2C = 1 + +include ../../common.mk diff --git a/examples/i2c_lcd_test/i2c_lcd.png b/examples/i2c_lcd_test/i2c_lcd.png new file mode 100644 index 0000000000000000000000000000000000000000..815f4febc0a8fa758ef5e04c1e5cc506ffecd7f2 GIT binary patch literal 14468 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 FzW|~En??Wt literal 0 HcmV?d00001 diff --git a/examples/i2c_lcd_test/main.c b/examples/i2c_lcd_test/main.c new file mode 100644 index 0000000..1951777 --- /dev/null +++ b/examples/i2c_lcd_test/main.c @@ -0,0 +1,71 @@ +/* + * Example of using driver for text LCD + * connected to I2C by PCF8574 + * + * Part of esp-open-rtos + * Copyright (C) 2016 Ruslan V. Uss + * BSD Licensed as described in the file LICENSE + */ +#include +#include +#include +#include + +#include + +#define SCL_PIN 5 +#define SDA_PIN 4 +#define ADDR 0x27 + +static const uint8_t char_data[] = { + 0x04, 0x0e, 0x0e, 0x0e, 0x1f, 0x00, 0x04, 0x00, + 0x1f, 0x11, 0x0a, 0x04, 0x0a, 0x11, 0x1f, 0x00 +}; + +void user_init(void) +{ + uart_set_baud(0, 115200); + printf("SDK version:%s\n", sdk_system_get_sdk_version()); + + i2c_init(SCL_PIN, SDA_PIN); + + hd44780_t lcd = { + .addr = ADDR, + .font = HD44780_FONT_5X8, + .lines = 2, + .pins = { + .rs = 0, + .e = 2, + .d4 = 4, + .d5 = 5, + .d6 = 6, + .d7 = 7, + .bl = 3 + }, + .backlight = true + }; + + hd44780_init(&lcd); + hd44780_upload_character(&lcd, 0, char_data); + hd44780_upload_character(&lcd, 1, char_data + 8); + + hd44780_gotoxy(&lcd, 0, 0); + hd44780_puts(&lcd, "\x08 Hello world!"); + hd44780_gotoxy(&lcd, 0, 1); + hd44780_puts(&lcd, "\x09 "); + + char time[16]; + + while (true) + { + hd44780_gotoxy(&lcd, 2, 1); + + snprintf(time, 7, "%u ", sdk_system_get_time() / 1000000); + time[sizeof(time) - 1] = 0; + + hd44780_puts(&lcd, time); + + for (uint32_t i = 0; i < 1000; i++) + sdk_os_delay_us(1000); + } +} diff --git a/extras/hd44780/component.mk b/extras/hd44780/component.mk new file mode 100644 index 0000000..56f4b8a --- /dev/null +++ b/extras/hd44780/component.mk @@ -0,0 +1,8 @@ +INC_DIRS += $(hd44780_ROOT).. +hd44780_SRC_DIR = $(hd44780_ROOT) + +HD44780_I2C ?= 1 + +hd44780_CFLAGS = -DHD44780_I2C=${HD44780_I2C} $(CFLAGS) + +$(eval $(call component_compile_rules,hd44780)) diff --git a/extras/hd44780/hd44780.c b/extras/hd44780/hd44780.c new file mode 100644 index 0000000..b44f65a --- /dev/null +++ b/extras/hd44780/hd44780.c @@ -0,0 +1,189 @@ +#include "hd44780.h" + +#if (HD44780_I2C) +#include +#else +#include +#endif +#include + +#define MS 1000 + +#define DELAY_CMD_LONG (3 * MS) // >1.53ms according to datasheet +#define DELAY_CMD_SHORT (60) // >39us according to datasheet +#define DELAY_TOGGLE (10) +#define DELAY_INIT (5 * MS) + +#define CMD_CLEAR 0x01 +#define CMD_RETURN_HOME 0x02 +#define CMD_ENTRY_MODE 0x04 +#define CMD_DISPLAY_CTRL 0x08 +#define CMD_SHIFT 0x10 +#define CMD_FUNC_SET 0x20 +#define CMD_CGRAM_ADDR 0x40 +#define CMD_DDRAM_ADDR 0x80 + +// CMD_ENTRY_MODE +#define ARG_EM_INCREMENT (1 << 1) +#define ARG_EM_SHIFT (1) + +// CMD_DISPLAY_CTRL +#define ARG_DC_DISPLAY_ON (1 << 2) +#define ARG_DC_CURSOR_ON (1 << 1) +#define ARG_DC_CURSOR_BLINK (1) + +// CMD_FUNC_SET +#define ARG_FS_8_BIT (1 << 4) +#define ARG_FS_2_LINES (1 << 3) +#define ARG_FS_FONT_5X10 (1 << 2) + +#if (HD44780_I2C) + #define init_delay() do { sdk_os_delay_us(DELAY_INIT); } while (0) + #define short_delay() + #define long_delay() do { sdk_os_delay_us(DELAY_CMD_LONG); } while (0) +#else + #define init_delay() do { sdk_os_delay_us(DELAY_INIT); } while (0) + #define short_delay() do { sdk_os_delay_us(DELAY_CMD_SHORT); } while (0) + #define long_delay() do { sdk_os_delay_us(DELAY_CMD_LONG); } while (0) + #define toggle_delay() do { sdk_os_delay_us(DELAY_TOGGLE); } while (0) +#endif + +static const uint8_t line_addr[] = { 0x00, 0x40, 0x14, 0x54 }; + +static void write_nibble(const hd44780_t *lcd, uint8_t b, bool rs) +{ +#if (HD44780_I2C) + uint8_t data = (((b >> 3) & 1) << lcd->pins.d7) + | (((b >> 2) & 1) << lcd->pins.d6) + | (((b >> 1) & 1) << lcd->pins.d5) + | ((b & 1) << lcd->pins.d4) + | (rs ? 1 << lcd->pins.rs : 0) + | (lcd->backlight ? 1 << lcd->pins.bl : 0); + + pcf8574_port_write(lcd->addr, data | (1 << lcd->pins.e)); + pcf8574_port_write(lcd->addr, data); +#else + gpio_write(lcd->pins.d7, (b >> 3) & 1); + gpio_write(lcd->pins.d6, (b >> 2) & 1); + gpio_write(lcd->pins.d5, (b >> 1) & 1); + gpio_write(lcd->pins.d4, b & 1); + gpio_write(lcd->pins.rs, rs); + gpio_write(lcd->pins.e, true); + toggle_delay(); + gpio_write(lcd->pins.e, false); +#endif +} + +static void write_byte(const hd44780_t *lcd, uint8_t b, bool rs) +{ + write_nibble(lcd, b >> 4, rs); + write_nibble(lcd, b, rs); +} + +void hd44780_init(const hd44780_t *lcd) +{ +#if (!HD44780_I2C) + gpio_enable(lcd->pins.rs, GPIO_OUTPUT); + gpio_enable(lcd->pins.e, GPIO_OUTPUT); + gpio_enable(lcd->pins.d4, GPIO_OUTPUT); + gpio_enable(lcd->pins.d5, GPIO_OUTPUT); + gpio_enable(lcd->pins.d6, GPIO_OUTPUT); + gpio_enable(lcd->pins.d7, GPIO_OUTPUT); + if (lcd->pins.bl != HD44780_NOT_USED) + gpio_enable(lcd->pins.bl, GPIO_OUTPUT); +#endif + // switch to 4 bit mode + for (uint8_t i = 0; i < 3; i ++) + { + write_nibble(lcd, (CMD_FUNC_SET | ARG_FS_8_BIT) >> 4, false); + init_delay(); + } + write_nibble(lcd, CMD_FUNC_SET >> 4, false); + + // Specify the number of display lines and character font + write_byte(lcd, + CMD_FUNC_SET + | (lcd->lines > 1 ? ARG_FS_2_LINES : 0) + | (lcd->font == HD44780_FONT_5X10 ? ARG_FS_FONT_5X10 : 0), + false); + short_delay(); + // Display off + hd44780_control(lcd, false, false, false); + // Clear + hd44780_clear(lcd); + // Entry mode set + write_byte(lcd, CMD_ENTRY_MODE | ARG_EM_INCREMENT, false); + short_delay(); + // Display on + hd44780_control(lcd, true, false, false); +} + +void hd44780_control(const hd44780_t *lcd, bool on, bool cursor, bool cursor_blink) +{ + write_byte(lcd, + CMD_DISPLAY_CTRL + | (on ? ARG_DC_DISPLAY_ON : 0) + | (cursor ? ARG_DC_CURSOR_ON : 0) + | (cursor_blink ? ARG_DC_CURSOR_BLINK : 0), + false); + short_delay(); +} + +void hd44780_clear(const hd44780_t *lcd) +{ + write_byte(lcd, CMD_CLEAR, false); + long_delay(); +} + +void hd44780_gotoxy(const hd44780_t *lcd, uint8_t col, uint8_t line) +{ + if (line >= lcd->lines) line = lcd->lines - 1; + uint8_t addr = line < sizeof(line_addr) ? line_addr[line] : 0; + write_byte(lcd, CMD_DDRAM_ADDR + addr + col, false); + short_delay(); +} + +void hd44780_putc(const hd44780_t *lcd, char c) +{ + write_byte(lcd, c, true); + short_delay(); +} + +void hd44780_puts(const hd44780_t *lcd, const char *s) +{ + while (*s) + { + hd44780_putc(lcd, *s); + s++; + } +} + +void hd44780_set_backlight(hd44780_t *lcd, bool on) +{ + if (lcd->pins.bl == HD44780_NOT_USED) + return; + +#if (HD44780_I2C) + pcf8574_gpio_write(lcd->addr, lcd->pins.bl, on); +#else + gpio_write(lcd->pins.bl, on); +#endif + + lcd->backlight = on; +} + +void hd44780_upload_character(const hd44780_t *lcd, uint8_t num, const uint8_t *data) +{ + if (num > 7) return; + + uint8_t bytes = lcd->font == HD44780_FONT_5X8 ? 8 : 10; + write_byte(lcd, CMD_CGRAM_ADDR + num * bytes, false); + short_delay(); + for (uint8_t i = 0; i < bytes; i ++) + { + write_byte(lcd, data[i], true); + short_delay(); + } + + hd44780_gotoxy(lcd, 0, 0); +} diff --git a/extras/hd44780/hd44780.h b/extras/hd44780/hd44780.h new file mode 100644 index 0000000..a00302b --- /dev/null +++ b/extras/hd44780/hd44780.h @@ -0,0 +1,115 @@ +/* + * Driver for LCD text displays on LCD connected to I2C by PCF8574 + * + * Part of esp-open-rtos + * Copyright (C) 2016 Ruslan V. Uss + * BSD Licensed as described in the file LICENSE + */ +#ifndef _EXTRAS_HD44780_H_ +#define _EXTRAS_HD44780_H_ + +#include +#include + +#ifndef HD44780_I2C +#define HD44780_I2C 0 +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#define HD44780_NOT_USED 0xff + +/** + * LCD font type. Please refer to the datasheet + * of your module. + */ +typedef enum +{ + HD44780_FONT_5X8 = 0, + HD44780_FONT_5X10 +} hd44780_font_t; + +/** + * LCD descriptor. Fill it before use. + */ +typedef struct +{ + uint8_t addr; //!< PCF8574 address (0b0100) + struct + { + uint8_t rs; //!< gpio/register bit used for RS pin + uint8_t e; //!< register bit used for E pin + uint8_t d4; //!< register bit used for D4 pin + uint8_t d5; //!< register bit used for D5 pin + uint8_t d6; //!< register bit used for D5 pin + uint8_t d7; //!< register bit used for D5 pin + uint8_t bl; //!< register bit used for backlight, 0xFF if not used + } pins; + hd44780_font_t font; //!< LCD Font type + uint8_t lines; //!< Number of lines for LCD. Many 16x1 LCD has two lines (like 8x2) + bool backlight; //!< Current backlight state +} hd44780_t; + +/** + * Init LCD. Set poition to (0, 0) + * \param lcd Pointer to the LCD descriptor + */ +void hd44780_init(const hd44780_t *lcd); + +/** + * On/off LCD, show/hide cursor, set cursor blink + * \param lcd Pointer to the LCD descriptor + */ +void hd44780_control(const hd44780_t *lcd, bool on, bool cursor, bool cursor_blink); + +/** + * Clear LCD memory and move char position to (0, 0) + * \param lcd Pointer to the LCD descriptor + */ +void hd44780_clear(const hd44780_t *lcd); + +/** + * Set current char position + * \param lcd Pointer to the LCD descriptor + * \param col Column + * \param line Line + */ +void hd44780_gotoxy(const hd44780_t *lcd, uint8_t col, uint8_t line); + +/** + * Print character + * \param lcd Pointer to the LCD descriptor + * \param c Character + */ +void hd44780_putc(const hd44780_t *lcd, char c); + +/** + * Print string + * \param lcd Pointer to the LCD descriptor + * \param s String + */ +void hd44780_puts(const hd44780_t *lcd, const char *s); + +/** + * Switch backlight + * \param lcd Pointer to the LCD descriptor + * \param on Turn backlight on if true + */ +void hd44780_set_backlight(hd44780_t *lcd, bool on); + +/** + * Upload character data to the CGRAM. + * Current position will be set to (0, 0) after uploading + * \param lcd Pointer to the LCD descriptor + * \param num Character number (0..7) + * \param data Character data: 8 or 10 bytes depending on the font + */ +void hd44780_upload_character(const hd44780_t *lcd, uint8_t num, const uint8_t *data); + +#ifdef __cplusplus +} +#endif + +#endif /* _EXTRAS_HD44780_H_ */