Google+ Facebook Twitter Pin It Reddit

Memory Card LCD Dispaly Code

Memory Card LCD Display Code

This page contains sample code for the My Story electronics project DIY Memory Card LCD Display by Lance Summers.

Contact Lance: [email protected]


/* ------------------------------------------------------------------------------- */

// character LCD and SD Arduino Code.  Copy into the Arduino sketch -> pde

//#include 
//#include 

#include 
#include 
#include 

//Buttons
#define NoButton 0
#define UpButton 1
#define DnButton 2
#define MenuButton 3
#define ErrorButton -1

//Display State
#define StateUnknown -1
#define StateIdle 0
#define StateCredits 1
#define StateMenu 2
#define StateFile 3
#define StateRecords 4
#define StateDelays 5

//Max Num Options/Choices in State
#define MaxMenuIndex 5
#define MaxFileNameIndex 29 // 0-29

//Preset our boolean values TRUE and FALSE
#define TRUE 1
#define FALSE 0

//Repeat Delay Range
#define LowDelay 250
#define HighDelay 1500

// Connections (How To Connect the LCD and SD to the Arduino):
// LCD:  
// LCD pin 01 to Grn
// LCD pin 02 to 5V
// rs (LCD pin 4) to Arduino pin 8
// rw (LCD pin 5) to Arduino pin 7
// enable (LCD pin 6) to Arduino pin 6
// LCD pin 15 to 5V through current limiting resistor
// LCD pins d4 (11), d5 (12), d6 (13), d7 (14) to Arduino pins 5, 4, 3, 2
// 1K Resister from Grn to pin 3 on LCD/
// 100 ohm Resister between LCD pin 15 & 5V
// LCD pin 16 to Grn
// Note:  100 ohm Res can be replaced with a 1K Pot.
//
// SD Card:
// 5V (6) to Arduino 5V
// Grn (5) to Arduino Grn
// MOSI (4) to Arduino 11
// SS (3) to Arduino 10
// SCK (2) to Arduino 13
// MISO (1) to Arduino 12
//
// 10K Resister From Grn to A0 and one to A1
// SPSTx2 one push button to A0 and one to A1
// A0 = UP, A1 = Down, Both = Menu
// SPST connected throu diodes x 2 to A0 & A1 for Menu Button

byte res; // Result Code for File operations
word result; // Our converted result code
char Buffer[121]; // Maximum chars read from file
char FPath[9]; // Path to Subdir where text files are
char FileNames[30][9]; // Ext not included in Filename

// You can change the size of the array and the Default entries
// to whatever you like.  This is my particular use of the LCD
char MenuOptions[6][20] = {"File Name Selection",
  "Delay Value Change", "Credits", "Back To Recs",
  "Read BookList", "Read MovieList"};

// General Variables used throughout program
int CurrentState = StateIdle; // Current Display state we are in
int MenuIndex = 0; // Current Menu option line to display
int FileNameIndex = 0; // Current File Name to work with
int NumFileNames = 0; // Number of Filenames in the FileNames array
int RecordIndex = -1; // Current Record number to display
int FileOpen = -1; // Same as FileNameIndex or -1 if none open
int RepeatDelay = 700; // Our Delay between button checks
int ButtonOnValue = 700; // Minimum Value of A0/A1 to be ON

// Define the Pins used by the LCD on the Arduino
LiquidCrystal lcd(8, 7, 6, 5, 4, 3, 2);

//*******************************************************
// Read the 2 analog values to see if we have 
// a button pushed
// We have to do this because of button bounce
// Analog0 = Up
// Analog1 = Dn
// Analog0 & 1 = Menu Button
int WaitOnResponse()
{
  int UpPressed;
  int DnPressed;
  int KeyPressed;
  
  KeyPressed = NoButton;
  while(KeyPressed == NoButton)
  {
    UpPressed = analogRead(0);
    DnPressed = analogRead(1);
    
    if(UpPressed >= ButtonOnValue)
    {
      if(DnPressed >= ButtonOnValue)
      {
        KeyPressed = MenuButton;
      }
      else
      {
        KeyPressed = UpButton;
      }
    }
    else
    {
      if(DnPressed >= ButtonOnValue)
      {
        KeyPressed = DnButton;
      }
      else
      {
        delay(20);
      }
    }
  }
  Serial.print("Response Received: ");
  Serial.println(KeyPressed);
  return(KeyPressed);
} // WaitOnResponse

