Go Down

Topic: changing clock/date setting on Real Time Clock pcf8563 [solved] (Read 2992 times) previous topic - next topic

mark7w

Jan 15, 2013, 11:27 pm Last Edit: May 10, 2013, 02:31 am by mark7w Reason: 1
hello, I have a RTC working on a LCD but to set the time I have to use Serial monitor. You guess the question.

heres the code.

Code: [Select]

/*
Program:      clock

Description:  Reads the time from a PCF8563 RTC (Real Time
Clock). Displays the time and date on a LCD
and serial port. Allows the time to be set through the serial
port.

Date:         20 April 2012

Author:       W.A. Smith, http://startingelectronics.com
*/
#include <Wire.h>
#include <LiquidCrystal.h>

#define RTC_ADDR  (0xA2 >> 1)

// Arduino pins used for LCD
LiquidCrystal lcd(7,8,9,10,11,12);

void setup() {
 Wire.begin();        // initialize the I2C/TWI interface
 Serial.begin(9600);  // initialize the serial port
 lcd.begin(16, 2);    // initialize the LCD display

}

void loop() {
 int rx_byte = 0;    // stores data byte received on serial port

 // check for data from the serial port
 if (Serial.available()) {
   rx_byte = Serial.read();
 }
 if ((rx_byte == 's') || (rx_byte == 'S')) {
   // set the time
   SetTime();
 }
 else {
   // print the time
   PrintTime();
 }
 rx_byte = 0;
}

// print the time to the serial port and LCD
void PrintTime(void)
{
 unsigned char time_date_raw[7];      // time/date read from RTC
 int index = 0;              // index into above array
 char time[] = "hh:mm:ss";   // time string
 char date[] = "dd-mm-20yy"; // date string
 static unsigned char raw_time = 0;   // stores old seconds value

 // point to the time registers in the RTC
 Wire.beginTransmission(RTC_ADDR);
 Wire.write(0x02);
 Wire.endTransmission();

 // get the time
 Wire.requestFrom(RTC_ADDR, 7);
 while (Wire.available()) {
   time_date_raw[index] = Wire.read();
   index++;
   if (index >= 7) {
     index = 0;
     break;
   }
 }

 // convert the time / date to a string only every second
 if (raw_time != time_date_raw[0]) {
   raw_time = time_date_raw[0];

   Serial.println("Send \"s\" to set the date and time.");

   // convert time to a string
   // hours
   time[0] = ((time_date_raw[2] >> 4) & 0x03) + '0';
   time[1] = (time_date_raw[2] & 0x0F) + '0';
   // minutes
   time[3] = ((time_date_raw[1] >> 4) & 0x07) + '0';
   time[4] = (time_date_raw[1] & 0x0F) + '0';
   // seconds
   time[6] = ((time_date_raw[0] >> 4) & 0x07) + '0';
   time[7] = (time_date_raw[0] & 0x0F) + '0';
   Serial.println(time);
   lcd.setCursor(0, 0);
   lcd.print(time);

   // convert date to a string
   // day
   date[0] = ((time_date_raw[3] >> 4) & 0x03) + '0';
   date[1] = (time_date_raw[3] & 0x0F) + '0';
   // month
   date[3] = ((time_date_raw[5] >> 4) & 0x01) + '0';
   date[4] = (time_date_raw[5] & 0x0F) + '0';
   //year
   date[8] = (time_date_raw[6] >> 4) + '0';
   date[9] = (time_date_raw[6] & 0x0F) + '0';
   Serial.println(date);
   Serial.print("\r\n");
   lcd.setCursor(0, 1);
   lcd.print(date);
 }
}

