Help needed with keypad and LCD display

Hi, Iwant to make an arduino project - showing real time clock, date, day and temperature. I'll use DS1307 and TMP36. I haven't problems with showing them on the LCD. But I also want to use a matrix 3x4 keypad for adjusting the time etc. The idea is to use the # key to turn the program in adjustable sequence - hours, minutes, seconds, date etc. I'm not a pro with C programming, but I'm trying to learn it. So I need some help how to take care of the keypad.

/*

#include <Keypad.h>
#include "Wire.h"
#define DS1307_I2C_ADDRESS 0x68
#include <LiquidCrystal.h>
LiquidCrystal lcd(10,11,12,9,8,7,6);

const byte ROWS = 4; //four rows
const byte COLS = 3; //three columns
char keys[ROWS][COLS] = {
  {'1','2','3'},
  {'4','5','6'},
  {'7','8','9'},
  {'#','0','*'}
};
byte rowPins[ROWS] = { 3, 2, 1, 0}; //connect to the row pinouts of the keypad
byte colPins[COLS] = { 6, 5, 4}; //connect to the column pinouts of the keypad

Keypad keypad = Keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS );

int sensorPin = 0;
// Convert normal decimal numbers to binary coded decimal
byte decToBcd(byte val)
{
return ( (val/10*16) + (val%10) );
}
// Convert binary coded decimal to normal decimal numbers
byte bcdToDec(byte val)
{
return ( (val/16*10) + (val%16) );
}
// 1) Sets the date and time on the ds1307
// 2) Starts the clock
// 3) Sets hour mode to 24 hour clock
// Assumes you're passing in valid numbers
void setDateDs1307(byte second, // 0-59
byte minute, // 0-59
byte hour, // 1-23
byte dayOfWeek, // 1-7
byte dayOfMonth, // 1-28/29/30/31
byte month, // 1-12
byte year) // 0-99
{
Wire.beginTransmission(DS1307_I2C_ADDRESS);
Wire.send(0);
Wire.send(decToBcd(second)); // 0 to bit 7 starts the clock
Wire.send(decToBcd(minute));
Wire.send(decToBcd(hour));
Wire.send(decToBcd(dayOfWeek));
Wire.send(decToBcd(dayOfMonth));
Wire.send(decToBcd(month));
Wire.send(decToBcd(year));
Wire.send(0x10); // sends 0x10 (hex) 00010000 (binary) to control register - turns on square wave
Wire.endTransmission();
}
// Gets the date and time from the ds1307
void getDateDs1307(byte *second,
byte *minute,
byte *hour,
byte *dayOfWeek,
byte *dayOfMonth,
byte *month,
byte *year)
{
// Reset the register pointer
Wire.beginTransmission(DS1307_I2C_ADDRESS);
Wire.send(0);
Wire.endTransmission();
Wire.requestFrom(DS1307_I2C_ADDRESS, 7);
// A few of these need masks because certain bits are control bits
*second = bcdToDec(Wire.receive() & 0x7f);
*minute = bcdToDec(Wire.receive());
*hour = bcdToDec(Wire.receive() & 0x3f); // Need to change this if 12 hour am/pm

*dayOfWeek = bcdToDec(Wire.receive());
*dayOfMonth = bcdToDec(Wire.receive());
*month = bcdToDec(Wire.receive());
*year = bcdToDec(Wire.receive());
 
}
void setup()
{
   
byte second, minute, hour, dayOfWeek, dayOfMonth, month, year;
Wire.begin();
// Change these values to what you want to set your clock to.
// You probably only want to set your clock once and then remove
// the setDateDs1307 call.
second = 0;
minute = 23;
hour = 23;
dayOfWeek = 4;
dayOfMonth = 19;
month = 5;
year = 10;
// setDateDs1307(second, minute, hour, dayOfWeek, dayOfMonth, month, year);
lcd.begin(16, 2); // tells Arduino the LCD dimensions

lcd.clear(); // clear LCD screen

}
void loop()
{

/* char key = keypad.getKey(); // FROM HERE DOWN is the Problem
 if (key != NO_KEY){
   int h_counter = 1;
   int m_counter = 1;
   int s_counter = 1;
 
    switch (key){
      case '#':
      lcd.clear();
      lcd.print("Hour:");
     
     switch (keypad.getState()) {
       case PRESSED: {
      h_counter++;
      key = keypad.getKey();
      int h_deseti = key;
      lcd.print(h_deseti);
      key = keypad.getKey();
      int h_edinici = key;
      lcd.print(h_edinici); 
      break; }
   
      hour = h_deseti*10 + h_edinici; 
      
    }
  }
 
 */
 
 