//**************************************************
// Get List text file of given name into FileNames()
// I have two list files atm, "Movies" & "Books"
boolean GetFList(char *ListName)
{
  boolean NoError;
  int Index;
  char FNameBuf[8];
 
  PleaseWait();
  if(FileOpen >= 0)
  {
    file.closeFile();
    FileOpen = -1;
  }
  else
  {
    // File is already closed
  }
  FileNameIndex = 0;
  RecordIndex = 0;
  //Serial.print("Reading List File: ");
  //Serial.println(ListName);

  // format ListName with a .txt file extention
  sprintf(FNameBuf, "%s.txt", ListName); 
  //Serial.print("File To Open: ");
  //Serial.println(FNameBuf);

  res = file.openFile(FNameBuf, FILEMODE_TEXT_READ);
  if(res == NO_ERROR)
  {
    //Serial.println("File Opened OK");
    Index = 0;
    NoError = ReadOneLine(); // First line in File is List Content
    while((Buffer[Index] != NULL) && (Index < 8))
    {
      FPath[Index] = Buffer[Index];
      FPath[Index+1] = NULL;
      Index++;
    }
    //Serial.print("Path Read from File: ");
    //Serial.println(FPath);

    NumFileNames = 0;
    while((NoError == TRUE) && (NumFileNames < MaxFileNameIndex))
    {
      NoError = ReadOneLine();
      if(NoError == TRUE)
      {
        //Serial.print("Buffer Read from File: ");
        //Serial.println(Buffer);
        if(strlen(Buffer) > 0)
        {
          FNameBuf[0] = NULL;
          Index = 0;
          while((Index < strlen(Buffer))  && (Index < 8))
          {
            FNameBuf[Index] = Buffer[Index];
            FNameBuf[Index+1] = NULL;
            Index++;
          }
          sprintf(FileNames[NumFileNames], "%s", FNameBuf);
          //Serial.print("Name Read from File: ");
          //Serial.println(FileNames[NumFileNames]);
          NumFileNames++;
        }
        else
        {
          NoError = FALSE;
        }
      }
      else
      {
        // We have reached the end of the File???
      }
    }
    file.closeFile();
    NoError = TRUE;
  }
  else
  {
    //Serial.println("File did not open OK");
    NoError = FALSE;
  }
  MenuIndex = 0;
  CurrentState = StateMenu;
  FileNameIndex = 0;
  MenuDisplay();
  return(NoError);
} // GetFList

//******************************************************
// Display the Credits on the LCD
// This is my Credit information, you may change it to yours
void CreditDisplay()
{
  lcd.clear();  // Clear current display
  lcd.setCursor(0,0);  // set cursor to column 0, row 0 (the first row)
  lcd.print("Science Fiction Book");  // Title Line
  lcd.setCursor(0,1);  // set cursor to column 0, row 1
  lcd.print("Program Created by:");   // Sub-Title Line
  lcd.setCursor(0,2);         // set cursor to column 0, row 2
  lcd.print("Lance Summers");
  lcd.setCursor(0,3);         // set cursor to column 0, row 3
  lcd.print("For the Arduino");
  return;
} // CreditDisplay

//******************************************************
// Display The MENU screen on the LCD with the Indexed option
// Each Menu Item is displayed one at a time.
// Use Up/down buttons to display the next/last menu option
void MenuDisplay()
{
  lcd.clear();  // Clear current display
  lcd.setCursor(0,0);  // set cursor to column 0, row 0 (the first row)
  lcd.print("Menu Options");  // Title Line
  lcd.setCursor(0,1);  // set cursor to column 0, row 1
  lcd.print("(Up/Down to change)");   // Sub-Title Line
  lcd.setCursor(0,2);         // set cursor to column 0, row 2
  lcd.print(" ");
  lcd.setCursor(0,3);         // set cursor to column 0, row 3
  lcd.print(MenuOptions[MenuIndex]);
  return;
} // MenuDisplay

//******************************************************
// Display the File Name Selection screen with current File Name
void FileNameDisplay()
{
  lcd.clear();  // Clear current display
  lcd.setCursor(0,0);  // set cursor to column 0, row 0 (the first row)
  lcd.print("File Name Select");  // Title Line
  lcd.setCursor(0,1);  // set cursor to column 0, row 1
  lcd.print("(Up/Down to change)");   // Sub-Title Line
  lcd.setCursor(0,2);         // set cursor to column 0, row 2
  lcd.print(" ");
  lcd.setCursor(0,3);         // set cursor to column 0, row 3
  lcd.print(FileNames[FileNameIndex]);  
  return;
} // FileNameDisplay

