Highschool Project Help

Hi, I'm new to Arduino and I'm doing a high school project on it. I did this project: Arduino Lock Box | Arduino Project Hub and it seems to be working fine, the only thing is that the timer isn't showing up on the LCD screen; I might have used the wrong library for time, the project description didn't really say which one to use. Or, I just don't understand how to work it. Also, I wanted to add LED lights or something else after it gets unlocked but there isn't enough space on the board. Is there a way to combine 2 boards in a sketch? I'm using Arduino IDE 2.3.5 to code. Thanks!

Update-
Here is my code and pictures of my board:

#include <Time.h>
#include <TimeLib.h>
#include <LiquidCrystal.h>
#include <EEPROM.h>
#include <Servo.h>

LiquidCrystal lcd(12, 11, 5, 4, 3, 2);

Servo myServo;

const int BackButtonPin = 6;
const int StartButtonPin = 7;
const int MinusButtonPin = 8;
const int PlusButtonPin = 9;

int settingHours = 0;
int settingMinutes = 0;
int settingSeconds = 0;
time_t settingTime = 0;
int activeHours = 0;
int activeMinutes = 0;
int activeSeconds = 0;
time_t activeTime = 0;
time_t startTime = 0;
time_t elapsedTime = 0;

int BackButtonState = LOW;
long BackButtonLongPressTime = 0;
int StartButtonState = LOW;
int PlusButtonState = LOW;
int MinusButtonState = LOW;
int BackButtonPrevState = LOW;
int StartButtonPrevState = LOW;
int PlusButtonPrevState = LOW;
int MinusButtonPrevState = LOW;
bool BackButtonPress = false;
bool BackButtonLongPress = false;
bool StartButtonPress = false;
bool PlusButtonPress = false;
bool MinusButtonPress = false;
bool locked = false;

const int READY = 0;
const int SETTINGS = 1;
const int LOCKED = 2;
const int UNLOCKED = 3;

int activeState = READY;
int timeData = 0;

void setup() {
  lcd.begin(16, 2);
  pinMode(BackButtonPin, INPUT);
  pinMode(StartButtonPin, INPUT);
  pinMode(PlusButtonPin, INPUT);
  pinMode(MinusButtonPin, INPUT);
  myServo.attach(10);
  Serial.begin(9600);
  myServo.write(90);
}

