Pages: [1] 2   Go Down
Author Topic: Universal Countdown Clock  (Read 4255 times)
0 Members and 1 Guest are viewing this topic.
Offline Offline
Full Member
***
Karma: 5
Posts: 112
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

i am in the planning stages of making a "Universal Countdown Clock" using the following hardware:

7" LCD screen - http://www.ebay.com/itm/7-7-0-inch-TFT-LCD-module-Font-IC-800x480-SSD1963-arduino-DUE-MEGA2560-3-5-4-3-/111008432389?
LCD screen shield - http://www.ebay.com/itm/TFT-SD-Shield-for-Arduino-DUE-TFT-LCD-Module-SD-Card-Adapter-2-8-3-2-inch-Mega-/121057447668?
Arduino Due - http://www.amazon.com/Arduino-A000062-Due/dp/B00A6C3JN2/ref=wl_it_dp_o_pC_nS_nC?ie=UTF8&colid=2T79BVD0S9MWW&coliid=I2UODE0TCIYT07
RTC - http://www.amazon.com/ADAFRUIT-INDUSTRIES-DS1307-Clock-Breakout/dp/B00C9NWMJ8/ref=wl_it_dp_o_pC_nS_nC?ie=UTF8&colid=2T79BVD0S9MWW&coliid=I1OJ1VK96A9NRB
External EEPROM - http://www.amazon.com/microtivity-24LC256-256Kbit-Serial-EEPROM/dp/B0092CRK14/ref=wl_it_dp_o_pC_nS_nC?ie=UTF8&colid=2T79BVD0S9MWW&coliid=I1O789MJ03CX23
Enclosure - http://www.amazon.com/BUD-Industries-PN-1341-DG-High-Impact-Indoor/dp/B005T7BAGW/ref=wl_it_dp_o_pC_S_nC?ie=UTF8&colid=2T79BVD0S9MWW&coliid=I2CG7AAIMPYX2K

The project will allow for multiple simultaneous countdowns for the following:

Christmas Adjust
Cinco De Mayo Adjust
Valintine's' Day Adjust
Easter Adjust
Forth of July Adjust
Halloween Adjust
New Years Adjust
St Patric's Day Adjust
Thanksgiving Adjust
Birthday 1 Adjust
Birthday 2 Adjust
Anniversary Adjust
Custom 1 Adjust
Custom 2 Adjust

the pre-defined holidays, since their dates are always known will not have adjustable dates. the different birthdays will allow you to say the name of the individual who's birthday is bring counted down to, and obviously the date of their birthday. the custom countdowns allow you to count down to anything (like retirement for instance).

each pre-defined holiday, the birthdays, and custom countdowns ect.. allows you to change the color of the font, and the screen background color to be changed independently of one another. thanks to the LCD screen's ability to store images for me in its own 64mbit flash, each holiday will have its own image associated that will be displayed along with the count down.

the user will be able to enable or disable the different holidays independently, and if no countdowns are enabled at all, then the unit will act as a simple clock.

The system is powered by DueGUI library so that all user settings can be easily adjusted through the touch interface.

i will update this thread as the build progresses.


[edit] edited to reflect latest design information
« Last Edit: September 11, 2013, 02:35:16 pm by wallaceb » Logged

Offline Offline
Sr. Member
****
Karma: 9
Posts: 272
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Sounds like a cool project.

A few questions though:
1) Why a 7" LCD? Why not an LED sign like this (or the DIY equivalent) for example:
http://www.ebay.com/itm/New-Color-LED-Programmable-Scrolling-Message-Display-Sign-26-x4-FREE-SHIPPING-/320823352036?pt=LH_DefaultDomain_0&hash=item4ab28fdae4

2) Why an external EEPROM? Even the ATTiny85 has enough EEPROM space for various countdowns/config settings.

3) Speeking of EEPROM space, why the Due? Seems total overkill for something like this, no?

4) Maybe get a board with Ethernet already on-board?

5) Or why not Wifi?
Logged

Offline Offline
Full Member
***
Karma: 5
Posts: 112
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

please see my responses in red below

Sounds like a cool project.

A few questions though:
1) Why a 7" LCD? Why not an LED sign like this (or the DIY equivalent) for example:
http://www.ebay.com/itm/New-Color-LED-Programmable-Scrolling-Message-Display-Sign-26-x4-FREE-SHIPPING-/320823352036?pt=LH_DefaultDomain_0&hash=item4ab28fdae4 i want to be able to display full color background images  smiley-mr-green

2) Why an external EEPROM? Even the ATTiny85 has enough EEPROM space for various countdowns/config settings. the arduino due does not have eeprom, so i must use external eeprom

3) Speeking of EEPROM space, why the Due? Seems total overkill for something like this, no?  please refer to the following video, it clearly shows the MASSIVE performance difference between the due and the mega when using a color LCD

4) Maybe get a board with Ethernet already on-board? because i need the performance of the due, that is not an option  smiley-cry

5) Or why not Wifi? i like to make my projects as if they are a "commercial product" and since the wifi needs to be edited directly into the arduino sketch, i do not want to utilize that.
Logged

Offline Offline
Sr. Member
****
Karma: 9
Posts: 272
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Alright, all good reasons I suppose.
I got one more though: Raspberri Pi?!

$35 = Rapberri Pi, including HDMI out, Ethernet & SD Card for image storage and settings
Just add RTC and you're done...
Logged

