From 1713d44a4bd87fce2195fd5247cb1bb4e9a2c9a0 Mon Sep 17 00:00:00 2001 From: Sergey Kiselev Date: Mon, 5 Oct 2015 18:16:53 +0000 Subject: [PATCH] lcm1602: Add support for various LCD configurations / sizes Signed-off-by: Sergey Kiselev Signed-off-by: Mihai Tudor Panu --- examples/c++/lcd-parallel.cxx | 54 +++++++++++++++++++++++++++++++ src/lcd/lcm1602.cxx | 61 +++++++++++++++++++++++++++++++---- src/lcd/lcm1602.h | 10 ++++-- 3 files changed, 117 insertions(+), 8 deletions(-) create mode 100644 examples/c++/lcd-parallel.cxx diff --git a/examples/c++/lcd-parallel.cxx b/examples/c++/lcd-parallel.cxx new file mode 100644 index 00000000..e79559b7 --- /dev/null +++ b/examples/c++/lcd-parallel.cxx @@ -0,0 +1,54 @@ +/* + * Author: Sergey Kiselev + * Author: Yevgeniy Kiveish + * Copyright (c) 2014 - 2015 Intel Corporation. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include + +int +main(int argc, char **argv) +{ +//! [Interesting] + // LCD connection: + // LCD RS pin to digital pin 8 + // LCD Enable pin to digital pin 13 + // LCD D4 pin to digital pin 2 + // LCD D5 pin to digital pin 3 + // LCD D6 pin to digital pin 4 + // LCD D7 pin to digital pin 5 + // LCD R/W pin to ground + // 10K trimmer potentiometer: + // ends to +5V and ground + // wiper to LCD VO pin (pin 3) + upm::Lcm1602 *lcd = new upm::Lcm1602(8, 13, 2, 3, 4, 5, 20, 2); + lcd->setCursor(0,0); + lcd->write("Hello World"); + lcd->setCursor(1,2); + lcd->write("Hello World"); + + printf("Sleeping for 5 seconds\n"); + sleep(5); + delete lcd; +//! [Interesting] + return 0; +} diff --git a/src/lcd/lcm1602.cxx b/src/lcd/lcm1602.cxx index eb0eaccc..68f24990 100644 --- a/src/lcd/lcm1602.cxx +++ b/src/lcd/lcm1602.cxx @@ -39,10 +39,12 @@ using namespace upm; -Lcm1602::Lcm1602(int bus_in, int addr_in, bool isExpander) : +Lcm1602::Lcm1602(int bus_in, int addr_in, bool isExpander, + uint8_t numColumns, uint8_t numRows) : m_i2c_lcd_control(new mraa::I2c(bus_in)), m_gpioRS(0), m_gpioEnable(0), m_gpioD0(0), - m_gpioD1(0), m_gpioD2(0), m_gpioD3(0) + m_gpioD1(0), m_gpioD2(0), m_gpioD3(0), + m_numColumns(numColumns), m_numRows(numRows) { mraa::Result error = mraa::SUCCESS; m_name = "Lcm1602 (I2C)"; @@ -97,11 +99,13 @@ Lcm1602::Lcm1602(int bus_in, int addr_in, bool isExpander) : } Lcm1602::Lcm1602(uint8_t rs, uint8_t enable, uint8_t d0, - uint8_t d1, uint8_t d2, uint8_t d3) : + uint8_t d1, uint8_t d2, uint8_t d3, + uint8_t numColumns, uint8_t numRows) : m_i2c_lcd_control(0), m_gpioRS(new mraa::Gpio(rs)), m_gpioEnable(new mraa::Gpio(enable)), m_gpioD0(new mraa::Gpio(d0)), m_gpioD1(new mraa::Gpio(d1)), - m_gpioD2(new mraa::Gpio(d2)), m_gpioD3(new mraa::Gpio(d3)) + m_gpioD2(new mraa::Gpio(d2)), m_gpioD3(new mraa::Gpio(d3)), + m_numColumns(numColumns), m_numRows(numRows) { mraa::Result error = mraa::SUCCESS; m_name = "Lcm1602 (4-bit GPIO)"; @@ -196,9 +200,54 @@ mraa::Result Lcm1602::setCursor(int row, int column) { mraa::Result error = mraa::SUCCESS; + column = column % m_numColumns; + uint8_t offset = column; - int row_addr[] = { 0x80, 0xc0, 0x14, 0x54 }; - uint8_t offset = ((column % 16) + row_addr[row]); + switch (m_numRows) + { + case 1: + // Single row displays with more than 8 columns usually have their + // DDRAM split in two halves. The first half starts at address 00. + // The second half starts at address 40. E.g. 16x2 DDRAM mapping: + // 00 01 02 03 04 05 06 07 40 41 42 43 44 45 46 47 + if (m_numColumns > 8) + { + offset = (column % (m_numColumns / 2)) + + (column / (m_numColumns / 2)) * 0x40; + } + break; + case 2: + // this should work for any display with two rows + // DDRAM mapping: + // 00 .. 27 + // 40 .. 67 + offset += row * 0x40; + break; + case 4: + if (m_numColumns == 16) + { + // 16x4 display + // DDRAM mapping: + // 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F + // 40 41 42 43 43 45 46 47 48 49 4A 4B 4C 4D 4E 4F + // 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F + // 50 51 52 53 54 55 56 57 58 59 5A 5B 5C 5D 5E 5F + int row_addr[] = { 0x00, 0x40, 0x10, 0x50 }; + offset += row_addr[row]; + } + else + { + // 20x4 display + // DDRAM mapping: + // 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 + // 40 41 42 43 43 45 46 47 48 49 4A 4B 4C 4D 4E 4F 50 51 52 53 + // 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 + // 54 55 56 57 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 + int row_addr[] = { 0x00, 0x40, 0x14, 0x54 }; + offset += row_addr[row]; + } + break; + } return command(LCD_CMD | offset); } diff --git a/src/lcd/lcm1602.h b/src/lcd/lcm1602.h index bee9d15d..0ef992cb 100644 --- a/src/lcd/lcm1602.h +++ b/src/lcd/lcm1602.h @@ -72,7 +72,8 @@ class Lcm1602 : public LCD * @param isExpander True if we are dealing with an I2C expander, * false otherwise. Default is true. */ - Lcm1602(int bus, int address, bool isExpander=true); + Lcm1602(int bus, int address, bool isExpander=true, + uint8_t numColumns = 16, uint8_t numRows = 4); /** * Lcm1602 alternate constructor, used for GPIO based hd44780 @@ -87,7 +88,8 @@ class Lcm1602 : public LCD * @param d3 Data 3 pin */ Lcm1602(uint8_t rs, uint8_t enable, - uint8_t d0, uint8_t d1, uint8_t d2, uint8_t d3); + uint8_t d0, uint8_t d1, uint8_t d2, uint8_t d3, + uint8_t numColumns = 16, uint8_t numRows = 4); /** * Lcm1602 destructor @@ -225,6 +227,10 @@ class Lcm1602 : public LCD uint8_t m_displayControl; uint8_t m_entryDisplayMode; + // Display size + uint8_t m_numColumns; + uint8_t m_numRows; + // Add a command() and data() virtual member functions, with a // default implementation in lcm1602. This is expected to be // implemented by derived classes with different needs (Jhd1313m1,