void loop() {
  StartButtonPress = false;
  PlusButtonPress = false;
  MinusButtonPress = false;
  BackButtonPress = false;
  BackButtonLongPress = false;
  BackButtonState = digitalRead(BackButtonPin);
  if (BackButtonState != BackButtonPrevState) {
    BackButtonPress = BackButtonState == HIGH;
    BackButtonPrevState = BackButtonState;
  } else {
    if (BackButtonState == HIGH) {
      BackButtonLongPressTime++;
      if (BackButtonLongPressTime == 100) {
        BackButtonPress = false;
        BackButtonLongPress = true;
        BackButtonLongPressTime = 0;
      }
    } else {
      BackButtonLongPressTime = 0;
      BackButtonPress = false;
      BackButtonLongPress = false;
    }
  }
  StartButtonPress = false;
  StartButtonState = digitalRead(StartButtonPin);
  if (StartButtonState != StartButtonPrevState) {
    StartButtonPress = StartButtonState == HIGH;
    StartButtonPrevState = StartButtonState;
  }
  MinusButtonPress = false;
  MinusButtonState = digitalRead(MinusButtonPin);
  if (MinusButtonState != MinusButtonPrevState) {
    MinusButtonPress = MinusButtonState == HIGH;
    MinusButtonPrevState = MinusButtonState;
  }
  PlusButtonPress = false;
  PlusButtonState = digitalRead(PlusButtonPin);
  if (PlusButtonState != PlusButtonPrevState) {
    PlusButtonPress = PlusButtonState == HIGH;
    PlusButtonPrevState = PlusButtonState;
  }
  switch (activeState) {
    case READY:
      myServo.write(90);
      if (BackButtonPress) {
        Reset();
      }
      if (BackButtonPress) {
        activeState = SETTINGS;
      }
      if (StartButtonPress) {
        activeState = activeState == READY ? LOCKED : READY;
        if (activeState == LOCKED) {
          startTime = now();
        }
      }
      break;

    case SETTINGS:
      myServo.write(90);
      if (BackButtonPress) {
        settingTime = settingSeconds + (60 * settingMinutes) + (3600 * settingHours);
        activeHours = settingHours;
        activeMinutes = settingMinutes;
        activeSeconds = settingSeconds;
        timeData = 0;
        activeState = READY;
      }
      if (StartButtonPress) {
        timeData++;
        if (timeData == 3) {
          timeData = 0;
        }
      }
      if (MinusButtonPress) {
        switch (timeData) {
          case 0:
            settingHours--;
            if (settingHours == -1) {
              settingHours = 99;
            }
            break;
          case 1:
            settingMinutes--;
            if (settingMinutes == -1) {
              settingMinutes = 59;
            }
            break;
          case 2:
            settingSeconds--;
            if (settingSeconds == -1) {
              settingSeconds = 59;
            }
            break;
        }
      }
      if (PlusButtonPress) {
        switch (timeData) {
          case 0:
            settingHours++;
            if (settingHours == 100) {
              settingHours = 0;
            }
            break;
          case 1:
            settingMinutes++;
            if (settingMinutes == 60) {
              settingMinutes = 0;
            }
            break;
          case 2:
            settingSeconds++;
            if (settingSeconds == 60) {
              settingSeconds = 0;
            }
            break;
        }
      }
      break;

    case LOCKED:
      myServo.write(0);
      if (StartButtonPress) {
        activeState = READY;
      }
      if (BackButtonPress) {
        Reset();
        activeState = READY;
      }
      break;

    case UNLOCKED:
      myServo.write(90);
      if (BackButtonPress || StartButtonPress || MinusButtonPress || PlusButtonPress) {
        activeState = READY;
      }
      break;
  }
  switch (activeState) {
    case READY:
    case SETTINGS:

      break;
    case LOCKED:
      activeTime = settingTime - (now() - startTime);
      if (activeTime <= 0) {
        activeState = UNLOCKED;
      }
      break;
  }
  lcd.setCursor(0, 0);
  switch (activeState) {
    case READY:
      lcd.print("READY: Start ");
      lcd.setCursor(0, 1);
      lcd.print(activeHours);
      lcd.print(" ");
      lcd.print(activeMinutes);
      lcd.print(" ");
      lcd.print(activeSeconds);
      lcd.print(" ");
      break;
    case SETTINGS:
      lcd.print("Set Timer: ");
      switch (timeData) {
        case 0:
          lcd.print("HRS ");
          break;
        case 1:
          lcd.print("MINS");
          break;
        case 2:
          lcd.print("SECS");
          break;
      }
      lcd.setCursor(0, 1);
      lcd.print(settingHours);
      lcd.print(" ");
      lcd.print(settingMinutes);
      lcd.print(" ");
      lcd.print(settingSeconds);
      lcd.print(" ");
      break;
    case LOCKED:
      lcd.print("Waiting...  ");
      lcd.setCursor(0, 1);
      if (hour(activeTime) < 10) lcd.print("0");
      lcd.print(hour(activeTime));
      lcd.print(": ");
      if (minute(activeTime) < 10) lcd.print("0");
      lcd.print(minute(activeTime));
      lcd.print(": ");
      if (second(activeTime) < 10) lcd.print("0");
      lcd.print(second(activeTime));

      break;
    case UNLOCKED:
      lcd.print(" UNCLOCKED! ");
      lcd.setCursor(0, 1);
      lcd.print("   ");
      break;
  }
  delay(10);
}
void Reset() {
  activeState = READY;
  activeHours = settingHours;
  activeMinutes = settingMinutes;
  activeSeconds = settingSeconds;
}


I took this picture without the LCD as I was building it, I don't have one with it, but this link: LCD White Boxes has pictures with the LCD. In my opinion I think that it would be too difficult for me to include LEDs on this board because of the wires so that's why I want to add another board, I just don't know how.

What you mean with that? Not single pin free?

You have not used DIO 13, 14, 15, 16, or 17... minus the potentiometer mentioned.

HI, @59bumblewasp
Welcome to the forum.

Can you please post your code?

Can you please post a copy of your circuit, a picture of a hand drawn circuit in jpg, png?
Hand drawn and photographed is perfectly acceptable.
Please include ALL hardware, power supplies, component names and pin labels.

Thanks.. Tom.... :smiley: :+1: :coffee: :australia:

#include <Time.h>
#include <TimeLib.h>

TimeLib.h is the Time library by Paul Stoffregen, available in the Arduino IDE's library manager.

Time.h is not from any Arduino library that I am familiar with. If you are using Windows (or any other operating system that has a file system that is not case-sensitive), that will find the file time.h which is a standard C library. On a linux system, it will likely produce an error because the file does not exist.