Offline Offline
Full Member
***
Karma: 5
Posts: 112
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Alright, all good reasons I suppose.
I got one more though: Raspberri Pi?!

$35 = Rapberri Pi, including HDMI out, Ethernet & SD Card for image storage and settings
Just add RTC and you're done...

i thought of that, but i do not want to connect to a large screen as they draw more power than the arduino will, and i want to have the nice web-based interface. i used to do web-design with PHP, so i could easily make a PHP web-interface for the Pi...

i did not say it originally, but my wife and i want to attach the box that all the hardware is in to a picture frame, so people would only see the frame making it look much nice, using HDMI out to a larger screen will make that too difficult.
Logged

Offline Offline
Full Member
***
Karma: 5
Posts: 112
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

i have my code that calculates the remaining time based on the input target date. the code is more complicated than it has to be because i wanted the calculation to be exact based on the date. i did not want to use the method using the average hours per month as it will not be as accurate.

Code:
#include <SPI.h>
#include <Wire.h>
#include "Wire.h"
byte seconds, minutes, hours, dayOfWeek, dayOfMonth, months, years;
#define DS1307_I2C_ADDRESS 0x68 //address of the RTC on the SPI bus


void setup()  {
  Serial.begin(9600);  
  Wire.begin();//needed to comunicate with the real time clock  
}

double prevDisplay=0;
void loop()
{
  
  getDateDs1307(seconds, minutes, hours, dayOfWeek, dayOfMonth, months, years);
  char buffer[40];
  byte remaining_seconds, remaining_minuets, remaining_hours, remaining_days, remaining_months, remaining_years;
  if ((seconds + minutes + hours)  != prevDisplay) { //update the display only if time has changed
      prevDisplay = (seconds + minutes + hours);
      calculate_countdown(0,0,0,25,12,13, remaining_seconds, remaining_minuets, remaining_hours, remaining_days, remaining_months, remaining_years);
      sprintf (buffer, "%.2d Years : %.2d Months : %.2d Days", remaining_years, remaining_months, remaining_days);
      Serial.println(buffer);
      sprintf(buffer, "%d Hours : %d Minuets : %d Seconds", remaining_hours, remaining_minuets, remaining_seconds);
      Serial.println(buffer);
      Serial.println();
    }
}
void calculate_countdown(byte future_seconds,
byte future_minutes,
byte future_hours,
byte future_days,
byte future_months,
byte future_years,
byte &remaining_seconds,
byte &remaining_minuets,
byte &remaining_hours,
byte &remaining_days,
byte &remaining_months,
byte &remaining_years){

bool borrow_from_minutes = false;
bool borrow_from_hours = false;
bool borrow_from_days = false;
bool borrow_from_month = false;
bool borrow_from_years = false;



/******************************
/*CALCULATE REMIANING SECONDS
/*****************************/

if (future_seconds - seconds <0){
remaining_seconds = 60 - seconds;
borrow_from_minutes = true;
}else{
remaining_seconds = future_seconds - seconds;
       borrow_from_minutes = false;
}

/******************************
/*CALCULATE REMIANING MINUTES
/*****************************/

if (borrow_from_minutes == true){
if (future_minutes - minutes - 1 <0){
remaining_minuets = 60 - minutes - 1;
borrow_from_hours = true;
}else{
remaining_minuets = future_minutes - minutes - 1;
       borrow_from_hours = false;
}
}else{
if (future_minutes - minutes <0){
remaining_minuets = 60 - minutes;
borrow_from_hours = true;
       }else{
               remaining_minuets = future_minutes - minutes;
               borrow_from_hours = false;
       }
}

/******************************
/*CALCULATE REMIANING HOURS
/*****************************/

if (borrow_from_hours == true){
if (future_hours - hours - 1 <0){
remaining_hours = 24 - hours - 1;
borrow_from_days = true;
}else{
remaining_hours = future_hours - hours - 1;
borrow_from_days = false;
}
}else{
if (future_hours - hours <0){
remaining_hours = 24 - hours;
borrow_from_days = true;
}else{
remaining_hours = future_hours - hours;
borrow_from_days = false;
}
}

/******************************
/*CALCULATE REMIANING DAYS
/*****************************/

if (borrow_from_days == true){
if ((future_days - dayOfMonth - 1) <0){
if (months == 1){ //January has 31 days
remaining_days = 31 - dayOfMonth - 1;
borrow_from_month = true;
}else if (months == 2){ //February has 28 days
remaining_days = 28 - dayOfMonth - 1;
borrow_from_month = true;
}else if (months == 3){ //March has 31 days
remaining_days = 31 - dayOfMonth - 1;
borrow_from_month = true;
}else if (months == 4){ //April has 30 days
remaining_days = 30 - dayOfMonth - 1;
borrow_from_month = true;
}else if (months==5){ //May has 31 days
remaining_days = 31 - dayOfMonth - 1;
borrow_from_month = true;
}else if (months == 6){ //June has 30 days
remaining_days = 30 - dayOfMonth - 1;
borrow_from_month = true;
}else if (months == 7){ //July has 31 days
remaining_days = 31 - dayOfMonth - 1;
borrow_from_month = true;
}else if (months ==8){ //August has 31 days
remaining_days = 31 - dayOfMonth - 1;
borrow_from_month = true;
}else if (months == 9){ //September has 30 days
remaining_days = 30 - dayOfMonth - 1;
borrow_from_month = true;
}else if (months == 10){ //October has 31 days
remaining_days = 31 - dayOfMonth - 1;
borrow_from_month = true;
}else if (months == 11){ //February has 30 days
remaining_days = 30 - dayOfMonth - 1;
borrow_from_month = true;
}else if (months == 12){ //December has 31 days
remaining_days = 31 - dayOfMonth - 1;
borrow_from_month = true;
}
}else{
remaining_days = future_days - dayOfMonth - 1;
borrow_from_month = false;
}
}else{
if (future_days - dayOfMonth <0){
if (months == 1){ //January has 31 days
remaining_days = 31 - dayOfMonth;
borrow_from_month = false;
}else if (months == 2){ //February has 28 days
remaining_days = 28 - dayOfMonth;
borrow_from_month = false;
}else if (months == 3){ //March has 31 days
remaining_days = 31 - dayOfMonth;
borrow_from_month = false;
}else if (months == 4){ //April has 30 days
remaining_days = 30 - dayOfMonth;
borrow_from_month = false;
}else if (months ==5){ //May has 31 days
remaining_days = 31 - dayOfMonth;
borrow_from_month = false;
}else if (months == 6){ //June has 30 days
remaining_days = 30 - dayOfMonth;
borrow_from_month = false;
}else if (months == 7){ //July has 31 days
remaining_days = 31 - dayOfMonth;
borrow_from_month = false;
}else if (months ==8){ //August has 31 days
remaining_days = 31 - dayOfMonth;
borrow_from_month = false;
}else if (months == 9){ //September has 30 days
remaining_days = 30 - dayOfMonth;
borrow_from_month = false;
}else if (months == 10){ //October has 31 days
remaining_days = 31 - dayOfMonth;
borrow_from_month = false;
}else if (months == 11){ //February has 30 days
remaining_days = 30 - dayOfMonth;
borrow_from_month = false;
}else if (months == 12){ //December has 31 days
remaining_days = 31 - dayOfMonth;
borrow_from_month = false;
}
}else{
remaining_days = future_days - dayOfMonth;
borrow_from_days = false;
}
}

/******************************
/*CALCULATE REMIANING MONTHS
/*****************************/

if (borrow_from_month == true){
if ((future_months - months) - 1 <0){
remaining_months = 12 - abs(future_months - months) - 1;
borrow_from_years = true;
}else{
remaining_months = future_months - months - 1;
borrow_from_years = false;
}
}else{
if (future_months - months <0){
remaining_months = 12 - abs(future_months - months);
borrow_from_years = true;
}else{
remaining_months = future_months - months;
borrow_from_years = false;
}
}

/******************************
/*CALCULATE REMIANING YEARS
/*****************************/

if (borrow_from_years == true){
if (future_years - years - 1 <0){
remaining_years = 0;
}else{
remaining_years = future_years - years - 1;
}
}else{
if ((future_years - years) <0){
remaining_years = 0;
}else{
remaining_years = future_years - years;
}
}
}

