Laying out LCD display using for loops / arrays

Morning All,

I'm new on the forum, but have been lurking for a while.

I am making a project where where the end goal is to have two arduinos communicate via RS485 half duplex, communicating the status of each others inputs, to operate some function on the other (LEDs, stepper motor, LCD, etc). Each arduino has a 20x4 LCD using I2C.
My own version of a remote IO of sorts. I find the concept of controlling something very far away over serial comms quite fascinating. The end goal being to control another project I'm working on with RS485 full duplex, and potentially over fibre optics.

I've experience with the arduinos before, but only simple functions, but including displaying the status of inputs on the LCD.

I'm looking for some pointers to compact the if statements I'll use to display the status of the digitalReads on the LCD. (see *** if statements to print condition of digital pin ***)
There are three variables:

  1. dig_in_pins_status[i]
  2. X position on LCD (0, 5, 10, 15)
  3. Y position on LCD (1, 2, 3)

Currently the plan is to create 16x if / else if statements to handle the 8x digital inputs, but I'm sure that this isn't the best way, and seems quite wasteful.
My thoughts were that there should be a way using if loops and or arrays to handle this, but it's beyond me at the moment. Any pointers are appreciated, thanks.

kit:
2x Arduino Unos (328Ps)
Thinkpad T480 running Linux mint
Arduino IDE 1.8.19.

//************* LIBS & DEFS *************
#include <LiquidCrystal_I2C.h>  //add LCD I2C lib, change line 12 of LiquidCrystal_I2C.cpp from 1 to 0
#include <Wire.h>               //add wire lib

LiquidCrystal_I2C lcd(0x27,  4, 20); //initiate LCD via I2C, address is normally 0x27 (or 0x3F), rows, columns

#define delay_time 1000 //set delay variable

const uint8_t dig_in_pins[] = {4,5,6,7,8,9,10,11}; //create digital input array
                                                      //keep pins 0 and 1 free for TX and RX
                                                      //keep pins 2 and 3 free for DE and RE
uint8_t dig_in_pins_status[sizeof(dig_in_pins)/sizeof(dig_in_pins[0])];

void setup() { //************* START SETUP *************
  
  lcd.init(); //initialize lcd screen
  lcd.backlight(); // turn on the backlight

// SET INPUT PINS - ANALOG
  // keep pins A4 and A5 free for SDA and SCL
  pinMode(A0, INPUT); //set A0 as input pin

// SET INPUT PINS - DIGITAL
  //keep pins 0 and 1 free for TX and RX
  for(uint8_t i = 0; i <= sizeof(dig_in_pins)/sizeof(dig_in_pins[0]); i++) pinMode(dig_in_pins[i], INPUT_PULLUP); // create DIs inputs

// SET OUTPUT PINS
  pinMode(13, OUTPUT); //set pin 13 as output
  digitalWrite(13, LOW);
  
} //************* END SETUP *************

void loop() { //************* START LOOP *************

  digitalWrite(13, HIGH);               //set pin 13 high

  uint16_t pot_A = analogRead(A0);      //read pin A0

  for(uint8_t i = 0; i <= sizeof(dig_in_pins)/sizeof(dig_in_pins[0]); i++) {
  dig_in_pins_status[i] = {digitalRead(dig_in_pins[i])}; // digitalread array
}

// LCD write
  
  lcd.clear();  //clear lcd screen

// write pot value
  lcd.setCursor(0,0); //set curser (x, y)
  lcd.print("POT VAL="); //print text
  lcd.setCursor(9,0); //set curser (x, y)
  lcd.print(pot_A); //print pot value, 0-1023

// *** if statements to print condition of digital pin ***
  if(dig_in_pins_status[0] == HIGH) { 
    lcd.setCursor(0,1);
    lcd.print("1-ON ");
}
    else if(dig_in_pins_status[0] == LOW){ 
    lcd.setCursor(0,1);
    lcd.print("1-OFF");
    } //(close if loop 1.2)

// remaining if statements for dig_in_pins_status[1] through dig_in_pins_status[8] to go here

// Flash LED and delay
  digitalWrite(13, LOW);           //set pin 13 low
  delay(delay_time);                //delay
} //************* END LOOP *************
//************* END *************```

A for loop and an array sounds obvious since you didn't mention any conditions, just read all x pins.

Welcome to the forum

You already have the input pins in an array so using a for loop to iterate through them is simple and you are already using a for loop to set their pinMode so where are you stuck ?

Iterate through the array and test the state of each pin. There is no need for an array of pin statuses, just read them when you need to. There is also no need to test for HIGH and LOW. If the pin is not HIGH, then it is by definition LOW

That goes outside the bounds of the array, with unknown consequences.
Use:
i < sizeof(dig_in_pins)/sizeof(dig_in_pins[0])

