Go Down

Topic: Looking for help with Time Setting function (Read 457 times) previous topic - next topic

bratan

While working on my LED clock I hit a problem I wasn't able yet to solve :(
I'm running Arduino Mega 2560 and RTC module (battery powered).
I have two buttons connected (Set and Increment) with pulldown resistor.
It kind of works except when I press Increment button Time stops. Seconds are not updating until I stop pressing Set button.  I'm not sure if it's an issue with Time.h library or my debounce time is too long (But shorter debounce times give me erratic button behavior).
So for example if I'm incrementing hours, seconds stop at the last value and in the result my clock are behind when setting is over.  This adds up when I add Date setting, Alarm, etc.  Every press of Inc button stops time for the duration.
I removed all extra code, and this is just the basic. It will print time to Serial when Set button is pressed.
Code: [Select]
#include <Wire.h>
#include <Time.h> 
#include <DS1307RTC.h>  // a basic DS1307 library that returns time as a time_t
#define BOUNCE_TIME_BUTTON  500   // bounce time in ms for the menu button;
boolean isSettingTime = false;
boolean isSettingHours   = false;
boolean isSettingMinutes = false;
byte SET_BUTTON_PIN=A3;// "set time" button
byte INC_BUTTON_PIN=A2;// "inc time" button
byte hours;
byte minutes;
volatile unsigned long lastButtonTime = 0;// last time a button was pushed; used for debouncing;

void setup() {
  Serial.begin(9600);
  setSyncProvider(RTC.get);   // the function to get the time from the RTC
  if(timeStatus()!= timeSet)
     Serial.println("Unable to sync with the RTC");
  else
     Serial.println("RTC has set the system time"); 

}

void loop() {
  buttonProc();
}

// =======================================================================================
// ---- Check button input and act upon it ----
// =======================================================================================
void buttonProc(){
  // check SET button;
  if (digitalRead(SET_BUTTON_PIN) == HIGH)
  {
   
    // "Set time" button was pressed;
    processSetButton();
}

  // check INC button;
  if (isSettingTime)
  {
    // DEBUG
    Serial.print (hour());Serial.print (":");Serial.print (minute());Serial.print (":");Serial.println (second());
    if (digitalRead(INC_BUTTON_PIN) == HIGH)
    {
      // "Inc time" button was pressed;
      processIncButton();
      // save the new time;
      setTime(hours,minutes,second(),day(),month(),year());
      RTC.set(now());
    }
  }
 
  // display the menu option for 5 seconds after menu button was pressed;
  if ((lastButtonTime > 0) && (millis() - lastButtonTime < 6000)) {
   
    return;
  }

  // return the main mode if no button was pressed for 5 seconds;
   if (isSettingTime)
  {
    // just finished setting up the time;
    isSettingTime = false;
   
  }
 
}

// =======================================================================================
// ---- Process Set Button ----
// =======================================================================================
void processSetButton()
{
  // debouncing;
  if (abs(millis() - lastButtonTime) < BOUNCE_TIME_BUTTON)
    return;

  lastButtonTime = millis();
  isSettingTime    = true;
  isSettingHours   = !isSettingHours;
  isSettingMinutes = !isSettingMinutes;

}
// ---------------------------------------------------------------------------------------
// =======================================================================================
// ---- Process Increment button ----
// =======================================================================================
void processIncButton()
{
  // debouncing;
  if (abs(millis() - lastButtonTime) < BOUNCE_TIME_BUTTON)
    return;

  lastButtonTime = millis();
  hours=hour(); // Store current hour value from clock
  minutes=minute(); // Store current minute value from clock
  if (isSettingHours)
  {
    hours++;
   if (hours > 23) hours = 0;
  }
  else
  {
    minutes++;
    if (minutes > 59) minutes = 0;
  }
}


Other than problem with time setting everything works just fine. 
Xronos Clock - A talking arduino based alarm clock is now available. Check out xronosclock.com for pictures, source code, schematics, and purchasing info :)

NickPyner


Seconds are not updating until I stop pressing Set button. 


I think that is normal. Here is the code I have just used. Enter the date/time into the code in advance, run it, press reset, and release at the appropriate time.