byte second, minute, hour, dayOfWeek, dayOfMonth, month, year;
getDateDs1307(&second, &minute, &hour, &dayOfWeek, &dayOfMonth, &month, &year);
int reading = analogRead(sensorPin);
float voltage = reading * 5.0 / 1024; 
float temperatureC = (voltage - 0.5) * 100 ;
lcd.clear(); // clear LCD screen
lcd.setCursor(0,0);
lcd.print(" ");
lcd.print(hour, DEC);
lcd.print(":");
if (minute<10)
{
lcd.print("0");
}
lcd.print(minute, DEC);
lcd.print(":");
if (second<10)
{
lcd.print("0");
}
lcd.print(second, DEC);
lcd.print(temperatureC);
lcd.print("C");
lcd.setCursor(0,1);
lcd.print(" ");
switch(dayOfWeek){
case 1:
lcd.print("Sun");
break;
case 2:
lcd.print("Mon");
break;
case 3:
lcd.print("Tue");
break;
case 4:
lcd.print("Wed");
break;
case 5:
lcd.print("Thu");
break;
case 6:
lcd.print("Fri");
break;
case 7:
lcd.print("Sat");
break;
}
lcd.print(" ");
lcd.print(dayOfMonth, DEC);
lcd.print("/");
lcd.print(month, DEC);
lcd.print("/20");
lcd.print(year, DEC);
delay(1000);
}
key = keypad.getKey();
      int h_edinici = key;
      lcd.print(h_edinici);

This will only work if a key is being pressed when the function is called, which is unlikely.

There was sample code that came with the keypad library. You should examine those sketches, and understand how they read and store a key press.

The key.getState() function will tell you whether a key is being pressed, but what does that really matter? The key.getKey() function tells you which key, if any, was pressed, which is a much more useful piece of information.

If you want to wait for a key press, as I assume you do when setting the time, you should create a function that blocks until a key is pressed.

int waitForKey()
{
   int key = NO_KEY;
   while((key = keypad.getKey()) == NO_KEY)
   {
      // Do nothing
   }
   return key;
}

