GY-63_MS5611/libraries/I2C_LCD/I2C_LCD.cpp

437 lines
8.7 KiB
C++
Raw Normal View History

2023-12-17 07:01:57 -05:00
//
// FILE: I2C_LCD.cpp
// AUTHOR: Rob.Tillaart@gmail.com
2023-12-24 02:18:11 -05:00
// VERSION: 0.1.3
2023-12-17 07:01:57 -05:00
// DATE: 2023-12-16
// PUPROSE: Arduino library for I2C_LCD
// URL: https://github.com/RobTillaart/I2C_LCD
#include "I2C_LCD.h"
2023-12-24 02:18:11 -05:00
// 40 us is a save value at any speed.
// 20 us is a save value for I2C at 400K.
const uint8_t I2C_LCD_CHAR_DELAY = 0;
2023-12-17 07:01:57 -05:00
2023-12-21 13:55:56 -05:00
///////////////////////////////////////////////////////
//
// DO NOT CHANGE BELOW THIS LINE
//
2023-12-20 15:07:32 -05:00
// keep defines compatible / recognizable
// the zero valued defines are not used.
2023-12-17 07:01:57 -05:00
#define I2C_LCD_CLEARDISPLAY 0x01
#define I2C_LCD_RETURNHOME 0x02
#define I2C_LCD_ENTRYMODESET 0x04
#define I2C_LCD_DISPLAYCONTROL 0x08
#define I2C_LCD_CURSORSHIFT 0x10
#define I2C_LCD_FUNCTIONSET 0x20
#define I2C_LCD_SETCGRAMADDR 0x40
#define I2C_LCD_SETDDRAMADDR 0x80
#define I2C_LCD_ENTRYLEFT 0x02
#define I2C_LCD_ENTRYSHIFTINCREMENT 0x01
#define I2C_LCD_DISPLAYON 0x04
#define I2C_LCD_CURSORON 0x02
#define I2C_LCD_BLINKON 0x01
#define I2C_LCD_DISPLAYMOVE 0x08
#define I2C_LCD_MOVERIGHT 0x04
#define I2C_LCD_8BITMODE 0x10
#define I2C_LCD_2LINE 0x08
#define I2C_LCD_5x10DOTS 0x04
I2C_LCD::I2C_LCD(uint8_t address, TwoWire * wire)
{
_address = address;
_wire = wire;
2023-12-20 15:07:32 -05:00
_displayControl = I2C_LCD_DISPLAYCONTROL;
2023-12-17 07:01:57 -05:00
}
2023-12-20 15:07:32 -05:00
void I2C_LCD::config (uint8_t address, uint8_t enable, uint8_t readWrite, uint8_t registerSelect,
uint8_t data4, uint8_t data5, uint8_t data6, uint8_t data7,
2023-12-24 02:18:11 -05:00
uint8_t backLight, uint8_t polarity)
2023-12-17 07:01:57 -05:00
{
2023-12-20 15:07:32 -05:00
if (_address != address) return; // compatible?
2023-12-17 07:01:57 -05:00
_enable = ( 1 << enable);
2023-12-20 15:07:32 -05:00
_readWrite = ( 1 << readWrite);
_registerSelect = ( 1 << registerSelect);
2023-12-17 07:01:57 -05:00
_dataPin[0] = ( 1 << data4);
_dataPin[1] = ( 1 << data5);
_dataPin[2] = ( 1 << data6);
_dataPin[3] = ( 1 << data7);
2023-12-20 15:07:32 -05:00
_backLightPin = ( 1 << backLight);
2023-12-21 13:55:56 -05:00
_backLightPol = polarity;
2023-12-17 07:01:57 -05:00
_pinsInOrder = ((data4 < data5) && (data5 < data6) && (data6 < data7));
}
void I2C_LCD::begin(uint8_t cols, uint8_t rows)
{
_cols = cols;
_rows = rows;
2023-12-21 13:55:56 -05:00
// ALL LINES LOW.
2023-12-17 07:01:57 -05:00
_wire->beginTransmission(_address);
_wire->write(0x00);
_wire->endTransmission();
2023-12-20 15:07:32 -05:00
// Figure 24 for procedure on 4-bit initialization
// wait for more than 15 ms
2023-12-21 13:55:56 -05:00
delay(100); // no need to optimize as this is called only once.
2023-12-17 07:01:57 -05:00
2023-12-20 15:07:32 -05:00
// Force 4 bit mode
2023-12-17 07:01:57 -05:00
write4bits(0x03);
2023-12-20 15:07:32 -05:00
delayMicroseconds(5000); // > 4.1 millis
2023-12-17 07:01:57 -05:00
write4bits(0x03);
2023-12-20 15:07:32 -05:00
delayMicroseconds(200); // > 100 usec
2023-12-17 07:01:57 -05:00
write4bits(0x03);
2023-12-20 15:07:32 -05:00
delayMicroseconds(200); // > 100 usec
// command to set 4 bit interface
2023-12-17 07:01:57 -05:00
write4bits(0x02);
2023-12-20 15:07:32 -05:00
delayMicroseconds(200);
2023-12-17 07:01:57 -05:00
2023-12-24 02:18:11 -05:00
// set "two" lines LCD - fixed for now.
2023-12-17 07:01:57 -05:00
sendCommand(I2C_LCD_FUNCTIONSET | I2C_LCD_2LINE);
2023-12-20 15:07:32 -05:00
// default enable display
display();
clear();
}
bool I2C_LCD::isConnected()
{
_wire->beginTransmission(_address);
return (_wire->endTransmission() == 0);
}
/////////////////////////////////////////////////
//
// BACKLIGHT
//
2023-12-21 13:55:56 -05:00
void I2C_LCD::setBacklightPin(uint8_t pin, uint8_t polarity)
2023-12-20 15:07:32 -05:00
{
_backLightPin = ( 1 << pin);
2023-12-21 13:55:56 -05:00
_backLightPol = polarity;
2023-12-17 07:01:57 -05:00
}
void I2C_LCD::setBacklight(bool on)
{
2023-12-21 13:55:56 -05:00
_backLight = (on == _backLightPol);
if (_backLight) display();
else noDisplay();
2023-12-17 07:01:57 -05:00
}
2023-12-20 15:07:32 -05:00
/////////////////////////////////////////////////
//
// DISPLAY
//
2023-12-17 07:01:57 -05:00
void I2C_LCD::display()
{
2023-12-20 15:07:32 -05:00
_displayControl |= I2C_LCD_DISPLAYON;
sendCommand(_displayControl);
2023-12-17 07:01:57 -05:00
}
void I2C_LCD::noDisplay()
{
2023-12-20 15:07:32 -05:00
_displayControl &= ~I2C_LCD_DISPLAYON;
sendCommand(_displayControl);
2023-12-17 07:01:57 -05:00
}
2023-12-20 15:07:32 -05:00
/////////////////////////////////////////////////
//
// POSITIONING & CURSOR
//
2023-12-17 07:01:57 -05:00
void I2C_LCD::clear()
{
sendCommand(I2C_LCD_CLEARDISPLAY);
2023-12-20 15:07:32 -05:00
_pos = 0;
2023-12-17 07:01:57 -05:00
delay(2);
}
2023-12-20 15:07:32 -05:00
void I2C_LCD::clearEOL()
{
for (int i = _pos; i < _cols; i++)
{
print(' ');
}
}
2023-12-17 07:01:57 -05:00
void I2C_LCD::home()
{
sendCommand(I2C_LCD_RETURNHOME);
2023-12-20 15:07:32 -05:00
_pos = 0;
2023-12-17 07:01:57 -05:00
delay(2);
}
2023-12-20 15:07:32 -05:00
bool I2C_LCD::setCursor(uint8_t col, uint8_t row)
2023-12-17 07:01:57 -05:00
{
2023-12-20 15:07:32 -05:00
if ((col >= _cols) || (row >= _rows)) return false;
2023-12-24 02:18:11 -05:00
uint8_t offset = 0x00;
if (row & 0x01) offset += 0x40;
if (row & 0x02) offset += _cols;
offset += col;
2023-12-20 15:07:32 -05:00
_pos = col;
2023-12-24 02:18:11 -05:00
sendCommand(I2C_LCD_SETDDRAMADDR | offset );
2023-12-20 15:07:32 -05:00
return true;
2023-12-24 02:18:11 -05:00
// ORIGINAL SETCURSOR CODE
// all start position arrays start with 0x00 0x40
// they have an offset of 0x14, 0x10 or 0x0A
// so only 3 bytes are needed?
// note that e.g. 16x2 only uses the first 2 offsets.
// uint8_t startPos[4] = { 0x00, 0x40, 0x14, 0x54 }; // most displays
// uint8_t start16x4[4] = { 0x00, 0x40, 0x10, 0x50 }; // 16x4 display
// uint8_t start10x4[4] = { 0x00, 0x40, 0x0A, 0x4A }; // 10x4 LOGO display
// // if out of range exit!
// if ((col >= _cols) || (row >= _rows)) return false;
// _pos = col;
// if ((_rows == 4) && (_cols == 16))
// {
// sendCommand(I2C_LCD_SETDDRAMADDR | (start16x4[row] + col) );
// return true;
// }
// if ((_rows == 4) && (_cols == 10))
// {
// sendCommand(I2C_LCD_SETDDRAMADDR | (start10x4[row] + col) );
// return true;
// }
// sendCommand(I2C_LCD_SETDDRAMADDR | (startPos[row] + col) );
// return true;
2023-12-20 15:07:32 -05:00
}
void I2C_LCD::blink()
{
_displayControl |= I2C_LCD_BLINKON;
sendCommand(_displayControl);
}
void I2C_LCD::noBlink()
{
_displayControl &= ~I2C_LCD_BLINKON;
sendCommand(_displayControl);
}
void I2C_LCD::cursor()
{
_displayControl |= I2C_LCD_CURSORON;
sendCommand(_displayControl);
2023-12-17 07:01:57 -05:00
}
2023-12-24 02:18:11 -05:00
2023-12-17 07:01:57 -05:00
2023-12-20 15:07:32 -05:00
void I2C_LCD::noCursor()
2023-12-17 07:01:57 -05:00
{
2023-12-20 15:07:32 -05:00
_displayControl &= ~I2C_LCD_CURSORON;
sendCommand(_displayControl);
}
2023-12-24 02:18:11 -05:00
void I2C_LCD::scrollDisplayLeft(void)
2023-12-20 15:07:32 -05:00
{
2023-12-24 02:18:11 -05:00
sendCommand(I2C_LCD_CURSORSHIFT | I2C_LCD_DISPLAYMOVE);
2023-12-20 15:07:32 -05:00
}
2023-12-24 02:18:11 -05:00
void I2C_LCD::scrollDisplayRight(void)
2023-12-20 15:07:32 -05:00
{
2023-12-24 02:18:11 -05:00
sendCommand(I2C_LCD_CURSORSHIFT | I2C_LCD_DISPLAYMOVE | I2C_LCD_MOVERIGHT);
2023-12-20 15:07:32 -05:00
}
2023-12-24 02:18:11 -05:00
void I2C_LCD::moveCursorLeft(uint8_t n)
2023-12-20 15:07:32 -05:00
{
2023-12-24 02:18:11 -05:00
while ((_pos > 0) && (n--))
{
sendCommand(I2C_LCD_CURSORSHIFT);
_pos--;
}
2023-12-20 15:07:32 -05:00
}
2023-12-24 02:18:11 -05:00
void I2C_LCD::moveCursorRight(uint8_t n)
2023-12-20 15:07:32 -05:00
{
2023-12-24 02:18:11 -05:00
while ((_pos < _cols) && (n--))
{
sendCommand(I2C_LCD_CURSORSHIFT | I2C_LCD_MOVERIGHT);
_pos++;
}
2023-12-20 15:07:32 -05:00
}
2023-12-24 02:18:11 -05:00
void I2C_LCD::autoscroll(void)
2023-12-20 15:07:32 -05:00
{
sendCommand(I2C_LCD_ENTRYMODESET | I2C_LCD_ENTRYSHIFTINCREMENT);
}
2023-12-24 02:18:11 -05:00
void I2C_LCD::noAutoscroll(void)
2023-12-20 15:07:32 -05:00
{
sendCommand(I2C_LCD_ENTRYMODESET);
}
2023-12-24 02:18:11 -05:00
void I2C_LCD::leftToRight(void)
2023-12-20 15:07:32 -05:00
{
sendCommand(I2C_LCD_ENTRYMODESET | I2C_LCD_ENTRYLEFT);
}
2023-12-24 02:18:11 -05:00
void I2C_LCD::rightToLeft(void)
2023-12-20 15:07:32 -05:00
{
sendCommand(I2C_LCD_ENTRYMODESET);
}
/////////////////////////////////////////////////
//
// CHARMAP
//
void I2C_LCD::createChar(uint8_t index, uint8_t * charmap)
{
sendCommand(I2C_LCD_SETCGRAMADDR | ((index & 0x07) << 3));
uint8_t tmp = _pos;
for (uint8_t i = 0; i < 8; i++)
{
_pos = 0;
2023-12-24 02:18:11 -05:00
sendData(charmap[i]);
2023-12-20 15:07:32 -05:00
}
_pos = tmp;
}
2023-12-17 07:01:57 -05:00
2023-12-20 15:07:32 -05:00
size_t I2C_LCD::write(uint8_t c)
{
size_t n = 0;
if (c == (uint8_t)'\t') // TAB char
{
2023-12-24 02:18:11 -05:00
while (((_pos % 4) != 0) && (_pos < _cols))
2023-12-20 15:07:32 -05:00
{
2023-12-24 02:18:11 -05:00
moveCursorRight(); // increases _pos.
2023-12-20 15:07:32 -05:00
n++;
}
return n;
}
if (_pos < _cols) // overflow protect
{
sendData(c);
_pos++;
2023-12-24 02:18:11 -05:00
return 1;
2023-12-20 15:07:32 -05:00
}
2023-12-24 02:18:11 -05:00
// not allowed to print.
return 0;
2023-12-20 15:07:32 -05:00
};
2023-12-21 13:55:56 -05:00
size_t I2C_LCD::center(uint8_t row, const char * message)
{
uint8_t len = strlen(message) + 1;
setCursor(10 - len/2, row);
return print(message);
}
2023-12-20 15:07:32 -05:00
2023-12-17 07:01:57 -05:00
2023-12-21 13:55:56 -05:00
size_t I2C_LCD::right(uint8_t col, uint8_t row, const char * message)
2023-12-17 07:01:57 -05:00
{
2023-12-21 13:55:56 -05:00
uint8_t len = strlen(message);
setCursor(col - len, row);
return print(message);
}
2023-12-17 07:01:57 -05:00
2023-12-21 13:55:56 -05:00
//////////////////////////////////////////////////////////
//
// PRIVATE
//
void I2C_LCD::sendCommand(uint8_t value)
{
send(value, false);
2023-12-17 07:01:57 -05:00
}
void I2C_LCD::sendData(uint8_t value)
{
2023-12-21 13:55:56 -05:00
send(value, true);
}
void I2C_LCD::send(uint8_t value, bool dataFlag)
{
// calculate both most and least significant nibble
uint8_t MSN = 0;
if (dataFlag) MSN = _registerSelect;
2023-12-20 15:07:32 -05:00
if (_backLight) MSN |= _backLightPin;
2023-12-17 07:01:57 -05:00
uint8_t LSN = MSN;
if (_pinsInOrder)
{
MSN |= value & 0xF0;
LSN |= value << 4;
}
else
{
for ( uint8_t i = 0; i < 4; i++ )
{
2023-12-21 13:55:56 -05:00
if ( value & 0x01 ) LSN |= _dataPin[i];
value >>= 1;
2023-12-17 07:01:57 -05:00
}
for ( uint8_t i = 0; i < 4; i++ )
{
2023-12-21 13:55:56 -05:00
if ( value & 0x01 ) MSN |= _dataPin[i];
value >>= 1;
2023-12-17 07:01:57 -05:00
}
}
_wire->beginTransmission(_address);
_wire->write(MSN | _enable);
_wire->write(MSN);
_wire->write(LSN | _enable);
_wire->write(LSN);
_wire->endTransmission();
2023-12-24 02:18:11 -05:00
if (I2C_LCD_CHAR_DELAY) delayMicroseconds(I2C_LCD_CHAR_DELAY);
2023-12-17 07:01:57 -05:00
}
2023-12-21 13:55:56 -05:00
// needed for setup
2023-12-24 02:18:11 -05:00
void I2C_LCD::write4bits(uint8_t value)
2023-12-17 07:01:57 -05:00
{
2023-12-21 13:55:56 -05:00
uint8_t cmd = 0;
2023-12-17 07:01:57 -05:00
for ( uint8_t i = 0; i < 4; i++ )
{
if ( value & 0x01 ) cmd |= _dataPin[i];
value >>= 1;
}
2023-12-24 02:18:11 -05:00
2023-12-17 07:01:57 -05:00
_wire->beginTransmission(_address);
_wire->write(cmd | _enable);
2023-12-20 15:07:32 -05:00
_wire->endTransmission();
_wire->beginTransmission(_address);
2023-12-17 07:01:57 -05:00
_wire->write(cmd);
_wire->endTransmission();
}
// -- END OF FILE --