Code: [Select]
//Arduino 1.0+ Only
//Arduino 1.0+ Only
// pre-set the time in the void then use reset button to set it!

#include <LiquidCrystal.h>
#include "Wire.h"
#define DS1307_ADDRESS 0x68
byte zero = 0x00; //workaround for issue #527
LiquidCrystal lcd(8,9,16,5,6,7);
void setup(){
  Wire.begin();
  Serial.begin(9600);
        lcd.begin(16, 2);
      lcd.clear();
 
  setDateTime(); //MUST CONFIGURE IN FUNCTION
}

void loop(){
      lcd.clear();
  printDate();
 
  delay(1000);
}

void setDateTime(){

  byte second =      50; //0-59
  byte minute =    42; //0-59
  byte hour =        1; //0-23
  byte weekDay =     1; //1-7
  byte monthDay =    26; //1-31
  byte month =       11; //1-12
  byte year  =       12; //0-99

  Wire.beginTransmission(DS1307_ADDRESS);
  Wire.write(zero); //stop Oscillator

  Wire.write(decToBcd(second));
  Wire.write(decToBcd(minute));
  Wire.write(decToBcd(hour));
  Wire.write(decToBcd(weekDay));
  Wire.write(decToBcd(monthDay));
  Wire.write(decToBcd(month));
  Wire.write(decToBcd(year));

  Wire.write(zero); //start

  Wire.endTransmission();

}

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

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

void printDate(){

  // Reset the register pointer
  Wire.beginTransmission(DS1307_ADDRESS);
  Wire.write(zero);
  Wire.endTransmission();

  Wire.requestFrom(DS1307_ADDRESS, 7);

  int second = bcdToDec(Wire.read());
  int minute = bcdToDec(Wire.read());
  int hour = bcdToDec(Wire.read() & 0b111111); //24 hour time
  int weekDay = bcdToDec(Wire.read()); //0-6 -> sunday - Saturday
  int monthDay = bcdToDec(Wire.read());
  int month = bcdToDec(Wire.read());
  int year = bcdToDec(Wire.read());

  //print the date EG   3/1/11 23:59:59
  Serial.print(month);
  Serial.print("/");
  Serial.print(monthDay);
  Serial.print("/");
  Serial.print(year);
  Serial.print(" ");
  Serial.print(hour);
  Serial.print(":");
  Serial.print(minute);
  Serial.print(":");
  Serial.println(second);
 
  lcd.print(monthDay);
  lcd.print("/");
  lcd.print(month);
  lcd.print("/");
  lcd.print(year);
  lcd.print(" ");
  lcd.print(hour);
  lcd.print(":");
  lcd.print(minute);
  lcd.print(":");
  lcd.print(second);
}

PaulS

Quote
Seconds are not updating until I stop pressing Set button.

Because that's the way you've written the code. You really want to detect when the Set switch TRANSITIONS TO pressed, not when the switch IS pressed. To do that, you need to keep track of the previous state. Do whatever needs to be done when the switch transitions to pressed (is at some state now, and was not at that state before, and if the current state is pressed). It's best to use two if statements, not one compound statement.

bratan


Because that's the way you've written the code. You really want to detect when the Set switch TRANSITIONS TO pressed, not when the switch IS pressed. To do that, you need to keep track of the previous state. Do whatever needs to be done when the switch transitions to pressed (is at some state now, and was not at that state before, and if the current state is pressed). It's best to use two if statements, not one compound statement.