// Gets the date and time from the ds1307
void getDateDs1307(byte &get_second,
byte &get_minute,
byte &get_hour,
byte &get_dayOfWeek,
byte &get_dayOfMonth,
byte &get_month,
byte &get_year)
{
  // Reset the register pointer
  Wire.beginTransmission(DS1307_I2C_ADDRESS);
  Wire.write(0);
  Wire.endTransmission();

  Wire.requestFrom(DS1307_I2C_ADDRESS, 7);

  // A few of these need masks because certain bits are control bits
  get_second     = bcdToDec(Wire.read() & 0x7f);
  get_minute     = bcdToDec(Wire.read());
  get_hour       = bcdToDec(Wire.read() & 0x3f);  // Need to change this if 12 hour am/pm
  get_dayOfWeek  = bcdToDec(Wire.read());
  get_dayOfMonth = bcdToDec(Wire.read());
  get_month      = bcdToDec(Wire.read());
  get_year       = bcdToDec(Wire.read());
}


// Convert binary coded decimal to normal decimal numbers
byte bcdToDec(byte val)
{
  return ( (val/16*10) + (val%16) );
}

« Last Edit: August 16, 2013, 05:21:07 pm by wallaceb » Logged

Offline Offline
Sr. Member
****
Karma: 9
Posts: 272
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Wallace,

That code is needlessly long & complicated and uses lots of variables.
I'm trying to simplify the code for you, but need to understand your requirements.

What are you going to display?

For example, given "now" being January 2st and the countdown going to March 29th of the same year. The difference is 29 + 28 (non leap-year) + 29 = 86 days. How are you going to display this?
a) 86 days
b) 2 month, 26 days (this would be based on 30 days per month)
c) 1 month, 58 days (February is the only full month)

Based on what you want to display, I can post up code here to simplify the calculation.

Also already a heads-up:
The DS1307 gives you years 0-99. So you have to add 2000 when you read it (and subtract 2000 on write).
Logged

Offline Offline
Full Member
***
Karma: 5
Posts: 112
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

thanks for the help.

you can see what i wish to display by this code:

Code:
sprintf (buffer, "%.2d Years : %.2d Months : %.2d Days", remaining_years, remaining_months, remaining_days);
      Serial.println(buffer);
      sprintf(buffer, "%d Hours : %d Minuets : %d Seconds", remaining_hours, remaining_minuets, remaining_seconds);
      Serial.println(buffer);