Now, the only problem with this function is that it will wait forever. You could modify it to take an argument for how long to wait, and return when that time had elapsed (using millis() to determine "now" and when the function was called. But, that is an exercise for later.

Now I got it with this function, but can you show me how to make the function stay for 10s for example, and if there isn't pressed key to return to main program? Thanks a lot!

What you need to do is to make sure that 10000 mS has not passed in the 'while' logical condition

ie.
(pseudo)

store start time

while(button is not pushed AND current time - start time is less then 10s)
Do nothing
If there was no key pressed return no key

If there was a key pressed return a key

(/pseudo)

I'm sure that you would have no trouble with this.

How can time be stored and watched when 10s are elapsed?

Have a look into millis()

What you want to do is check to see if 10000 milliseconds has elapsed.

<--! untested -->

int waitForKey()
{
   int key = NO_KEY;
   unsigned long _start_time = millis();

   while(((key = keypad.getKey()) == NO_KEY) && ((millis()-_start_time) < L10000))
   {
      // Do nothing
   }
   return key;
}

(or something like that...)

So, as i said I want to make a clock with DS1307 and setting the time, date with a keypad 3x4. But I'm still having troubles with the source code.
I tried to write some functions (wait for a pressed key and set the clock) but there are some errors and I'm pretty sure some logical mistakes. I'll be grateful, if someone help me with it. The replies before were so much helpful for me. Thanks!

int waitForKey() { 
  char key = keypad.getKey();
 if (key != NO_KEY){
     if (key = '#') {
      
           int key = NO_KEY;
           unsigned long _start_time = millis();
           int countPressed = 0;
 while(((key = keypad.getKey()) == NO_KEY) && ((millis()-_start_time) < 10000))
   {
      // Do nothing
          if(key=PRESSED) {
            countPressed++;
            setClock();
            return key;
          }
          return;
   }
   return key;
}
 }
 }
 
  int setClock() {
    char key = keypad.getKey();
   switch(countPressed) {
    case 1: lcd.print ("Hours:");
            
            hour = key;
    case 2: lcd.print ("Minutes:");
            minute = key;
    case 3: lcd.print ("Seconds:")
            seconds = key;    
        }
            
  }

There is an error while compiling the code :

In function 'int waitForKey()':
error: return-statement with no value, in function returning 'int' In function 'int setClock()':

When you declare a function that returns an int, like you did with waitForKey, every return statement needs to return a value.

   return key;

returns the value in the variable key.

          if(key=PRESSED) {
            countPressed++;
            setClock();
            return key;
          }
          [glow]return[/glow];

What is the highlighted return statement supposed to return.

The if(key = PRESSED) statement is wrong, too. = is an assignment operator. == is the equality.

Stay after school and write this 1000 times. Then, maybe, you'll remember it.

Stay after school and write this 1000 times

Surely, I'll do it. Now I'll start reading a book about C/C++, but one more question (not about C syntax :slight_smile: )
This code says these statements give the values to the DS1307.

Wire.begin();
// Change these values to what you want to set your clock to.
[glow]// You probably only want to set your clock once and then remove
// the setDateDs1307 call.[/glow]
second = 0;
minute = 23;
hour = 23;
dayOfWeek = 4;
dayOfMonth = 19;
month = 5;
year = 10;
// setDateDs1307(second, minute, hour, dayOfWeek, dayOfMonth, month, year);

Wire.begin() is the set call for the DS1307? So, how I can change these values after the beginning of the program with my function setClock() ?

Wire.begin() is the set call for the DS1307?

No. Wire.begin() initiates communication with the clock.

So, how I can change these values after the beginning of the program with my function setClock() ?

Change which values? What does your setClock function do?

My aim is to use a 3x4 keypad to set the clock and date after the beginning of the program. The LCD will show the stats, but after '#' on keypad is pressed, it should enter in setting mode and change the values of the clock and date and write them in DS1307.

My aim is to use a 3x4 keypad to set the clock and date after the beginning of the program. The LCD will show the stats, but after '#' on keypad is pressed, it should enter in setting mode and change the values of the clock and date and write them in DS1307.

Sounds reasonable. Is there a question there somewhere, or some problem you are having?

The problems are, how to change the values of the hour, minute and so on, and after that to write them in the DS1307. Also, how to store the data which I should send to DS1307 ( the value of the hours for example, should be made by two digits form the keypad like all of the rest ). I'll tell more about my idea later, when I have more time. Thanks for helping me!

So, back to my problems :slight_smile: The program is running well - displaying clock date, day and temperature. I want to expand it with a 3x4 keypad. When '#' is pressed on the keypad it should enter in setting mode. First hour, minute and so on. The function waitForKey() is for taking what key is pressed or wait 10s and exit the setting mode. This value should be stored and with the next pressed key to make the new value for the "hour" for example. In this way I want to change all of the values and then write them in DS1307. The function setClock(), should take care of the pressed keys and sort them ( which keys are for the hours, which for minutes etc.).

This is the all source code so after.

#include "Wire.h"
#include <Keypad.h>
#define DS1307_I2C_ADDRESS 0x68
#include <LiquidCrystal.h> // we need this library for the LCD commands
LiquidCrystal lcd(12, 11, 10, 5, 4, 3, 2);
int countPressed;
/* Ot tuk e za keypad*/
const byte ROWS = 4; //four rows
const byte COLS = 3; //three columns
char keys[ROWS][COLS] = {
  {'1','2','3'},
  {'4','5','6'},
  {'7','8','9'},
  {'#','0','*'}
};
byte rowPins[ROWS] = { 3, 2, 1, 0}; //connect to the row pinouts of the keypad
byte colPins[COLS] = { 6, 5, 4}; //connect to the column pinouts of the keypad

Keypad keypad = Keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS );
/* do tuk e za keypad*/
// Convert normal decimal numbers to binary coded decimal
byte decToBcd(byte val)
{
return ( (val/10*16) + (val%10) );
}
// Convert binary coded decimal to normal decimal numbers
byte bcdToDec(byte val)
{
return ( (val/16*10) + (val%16) );
}
// 1) Sets the date and time on the ds1307
// 2) Starts the clock
// 3) Sets hour mode to 24 hour clock
// Assumes you're passing in valid numbers
void setDateDs1307(byte second, // 0-59
byte minute, // 0-59
byte hour, // 1-23
byte dayOfWeek, // 1-7
byte dayOfMonth, // 1-28/29/30/31
byte month, // 1-12
byte year) // 0-99
{
Wire.beginTransmission(DS1307_I2C_ADDRESS);
Wire.send(0);
Wire.send(decToBcd(second)); // 0 to bit 7 starts the clock
Wire.send(decToBcd(minute));
Wire.send(decToBcd(hour));
Wire.send(decToBcd(dayOfWeek));
Wire.send(decToBcd(dayOfMonth));
Wire.send(decToBcd(month));
Wire.send(decToBcd(year));
Wire.send(0x10); // sends 0x10 (hex) 00010000 (binary) to control register - turns on square wave
Wire.endTransmission();
}
// Gets the date and time from the ds1307
void getDateDs1307(byte *second,
byte *minute,
byte *hour,
byte *dayOfWeek,
byte *dayOfMonth,
byte *month,
byte *year)
{
// Reset the register pointer
Wire.beginTransmission(DS1307_I2C_ADDRESS);
Wire.send(0);
Wire.endTransmission();
Wire.requestFrom(DS1307_I2C_ADDRESS, 7);
// A few of these need masks because certain bits are control bits
*second = bcdToDec(Wire.receive() & 0x7f);
*minute = bcdToDec(Wire.receive());
*hour = bcdToDec(Wire.receive() & 0x3f); // Need to change this if 12 hour am/pm
*dayOfWeek = bcdToDec(Wire.receive());
*dayOfMonth = bcdToDec(Wire.receive());
*month = bcdToDec(Wire.receive());
*year = bcdToDec(Wire.receive());
}
void setup()
{
byte second, minute, hour, dayOfWeek, dayOfMonth, month, year;
Wire.begin();
// Change these values to what you want to set your clock to.
// You probably only want to set your clock once and then remove
// the setDateDs1307 call.
second = 0;
minute = 23;
hour = 23;
dayOfWeek = 4;
dayOfMonth = 19;
month = 5;
year = 10;
// setDateDs1307(second, minute, hour, dayOfWeek, dayOfMonth, month, year);
lcd.begin(16, 2); // tells Arduino the LCD dimensions
lcd.setCursor(0,0);
lcd.print("   Miroslav's   "); // print text and move cursor to start of next line
lcd.setCursor(0,1);
lcd.print("Diplomna Rabota ");
delay(5000);
lcd.clear(); // clear LCD screen
}