You make the same mistake in your other for loop.

Hi All,

looking for info on how to lay out the info on the LCD(4x20) for the digital inputs eg '1-ON', I want it to look like:


POT VAL = 1023
1-ON 2-ON 3-ON 4-ON
5-ON 6-ON 7-ON 8-ON


but without a separate if statement for each.

Use a struct to hold the data for each pin, ie pin number, display row, display column, text etc and create an array of such structs, one per pin

Iterate through the array of structs as you would any array and use the data in the struct for the current pin to test its state and, position the cursor and potentially print the text although this will normally be fixed

As an alternative, print the fixed text once in setup and calculate the row and column values using the index to your existing pin array

1 Like

Or go the extra step and create a class and embed the functions

1 Like

If you think the display is crowded when you show they are OFF...

... consider using single characters to indicate ON/OFF, perhaps: 1/0 or +/- or _/█

1 Like

Hi all,

I worked something out. I made a subroutine that i can pass the x,y coordinates to easily. Very easy to enter and check at a glance.
It took me a sec to work out why state 1 and 2 weren't showing up properly (N and Y were showing up as M and K), but i needed to use String instead of char.

it's pretty compressed now - so I'll leave it at that.

@PerryBebbington - thanks for pointing out the for loop was going out of bounds.

if_di_LCD_sub1(0, 1, dig_in_pins_status[0], 1, "N", "Y"); //1 - variables - x pos, y pos, pin, switch ID, "state 1", "state 2"

//************* SUBROUTINES *************

// 001 - if_di_LCD_sub1
void if_di_LCD_sub1(uint8_t x, uint8_t y, uint8_t p, uint8_t l, String xx, String yy) {

  lcd.setCursor(x,y);
  lcd.print(l);       //print pin label
  
  if(p == HIGH) { 
    lcd.print(xx);    //print state 1
}
    else { 
    lcd.print(yy);    //print state 2
    } 
}

Hi,
what's this program please? it looks very useful.

you can move the if into the print statement with a ? : operator

  
  lcd.print( p == HIGH ? xx : yy);

How are you storing the x, y coordinates in the sketch ?

The free, simulation, web site is wokwi.com. It is very useful to try ideas before compiling and uploading to your hardware.

that's fantastic, i've not seen that before, it works.

can you point me in the direction or more info?

hi,

i'm entering them into the 1st two inputs of the below subroutine.

if_di_LCD_sub1(0,1,dig_in_pins_status[0], 1, "N", "Y"); //1 - variables - x_pos, y_pos, pin, switch_ID, "state 1", "state 2"
if_di_LCD_sub1(2,1,dig_in_pins_status[1], 2, "N", "Y"); //2
if_di_LCD_sub1(4,1,dig_in_pins_status[2], 3, "N", "Y"); //3
if_di_LCD_sub1(6,1,dig_in_pins_status[3], 4, "N", "Y"); //4
if_di_LCD_sub1(8,1,dig_in_pins_status[4], 5, "N", "Y"); //5
if_di_LCD_sub1(10,1,dig_in_pins_status[5], 6, "N", "Y"); //6
if_di_LCD_sub1(12,1,dig_in_pins_status[6], 7, "N", "Y"); //7
if_di_LCD_sub1(14,1,dig_in_pins_status[7], 8, "N", "Y"); //8

Do you notice a pattern in the values of the x parameter ?
Suppose that you called your function in a for loop and used the value of the for loop value to derive the x value, the index to the status and the pin label number ?

for (int x = 0; x < 8; x++)
{
  if_di_LCD_sub1(x * 2,1,dig_in_pins_status[x], x + 1, "N", "Y");
}

It is called the ternary operator. If you google ternary operator C++, you will get plenty of reading material. It is basically a shorthand way of writing an if/else

  if(p == HIGH) { 
    lcd.print(xx);    //print state 1
  }
  else { 
    lcd.print(yy);    //print state 2
  } 

It might not be a good choice to send "N" and "Y" as strings...
As character might be easier --> 'N'.
Or as bool or as ENUM...

format can be easily changed

  0^  1_  2^  3^
  4^  5_  6_  7^
const uint8_t Pins [] = { 4, 5, 6, 7, 8, 9, 10, 11 };
const int     Npin    = sizeof(Pins);

char s [90];

void disp ()
{
    char t [9];
    int  row = 0;

    s [0] = 0;
    for (int n = 0; n < Npin; n++)  {
        sprintf (t, " %2d%c", n, digitalRead (Pins [n]) ? '^' : '_');
        strcat (s, t);

        if (! ((n+1) % 4))  {
            lcd.setCursor (0, row++);
            lcd.print     (s);
            s [0] = 0;
        }
    }
}