so i want it to say:
xx Years : xx Months : xx Days
xx Hours : xx Minutes : xx Seconds

for example, i entered the date for This year's xmas, and it says:
00 Years : 04 Months : 08 Days
3 Hours : 19 Minuets : 16 Seconds

i want to make sure that the countdown always takes into account the actual number of days that are in any particular month so the countdown is accurate

i have always been good at getting code to work how i want, but not really good as making the code the most efficient or elegant  smiley-mr-green
« Last Edit: August 16, 2013, 08:40:06 pm by wallaceb » Logged

Offline Offline
Sr. Member
****
Karma: 9
Posts: 272
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

for example, i entered the date for This year's xmas, and it says:
00 Years : 04 Months : 08 Days
3 Hours : 19 Minuets : 16 Seconds

i want to make sure that the countdown always takes into account the actual number of days that are in any particular month so the countdown is accurate

This is where I'm still confused... Why does the actual number of days matter here?
It's not used in this calculation. Here you have 24-16 = 8 days; 12-8 = 4 month

The actual number of days in a month would only be used if you wanted to calculate the total number of days - which you're not.
But I think I have enough to propose a new algorithm. I'll post up some code in a bit...
Logged

Offline Offline
Full Member
***
Karma: 5
Posts: 112
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

i have tried many different date combinations and the code i have does what i want, i am not sure how else to explain what i need.

i did simplify the code by defining the following array:
Code:
byte days_per_month[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};

i also removed the redundant "borrow" variables, as i realized i only need one.

Code:
void calculate_countdown(byte future_seconds,
byte future_minutes,
byte future_hours,
byte future_days,
byte future_months,
byte future_years,
byte &remaining_seconds,
byte &remaining_minuets,
byte &remaining_hours,
byte &remaining_days,
byte &remaining_months,
byte &remaining_years){
bool borrow = false;

/******************************
/*CALCULATE REMIANING SECONDS
/*****************************/

if (future_seconds - seconds <0){
remaining_seconds = 60 - seconds;
borrow = true;
}else{
remaining_seconds = future_seconds - seconds;
       borrow = false;
}

/******************************
/*CALCULATE REMIANING MINUTES
/*****************************/

if (borrow == true){
if (future_minutes - minutes - 1 <0){
remaining_minuets = 60 - minutes - 1;
borrow = true;
}else{
remaining_minuets = future_minutes - minutes - 1;
       borrow = false;
}
}else{
if (future_minutes - minutes <0){
remaining_minuets = 60 - minutes;
borrow = true;
       }else{
               remaining_minuets = future_minutes - minutes;
               borrow = false;
       }
}

/******************************
/*CALCULATE REMIANING HOURS
/*****************************/

if (borrow == true){
if (future_hours - hours - 1 <0){
remaining_hours = 24 - hours - 1;
borrow = true;
}else{
remaining_hours = future_hours - hours - 1;
borrow = false;
}
}else{
if (future_hours - hours <0){
remaining_hours = 24 - hours;
borrow = true;
}else{
remaining_hours = future_hours - hours;
borrow = false;
}
}

/******************************
/*CALCULATE REMIANING DAYS
/*****************************/

if (borrow == true){
if ((future_days - dayOfMonth - 1) <0){
                        remaining_days = days_per_month[months-1] - dayOfMonth - 1 + (days_per_month[months-1] - days_per_month[future_months-1]);
                        borrow = true;
}else{
remaining_days = future_days - dayOfMonth - 1;
borrow = false;
}
}else{
if (future_days - dayOfMonth <0){
                        remaining_days = days_per_month[months-1] - dayOfMonth + (days_per_month[months-1] - days_per_month[future_months-1]);
                        borrow = false;
}else{
remaining_days = future_days - dayOfMonth;
borrow = false;
}
}

/******************************
/*CALCULATE REMIANING MONTHS
/*****************************/

if (borrow == true){
if ((future_months - months) - 1 <0){
remaining_months = 12 - abs(future_months - months) - 1;
borrow = true;
}else{
remaining_months = future_months - months - 1;
borrow = false;
}
}else{
if (future_months - months <0){
remaining_months = 12 - abs(future_months - months);
borrow = true;
}else{
remaining_months = future_months - months;
borrow = false;
}
}

/******************************
/*CALCULATE REMIANING YEARS
/*****************************/

if (borrow == true){
if (future_years - years - 1 <0){
remaining_years = 0;
}else{
remaining_years = future_years - years - 1;
}
}else{
if ((future_years - years) <0){
remaining_years = 0;
}else{
remaining_years = future_years - years;
}
}
}

i corrected an issue where if the future date days was a lesser value than today's date's days.