// allows the date and time to be set via the serial monitor window
void SetTime(void)
{
 char menu_option = 0;
 unsigned char new_date_time[7] = {
   0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF  };  // 0xFF to mark unchanged field
 char ret_val = 0;

 PrintMenu();

 while (menu_option != 8) {
   if (Serial.available()) {
     menu_option = Serial.read();
     menu_option = menu_option - '0';
     // check if a valid menu option was entered
     if ((menu_option < 0) || (menu_option > 8)) {
       // invalid option selected
       Serial.println("Only 0 to 8 are valid, send 8 to quit.");
     }
     else {  // valid menu option selected
       switch (menu_option) {
       case 1:  // set year
         Serial.println("Enter 2 digit year (00 to 99 valid) or \"q\" to quit.");
         Serial.print("Year: ");
         ret_val = GetNewTime(&new_date_time[6], 0, 99);
         break;

       case 2: // set month
         Serial.println("Enter 2 digit month (01 to 12 valid) or \"q\" to quit.");
         Serial.print("Month: ");
         ret_val = GetNewTime(&new_date_time[5], 1, 12);
         break;

       case 3: // set day
         Serial.println("Enter 2 digit day (01 to 31 valid) or \"q\" to quit.");
         Serial.print("Day: ");
         ret_val = GetNewTime(&new_date_time[3], 1, 31);
         break;

       case 4: // set hour
         Serial.println("Enter 2 digit hour (01 to 23 valid) or \"q\" to quit.");
         Serial.print("Hour: ");
         ret_val = GetNewTime(&new_date_time[2], 1, 23);
         break;

       case 5: // set minute
         Serial.println("Enter 2 digit minute (00 to 59 valid) or \"q\" to quit.");
         Serial.print("Minute: ");
         ret_val = GetNewTime(&new_date_time[1], 0, 59);
         break;

       case 6: // set second
         Serial.println("Enter 2 digit second (00 to 59 valid) or \"q\" to quit.");
         Serial.print("Second: ");
         ret_val = GetNewTime(&new_date_time[0], 0, 59);
         break;

       case 7: // write changes
         WriteDateTime(new_date_time);
         menu_option = 8;
         break;

       default:
         break;
       }
       if (ret_val == 1) {  // user enters invalid value
         Serial.println("Invalid value.");
       }
       else if (ret_val == 2) {  // user presses 'q' key to quit
         Serial.print("\r\n");
         PrintMenu();
       }
       ret_val = 0;
     }
   }
 }
}

// print the Set Date & Time menu on the serial port
void PrintMenu(void)
{
 Serial.println("------------------------");
 Serial.println("| Set Date & Time Menu |");
 Serial.println("------------------------");
 Serial.println("(Select 1 to 8)");
 Serial.println("1. Set year.");
 Serial.println("2. Set month.");
 Serial.println("3. Set day.");
 Serial.println("4. Set hour.");
 Serial.println("5. Set minute.");
 Serial.println("6. Set second.");
 Serial.println("7. Write changes and finish.");
 Serial.println("8. Exit without changing.");
}

// get new time/date from user via serial port
// returns 0 if success, 1 if invalid data entered, 2 if user quits
// *p_data = value entered by user converted to BCD
// lower = lowest valid value user can enter on serial port
// upper = highest valid value that user can enter on serial port
char GetNewTime(unsigned char *p_data, unsigned char lower, unsigned char upper)
{
 char rx_data[3];          // data received from serial port
 int index = 0;            // index into above array
 unsigned char data_val;   // stores converted data for limit checking

 // get 2 characters from the user over the serial port
 while (index < 2) {
   if (Serial.available()) {
     rx_data[index] = Serial.read();
     if (rx_data[index] == 'q') {
       return 2;    // user enters 'q' to quit
     }
     index++;
   }
   if (index > 1) {  // only proceed if 2 character entered
     data_val = ((rx_data[0] - '0') * 10) + (rx_data[1] - '0'); // convert ASCII BCD to binary
     // check for valid range and valid characters
     if ((data_val >= lower) && (data_val <= upper) && (rx_data[0] >= '0') &&
       (rx_data[0] <= '9') && (rx_data[1] >= '0') && (rx_data[1] <= '9')) {
       // send entered data over the serial port for feedback to user
       rx_data[2] = 0;  // terminate string
       Serial.println(rx_data);
       // convert 2 ASCII characters received to BCD
       rx_data[0] = rx_data[0] - '0';
       rx_data[1] = rx_data[1] - '0';
       *p_data = rx_data[1];
       *p_data |= (rx_data[0] << 4);

     }
     else {
       return 1;  // invalid data entered
     }
   }
 }
 return 0;    // success
}

// write all 7 time/date fields to the RTC registers
// new_d_t[] array contains 0xFF in date/time fields that are not to be changed
// and contains valid BCD data in fields that are to be changed
void WriteDateTime(unsigned char new_d_t[])
{
 char time_date_raw[7];      // time/date read from RTC
 int index = 0;              // index into above array

 // point to the time registers in the RTC
 Wire.beginTransmission(RTC_ADDR);
 Wire.write(0x02);
 Wire.endTransmission();

 // get the time
 Wire.requestFrom(RTC_ADDR, 7);
 while (Wire.available()) {
   time_date_raw[index] = Wire.read();
   index++;
   if (index >= 7) {
     index = 0;
     break;
   }
 }

 // write the new time/date values to the array that contains values read from the RTC
 for (int i = 0; i < 7; i++) {
   if (new_d_t[i] != 0xFF) {         // skip unchanged fields
     time_date_raw[i] = new_d_t[i];  // copy value if changed
   }
 }

 // point to the time registers in the RTC and send the time and date
 // write new values and old unchanged values
 Wire.beginTransmission(RTC_ADDR);
 Wire.write(0x02);
 Wire.write((uint8_t*)time_date_raw, 7);
 Wire.endTransmission();
}


