#include "lcd.h" // commands constexpr int LCD_CLEARDISPLAY = 0x01; constexpr int LCD_RETURNHOME = 0x02; constexpr int LCD_ENTRYMODESET = 0x04; constexpr int LCD_DISPLAYCONTROL = 0x08; constexpr int LCD_CURSORSHIFT = 0x10; constexpr int LCD_FUNCTIONSET = 0x20; constexpr int LCD_SETCGRAMADDR = 0x40; constexpr int LCD_SETDDRAMADDR = 0x80; // flags for display entry mode constexpr int LCD_ENTRYSHIFTINCREMENT = 0x01; constexpr int LCD_ENTRYLEFT = 0x02; // flags for display and cursor control constexpr int LCD_BLINKON = 0x01; constexpr int LCD_CURSORON = 0x02; constexpr int LCD_DISPLAYON = 0x04; // flags for function set constexpr int LCD_5x10DOTS = 0x04; constexpr int LCD_2LINE = 0x08; constexpr int LCD_8BITMODE = 0x10; constexpr int LCD_BACKLIGHT = 0x08; constexpr int LCD_ENABLE_BIT = 0x04; LCD::LCD(i2c_inst_t *i2c, const uint gpio_sda, const uint gpio_scl, const uint8_t i2c_addr, uint8_t num_cols, uint8_t num_lines) : i2c{i2c}, i2c_addr{i2c_addr}, num_cols{num_cols}, num_lines{num_lines} { i2c_init(i2c1, 100 * 1000); gpio_set_function(gpio_sda, GPIO_FUNC_I2C); gpio_set_function(gpio_scl, GPIO_FUNC_I2C); gpio_pull_up(gpio_sda); gpio_pull_up(gpio_scl); sendByte(0x03, Mode::COMMAND); sendByte(0x03, Mode::COMMAND); sendByte(0x03, Mode::COMMAND); sendByte(0x02, Mode::COMMAND); sendByte(LCD_ENTRYMODESET | LCD_ENTRYLEFT, Mode::COMMAND); sendByte(LCD_FUNCTIONSET | LCD_2LINE, Mode::COMMAND); sendByte(LCD_DISPLAYCONTROL | LCD_DISPLAYON, Mode::COMMAND); clear(); } // go to location on LCD void LCD::setCursor(int line, int position) { int val = (line == 0) ? 0x80 + position : 0xC0 + position; sendByte(val, Mode::COMMAND); cursor_x = line; cursor_y = position; } void LCD::sendChar(char val) { sendByte(val, Mode::CHARACTER); } void LCD::sendString(const std::string &str) { for (const char &c : str) { if (c == '\n') { cursor_y++; setCursor(cursor_y, 0); } else { sendChar(c); cursor_x++; } } } void LCD::clear() { sendByte(LCD_CLEARDISPLAY, Mode::COMMAND); } void LCD::i2cWriteByte(uint8_t val) { i2c_write_blocking(i2c, i2c_addr, &val, 1, false); } void LCD::toggleEnable(uint8_t val) { // Toggle enable pin on LCD display // We cannot do this too quickly or things don't work constexpr uint64_t DELAY_US = 600; sleep_us(DELAY_US); i2cWriteByte(val | LCD_ENABLE_BIT); sleep_us(DELAY_US); i2cWriteByte(val & ~LCD_ENABLE_BIT); sleep_us(DELAY_US); } // The display is sent a byte as two separate nibble transfers void LCD::sendByte(uint8_t val, Mode mode) { uint8_t high = static_cast(mode) | (val & 0xF0) | LCD_BACKLIGHT; uint8_t low = static_cast(mode) | ((val << 4) & 0xF0) | LCD_BACKLIGHT; i2cWriteByte(high); toggleEnable(high); i2cWriteByte(low); toggleEnable(low); }