//******************************************************
// Display the Repeat Delay Value screen
// The Delay value is used to determine when it is
// legal to read a button value again
// And yes, you may hold the up/down buttons down
void DelayDisplay()
{
  char DelayString[10];
  
  lcd.clear();  // Clear current display
  lcd.setCursor(0,0);  // set cursor to column 0, row 0 (the first row)
  lcd.print("Repeat Delay Change");  // Title Line
  lcd.setCursor(0,1);  // set cursor to column 0, row 1
  lcd.print("(Up/Down to change)");   // Sub-Title Line
  lcd.setCursor(0,2);         // set cursor to column 0, row 2
  lcd.print(" ");
  sprintf(DelayString, "%u", RepeatDelay); // %u = unsigned integer
  lcd.setCursor(0,3);         // set cursor to column 0, row 3
  lcd.print(DelayString);
  return;
} // DelayDisplay

//*******************************************************
// Display a RECORD ERROR message on the LCD
void RecordError()
{
  lcd.clear();  // Clear current display
  lcd.setCursor(0,0);  // set cursor to column 0, row 0 (the first row)
  lcd.print("-- ERROR --");  // Title Line
  lcd.setCursor(0,1);  // set cursor to column 0, row 1
  lcd.print("Was Unable to ");   // Sub-Title Line
  lcd.setCursor(0,2);         // set cursor to column 0, row 2
  lcd.print("Retrieve Record");
  lcd.setCursor(0,3);         // set cursor to column 0, row 3
  lcd.print(" ");  
  return;
} // RecordError

//*******************************************************
// Convert one text line to Author, Series, Title, etc...
// Each line has four fields separated by a '|'
// You can have the text file contain any info you want,
// using this format to separate what info goes on what
// line of the LCD
void RecordDisplay()
{
  char *separator;
  char Trash[41];
  char LineOne[21];
  char LineTwo[21];
  char LineThree[21];
  char LineFour[21];
  int Length;
  int Index;
  int Field;
  int FieldLen;

  LineOne[0] = NULL;
  LineTwo[0] = NULL;
  LineThree[0] = NULL;
  LineFour[0] = NULL;
  Field = 0;
  Index = 0;  
  Length = strlen(Buffer);
  while(Index < Length)
  {
    if(Buffer[Index] == '|')
    {
      Field++;
    }
    else
    {
      switch(Field)
      {
        case 0:
          FieldLen = strlen(LineOne);
          if(FieldLen < 20)
          {
            LineOne[FieldLen] = Buffer[Index];
            LineOne[FieldLen+1] = NULL;
          }
          else
          {
            // We ignore anything over 20 chars
          }
          break;
        case 1:
          FieldLen = strlen(LineTwo);
          if(FieldLen < 20)
          {
            LineTwo[FieldLen] = Buffer[Index];
            LineTwo[FieldLen+1] = NULL;
          }
          else
          {
            // Ignore anything over 20 chars
          }
          break;
        case 2:
          FieldLen = strlen(LineThree);
          if(FieldLen < 20)
          {
            LineThree[FieldLen] = Buffer[Index];
            LineThree[FieldLen+1] = NULL;
          }
          else
          {
            // Ignore anything over 20 chars
          }
          break;
        case 3:
          FieldLen = strlen(LineFour);
          if(FieldLen < 20)
          {
            LineFour[FieldLen] = Buffer[Index];
            LineFour[FieldLen+1] = NULL;
          }
          else
          {
            // Ignore anything over 20 chars
          }
          break;
      }
    }
    Index++;
  }
  
  // Do we have any Info to display?
  if(Field > 0)
  {
    lcd.clear(); 
    lcd.setCursor(0,0);
    //Serial.print("Line One: ");
    //Serial.println(LineOne);
    lcd.print(LineOne);
    
    lcd.setCursor(0,1);
    lcd.print(LineTwo);
    //Serial.print("Line Two: ");
    //Serial.println(LineTwo);
    
    lcd.setCursor(0,2);
    lcd.print(LineThree);
    //Serial.print("Line Three: ");
    //Serial.println(LineThree);
    
    lcd.setCursor(0,3);
    lcd.print(LineFour);
    //Serial.print("Line Four: ");
    //Serial.println(LineFour);
  }
  else
  {
    Serial.println(Buffer);
  }
  return;
} // RecordDisplay