So can I Edit this code to use push buttons. How easy would it be. What about incrementing the units 0 to 59 on pushbuttons. Can anyone point me in the right direction. Even have code for the RTC pcf8563 chip. I have seen sketches for the DS1307 RTC, would it be eaiser to use one of those sketches?

PaulS

Quote
You guess the question.

No. You ask the question.

Quote
So can I Edit this code to use push buttons.

To do what?

Quote
How easy would it be.

Somewhere between trivial and damn-near-impossible. Mostly depends on your coding skills and understanding of hardware and how the loop() function gets called over and over again.

Quote
What about incrementing the units 0 to 59 on pushbuttons.

Pushbuttons don't have units.

Quote
Can anyone point me in the right direction.

Without knowing which way that would be? Sure. Turn left. Again.

Quote
Even have code for the RTC pcf8563 chip.

No. But, the very last thing you need to do is tell the chip the new time. THAT part is trivial, and is exactly the same as when getting the new time from any other source.

Quote
I have seen sketches for the DS1307 RTC, would it be eaiser to use one of those sketches?

Sure. First, you get a DS1307...

mark7w

I have an lcd and a Pcf8563 Real Time Clock. I have the following sketch which is used to set the time and date.

Code: [Select]

/* Demonstration of Rtc_Pcf8563 Clock on LCD.
*
* I used a Arduino mega 2560,
* SCL -21, SDA - 20,
*
* This sketch connects a lcd to display the clock output.
*  written by               
* Joe Robertson, jmr
* orbitalair@bellsouth.net
*/

#include <Wire.h>
#include <Rtc_Pcf8563.h>
/* add the lcd support */
#include <LiquidCrystal.h>

//init the real time clock
Rtc_Pcf8563 rtc;

/* initialize the library objects */

LiquidCrystal lcd(7,8,9,10,11,12);

void setup()
{
  // set up the LCD's number of rows and columns:
  lcd.begin(16, 2);
 
  //clear out all the registers
  rtc.initClock();
  //set a time to start with.
  //day, weekday, month, century, year
  rtc.setDate(14, 6, 3, 0, 10);
  //hr, min, sec
  rtc.setTime(1, 15, 40);
}

void loop()
{
  // set the cursor to column 0, line 1
  // (note: line 1 is the second row, since counting begins with 0):
  lcd.setCursor(0, 0);
  //lcd.print(rtc.formatTime(RTCC_TIME_HM));
  lcd.print(rtc.formatTime());
  lcd.setCursor(0, 1);
  //lcd.print(rtc.formatDate(RTCC_DATE_ASIA));
  lcd.print(rtc.formatDate());
 
  delay(1000);
   
}


The sketch allows for the time and date to be set before the sketch is compliled. But I want to SET both using push buttons to change time and date variables.
The Libray for this  "Rtc_Pcf8563.h", has the code for changing the time and date. So would the answer lie in the library. Do I cut and past the code from the libray into the sketch above .

Quick5pnt0

#3
Jan 20, 2013, 01:34 pm Last Edit: Jan 20, 2013, 01:42 pm by Quick5pnt0 Reason: 1
No, you use the setTime method. Lets say you want to set it to 11:30, then you'd do something like this...

Code: [Select]

//setTime(byte sec, byte minute, byte hour)
rtc.setTime(00, 30, 11)


Of course you'd need to work it into your code so your buttons increase/decrease each variable but that is another subject and if you aren't sure how to work with buttons then you might want to start back at square one.

There is more info on the library here: http://playground.arduino.cc/Main/RTC-PCF8563

mark7w

#4
Jan 20, 2013, 05:05 pm Last Edit: Jan 20, 2013, 05:09 pm by mark7w Reason: 1
Quote
No, you use the setTime method. Lets say you want to set it to 11:30, then you'd do something like this...


Code: [Select]

//setTime(byte sec, byte minute, byte hour)
rtc.setTime(00, 30, 11)


I dont think it's as simple as that. It looks like I need to set some sort of pointer to each of the variables "hour", "min","sec".
I found this in the library

