Driver for HD44780 LCDs (#246)
Driver for HD44780 LCDs connected directly to GPIO / to I2C by PCF8574-like GPIO expanders (#246)
This commit is contained in:
parent
698f7424eb
commit
574f944fbb
9 changed files with 457 additions and 0 deletions
6
examples/hd44780_lcd/Makefile
Normal file
6
examples/hd44780_lcd/Makefile
Normal file
|
@ -0,0 +1,6 @@
|
|||
PROGRAM = hd44780_lcd
|
||||
EXTRA_COMPONENTS = extras/hd44780
|
||||
|
||||
HD44780_I2C = 0
|
||||
|
||||
include ../../common.mk
|
62
examples/hd44780_lcd/main.c
Normal file
62
examples/hd44780_lcd/main.c
Normal file
|
@ -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 <unclerus@gmail.com>
|
||||
* BSD Licensed as described in the file LICENSE
|
||||
*/
|
||||
#include <esp/uart.h>
|
||||
#include <espressif/esp_common.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <hd44780/hd44780.h>
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
BIN
examples/hd44780_lcd/schematics.png
Normal file
BIN
examples/hd44780_lcd/schematics.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 30 KiB |
6
examples/i2c_lcd_test/Makefile
Normal file
6
examples/i2c_lcd_test/Makefile
Normal file
|
@ -0,0 +1,6 @@
|
|||
PROGRAM = i2c_lcd_test
|
||||
EXTRA_COMPONENTS = extras/i2c extras/pcf8574 extras/hd44780
|
||||
|
||||
HD44780_I2C = 1
|
||||
|
||||
include ../../common.mk
|
BIN
examples/i2c_lcd_test/i2c_lcd.png
Normal file
BIN
examples/i2c_lcd_test/i2c_lcd.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 14 KiB |
71
examples/i2c_lcd_test/main.c
Normal file
71
examples/i2c_lcd_test/main.c
Normal file
|
@ -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 <unclerus@gmail.com>
|
||||
* BSD Licensed as described in the file LICENSE
|
||||
*/
|
||||
#include <esp/uart.h>
|
||||
#include <espressif/esp_common.h>
|
||||
#include <i2c/i2c.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <hd44780/hd44780.h>
|
||||
|
||||
#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);
|
||||
}
|
||||
}
|
8
extras/hd44780/component.mk
Normal file
8
extras/hd44780/component.mk
Normal file
|
@ -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))
|
189
extras/hd44780/hd44780.c
Normal file
189
extras/hd44780/hd44780.c
Normal file
|
@ -0,0 +1,189 @@
|
|||
#include "hd44780.h"
|
||||
|
||||
#if (HD44780_I2C)
|
||||
#include <pcf8574/pcf8574.h>
|
||||
#else
|
||||
#include <esp/gpio.h>
|
||||
#endif
|
||||
#include <espressif/esp_common.h>
|
||||
|
||||
#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);
|
||||
}
|
115
extras/hd44780/hd44780.h
Normal file
115
extras/hd44780/hd44780.h
Normal file
|
@ -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 <unclerus@gmail.com>
|
||||
* BSD Licensed as described in the file LICENSE
|
||||
*/
|
||||
#ifndef _EXTRAS_HD44780_H_
|
||||
#define _EXTRAS_HD44780_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#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<A2><A1><A0>)
|
||||
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_ */
|
Loading…
Reference in a new issue