//******************************************************
// Error in Switch statement
void DisplayError(char *ErrorLine)
{
  lcd.clear();  // Clear current display
  lcd.setCursor(0,0);  // set cursor to column 0, row 0 (the first row)
  lcd.print("***  ERROR  ***");  // Title Line
  lcd.setCursor(0,1);  // set cursor to column 0, row 1
  lcd.print("From Switch Default");   // Sub-Title Line
  lcd.setCursor(0,2);         // set cursor to column 0, row 2
  lcd.print(" ");
  lcd.setCursor(0,3);         // set cursor to column 0, row 3
  lcd.print(ErrorLine);
  delay(2000);
  MenuIndex = 0;
  CurrentState = StateMenu;
  FileNameIndex = 0;
  MenuDisplay();
  return;
} // DisplayError

//******************************************************
// Read one line from the open file into Buffer or return error
boolean ReadOneLine()
{
  boolean ReturnCode;
  
  ReturnCode = FALSE;
  result = file.readLn(Buffer, 120);
  if((result != FILE_IS_EMPTY) &&
    (result != BUFFER_OVERFLOW))
  {
    // We should have a good read
    ReturnCode = TRUE;
  }
  else
  {
    ReturnCode = FALSE;
  }
  return(ReturnCode);
} // ReadOneLine

//******************************************************
// Open the selected file or return err code
boolean GetRecord()
{
  boolean ReturnCode;
  char PathFile[20];
  
  ReturnCode = FALSE; // Preset this so we at least have a return value
  if(FileOpen != FileNameIndex)
  {
    if(FileOpen >= 0)
    {
      file.closeFile();
    }
    else
    {
      // File is already closed
    }
    // At this point we should not have an open file
    FileOpen = -1;
    Serial.print("New File to Open: ");
    sprintf(PathFile, "%s-%s.txt", FPath, FileNames[FileNameIndex]);
    Serial.println(PathFile);
    if(file.exists(PathFile) == TRUE)
    {
      Serial.print("File Exists: ");
      Serial.println(PathFile);
      // We try to open the file and change the state to rec
      res = file.openFile(PathFile, FILEMODE_TEXT_READ);
      if(res == NO_ERROR)
      {
        Serial.println("File Opened");
        // so far so good, now we have to read one line into Buffer
        FileOpen = FileNameIndex;
        RecordIndex = 0;
        ReturnCode = ReadOneLine();
      }
      else
      {
        Serial.println("File did NOT open");
        ReturnCode = FALSE;
      }
    }
    else
    {
      Serial.println("File Not Found");
      // We did not file the file so we return false
      ReturnCode = FALSE;
    }
  }
  else
  {
    // We are asking to open a file that is already open
    // So we let stand what is in the buffer
    ReturnCode = TRUE;
  }
  return(ReturnCode);
}

//*********************************************************
// Get the next record line in the open text file
boolean GetNextRecord()
{
  boolean ReturnCode;
  
  ReturnCode = ReadOneLine();
  if(ReturnCode == TRUE)
  {
    RecordIndex++;
  }
  else
  {
    // We did NOT get a good record
  }
  return(ReturnCode);
} // GetNextRecord

//*********************************************************
// Get the previous record line from the open text file
// TinyFat does not have a SEEK function so we do it the hard way
boolean GetPreviousRecord()
{
  int Index;
  boolean ReturnCode;
  char PathFile[21];
  
  PleaseWait();
  if(RecordIndex > 0)
  {
    if(FileOpen >= 0)
    {
      file.closeFile();
    }
    else
    {
      // File is already closed
    }
    FileOpen = -1;
    sprintf(PathFile, "%s-%s.txt", FPath, FileNames[FileNameIndex]);
    res = file.openFile(PathFile, FILEMODE_TEXT_READ);
    if(res == NO_ERROR)
    {
      FileOpen = FileNameIndex;
      // so far so good, now we have to read one line into Buffer
      ReturnCode = TRUE;
      Index = 0;
      while((Index < RecordIndex) && (ReturnCode == TRUE))
      {
        ReturnCode = ReadOneLine();
        Index++;
      }
      RecordIndex = Index - 1;
    }
    else
    {
      ReturnCode = FALSE;
    }
  }
  else
  {
    // We are already at the first one
    ReturnCode = TRUE;
  }
  return(ReturnCode);
} // GetPreviousRecord

//***************************************************
// Initialize the LCD, Serial, and SD Card File FAT
void setup()
{
  Serial.begin(115200);
  Serial.println();
  
  //initialize the LCD
  lcd.begin(20,4);   // columns, rows.  use 16,2 for a 16x2 LCD, etc.
  lcd.clear();       // start with a blank screen
  
  //initialize tinyFAT
  res=file.initFAT();
  if(res != NO_ERROR)
  {
    Serial.print("***** ERROR Initializing FAT: ");
    //Serial.println(verboseError(res));
    while(true)
    {
    }
  }
  
  GetFList("ListBook");

  CreditDisplay();
  CurrentState = StateCredits;
  Serial.flush();
  return;
} // Setup