Does other text show on the LCD, and only the time is missing, or is the LCD completely non-functional?

You are not familiar with the history of the Time library and perhaps not overly familiar how names and libraries work on Arduino.

"TimeLib.h" is the file name of a header file not the name of a library.

The name of the library is "Time" not "TimeLib".
There is no such library called "TimeLib"

The library was originally written by Michael Margolis, and is called the "Time" library and had a header file called "Time.h"
It came out back around the 2008 / 2009 time frame.
Paul Stroffregen included the Time library as part of his Teensy library package as part of his effort to make things easier for his Teensy board users.
He also hosted the library on his site for use by other Arduino users.

A few years later the avr gcc package began to be included as part of the Arduino IDE installation and a few years after that some platforms included the unix time library functions which use a "time.h" header file.
On Oses that ignore case in filenames this created a problem since OSes like Windows by default can't tell the difference between Time.h and time.h
Because of this including <Time.h> will sometimes include <time.h> instead on Windows.
The real issue is an issue the IDE platform compiler rule that doesn't put the Arduino library directories ahead of the system library header directories. The arduino.cc developers could have fixed this by altering the include paths handed to gcc, but I never could get them make the change.

Paul decided to tweak the Time library by adding a file called "TimeLib.h" to the Time library.
Because of the way the IDE locates header files, you can have a file named TimeLib.h in library named Time and it can still work.
This change avoids the Windows issue of not being able to distinguish between Time.h and time.h

Paul eventually took over the maintenance of the Time library.

But still to this day, even though many call it the "TimeLib" library, the library is still named "Time" not "TimeLib"
I just checked the github repo for the Time library and about 5 years ago Paul added a warning to Time.h telling users to use TimeLib.h instead and then about 4 years ago (version 1.6.1 the most recent release) removed Time.h from the Time library.

Removing "Time.h" from the Time library doesn't fully solve the issue.

IMO, Paul should have renamed the Time library to TimeLib LONG ago.
Like when it was added to the library manager.

--- bill

1 Like

I was aware of why the library changed from Time.h to TimeLib.h, but the sketch literally has the following, invoking both Time.h and TimeLib.h. I am not aware of any library that currently uses Time.h with the capital 'T'. Not sure why the sketch has both, possibly it was written in the short time in which the Time library had both header files.

        #include <Time.h> 
#include <TimeLib.h> 
 
#include <LiquidCrystal.h>  
 
#include <EEPROM.h> 
#include <Servo.h> 
 

I maybe should have worded that "TimeLib.h is from the Time library".

The Time library had both header files, and it wasn't a short period of time.
Go look at the history of the Time library on its github repository.
Both Time.h and TimeLib.h existed in the Time library from Nov 11, 2015 to June 21, 2021 a period of about 5.5 years.

TimeLib.h was added in version 1.5 of the Time library on Nov 11, 2015
At that point TimeLib.h was added and Time.h was changed to simply include "TimeLib.h" for backward compatibility for those that still used it.
On May 5, 2020 a warning was added to Time.h
#warning "Please include TimeLib.h, not Time.h. Future versions will remove Time.h"
But there was never a Time library release with that version of Time.h
The next version of the Time library was released June 21, 2021.

Time.h was removed from the Time library in version 1.6.1 released on June 21, 2021
IMO, this is where TimeLib should have been created and everything moved over to that library.
Time could continue to exist as a single header file that printed a warning and included <TimeLib.h>

I was not paying attention to this, or I would have contacted Paul and suggested this path.

As to how both header files are in the sketch code.
Its not hard to imagine how this could happen.

The sketch code was written using Time library version 1.5 or version 1.6 which are the two versions that had both header files in it.
including <Time.h> will work on an OS that doesn't ignore case in file names.
Using <Time.h> will it also work on an OS that ignores case as long as the Arduino platform core being used doesn't provide unix time library functions which provides a <time.h> in the compiler tools include libraries,
It would also work on an Arduino core platform that uses a gcc build rule that puts the Arduino library include directories ahead of the gcc system include header files (which could and should be done but that is what I could never get Arduino.cc devs to change in their cores)
Had the include paths been changed in the Arduino build rules, all these case mismatch collision of file names stuff for any/all Arduino libraries would go away since the IDE would grab the Arduino header file instead of the system header file is typically what is wanted/needed.

