lcm1602: Add support for various LCD configurations / sizes

Signed-off-by: Sergey Kiselev <sergey.kiselev@intel.com>
Signed-off-by: Mihai Tudor Panu <mihai.tudor.panu@intel.com>
This commit is contained in:
Sergey Kiselev 2015-10-05 18:16:53 +00:00 committed by Mihai Tudor Panu
parent 5ff625eaf4
commit 1713d44a4b
3 changed files with 117 additions and 8 deletions

View File

@ -0,0 +1,54 @@
/*
* Author: Sergey Kiselev <sergey.kiselev@intel.com>
* Author: Yevgeniy Kiveish <yevgeniy.kiveisha@intel.com>
* 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 <upm/lcm1602.h>
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;
}

View File

@ -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);
}

View File

@ -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,