//****************************************************
// Notify User to Wait to Hit a Button
void PleaseWait()
{
  lcd.clear();  // Clear current display
  lcd.setCursor(0,0);
  lcd.print("*** PLEASE WAIT ***");
  lcd.setCursor(0,1);
  lcd.print(" ");
  lcd.setCursor(0,2);
  lcd.print("Reading Info");
  lcd.setCursor(0,3);
  lcd.print("From SD Card");
  return;
}

//****************************************************
// We loop, waiting for a pushbutton
// Menu State:
 
//    Page DN = List the next Option in the Menu
//    Menu Button = Select Option
// File State:
//    Page Up = List the previous File Name
//    Page Dn = List the next File Name
//    Menu Button = Select the File name then go to Menu
// Record State:
//    Page Up = Go to the Previous Record
//    Page Dn = Go to the Next Record
// Delays
//    Page Up = Decrease the Delay Value
//    Page Dn = Increase the Delay Value
//
void loop()
{
  int KeyPressed;
  
  KeyPressed = WaitOnResponse();
  //Serial.print("Button Pressed: ");
  switch (KeyPressed)
  {
    case MenuButton:
      //Serial.println("Menu Button");
      switch (CurrentState)
      {
        case StateCredits:
          CurrentState = StateMenu;
          MenuDisplay();
          break;
        case StateMenu:
          switch(MenuIndex)
          {
            case 0: // File Display
              CurrentState = StateFile;
              FileNameDisplay();
              break;
            case 1: // Delay Value Change
              CurrentState = StateDelays;
              DelayDisplay();
              break;
            case 2: // Credits Display
              CurrentState = StateCredits;
              CreditDisplay();
              break;
            case 3: // Return to Record Display
              CurrentState = StateRecords;
              GetRecord();
              RecordDisplay();
              break;
            case 4: // Read BookList
              GetFList("ListBook");
              //CurrentState = StateFile;
              //FileNameDisplay();
              break;
            case 5: // Read MovieList
              GetFList("ListDVD");
              //CurrentState = StateFile;
              //FileNameDisplay();
              break;
            default:
              // We should never get here
              DisplayError("Menu Index");
              break;
          }
          break;
        case StateFile:
          CurrentState = StateRecords;
          GetRecord();
          RecordDisplay();
          break;
        case StateRecords:
          CurrentState = StateMenu;
          MenuDisplay();
          break;
        case StateDelays:
          CurrentState = StateMenu;
          MenuDisplay();
          break;
        default:
          DisplayError("Menu Button");
          delay(2000);
          CurrentState = StateMenu;
          break;
      }
      break;
    case UpButton:
      //Serial.println("Up Button");
      switch (CurrentState)
      {
        case StateMenu:
          if(MenuIndex > 0)
          {
            MenuIndex--;
            MenuDisplay();
          }
          else
          {
            // We are already at the top
          }
          break;
        case StateFile:
          if(FileNameIndex > 0)
          {
            FileNameIndex--;
            FileNameDisplay();
          }
          else
          {
          }
          break;
        case StateRecords:
          GetPreviousRecord();
          RecordDisplay();
          break;
        case StateDelays:
          if(RepeatDelay > LowDelay)
          {
            RepeatDelay = RepeatDelay - 10;
          }
          else
          {
          }
          DelayDisplay();
          break;
        default:
          DisplayError("Up Button");
          break;
      }
      break;
    case DnButton:
      //Serial.println("Down Button");
      switch (CurrentState)
      {
        case StateMenu:
          if(MenuIndex < MaxMenuIndex)
          {
            MenuIndex++;
            MenuDisplay();
          }
          else
          {
          }
          break;
        case StateFile:
          if(FileNameIndex < MaxFileNameIndex)
          {
            FileNameIndex++;
            FileNameDisplay();
          }
          else
          {
          }
          break;
        case StateRecords:
          GetNextRecord();
          RecordDisplay();
          break;
        case StateDelays:
          if(RepeatDelay < HighDelay)
          {
            RepeatDelay = RepeatDelay + 10;
          }
          else
          {
          }
          DelayDisplay();
          break;
        default:
          DisplayError("Down Button");
          break;
      }
      break;
    default:
      //Serial.println("Unknown");
      break;
  }
  delay(RepeatDelay);
} 

/* ------------------------------------------------------------------------------- */