Thank you Paul! I rewrote code as per your suggestion. Issue remains :(  As long as I keep pressing Increment button faster than each 1 second, time is stopped.
I think problem is setTime function. If I don't call it, time is not stopping, but as soon as it's called faster than each second it's not updating :( 
Code: [Select]
#include <Wire.h>
#include <Time.h> 
#include <DS1307RTC.h>  // a basic DS1307 library that returns time as a time_t
#define BOUNCE_TIME_BUTTON  500   // bounce time in ms for the menu button;
boolean isSettingTime = false;
boolean isSettingHours   = false;
boolean isSettingMinutes = false;
byte SET_BUTTON_PIN=A3;// "set time" button
byte INC_BUTTON_PIN=A2;// "inc time" button
byte hours;
byte minutes;
byte seconds;
volatile unsigned long lastButtonTime = 0;// last time a button was pushed; used for debouncing;
int cStateSet = LOW; // Current state of Set Button
int pStateSet = LOW; // Previous state of Set Button
int cStateInc = LOW; // Current state of inc Button
int pStateInc = LOW; // Previous state of inc Button


void setup() {
  Serial.begin(9600);
  setSyncProvider(RTC.get);   // the function to get the time from the RTC
  if(timeStatus()!= timeSet)
     Serial.println("Unable to sync with the RTC");
  else
     Serial.println("RTC has set the system time"); 
  Serial.print (month());Serial.print(", "); Serial.println (day());
  Serial.print (hour());Serial.print (":");Serial.print (minute());Serial.print (":");Serial.println (second());
}

void loop() {
  buttonProc();
}

// =======================================================================================
// ---- Check button input and act upon it ----
// =======================================================================================
void buttonProc(){
  // check SET button;
  cStateSet = digitalRead(SET_BUTTON_PIN); //Get State of the Set button
  if ( (cStateSet != pStateSet) && (cStateSet == HIGH) )
    processSetButton(); // Set Time Button Was pressed
  pStateSet = cStateSet; // Update previous state
 
  // check INC button;
  if (isSettingTime)
  {
    hours=hour(); // Store current hour value from clock
    minutes=minute(); // Store current minute value from clock
    seconds=second(); // Store current second value from clock
    cStateInc = digitalRead(INC_BUTTON_PIN); //Get State of the Set button
    if ( (cStateInc != pStateInc) && (cStateInc == HIGH) ) processIncButton(); // Set Time Button Was pressed
    //setTime(hours,minutes,seconds,day(),month(),year());
    //RTC.set(now());
    Serial.print (hour());Serial.print (":");Serial.print (minute());Serial.print (":");Serial.println (second());
  }
 
  // display the menu option for 5 seconds after menu button was pressed;
  if ((lastButtonTime > 0) && (millis() - lastButtonTime < 6000)) {
    return;
  }

  // return the main mode if no button was pressed for 5 seconds;
   if (isSettingTime)
  {
    // just finished setting up the time;
    isSettingTime = false;
   
  }
 
}

// =======================================================================================
// ---- Process Set Button ----
// =======================================================================================
void processSetButton()
{
  Serial.println ("Set button pressed");
  //hours=hour(); // Store current hour value from clock
  //minutes=minute(); // Store current minute value from clock
  lastButtonTime = millis();
  isSettingTime    = true;
  isSettingHours   = !isSettingHours;
  isSettingMinutes = !isSettingMinutes;
  delay (50); //Debounce

}
// ---------------------------------------------------------------------------------------
// =======================================================================================
// ---- Process Increment button ----
// =======================================================================================
void processIncButton()
{
  Serial.println ("Set button pressed");
  lastButtonTime = millis();

  if (isSettingHours)
  {
    hours++;
   if (hours > 23) hours = 0;
  }
  else
  {
    minutes++;
    if (minutes > 59) minutes = 0;
  }
  setTime(hours,minutes,seconds,day(),month(),year());
  RTC.set(now());
  delay (50);
}
Xronos Clock - A talking arduino based alarm clock is now available. Check out xronosclock.com for pictures, source code, schematics, and purchasing info :)

bratan

Anyway I figured it out!  Thank you PaulS for your input, good info!  I now learned how to control Press/Release states of the button. Unfortunate it has nothing to do the problems I had. Issue was basically that I'm getting current second and storing it in variable, then changing time and writing this variable back to RTC chip. If whole process happens faster than second, seconds value never changes!
So I created a way to keep track of seconds with millis() function.  Now if it's been more than 1 second, I "artificially" increment "seconds" var :)
It's still not 100% precise, as I will increment seconds if I wait some time between presses of the "Set" and "Incr" buttons, but it should not be more than 5 seconds (because of timeout) in most cases. I can live with that! :)
Code: [Select]
#include <Wire.h>
#include <Time.h> 
#include <DS1307RTC.h>  // a basic DS1307 library that returns time as a time_t
#define BOUNCE_TIME_BUTTON  500   // bounce time in ms for the menu button;
boolean isSettingTime = false;
boolean isSettingHours   = false;
boolean isSettingMinutes = false;
byte SET_BUTTON_PIN=A3;// "set time" button
byte INC_BUTTON_PIN=A2;// "inc time" button
byte hours;
byte minutes;
byte seconds;
int pSeconds;
volatile unsigned long lastButtonTime = 0;// last time a button was pushed; used for debouncing;
volatile unsigned long last_ms = 0;// last time a button was pushed; used for debouncing;
int cStateSet = LOW; // Current state of Set Button
int pStateSet = LOW; // Previous state of Set Button
int cStateInc = LOW; // Current state of inc Button
int pStateInc = LOW; // Previous state of inc Button


