/*
  Analog Input wiht Fault
  RAW:  0-1024
  MA:   0-21mA
  EU:   -25.0 - 100.00 %
*/

#include <LiquidCrystal_I2C.h>
#define I2C_ADDR    0x27
#define LCD_COLUMNS 20
#define LCD_LINES   4
LiquidCrystal_I2C lcd(I2C_ADDR, LCD_COLUMNS, LCD_LINES);

#define ZERO_RANGE  0.0F
#define FULL_RANGE  20.0F
#define BLINK_TIME_DELAY 500UL
#define LCD_TIME_DELAY 100UL

#define zeroRangePin 2
#define fullRangePin  3
#define analogInputPin A0

typedef struct {
  private:
    unsigned long startTime;
    bool enable;
  public:
    bool state;
    bool timerOn(unsigned long dt, bool en = true);
} timer_t;

bool timer_t::timerOn(unsigned long delayTime, bool en) {
  if (en) {
    if (!state) {
      unsigned long currTime = millis();
      if (!enable) startTime = currTime;
      unsigned long elapsedTime = currTime - startTime;
      if (elapsedTime >= delayTime) {
        state = true;
      }
    }
  } else {
    state = false;
  }
  enable = en;
  return state;
}

timer_t blinkTimer;
timer_t lcdPrintTimer;

int raw;
float voltageInput;
float currentInput;
float percentage;

bool fullRange;
bool zeroRange;

bool toggle;

void setup() {
  lcd.init();
  lcd.backlight();
  lcd.setCursor(4, 0);
  lcd.print("ANALOG INPUT");

  pinMode(zeroRangePin, OUTPUT);
  pinMode(fullRangePin, OUTPUT);
  pinMode(LED_BUILTIN, OUTPUT);
}

void loop() {
  Blink();
  AnalogCondition();
  LCDPrint();
}

void AnalogCondition() {
  raw = analogRead(analogInputPin);
  voltageInput = Scale(raw, 0, 1023, 0, 5);         // Voltage: 0.0 -   5.0 V
  currentInput = Scale(raw, 0, 1023, 0, 20);        // Current: 0.0 -  20.0 mA
  percentage = Scale(currentInput, 4, 20, 0, 100);  // Percent: 0.0 - 100.0 % @4-20mA

  zeroRange = currentInput <= ZERO_RANGE;
  fullRange = currentInput >= FULL_RANGE;
  digitalWrite(zeroRangePin, zeroRange);
  digitalWrite(fullRangePin, fullRange);
}


void Blink() {
  if (!blinkTimer.timerOn(BLINK_TIME_DELAY, !blinkTimer.state)) return;
  toggle = !toggle;
  digitalWrite(LED_BUILTIN, toggle);
}

float Scale(float value, int rawMin, int rawMax, int euMin, int euMax) {
  return (value - rawMin) * (euMax - euMin) / (rawMax - rawMin) + euMin;
}

void LCDPrint() {
  if (!lcdPrintTimer.timerOn(LCD_TIME_DELAY, !lcdPrintTimer.state)) {
    lcd.setCursor(0, 1);
    lcd.print("Votage:");
    lcd.print(PadLeft(String(voltageInput, 2), 7, ' '));
    lcd.setCursor(0, 2);
    lcd.print("Current:");
    lcd.print(PadLeft(String(currentInput, 2), 6, ' '));
    lcd.setCursor(0, 3);
    lcd.print("Percent:");
    lcd.print(PadLeft(String(percentage, 2), 6, ' '));
  }
}

String PadLeft(String message, int length, char paddingChar) {
  int lenPad = length - message.length();
  for (int index = 0; index < lenPad; index++) {
    message = paddingChar + message;
  }
  return message.substring(0, length);
}
100.0%
EU MAX
|
4.0mA
0.0%
|
0.0
EU MIN
|
50.0
|
0.0mA
-25.0%
|
20.0mA
ZERO
FULL
An example of the signal level for the failure