While I never use it, and recommend against users ever using it,
if a user goes into the IDE and uses the IDE to "include" a library into their sketch by using: [Sketch]->Include Library->{Libraryname}
The ide will insert every single header file in that library at the top of the sketch.
This has lots of potential issues and fails to work for many libraries and IMO, the Arduino.cc devs never should have added this capability to the IDE given its issues. IMO, and Arduino user should at a minimum know how to include the appropriate header file for a library.

So for how this happened, here is my best guess.
The code was written using Time library version 1.5 or version 1.6
The user used [Sketch]->Include Library->Time
And the IDE inserted

#include <Time.h>
#include <TimeLib.h>

into the sketch.

because in TIme library versions 1.5 and 1.6 both header files existed.
And then for whatever Ardino platform core and/or OS was being used for development, there was no issue with a system <time.h> header file so including <Time.h> worked without issue in that development environment.

Like I previously said, Paul should have completely deprecated the Time library and moved everything to a new library called TimeLib LONG ago.
Nearly all these types of Time vs TimeLib issues would be gone by now.

--- bill

@59bumblewasp
If you are able to print things on the LCD which it looks like you are, then the LCD library is working.

in terms of not seeing what you expect on the LCD, that will be some sort of issue in the sketch code.
That would require digging deeper into the logic of the code and doing some debugging.

In glancing at the code, it appears that it is not actually needing the time of day but simply needing elapsed time.

The Time library time_t values can be used to track elapsed time in seconds
but if all you wanting/need is elapsed time, then you don't need an actual time library to track time of day and all the associated housekeeping code of that library.
What you may not be aware of is that the Arudino system includes an internal background timer tracking elapsed time since reset/powerup in milliseconds without needing any sort of time library.
Elapsed time could be determined by looking at the millis() return values.
i.e. divide millis() return values by 1000 and you have elapsed seconds.
IMO, if you don't need the actual date & time, and don't need elapsed time of more than 1100 hours, then I would just use millis() rather than the Time library.
i.e. use millis() / 1000 instead of calling now()

But if you want to have more than about 1100 hours of elapsed time then you can't use millis() as it fully wraps around in about 49 days or about 1100 hours

If you want to use the Time library time_t values to track elapsed time to avoid any wrap issues that is ok too.
Here are some comments about using it.
There is a lot of code for the house keeping going on in the Time library to track the actual datetime variables and the datetime is not really correct unless you set it.
However, if all you are using it for is to get a bumping time_t value and are ignoring the datetime, then you can use the time_t for this.
But , again, if you don't need more than 1100 hours of elapsed time, you could just use milis() / 1000 instead of using a time_t value from now() to get the same elapsed seconds since board power up value and not need to use the Time library.

Due to the way the Time library is constructed, there is some confusion over the header files.
I would do two things,

  • make sure you using the most recent version of the Time library (1.6.1 as of now)
  • Do not include <Time.h> just <TimeLib.h>
    But you will discover this if you have version 1.6.1 as there is no Time.h header file in version 1.6.1 of the Time library.

--- bill

Have you gotten the LCD display to display anything?
Most people I have talked to use LiquidCrystal library for the display.
If I could see the code I could offer some more help.

I just looked a little deeper at the code.
It is not a drop in to use millis() for the existing code.
There are some uses of the Time library API to get time of day values.
While it could be done, it isn't a drop in swap.

That said, based on my initial look at the code,
I see some what might be some issues related to how time and elapsed time is tracked.
The Time library hour() function returns the time of day hour, not the number of elapsed hours in the time_t passed in. If you never set the date / time i.e. use a zero based epoch value, then the hour() , minute() , second() of the time of day returned by these functions can look like elapsed times but it isn't.
For example, when the number of elapsed hours bumps to 24, the hour will roll back to zero because the Time library will be bumping the date to the next day and the time of day hour goes back to zero at the start of each day.

The code appears to allow setting the timer hours to be up to 99 hours.
It appears that may it have an issue using the Time library the way it is being used since for time periods longer than 24 hours the date will increment and the hour value returned by hour() will roll over back to zero.

Since the max timer is 99 hours you could convert the code to use millis() and then write your your own functions for hour() , minute(), second() that calculate how many hours, minutes, seconds are in that elapsed time.
The calculations are pretty trivial.

Alternatively stick with the current method using the Time library and
simply limit the maximum timer to no more than 23:59:59
to avoid all the rollover date time stuff.

--- bill

The LCD is working, but it's only showing white boxes. I tried to press all the buttons and nothing happens. After some time when I was pressing the 2 middle buttons it would move the servo motor but that's all that happened.

Hi Tom, thanks for letting me know. I just posted the code and a picture as well.

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