void setup() {
  Serial.begin(9600);
  setSyncProvider(RTC.get);   // the function to get the time from the RTC
  if(timeStatus()!= timeSet)
     Serial.println("Unable to sync with the RTC");
  else
     Serial.println("RTC has set the system time"); 
  Serial.print (month());Serial.print(", "); Serial.println (day());
  Serial.print (hour());Serial.print (":");Serial.print (minute());Serial.print (":");Serial.println (second());
}

void loop() {
  buttonProc();
}

// =======================================================================================
// ---- Check button input and act upon it ----
// =======================================================================================
void buttonProc(){
  // check SET button;
  cStateSet = digitalRead(SET_BUTTON_PIN); //Get State of the Set button
  if ( (cStateSet != pStateSet) && (cStateSet == HIGH) )
    processSetButton(); // Set Time Button Was pressed
  pStateSet = cStateSet; // Update previous state
 
  // check INC button;
  if (isSettingTime)
  {
    hours=hour(); // Store current hour value from clock
    minutes=minute(); // Store current minute value from clock
    seconds=second(); // Store current second value from clock
    cStateInc = digitalRead(INC_BUTTON_PIN); //Get State of the Set button
    if ( (cStateInc != pStateInc) && (cStateInc == HIGH) ) processIncButton(); // Set Time Button Was pressed
    //setTime(hours,minutes,seconds,day(),month(),year());
    //RTC.set(now());
    //Serial.print (hour());Serial.print (":");Serial.print (minute());Serial.print (":");Serial.println (second());
    Serial.println (second());
  }
 
  // display the menu option for 5 seconds after menu button was pressed;
  if ((lastButtonTime > 0) && (millis() - lastButtonTime < 6000)) {
    return;
  }

  // return the main mode if no button was pressed for 5 seconds;
   if (isSettingTime)
  {
    // just finished setting up the time;
    isSettingTime = false;
   
  }
 
}

// =======================================================================================
// ---- Process Set Button ----
// =======================================================================================
void processSetButton()
{
  Serial.println ("Set button pressed");
  hours=hour(); // Store current hour value from clock
  minutes=minute(); // Store current minute value from clock
  seconds=second();
  lastButtonTime = millis();
    last_ms=millis();
  isSettingTime    = true;
  isSettingHours   = !isSettingHours;
  isSettingMinutes = !isSettingMinutes;
  delay (150); //Debounce

}
// ---------------------------------------------------------------------------------------
// =======================================================================================
// ---- Process Increment button ----
// =======================================================================================
void processIncButton()
{
  Serial.println ("Set button pressed");
  lastButtonTime = millis();

  if (isSettingHours)
  {
    hours++;
   if (hours > 23) hours = 0;
  }
  else
  {
    minutes++;
    if (minutes > 59) minutes = 0;
  }
   // This will keep track of seconds for better time setting
      if ( millis()-last_ms > 1000) {
        Serial.println("Overflow!");
        seconds++;
                if (seconds >59) {
          seconds=0;
          minutes++;
        }
        if (minutes > 59) {
            minutes=0;
       }
        if (hours > 23) {
          hours=0;
        }
      last_ms=millis();   
      }
  setTime(hours,minutes,seconds,day(),month(),year());
  RTC.set(now());
  delay (150);
}
Xronos Clock - A talking arduino based alarm clock is now available. Check out xronosclock.com for pictures, source code, schematics, and purchasing info :)

Go Up