Code: [Select]
setTime(byte sec, byte minute, byte hour)

which I believe is

Code: [Select]
rtc.setTime(00, 30, 11)

So I think I need to interact with/point to, the "byte sec, byte minute, byte hour". If i can manipulate those at the byte level I think it might work?

PaulS

Quote
If i can manipulate those at the byte level I think it might work?

What makes you think that? Have you tried anything? Where is your code, and a detailed explanation of what is/is not working, with serial output to prove it?

johncc


I dont think it's as simple as that. It looks like I need to set some sort of pointer to each of the variables "hour", "min","sec".


I don't see any pointers involved or needed here.
Code: [Select]

byte hr,min,sec;
void loop() {
   ... // warning untested code :)
   if (incrementMinuteButtonPressDectected) min = ++min % 60 // increment and rollover past 59
   if (decrementMinuteButtonPressDectected) min = (--min + 60) % 60 // decrement and rollunder past 0
   ...
   rtc.setTime( sec, min, hr);
   ...
}

mark7w

Code: [Select]
rtc.setTime(00, 30, 11)

In the snippet above, if I change the variables 00,30,11 to the current time. Then compile the sketch, the time on the lcd is updated. I am trying to get away from compiling the sketch each time JUST to update the "Time".

but I dont know how to enter the variables from my sketch AFTER it has been compliled.

the original sketch is here

Code: [Select]
/* Demonstration of Rtc_Pcf8563 Clock on LCD.
*

* This sketch connects a lcd to display the clock output.
*
* setup:  see Pcf8563 data sheet.
*         1x 10Kohm pullup on Pin3 INT
*         No pullups on Pin5 or Pin6 (I2C internals used)
*         1x 0.1pf on power
*         1x 32khz chrystal
*         1x h44780 LCD
*
* Joe Robertson, jmr
* orbitalair@bellsouth.net
*/

#include <Wire.h>
#include <Rtc_Pcf8563.h>
/* add the lcd support */
#include <LiquidCrystal.h>

//init the real time clock
Rtc_Pcf8563 rtc;

/* initialize the library objects */
LiquidCrystal lcd(7,8,9,10,11,12);

void setup()
{
  // set up the LCD's number of rows and columns:
  lcd.begin(16, 2);

  //clear out all the registers
  rtc.initClock();
  //set a time to start with.
  //day, weekday, month, century, year
  rtc.setDate(14, 6, 3, 0, 10);
  //hr, min, sec
  rtc.setTime(1, 15, 40);
}

void loop()
{
  // set the cursor to column 0, line 1
  // (note: line 1 is the second row, since counting begins with 0):
  lcd.setCursor(0, 0);
  lcd.print(rtc.formatTime());
  lcd.setCursor(0, 1);
  lcd.print(rtc.formatDate());

  delay(1000);

}


I am going to use push buttons to change the "hour" "minute" and "sec". but "rtc.setTime(1, 15, 40);" how will the sketch know what 1,15,40 is. In the library these appear to be

Code: [Select]
setTime(byte sec, byte minute, byte hour)

so my thinking is byte sec, byte minute, byte hour tell ME what "(1, 15, 40)" are and therfore I would create a function to change byte sec, byte minute, byte hour byte

johncc

#8
Jan 20, 2013, 06:34 pm Last Edit: Jan 20, 2013, 06:42 pm by johncc Reason: 1

Code: [Select]
rtc.setTime(00, 30, 11)
I am going to use push buttons to change the "hour" "minute" and "sec". but "rtc.setTime(1, 15, 40);" how will the sketch know what 1,15,40 is. In the library these appear to be

so my thinking is byte sec, byte minute, byte hour tell ME what "(1, 15, 40)" are and therfore I would create a function to change byte sec, byte minute, byte hour byte


I think you have it backwards.  setTime() is for "you to tell it" what the time is.  For "it to tell you" what the time is, looks like you need to use rtc.getTime(); hr=rtc.getHour(); min=rtc.getMinute(); sec=rtc.getSecond(); [corrected]

Cheers,
John

PaulS

Write some simple code, in setup():

Code: [Select]
byte hour = 5;
byte min = 10;
byte sec = 14;

hour += 3;
min +=27;
sec +=10;

rtc.setTime(hour, min, sec);


What time does the RTC get set to? Read the time in loop(), and print the values.

Incrementing hour, min, and sec by other values is what you need to make the switches do.

mark7w

#10
Jan 20, 2013, 07:04 pm Last Edit: Jan 20, 2013, 07:10 pm by mark7w Reason: 1

Write some simple code, in setup():