the best way i think i can explain what i want is if you were to take the calculation's remaining months, flip that many months/pages on a calendar, then add on the remaining days to today's date (which should then land on the correct future month's future day) and then take the hours/minutes/seconds into account. when i do this, my calculation works exactly as i want...

i welcome help getting the code to be simplier, but i need to make sure i am relaying my desired properly...  smiley-red
« Last Edit: August 16, 2013, 09:43:15 pm by wallaceb » Logged

Offline Offline
Sr. Member
****
Karma: 9
Posts: 272
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Alright, I tested your function, and as I would expect from overly complex code like that, it doesn't seem to calculate the dates correctly.

Hopefully, this code is much easier to read and debug and also performs well on the device.
I did manage to reduce ~120 lines down to about 30 smiley

Code:
const byte DAYS_IN_MONTH[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};

struct TimeStamp
{
    unsigned int yy;
    byte mm;
    byte dd;
    byte hh;
    byte min;
    byte ss;
};

TimeStamp calcDiff(TimeStamp now, const TimeStamp &future)
{
    unsigned long sec_now = now.ss + (now.min * 60) + (now.hh * 3600);
    unsigned long sec_future = future.ss + (future.min * 60) + (future.hh * 3600);

    if (sec_future < sec_now)
    {
        sec_future += 86400;
        ++now.dd;
    }

    if (future.dd < now.dd)
    {
        now.dd = DAYS_IN_MONTH[now.mm-1] - now.dd + future.dd;
        ++now.mm;
    } else {
        now.dd = future.dd - now.dd;
    }

    if (future.mm < now.mm)
    {
        now.mm = future.mm + 12 - now.mm;
        ++now.yy;
    } else {
        now.mm = future.mm - now.mm;
    }

    sec_now = sec_future - sec_now;
    now.yy = future.yy - now.yy;
    now.hh = sec_now / 3600;
    now.min = (sec_now - (now.hh * 3600)) / 60;
    now.ss = sec_now % 60;

    return now;
}
Logged

Offline Offline
Full Member
***
Karma: 5
Posts: 112
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

i tested your code, and it made me look at mine a little more, and i discovered that both of our codes had issues. i was able to correct my code such that it works perfectly based on my test results. i did previously say i can get code to work, but getting it to be simple and elegant like yours is not my strong suit  smiley-mr-green  smiley-cool

Code:
void calculate_countdown(byte future_seconds,
byte future_minutes,
byte future_hours,
byte future_days,
byte future_months,
byte future_years,
byte &remaining_seconds,
byte &remaining_minuets,
byte &remaining_hours,
byte &remaining_days,
byte &remaining_months,
byte &remaining_years){
bool borrow = false;

/******************************
/*CALCULATE REMIANING SECONDS
/*****************************/

if (future_seconds - seconds <0){
remaining_seconds = 60 - seconds;
borrow = true;
}else{
remaining_seconds = future_seconds - seconds;
       borrow = false;
}

/******************************
/*CALCULATE REMIANING MINUTES
/*****************************/

if (borrow == true){
if (future_minutes - minutes - 1 <0){
remaining_minuets = 60 - minutes - 1;
borrow = true;
}else{
remaining_minuets = future_minutes - minutes - 1;
       borrow = false;
}
}else{
if (future_minutes - minutes <0){
remaining_minuets = 60 - minutes;
borrow = true;
       }else{
               remaining_minuets = future_minutes - minutes;
               borrow = false;
       }
}

/******************************
/*CALCULATE REMIANING HOURS
/*****************************/

if (borrow == true){
if (future_hours - hours - 1 <0){
remaining_hours = 24 - hours - 1;
borrow = true;
}else{
remaining_hours = future_hours - hours - 1;
borrow = false;
}
}else{
if (future_hours - hours <0){
remaining_hours = 24 - hours;
borrow = true;
}else{
remaining_hours = future_hours - hours;
borrow = false;
}
}

/******************************
/*CALCULATE REMIANING DAYS
/*****************************/

if (borrow == true){
if ((future_days - dayOfMonth - 1) <0){
                        
                        remaining_days = days_per_month[months-1] - dayOfMonth - 1 + future_days;
                        borrow = true;
}else{
remaining_days = future_days - dayOfMonth - 1;
borrow = false;
}
}else{
if (future_days - dayOfMonth <0){
                        remaining_days = days_per_month[months-1] - dayOfMonth + future_days;
                        borrow = false;
}else{
remaining_days = future_days - dayOfMonth;
borrow = false;
}
}

/******************************
/*CALCULATE REMIANING MONTHS
/*****************************/

if (borrow == true){
if ((future_months - months) - 1 <0){
remaining_months = 12 - abs(future_months - months) - 1;
                        if ((months + remaining_months) > 12){
                          remaining_days -= (days_per_month[months-1] - days_per_month[(months + remaining_months - 12)-1]);
                        }else{
                          remaining_days -= (days_per_month[months-1] - days_per_month[(months + remaining_months)-1]);
                        }
borrow = true;
}else{
remaining_months = future_months - months - 1;
                        if ((months + remaining_months) > 12){
                          remaining_days -= (days_per_month[months-1] - days_per_month[(months + remaining_months - 12)-1]);
                        }else{
                          remaining_days -= (days_per_month[months-1] - days_per_month[(months + remaining_months)-1]);
                        }
borrow = false;
}
}else{
if (future_months - months <0){
remaining_months = 12 - abs(future_months - months);
borrow = true;
}else{
remaining_months = future_months - months;
borrow = false;
}
}

/******************************
/*CALCULATE REMIANING YEARS
/*****************************/

if (borrow == true){
if (future_years - years - 1 <0){
remaining_years = 0;
}else{
remaining_years = future_years - years - 1;
}
}else{
if ((future_years - years) <0){
remaining_years = 0;
}else{
remaining_years = future_years - years;
}
}
}


the resulting remaining time for different date (please note i performed the tests below on 8/17/2013) is:

Code:
Time Until 1 / 10 / 2014
00 Years : 04 Months : 23 Days
3 Hours : 28 Minuets : 37 Seconds


Time Until 1 / 20 / 2014
00 Years : 05 Months : 02 Days
3 Hours : 26 Minuets : 51 Seconds


Time Until 2 / 10 / 2014
00 Years : 05 Months : 23 Days
3 Hours : 25 Minuets : 50 Seconds


Time Until 2 / 20 / 2014
00 Years : 06 Months : 02 Days
3 Hours : 24 Minuets : 30 Seconds


Time Until 3 / 10 / 2014
00 Years : 06 Months : 20 Days
3 Hours : 23 Minuets : 26 Seconds

Time Until 3 / 20 / 2014
00 Years : 07 Months : 02 Days
3 Hours : 22 Minuets : 21 Seconds

Time Until 4 / 10 / 2014
00 Years : 07 Months : 23 Days
3 Hours : 21 Minuets : 32 Seconds


Time Until 4 / 20 / 2014
00 Years : 08 Months : 02 Days
3 Hours : 20 Minuets : 14 Seconds




Time Until 5 / 10 / 2014
00 Years : 08 Months : 22 Days
3 Hours : 18 Minuets : 19 Seconds


Time Until 5 / 20 / 2014
00 Years : 09 Months : 02 Days
3 Hours : 16 Minuets : 51 Seconds


Time Until 6 / 10 / 2014
00 Years : 09 Months : 23 Days
3 Hours : 15 Minuets : 55 Seconds


Time Until 6 / 20 / 2014
00 Years : 10 Months : 02 Days
3 Hours : 14 Minuets : 52 Seconds


Time Until 7 / 10 / 2014
00 Years : 10 Months : 22 Days
3 Hours : 13 Minuets : 47 Seconds


Time Until 7 / 20 / 2014
00 Years : 11 Months : 02 Days
3 Hours : 12 Minuets : 43 Seconds


Time Until 8 / 10 / 2014
00 Years : 11 Months : 23 Days
3 Hours : 11 Minuets : 48 Seconds


Time Until 8 / 20 / 2014
01 Years : 00 Months : 02 Days
3 Hours : 10 Minuets : 20 Seconds


Time Until 9 / 10 / 2014
01 Years : 00 Months : 23 Days
3 Hours : 9 Minuets : 28 Seconds


Time Until 9 / 20 / 2014
01 Years : 01 Months : 02 Days
3 Hours : 7 Minuets : 18 Seconds


Time Until 10 / 10 / 2014
01 Years : 01 Months : 22 Days
3 Hours : 5 Minuets : 33 Seconds

i choose the days of "10" and "20" within each month to test both cases where "future days" is greater than and less than "today's day).



the main area that i had a correction was when "future_months - months < 0"
because the different months have different numbers of days within them, the code had to take that into account so it knew when the transition to the next month began. that was taken care of by this code:

Code:
if ((months + remaining_months) > 12){
                          remaining_days -= (days_per_month[months-1] - days_per_month[(months + remaining_months - 12)-1]);
                        }else{
                          remaining_days -= (days_per_month[months-1] - days_per_month[(months + remaining_months)-1]);
                        }


just to make sure i am not doing anything wrong with your code, would you be able to send me your entire code set you used to test your function?  smiley-grin
« Last Edit: August 17, 2013, 09:23:49 pm by wallaceb » Logged

Offline Offline
Sr. Member
****
Karma: 9
Posts: 272
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

What issue did you find in my code?
I tried it on the Arduino and noticed there was a variable size issue, but the math still adds app as far as I can tell.

Here's the code I've been testing with:
Code:
const byte DAYS_IN_MONTH[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};

struct TimeStamp
{
    unsigned int yy;
    byte mm;
    byte dd;
    byte hh;
    byte min;
    byte ss;
};

TimeStamp calcDiff(TimeStamp now, const TimeStamp &future)
{
    unsigned long sec_now = now.ss + (now.min * 60) + (now.hh * 3600);
    unsigned long sec_future = future.ss + (future.min * 60) + (future.hh * 3600);
   
    if (sec_future < sec_now)
    {
        sec_future += 86400;
        ++now.dd;
    }
   
    if (future.dd < now.dd)
    {
        now.dd = DAYS_IN_MONTH[now.mm-1] - now.dd + future.dd;
        ++now.mm;
    } else {
        now.dd = future.dd - now.dd;
    }
   
    if (future.mm < now.mm)
    {
        now.mm = future.mm + 12 - now.mm;
        ++now.yy;
    } else {
        now.mm = future.mm - now.mm;
    }
   
    sec_now = sec_future - sec_now;
    now.yy = future.yy - now.yy;
    now.hh = sec_now / 3600;
    now.min = (sec_now - ((unsigned long)now.hh * 3600)) / 60;
    now.ss = sec_now % 60;
   
    return now;
}


void setup()
{
    Serial.begin(115200);

    TimeStamp future = {2015, 2,  17, 18,  0,  0};
    TimeStamp now =    {2014, 2,  17, 18,  0,  1};
   
    TimeStamp diff = calcDiff(now, future);

    char buffer[100] = {0};
    sprintf(buffer, "%d years, %d month, %d days\r\n%d hours, %d minutes, %d seconds", diff.yy, diff.mm, diff.dd, diff.hh, diff.min, diff.ss);
    Serial.println(buffer);
}

void loop()
{
}

If you try the dates that I've put in my sample code, you'll not that your code still has issues with some hours and also days.

You're up to 130 lines of code in your function, including various state variables (like borrow) that are very hard to track in your head. I'd highly recommend you switch to a more math based approach to keep the code compact and make it much easier to debug...
Logged

Offline Offline
Full Member
***
Karma: 5
Posts: 112
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

i corrected the issues with hours and days in mine. 

here is side by side comparisons between our calculations:
mine:
Code:
Time Until 10 / 10 / 2014  - 0 : 0 : 0 hours
01 Years : 01 Months : 21 Days
13 Hours : 9 Minuets : 36 Seconds
yours:
Code:
Time Until 10 / 10 / 2014  - 0 : 0 : 0 hours
1 years, 1 month, 22 days
31 hours, 21 minutes, 15 seconds

both are counting down until  0:0:0 hours, the codes are using the real time clock on my setup for the current time and so will be off from one-another by around 1 or so minutes as time continues to move.

based on my calculation result , taking a calender, starting on today's date, "flipping " 13 months, that lands me on the 18th of September 2014. if i then add on the 13 hours, 9 minutes, 36 seconds to today, that brings me to midnight 19th of September. moving 21 days from the 19th, brings be to the 10th of October as i wanted

i am not sure how your code is calculating 31 hours, but it does not get the result i am looking for, this is the same issue i said i saw last night.

i understand mine is longer, but i wrote it based on how a person would perform the math on paper by performing date/time subtraction which to me is easy to follow...

i would gladly use your more efficient and elegant code, but i consistently cannot get it to calculate what i am expecting.

my final code appears to be this:

Code:
/*
#include <SPI.h>
#include <Wire.h>
#include "Wire.h"
byte seconds, minutes, hours, dayOfWeek, dayOfMonth, months, years;
#define DS1307_I2C_ADDRESS 0x68 //address of the RTC on the SPI bus
byte days_per_month[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};


void setup()  {
  Serial.begin(115200); 
  Wire.begin();//needed to comunicate with the real time clock 
}

double prevDisplay=0;
void loop()
{
  getDateDs1307(seconds, minutes, hours, dayOfMonth, dayOfMonth, months, years);
  char buffer[40];
  byte remaining_seconds, remaining_minuets, remaining_hours, remaining_days, remaining_months, remaining_years;
  if ((seconds + minutes + hours)  != prevDisplay) { //update the display only if time has changed
      prevDisplay = (seconds + minutes + hours);
      calculate_countdown(0,0,0,10,10,14, remaining_seconds, remaining_minuets, remaining_hours, remaining_days, remaining_months, remaining_years);
      sprintf (buffer, "Time Until %.d / %.d / %.d ", 10, 10, 2014);
      Serial.println(buffer);
      sprintf (buffer, "%.2d Years : %.2d Months : %.2d Days", remaining_years, remaining_months, remaining_days);
      Serial.println(buffer);
      sprintf(buffer, "%d Hours : %d Minuets : %d Seconds", remaining_hours, remaining_minuets, remaining_seconds);
      Serial.println(buffer);
      Serial.println();
    }
}
void calculate_countdown(byte future_seconds,
byte future_minutes,
byte future_hours,
byte future_days,
byte future_months,
byte future_years,
byte &remaining_seconds,
byte &remaining_minuets,
byte &remaining_hours,
byte &remaining_days,
byte &remaining_months,
byte &remaining_years){
bool borrow = false;

/******************************
/*CALCULATE REMIANING SECONDS
/*****************************/

if (future_seconds - seconds <0){
remaining_seconds = 60 - seconds;
borrow = true;
}else{
remaining_seconds = future_seconds - seconds;
        borrow = false;
}

/******************************
/*CALCULATE REMIANING MINUTES
/*****************************/

if (borrow == true){
if (future_minutes - minutes - 1 <0){
remaining_minuets = 60 - minutes - 1 + future_minutes;
borrow = true;
}else{
remaining_minuets = future_minutes - minutes - 1;
        borrow = false;
}
}else{
if (future_minutes - minutes <0){
remaining_minuets = 60 - minutes + future_minutes;
borrow = true;
        }else{
                remaining_minuets = future_minutes - minutes;
                borrow = false;
        }
}

/******************************
/*CALCULATE REMIANING HOURS
/*****************************/

if (borrow == true){
if (future_hours - hours - 1 <0){
remaining_hours = 24 - hours - 1 + future_hours;
borrow = true;
}else{
remaining_hours = future_hours - hours - 1;
borrow = false;
}
}else{
if (future_hours - hours <0){
remaining_hours = 24 - hours + future_hours;
borrow = true;
}else{
remaining_hours = future_hours - hours;
borrow = false;
}
}

/******************************
/*CALCULATE REMIANING DAYS
/*****************************/

if (borrow == true){
if ((future_days - dayOfMonth - 1) <0){
                       
                        remaining_days = days_per_month[months-1] - dayOfMonth - 1 + future_days;
                        borrow = true;
}else{
remaining_days = future_days - dayOfMonth - 1;
borrow = false;
}
}else{
if (future_days - dayOfMonth <0){
                        remaining_days = days_per_month[months-1] - dayOfMonth + future_days;
                        borrow = false;
}else{
remaining_days = future_days - dayOfMonth;
borrow = false;
}
}

/******************************
/*CALCULATE REMIANING MONTHS
/*****************************/

if (borrow == true){
if ((future_months - months) - 1 <0){
remaining_months = 12 - abs(future_months - months) - 1;
                        if ((months + remaining_months) > 12){
                          remaining_days -= (days_per_month[months-1] - days_per_month[(months + remaining_months - 12)-1]);
                        }else{
                          remaining_days -= (days_per_month[months-1] - days_per_month[(months + remaining_months)-1]);
                        }
borrow = true;
}else{
remaining_months = future_months - months - 1;
                        if ((months + remaining_months) > 12){
                          remaining_days -= (days_per_month[months-1] - days_per_month[(months + remaining_months - 12)-1]);
                        }else{
                          remaining_days -= (days_per_month[months-1] - days_per_month[(months + remaining_months)-1]);
                        }
borrow = false;
}
}else{
if (future_months - months <0){
remaining_months = 12 - abs(future_months - months);
borrow = true;
}else{
remaining_months = future_months - months;
borrow = false;
}
}

/******************************
/*CALCULATE REMIANING YEARS
/*****************************/

if (borrow == true){
if (future_years - years - 1 <0){
remaining_years = 0;
}else{
remaining_years = future_years - years - 1;
}
}else{
if ((future_years - years) <0){
remaining_years = 0;
}else{
remaining_years = future_years - years;
}
}
}

