Using analog pins for LCD [SOLVED]

I've ran out of digital I/O pins to use on my ELEGOO UNO board (based on the ATmega328) and I've tried simply using the liquid crystal library and declaring the pins:

(LiquidCrystal lcd(A0, A1, A2, A3, A4, A5)

but my screen is just printing garbage. Is there any way I could get this to work?

You can certainly use analogue pins as digital pins as long as they are not being used for anything else at the same time. Are you using an SPI device in your project by any chance ?

Please post your complete sketch where you used

/*    _______________________________________________________________________________________________________________________________________________________________________
ㅤㅤ /\             \                                                                                                                                          /            /\
ㅤ ㅤ|_\             \                                                               DATALOGGER                                                               /            /_|
ㅤㅤ |__\             \________________________________  16x2 LCD, SD ADAPTER, DS1307, DS18B20 (5.1kPU), 10k NTC THERMISTOR  ________________________________/            /__| 
ㅤㅤ |___\                                             \____________________________________________________________________/                                            /___|  
ㅤㅤ |____\                                                                                                                                                             /____|
ㅤ ㅤ|_____\                  _______________________________________________________________________________________________________________________                  /_____|
ㅤㅤ \______\                /                                                                                                                       \                /______/                                            
ㅤㅤ  \_____/\______________/  THIS PROGRAM MAY ALSO BE USED AS A GENERAL DATA LOGGER BY MODIFYING THE SENSOR CODE AND INPUTTING THE NECESSARY CODE   \______________/\_____/
ㅤ ㅤ                        \________________________________________________________________________________________________________________________/                     

___________________________________________________________________________________________________________________________________________________________________________________
ㅤ  ㅤ   ㅤ           ㅤ/                                                   \                           /
HARDWARE WIRING LIST: /                                                     \   PROGRAM DESCRIPTION:  /   
_____________________/                                                       \_______________________/
ㅤ                                                      
_________________________________                        _________________________________________________________________
FOR 16X2 LIQUID CRYSTAL DISPLAY: \                      /                                                                 \
............_____________________/                     /  This program is designed to log data from a DS18B20 temperature  \
-VSS GND   /                                           |  sensor   and   a  10K  NTC  thermistor.  Once the  SD  card  is  | 
-VDD 5V    \                                           |  initialised and the start button is pressed, the  program  will  | 
-V0 10K POT \                                          |  create a file in the SD card and name it according to the  date  | 
-RS PIN D2  |                                          |  (the date is retrieved using a DS1307 RTC). once the  file  and  | 
-RW GND    /                                           |  file name is created, 8 data samples from  the  DS18B20  sensor  | 
-E PIN D3  |                                           |  and thermistor are  averaged  and  logged  within  the  logging  | 
-D0 X     /                                            |  interval into the created file, as well as the time in  seconds  | 
-D1 X    /                                             |  that the program started  and  the  real  time  clock.  If  the  | 
-D2 X    \                                             |  program is ran  until  the  next  day,  data  logging  will  be  | 
-D3 X     \                                            |  stopped, and another file will be created and  named  according  | 
-D4 PIN D4 \                                           |  to the date. The  liquid  crystal  display  or  serial  monitor  | 
-D5 PIN D5  \                                          |  (dependant on the DEBUG state) can be used to ensure  that  the  | 
-D6 PIN D6  |                                          |  program runs correctly, displaying SD card initialisation,  RTC  | 
-D7 PIN D7  /                                          |  initialisation, the filename the data is writing to,  the  time  | 
-A 5V      /                                           |  the data started logging in seconds, and the  current  time  of  | 
-K GND    /                                            \  the RTC. If any errors occur, the LCD or  serial  monitor  will  / 
_________/                                              \__________________  display an error message.  __________________/ 
ㅤ                                                                         \___________________________/
____________________________
FOR SD CARD ADAPTER MODULE: \
....................________/
-chipSelect PIN D10 \
-MOSI PIN D11  _____/
-MISO PIN D12 /
-SCK PIN D13 /
____________/

_________________
FOR DS1307 RTC:  \
.............____/
-SCL PIN SCL \
-SDA PIN SDA  |
-SQW X  _____/
_______/

________________________________
FOR DS18B20 TEMPERATURE SENSOR: \
........._______________________/
-POS 5V  \
-NEG GND  \__
-DQ 5.1kPU   \________________
-5.1kPU LINKING PIN D9 AND 5V \______________
-104pF CERAMIC CAPACITOR LIKNING POS AND NEG \
_____________________________________________/


// INCLUDE LIBRARIES AND DEFINED CONSTANTS:                                                                                      
/********************************************************************************************************************************************************************************/

#include <OneWire.h> //one wire communication
#include <DallasTemperature.h> //library for DS18B20 temperature sensor
#include <SPI.h> //library for SPI pins of the SD card module adapter
#include <SD.h> //library for the SD card 
#include <LiquidCrystal.h> //library for the LCD
#include <TimeLib.h> //time elements library
#include <DS1307RTC.h> //library for the DS1307 RTC

#define totalTime() millis() / 1000 //gives the total time in seconds
#define ONE_WIRE_BUS 9 //define the communication pin of the DS18B20 temperature sensor to digital pin 9
#define year() tmYearToCalendar(tm.Year) - 2000 //gives the year as a 2 digit integer
#define degrees 0xDF




// DEBUG STATE: 
/********************************************************************************************************************************************************************************/
// with this define constant, the user has the ability to either send debugging information to the serial monitor or to the LCD. The serial monitor sends more detailed debugging
// information, at a cost of decreased storage; the LCD prints vague error messages, but allows the debugging info to be viewed remotely and increases program storage

#define DEBUG 0 //current DEBUG state, spaced out for ease of navigation. Equal to 0 or 1: 0 for LCD debugging data, 1 for serial monitor debugging data

// IF DEBUG STATE
/********************************************************************************************************************************************************************************/




#if DEBUG == 1 //if DEBUG == 1 then serial debugging data will be printed, lcd debugging data will not. x in all of these arguments are placeholders

#define debug(x) Serial.print(x) //define debug as serial print
#define debugln(x) Serial.println(x) //define debugln as serial println
#define debugLCD(x) //lcd print undefined, therefore it will not be compiled
#define clearLCD() //lcd clear undefined, therefore it will not be compiled
#define SCLCD() //set cursor undefined, therefore it will not be compiled

#else //if DEBUG == 0 then lcd debugging data will be printed, serial debugging data will not

#define debug(x) //serial print undefined, therefore it will not be compiled
#define debugln(x) //serial println undefined, therefore it will not be compiled
#define debugLCD(x) lcd.print(x) //define debugLCD as lcd prin
#define clearLCD() lcd.clear() //define lcd clear as clearLCD
#define SCLCD() lcd.setCursor(0, 0) //define set cursor LCD as lcd set cursor to 0, 0 on the display

#endif //end if definitions

// GENERAL DATALOGGER GLOBAL VARIABLES:                    
/********************************************************************************************************************************************************************************/

File dataFile; //the file we will be using to create the filename and write to
LiquidCrystal lcd(A0, A1, A2, A3, A4, A5); //set pins on the lcd

tmElements_t tm; //time elements

const short chipSelect = 10; //chip select pin for the micro SD card adapter module
const short buzzer = 8; //pin for buzzer 

const short logInterval = 10; //the interval of which the data is written to the file
const float sampleInterval = 1.25; //the interval of which the samples will be take
static unsigned long logTime = totalTime() + logInterval; //the total log time of the data logger
static float sampleTime = totalTime() + sampleInterval; //the total sample time of the data logger
const short userDelay = 2000; //delay for user opimisation
static short numSamples = 0; //the number of samples taken


// TEMPERATURE DATALOGGER GLOBAL VARIABLES:                    
/********************************************************************************************************************************************************************************/

OneWire oneWire(ONE_WIRE_BUS); //data communication 
DallasTemperature sensors(&oneWire); //used for the DS18B20 sensor

static float averageT1; //the average of the sum of samples of temperature sensor 1, divided by the number of samples
static float totalT1 = 0; //the total of the sum of samples of temperature sensor 1

// INITIALISATION FUNCTION:
/********************************************************************************************************************************************************************************/

void initialisation() { //used in setup to initialise the RTC and SD card

  sensors.setWaitForConversion(false);
  pinMode(buzzer, OUTPUT);
  delay(userDelay); //delay for user optimisation
  Serial.begin(115200); //begins serial communication
  lcd.begin(16, 2); //begins LCD communication
  SD.begin();
  SCLCD(); //sets the cursor of the LCD to 0, 0
  debugln(); //prints a new line to format serial monitor data in case of zero bytes printed during serial connection
  clearLCD(); //clears the LCD

  if (!SD.begin(chipSelect)) { //checks if SD card is available and prints error message if not

    debugln(F("SD card failed. Check hardware")); //prints that the SD card has failed to the serial monitor
    debugLCD(F("SD card failed")); //prints that the SD card has failed to the LCD 
    while (1) {

      
      digitalWrite(buzzer, HIGH);
      delay(100);
      digitalWrite(buzzer, LOW);
      delay(userDelay);
    } //end while (1) loop
  } //end if (!SD.begin(chipSelect))
  
  clearLCD(); //clears the LCD

  if (!RTC.read(tm)) { //prints message that the RTC has been initialised

    debugln(F("RTC failed. Check hardware")); //prints RTC failed message to the serial monitor
    debugLCD(F("RTC failed")); //prints RTC failed message to the LCD 

    while (1) {
      
      digitalWrite(buzzer, HIGH);
      delay(100);
      digitalWrite(buzzer, LOW);
      delay(userDelay);
    } //end while (1) loop
  } //end if (RTC.read(tm))

  clearLCD(); //clears the LCD

  SCLCD(); //set cursor of LCD to (0, 0)

  sensors.requestTemperatures();  //requests data before first loop iteration to print data at the log interval
 
} //end initialisation()

// CREATE FILE AND NAME() FUNCTION:
/*******************************************************************************************************************************************************************************/

void createFileAndName() { //creates file and names the file according to the date


  char fileName[13]; //buffer to store file name
  char directoryName[9] = "TempData";
  sprintf(fileName, "%02d-%02d-%d.txt", tm.Day, tm.Month, year());  //formats and concatenates the RTC data to create the file name

  char fullPath[25]; //adjust 50 to your needs
  strlcpy(fullPath, directoryName, sizeof fullPath);
  strlcat(fullPath, "/", sizeof fullPath);
  strlcat(fullPath, fileName, sizeof fullPath);


  if (!SD.exists(fullPath)) { //creates file if the file is not already created

    SD.mkdir(directoryName);
    debugln(fileName); //prints the file name to the serial monitor
  } //end if (!SD.exists(fileName))

  else { //appends data to already existing file

    debug(F("The file: ")); //prints the beginning of the sentence to the file name
    debug(fileName); //prints file name to the serial monitor
    debugln(F(" already exists. Opening file...")); //prints message to the serial monitor
  } //end else if (!SD.exists(fileName))

// SD CARD FIRST WRITE- HEADER:
/********************************************************************************************************************************************************************************/

  dataFile = SD.open(fullPath, FILE_WRITE); //opens the dataFile named after the current date on the RTC
  
  if (!dataFile) { //if the dataFile opens it will print the datalogging header

    debugln(F("Error opening and writing header to file")); //prints error message to the serial monitor
    clearLCD(); //clears the CLCD to print the error message
    debugLCD(F("File write error")); //prints error message to the LCD

    while (1) {

      digitalWrite(buzzer, HIGH);
      delay(100);
      digitalWrite(buzzer, LOW);
      delay(userDelay); 
    } //end while (1) loop
  } //end if (!dataFile)

    dataFile.println(); // Helps format the data if more than one logging process has been utilised that day.
    dataFile.println(F("TEMPERATURE DATA LOGGER")); //prints the datalogging header to the dataFile
    dataFile.println();
    dataFile.close(); //closes the data file to avoid data corruption

} //end createFileAndName()

// GET AVERAGE READING() FUNCTION:
/********************************************************************************************************************************************************************************/

void getAverageReading() { //prints and logs average temperature data to the file 

  char fileName[13]; //buffer to store file name
  sprintf(fileName, "%02d-%02d-%d.txt", tm.Day, tm.Month, year());  //formats and concatenates the RTC data to create the file name
  char directoryName[9] = "TempData";
  char fullPath[25]; //adjust 50 to your needs
  strlcpy(fullPath, directoryName, sizeof fullPath);
  strlcat(fullPath, "/", sizeof fullPath);
  strlcat(fullPath, fileName, sizeof fullPath);

  if(tm.Hour == 0 && tm.Minute == 0 && tm.Second == 0) {

   createFileAndName();
    delay(750);
  }


// RTC TIME INFO PRINT TO LCD:
/********************************************************************************************************************************************************************************/
 
  char displayTime[9]; //placeholder for displaying real time
  RTC.read(tm); //reads the time from the RTC
  sprintf(displayTime, "%02d:%02d:%02d", tm.Hour, tm.Minute, tm.Second); //concatenates and formats the data of the real time clock
  debugLCD(displayTime); //prints the real time to the LCD

/********************************************************************************************************************************************************************************/
  SCLCD();
  sensors.getTempCByIndex(0); //gets the temperature from the request within setup
  debugLCD(sensors.getTempCByIndex(0));
  debugLCD("\337C");
  sensors.requestTemperatures(); //requests temperature in the loop, which will be used in the next loop iteration
  

// CHARACTER ARRAYS: 
/********************************************************************************************************************************************************************************/
  
  char averageData[50]; //character buffer for sprintf()
  char charLogTime[8]; //placeholder for log time character
  char charAverageT1[9]; //placeholder for averageT1 character

// DTOSTRF FUNCTIONS: 
/********************************************************************************************************************************************************************************/ 

  dtostrf(logTime, 7, 0, charLogTime); //converts integer to character array and used to format the logTime data within the lcd screen and the average data character buffer
  dtostrf(averageT1, 8, 2, charAverageT1); //converts floating point number to a character array as sprintf cannot use float values

// SPRINTF TO CONCATENATE/FORMAT LOGGED DATA:
/********************************************************************************************************************************************************************************/

  sprintf(averageData, "TIME:  %02d:%02d:%02d  LOG:%ss  T1:%sºC", tm.Hour, tm.Minute, tm.Second, charLogTime, charAverageT1);

// OPEN FILE:
/********************************************************************************************************************************************************************************/

  dataFile = SD.open(fullPath, FILE_WRITE); //opens file to write to

// TAKE SAMPLE:
/********************************************************************************************************************************************************************************/

   if (totalTime() > sampleTime) { //increments the following every 1.25 seconds

    numSamples += 1; //increments the number of samples by 1
    totalT1 += sensors.getTempCByIndex(0); //increments the total of T1 by the sample reading
    averageT1 = totalT1 / numSamples;  //calculate total of T1
  

    if (sensors.getTempCByIndex(0) <= -10 || sensors.getTempCByIndex(0) >= 70) { //highlights faulty readings so that they can be discarded

      dataFile.print(F("*")); //prints to the file
      debug(F("*")); //prints to the serial monitor
      lcd.setCursor(15, 0); //sets LCD sursor 
      debugLCD(F("*")); //prints to the LCD
    } //end if
    
    debug(numSamples);
    debug("  ");
    debug(sampleTime);
    debug("s");
    debug("  ");
    debug("T1:  ");
    debug(sensors.getTempCByIndex(0));
    debug("ºC  Total T1:  ");
    debug(totalT1);

    sensors.requestTemperatures();
    sampleTime += sampleInterval; //increments the sample time by the sample interval

  }  //end if (totalTime() > sampleTime)

// AVERAGE TEMPERATURE READINGS:
/********************************************************************************************************************************************************************************/

  averageT1 = totalT1 / numSamples;  //calculate total of T1

// WRITE AND PRINT DATA TO SD & LCD:
/********************************************************************************************************************************************************************************/

  lcd.setCursor(0, 1);
  if (dataFile) {  //checks if the file is available

    if (totalTime() > logTime) {  //prints the data within the logging interval

      dataFile.println(averageData);  //prints the average data to the dataFile
      debugln(averageData); //prints the average data to the serial monitor
      lcd.setCursor(8, 1); //sets the cursor so the LCD displays the time at the bottom right of the LCD 
      debugLCD(charLogTime); //prints the log time to the LCD 
      debugLCD(F("s")); //prints s to format the printed log time on the LCD 
      logTime += logInterval; //increments the log time by the log interva
    }  //end if (totalTime() > logTime)

    if (numSamples > 7) {  //resets the number of samples and the total temperature readings

      numSamples = 0; //resets the number of samples back to 0
      totalT1 = 0; //resets the total of T1 back to 0
    }  //end if (numSamples > 7)
  }  //end if (dataFile)

  else {  //if the file does not open

    debugln(F("Error opening and writing to file")); //prints error message to the serial monitor
    clearLCD(); //clears the LCD to print the error message
    debugLCD(F("File write error")); //prints error message to the LCD
    while (1) {

      digitalWrite(buzzer, HIGH);
      delay(100);
      digitalWrite(buzzer, LOW);
      delay(userDelay);
    }  //end while (1) loop
  }  //end else if (dataFile)

  dataFile.close(); //closes the data file at the end to avoid file corruption 
}  //end getAverageReading()

// SETUP() FUNCTION
/********************************************************************************************************************************************************************************/

void setup() {  //runs once at the start of the program

  initialisation(); //runs initialisation() user defined function in setup
  createFileAndName();  //runs createFileDirAndName() user defined function in setup
}  //end setup()

// LOOP() FUNCTION
/********************************************************************************************************************************************************************************/

void loop() {  //loops getAverageReading() user defined function and displays info on the 16x2 LCD screen
  
  getAverageReading(); //runs the getAverageReading() user defined function
}  //end loop()

// END OF PROGRAM
/********************************************************************************************************************************************************************************/

I'm using an SD card, which uses the SPI library. I still need to alter the code a little (the description etc as I'm only using one temp sensor now) but it should work apart from that

@chrisd79
A4 and A5 are also the I2C pins. Your RTC uses those pins so you can't use them for anyrhing else

1 Like
_________________
FOR DS1307 RTC:  \
.............____/
-SCL PIN SCL \
-SDA PIN SDA  |
-SQW X  _____/
_______/

There is the problem

The SCL pin is actually pin A5 and SDA is pin A4

The confusion arises because the Uno board has pins marked SDA and SCL but they are also connected to A4 and A5

ohh, so I should be able to just use 4 analog pins then use 2 digital pins?

EDIT: I'm not 100% sure what pins to use and where- I'm now using:

LiquidCrystal lcd(A0, A1, A2, A3, 8, 9);

The error message for the sd and rtc failing work fine but as soon as everything is wired properly and working, it starts spewing japanese katakana characters at me.

EDIT 2: nevermind, I got it working. Digital pins 8 and 9 for some reason output katakana... I have no idea why

I am glad that you got it working

Note that you are using pin 9 for ONE_WIRE_BUS and 8 for the buzzer so no wonder that they caused problems when you tried to use them for the LCD as well

Yeah I noticed that later on, never knew that a DS18B20 temperature sensor and a buzzer could speak Japanese.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.