Custom Arduino library for I2C LCD2004

Free up a lot of the IOs of your microcontroller by using an I2C liquid crystal display. Let’s create a custom LCD2004 library for Arduino.

June 26, 2020

What is covered

Code repository

Primers

Defining the Lcd.h header file

Let’s take a look at the /arduino/server-ble/Lcd.h header file with the library’s definitions. LiquidCrystal_I2C.h is the library created by Frank de Brabander (fdebrabander github account). We need it to be able write messages on LCD2004. The public attributes and methods (lines 15-19) include: the constructor using two parameters (sda serial data line pin, clk serial clock line pin), printSettings, getSettingsAsString and printNoSettings.

The private attributes (lines 22-28) are one for each ventilator setting (volume, breaths per minute, inspiration ratio, expiration ratio), one for the object of type LiquidCrystal_I2C, sda serial data line pin, clk serial clock line pin for the Wire object parameters to define the GPIOs of the ESP32 board for the I2C. The private method setSettings is used to update the values of private attributes after each I2C receive event.

/*
  Lcd.h - Library for printing data on a LCD 2004 via I2C
  Created by Catalin Rizea, May 1, 2020
  Released into the public domain 
*/
#ifndef Lcd_h
#define Lcd_h

#include <Arduino.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>

class Lcd {
  public:
    Lcd(int sda, int clk);
    void start();
    void printSettings(int volume, int bpm, int inspiration, int expiration);
    String getSettingsAsString();
    void printNoSettings();
  private:
    void setSettings(int volume, int bpm, int inspiration, int expiration);
    int _volume;
    int _bpm;
    int _inspiration;
    int _expiration;
    int _sda;
    int _clk;
    LiquidCrystal_I2C _lcd;
};

#endif

Implementing the class Lcd.cpp

arduino/server-ble/Lcd.cpp starts by importing all the dependencies (lines 6-11). The constructor (lines 13-16) uses two parameters and instantiates the private attribute _lcd of the LiquidCrystal_I2C.h type passing as arguments the address, the columns, and rows number. The start public method (lines 18-25) is in charge of initiating the Wire object with the data and clock pin numbers, the _lcd object by also turning on its backlighting.

printNoSettings public method (lines 27-33) is putting the appropriate message on the LCD when there is nothing to do for the stepper motor. printSettings public method (lines 42-58) is in charge of changing the text on the LCD with the new ventilator settings (volume, breaths per minute, inspiration and expiration ratio). getSettingsAsString public method (lines 60-62) takes the settings values, converts them as String and it concatenates them before returning the cumulated string.

/*
  Lcd.cpp - Library for printing data on a LCD 2004 via I2C
  Created by Catalin Rizea, May 1, 2020
  Released into the public domain 
*/
#include <Arduino.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>

#include "Lcd.h"
#include "translations.h"

Lcd::Lcd(int sda, int clk): _lcd(0x3F, 20, 4)  {
  this->_sda = sda;
  this->_clk = clk;
}

void Lcd::start() {
  Wire.begin(this->_sda, this->_clk);
  
  this->_lcd.init();
  this->_lcd.backlight();
  
  this->printNoSettings();
}

void Lcd::printNoSettings() {
  this->_lcd.clear();
  this->_lcd.setCursor(0, 0);
  this->_lcd.print(settings);
  this->_lcd.setCursor(0, 1);
  this->_lcd.print(noSettings);
}

void Lcd::setSettings(int volume, int bpm, int inspiration, int expiration) {
  this->_volume = volume;
  this->_bpm = bpm;
  this->_inspiration = inspiration;
  this->_expiration = expiration;
}

void Lcd::printSettings(int volume, int bpm, int inspiration, int expiration) {
  this->setSettings(volume, bpm, inspiration, expiration);
  
  String secondRow = "TV " + String(volume) + " ml";
  String thirdRow = "RR " + String(bpm) + " resp/min";
  String fourthRow = "I:E " + String(inspiration) + ":" + String(expiration);

  this->_lcd.clear();
  this->_lcd.setCursor(0, 0);
  this->_lcd.print(settings);
  this->_lcd.setCursor(0, 1);
  this->_lcd.print(secondRow);
  this->_lcd.setCursor(0, 2);
  this->_lcd.print(thirdRow);
  this->_lcd.setCursor(0, 3);
  this->_lcd.print(fourthRow);
}

String Lcd::getSettingsAsString() {
  return "Volume=" + String(this->_volume) + " BPM=" + String(this->_bpm) + " I:E=" + String(this->_inspiration) + ":" + String(this->_expiration);
}

Using the custom library

arduino/server-ble/server-ble.ino is making use of this class by importing its header on line 8 and by instantiating the lcd object on line 11. It is passing those two values as arguments for the data and clock pins. The setup function calls the start method of the lcd object on line 53. The loop function is calling the printNoSettings method on line 62 and printSettings method on line 64.