// Gets the date and time from the ds1307
void getDateDs1307(byte &get_second,
byte &get_minute,
byte &get_hour,
byte &get_dayOfWeek,
byte &get_dayOfMonth,
byte &get_month,
byte &get_year)
{
  // Reset the register pointer
  Wire.beginTransmission(DS1307_I2C_ADDRESS);
  Wire.write(0);
  Wire.endTransmission();

  Wire.requestFrom(DS1307_I2C_ADDRESS, 7);

  // A few of these need masks because certain bits are control bits
  get_second     = bcdToDec(Wire.read() & 0x7f);
  get_minute     = bcdToDec(Wire.read());
  get_hour       = bcdToDec(Wire.read() & 0x3f);  // Need to change this if 12 hour am/pm
  get_dayOfWeek  = bcdToDec(Wire.read());
  get_dayOfMonth = bcdToDec(Wire.read());
  get_month      = bcdToDec(Wire.read());
  get_year       = bcdToDec(Wire.read());
}


// Convert binary coded decimal to normal decimal numbers
byte bcdToDec(byte val)
{
  return ( (val/16*10) + (val%16) );
}



thanks for all your assistance!  smiley-grin
Logged

Offline Offline
Sr. Member
****
Karma: 9
Posts: 272
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

based on my calculation result , taking a calender, starting on today's date, "flipping " 13 months, that lands me on the 18th of September 2014. if i then add on the 13 hours, 9 minutes, 36 seconds to today, that brings me to midnight 19th of September. moving 21 days from the 19th, brings be to the 10th of October as i wanted

