Let's go through the hardware connections step by step.
We have two I2C masters, Master 1 and Master 2, each requiring separate control to interface with the I2C 16x2 LCD. However, the standard LiquidCrystal_I2C
library posed the following challenges:
Wire.endTransmission();
to release the I2C bus, allowing other masters to take control.To resolve these issues, we made custom modifications to the LiquidCrystal_I2C.h
library. This allows both masters to communicate with the LCD and display their data independently without interference.
Issue with the Original Code
expanderWrite()
function uses Wire.endTransmission();
to release the I2C bus after sending data. Wire.endTransmission()
function, the parameter stop
determines whether the bus is released.stop: true
sends a stop message, releasing the bus after transmission (default behavior).stop: false
sends a restart condition, keeping the connection active for further communication.Wire.endTransmission();
uses stop: true
, which causes the bus to be released prematurely. This allows other masters to take control of the bus before Master 1 finishes its required set of commands.Solution
Wire.endTransmission();
with Wire.endTransmission(false);
.Wire.endTransmission();
(with stop: true
) to release the bus, allowing Master 2 to send its data.Code before changes
void LiquidCrystal_I2C::expanderWrite(uint8_t _data) {
Wire.beginTransmission(_Addr);
printIIC((int)(_data) | _backlightval);
Wire.endTransmission();
}
Code after changes:
void LiquidCrystal_I2C::expanderWrite(uint8_t _data) {
Wire.beginTransmission(_Addr);
printIIC((int)(_data) | _backlightval);
Wire.endTransmission(false);
}
Recommendation
LiquidCrystal_I2C
library for custom modifications.Steps to Create the Custom Library
libraries
directory.MyLiquidCrystal_I2C
)..h
and .cpp
files from the original LiquidCrystal_I2C
library into the newly created folder.MyLiquidCrystal_I2C.h
and MyLiquidCrystal_I2C.cp
p) to reflect the custom library..h
and .cpp
files in a text editor or IDE.expanderWrite()
function).#include <MyLiquidCrystal_I2C.h>
For information about how to add a custom library to the Arduino IDE and use examples from it, refer to Adding Library To Arduino IDE.
Displays the system's start time in seconds on the I2C16x2LCD display.
#include <MyLiquidCrystal_I2C.h>
// Create an LCD object with the detected I2C address
LiquidCrystal_I2C lcd(0x27, 16, 2); // Replace 0x27 with your LCD's I2C address
void setup() {
lcd.begin(16, 2); // Initialize the LCD with 16 columns and 2 rows
lcd.backlight(); // Turn on the backlight
}
void loop() {
unsigned long timeSec = millis() / 1000; // Get system time in seconds
char buff[20]; // Buffer for time string
uint8_t hours = timeSec / 3600;
uint8_t minutes = (timeSec % 3600) / 60;
uint8_t seconds = timeSec % 60;
sprintf(buff, " %02d:%02d:%02d", hours, minutes, seconds); // Convert time to string
lcd.setCursor(0, 0); // Set cursor to the first row, first column
lcd.print("Uptime: ");
lcd.setCursor(7, 0);
lcd.print(" "); // Print text
lcd.setCursor(7, 0);
lcd.print(buff); // Print text
Wire.endTransmission(); //It will release the I2C Bus
while(millis() % 1000);
}
lcd.begin()
and turns on the backlight using lcd.backlight()
.millis()
and formatted as hh:mm:ss
.Wire.endTransmission()
releases the I2C bus, allowing other devices to communicate if needed.while(millis() % 1000)
.Displays the potentiometer value (from A0) on the I2C16x2LCD display.
#include <MyLiquidCrystal_I2C.h>
// Create an LCD object with the detected I2C address
LiquidCrystal_I2C lcd(0x27, 16, 2); // Replace 0x27 with your LCD's I2C address
void setup() {
lcd.begin(16, 2); // Initialize the LCD with 16 columns and 2 rows
lcd.backlight(); // Turn on the backlight
}
void loop() {
uint16_t adcValue = analogRead(A0); // Read potentiometer value
char buff[4]; // Buffer for value
sprintf(buff, "%d", adcValue); // Convert value to string
lcd.setCursor(0, 1); // Set cursor to the second row, first column
lcd.print("POT Value: ");
lcd.setCursor(11, 1);
lcd.print(" ");
lcd.setCursor(11, 1);
lcd.print(buff);
Wire.endTransmission(); //It will release the I2C Bus
while(millis() % 1000);
}
analogRead(A0)
and formats it into a string.Wire.endTransmission()
releases the I2C bus, ensuring that other devices can access it if required.