void loop()
{
  char key = keypad.getKey();
     
   
  int sensorPin = 0;  
int reading = analogRead(sensorPin);  

 // converting that reading to voltage, for 3.3v arduino use 3.3
 float voltage = reading * 5.0 / 1024; 
 
 // print out the voltage
 
 // now print out the temperature
 float temperatureC = (voltage - 0.5) * 100 ; 
byte second, minute, hour, dayOfWeek, dayOfMonth, month, year;
getDateDs1307(&second, &minute, &hour, &dayOfWeek, &dayOfMonth, &month, &year);
lcd.clear(); // clear LCD screen
lcd.setCursor(0,0);
lcd.print(hour, DEC);
lcd.print(":");
if (minute<10)
{
lcd.print("0");
}
lcd.print(minute, DEC);
lcd.print(":");
if (second<10)
{
lcd.print("0");
}
lcd.print(second, DEC);
lcd.print(" ");
lcd.print(temperatureC);
  lcd.print("C");
lcd.setCursor(0,1);
lcd.print(" ");
switch(dayOfWeek){
case 1:
lcd.print("Sun");
break;
case 2:
lcd.print("Mon");
break;
case 3:
lcd.print("Tue");
break;
case 4:
lcd.print("Wed");
break;

case 5:
lcd.print("Thu");
break;
case 6:
lcd.print("Fri");
break;
case 7:
lcd.print("Sat");
break;
}
lcd.print(" ");
lcd.print(dayOfMonth, DEC);
lcd.print("/");
lcd.print(month, DEC);
lcd.print("/20");
lcd.print(year, DEC);
delay(1000);
}
int waitForKey() { 
  char key = keypad.getKey();
 if (key != NO_KEY){
     if (key == '#') {
      
           int key = NO_KEY;
           unsigned long _start_time = millis();
           int countPressed = 0;
 while(((key = keypad.getKey()) == NO_KEY) && ((millis()-_start_time) < 10000))
   {
      // Do nothing
          if(key==PRESSED) {
            countPressed++;
            setClock();
            return key;
          }
         
   }
   return key;
}
 } return countPressed;
 }
 
  int setClock() {
    
    char key = keypad.getKey();
   switch(countPressed) {
    case 1: lcd.print ("Hours:");
            
            hour = key;
    case 2: lcd.print ("Minutes:");
            minute = key;
    case 3: lcd.print ("Seconds:")
            seconds = key;    
        }
            
  }