Code: [Select]
byte hour = 5;
byte min = 10;
byte sec = 14;

hour += 3;
min +=27;
sec +=10;

rtc.setTime(hour, min, sec);


What time does the RTC get set to? Read the time in loop(), and print the values.


Tme is set to 08:37:24. in which case I kinda understand.

Quick5pnt0

#11
Jan 20, 2013, 09:40 pm Last Edit: Jan 20, 2013, 09:46 pm by Quick5pnt0 Reason: 1


Write some simple code, in setup():

Code: [Select]
byte hour = 5;
byte min = 10;
byte sec = 14;

hour += 3;
min +=27;
sec +=10;

rtc.setTime(hour, min, sec);


What time does the RTC get set to? Read the time in loop(), and print the values.


Tme is set to 08:37:24. in which case I kinda understand.


Ok, so then think of what would be the next step. There are a lot of ways of going about this but to make things easy you could have two buttons, one for hours and one for minutes. Each press of the button would increment the hour or min variable.

Something like this:
Code: [Select]
if(digitalRead(minButton) == HIGH)
   {
      min += 1;
   }


You would also have to make sure hours and minutes don't go too high.

mark7w


Code: [Select]
if(digitalRead(minButton) == HIGH)
   {
      min += 1;
   }


I managed to reset the time back to the defaults but I cant get the minute to increase based in the snippet you gave.

I changed the code around since then and it does not do anything now.

Code: [Select]

#include <Wire.h>
#include <Rtc_Pcf8563.h>
#include <LiquidCrystal.h>

//init the real time clock
Rtc_Pcf8563 rtc;


LiquidCrystal lcd(7,8,9,10,11,12);

int minButton = 42;

void setup()
{
  lcd.begin(16, 2);
  pinMode (minButton,INPUT);
  //clear out all the registers
  rtc.initClock();
  //set a time to start with.
  //day, weekday, month, century, year
  byte day = 1;
  byte weekday= 1;
  byte month = 1;
  byte century =0;
  byte year = 13;

  day =20;
  weekday =7;
  month =1;
  century =20;
  year =13;
  rtc.setDate(day,weekday, month, century, year);
}

void loop()
{
  // set the cursor to column 0, line 1
  // (note: line 1 is the second row, since counting begins with 0):
  lcd.setCursor(0, 0);
  lcd.print(rtc.formatTime());
  lcd.setCursor(0, 1);
  lcd.print(rtc.formatDate());
  delay(1000);
}

void changeTime(){

  byte hour = 5;
  byte min = digitalRead(minButton);
  byte sec = 14;

  hour = 18;
  min = 20;
  sec = 00;
  rtc.setTime(hour, min,sec);

  if(digitalRead(minButton) == HIGH)
  {
    min += 1; 
  }
}

PaulS

Quote
I changed the code around since then and it does not do anything now.

Perhaps because you never call changeTime().

mark7w

#14
Jan 21, 2013, 07:48 am Last Edit: Jan 21, 2013, 08:09 am by mark7w Reason: 1
Even with the call, all that happens is the Time defaults to 18:20:00. I can't get the minutes to increase when the minButton goes HIGH.

Code: [Select]

#include <Wire.h>
#include <Rtc_Pcf8563.h>
#include <LiquidCrystal.h>

//init the real time clock
Rtc_Pcf8563 rtc;


LiquidCrystal lcd(7,8,9,10,11,12);

int minButton = 42;

void setup()
{
 lcd.begin(16, 2);
 pinMode (minButton,INPUT);
 //clear out all the registers
 rtc.initClock();
 //set a time to start with.
 //day, weekday, month, century, year
 byte day = 1;
 byte weekday= 1;
 byte month = 1;
 byte century =0;
 byte year = 13;

 day =20;
 weekday =7;
 month =1;
 century =20;
 year =13;
 rtc.setDate(day,weekday, month, century, year);
}

void loop()
{
 // set the cursor to column 0, line 1
 // (note: line 1 is the second row, since counting begins with 0):
 lcd.setCursor(0, 0);
 lcd.print(rtc.formatTime());
 lcd.setCursor(0, 1);
 lcd.print(rtc.formatDate());
 delay(1000);

 if(digitalRead(minButton) == HIGH)
   changeTime();
}

void changeTime(){

 byte hour = 5;
 byte min = 30;
 byte sec = 14;

 hour = 18;
 min = 20;
 sec = 00;
 rtc.setTime(hour, min,sec);

 if(digitalRead(minButton) == HIGH)
 {
   min += 1;  
 }
}

Go Up