Your code is not taking into considerations the days in the current month. Try it with a current time in February and counting down until March. You'll see what I mean. As I mentioned previously, if you're just going to "flip the calendar" without counting the days remaining in the current month, you can remove the "days_in_month" part of your code completely.

Code:
i am not sure how your code is calculating 31 hours, but it does not get the result i am looking for, this is the same issue i said i saw last night.

It's not a calculation error, it's an integer overflow. I tested this on a non-avr compiler first and it looks like the avt-g++ is a little daft when it comes to casting variables. Below is the code with manual type casting to make the compiler happy.

Quote
i understand mine is longer, but i wrote it based on how a person would perform the math on paper by performing date/time subtraction which to me is easy to follow...

Hey, it's your project smiley

Since software development is my bread & butter, I'd just like to point out that short, easy to maintain code is not only valuable in terms of ROM/RAM space, but much more importantly in portability and maintenance down the road.

Another tip, before I bow out of this thread:
You're mixing passing variables by value (future_*), passing variables by reference (remaining_*) and sneakily using global variables inside your function (minutes, hours,...). This is adding to the overall confusion, makes this function much less reusable for other programs and makes the code that much harder to follow. If nothing else, I recommend you adopt the struct and the function signature I proposed.

Here's the final revision of the code (same as above, just type casting):

Code:
const byte DAYS_IN_MONTH[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};

struct TimeStamp
{
    unsigned int yy;
    byte mm;
    byte dd;
    byte hh;
    byte min;
    byte ss;
};

TimeStamp calcDiff(TimeStamp now, const TimeStamp &future)
{
    unsigned long sec_now = now.ss + ((unsigned long)now.min * 60) + ((unsigned long)now.hh * 3600);
    unsigned long sec_future = future.ss + ((unsigned long)future.min * 60) + ((unsigned long)future.hh * 3600);

    if (sec_future < sec_now)
    {
        sec_future += 86400;
        ++now.dd;
    }

    if (future.dd < now.dd)
    {
        now.dd = DAYS_IN_MONTH[now.mm-1] - now.dd + future.dd;
        ++now.mm;
    } else {
        now.dd = future.dd - now.dd;
    }

    if (future.mm < now.mm)
    {
        now.mm = future.mm + 12 - now.mm;
        ++now.yy;
    } else {
        now.mm = future.mm - now.mm;
    }

    Serial.println(sec_now);
    Serial.println(sec_future);
    sec_now = sec_future - sec_now;
    now.yy = future.yy - now.yy;
    now.hh = sec_now / 3600;
    now.min = (sec_now - ((unsigned long)now.hh * 3600)) / 60;
    now.ss = sec_now % 60;

    return now;
}
Logged

Pages: [1] 2   Go Up
Jump to: