Voting resources, early voting, and poll worker information - VOTE. ... Adafruit is open and shipping.
0

Analog Meter Clock
Moderators: adafruit_support_bill, adafruit

Please be positive and constructive with your questions and comments.

Analog Meter Clock

by Ratki on Mon Jun 09, 2014 10:40 pm

I recently built an analog meter clock using a trinket and RTC circuit. The clock works great, but I do however have one issue. When I set the time on the clock it sets 4 to 5 minutes ahead of the clock on my computer. I know this because the "minute" needle deflects back to zero and the "hour" needle jumps ahead an hour about 4 minutes before the computer changes to the new hour. So it's not that my scales are placed improperly/misaligned and its just reading wrong, it is actually set fast. Any ideas on how this can be happening? This is the second clock that I have built and did not have this issue with the first one. I can post the code I am using if necessary. Thanks.

Ratki
 
Posts: 20
Joined: Mon Jun 09, 2014 10:28 pm

Re: Analog Meter Clock

by adafruit_support_bill on Tue Jun 10, 2014 5:58 am

That does sound strange. Please post the code.

adafruit_support_bill
 
Posts: 78748
Joined: Sat Feb 07, 2009 10:11 am

Re: Analog Meter Clock

by Ratki on Wed Jun 11, 2014 8:57 pm

Thanks Bill,

I do not recall where I found the following code but it has worked fine in the other clock I built.
Code: Select all | TOGGLE FULL SIZE
// Adafruit Trinket analog meter clock
// Date and time functions using a DS1307 RTC connected via I2C and the TinyWireM lib

// Download these libraries from Adafruit's Github repository and install in Arduino Libraries
#include <TinyWireM.h>
#include <TinyRTClib.h>
//For debug, uncomment serial code, use a FTDI Friend with its RX pin connected to Pin 3
//   You will need a terminal program (such as freeware PuTTY for Windows) set to the
//   USB port of the FTDI friend at 9600 baud.  Uncomment out Serial commands to see what's up
//#include <SendOnlySoftwareSerial.h>  // See http://forum.arduino.cc/index.php?topic=112013.0
 
#define HOUR_PIN     1   // Hour display via PWM on Trinket GPIO #1
#define MINUTE_PIN   4   // Minute display via PWM on Trinket GPIO #4 (via Timer 1 calls)
boolean winter;          // Use to keep track if we're in Daylight Savings Time (DST) or not
 
//SendOnlySoftwareSerial Serial(3);  // Serial transmission on Trinket Pin 3
RTC_DS1307 rtc;                      // Set up real time clock

void setup () {
  pinMode(HOUR_PIN, OUTPUT);    // define PWM meter pins as outputs
  pinMode(MINUTE_PIN, OUTPUT);
  PWM4_init();                  // Set timer 1 to work PWM on Trinket Pin 4

 
  TinyWireM.begin();            // Begin I2C
  rtc.begin();                  // Begin DS1307 real time clock
  //Serial.begin(9600);           // Begin Serial Monitor at 9600 baud
  if (! rtc.isrunning()) {      // Uncomment lines below first use of clock to set time
    //Serial.println("RTC is NOT running!");
    //following line sets the RTC to the date & time this sketch was compiled
      //rtc.adjust(DateTime(__DATE__, __TIME__));
  }
     
  DateTime now = rtc.now();           // Get the RTC info
  /* This version of the code implements U.S. DST ( http://www.nist.gov/pml/div688/dst.cfm ). Since the RTC doesn't store whether it's DST or standard time, we have to initialize
     every time the clock powers up. If the clock looses power when the switch should happen or during the first hour after the fall switch has been made, this algorithm will be screwed up.
     But seriously, how likely is that? If that happens you'll have to manually reset the time just like you did the first time you powered up the clock after you built it.
     
     The next block of code checks to see if it's the time of year for standard time, which happens in winter. Hence, the flag variable is called winter. If we're in DST then it's not winter.
     To find if it's the first or second Sunday of the month we use an interesting property of the the quantity (date minus day of the week), where Sunday = 0 through Saturday = 6.
     
     Date - Day of week           Date
                                 |  1 |  2 |  3 |  4 |  5 |  6 |  7 |  8 |  9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 |...
                                 ____________________________________________________________________________________
     The first Sunday is the 1st |  1 |  1 |  1 |  1 |  1 |  1 |  1 |  8 |  8 |  8 |  8 |  8 |  8 |  8 | 15 | 15 |...
                             2nd | -5 |  2 |  2 |  2 |  2 |  2 |  2 |  2 |  9 |  9 |  9 |  9 |  9 |  9 |  9 | 16 |...
                             3rd | -4 | -4 |  3 |  3 |  3 |  3 |  3 |  3 |  3 | 10 | 10 | 10 | 10 | 10 | 10 | 10 |...
                             4th | -3 | -3 | -3 |  4 |  4 |  4 |  4 |  4 |  4 |  4 | 11 | 11 | 11 | 11 | 11 | 11 |...
                             5th | -2 | -2 | -2 | -2 |  5 |  5 |  5 |  5 |  5 |  5 |  5 | 12 | 12 | 12 | 12 | 12 |...
                             6th | -1 | -1 | -1 | -1 | -1 |  6 |  6 |  6 |  6 |  6 |  6 |  6 | 13 | 13 | 13 | 13 |...
                             7th |  0 |  0 |  0 |  0 |  0 |  0 |  7 |  7 |  7 |  7 |  7 |  7 |  7 | 14 | 14 | 14 |...
                             
      The first Sunday of the month (no matter what date it lands on) is the first time this quantity is greater than 0 and the second Sunday is the first time the quantity is greater than 7.
  */
  if((now.month()>11)||(now.month()<3)) winter = true;   // If its after November but before March DST isn't in effect. This is also winter.
  if((now.month()<11)&&(now.month()>3)) winter = false;  // If its between April and October, DST is in effect. It's also not winter.
  if(now.month()==11)                                    // In November
  {  if((now.day()-now.dayOfWeek())>0)                   // On or after the first Sunday DST is not in effect, so it's winter.
     {  winter = true;
     }
     else                                 
     {  winter = false;                                  // Otherwise, DST is in effect
     }
  }
  if((now.month()==11)&&(now.dayOfWeek()==0)&&(now.day()<8)&&(now.hour()<2)) winter = false; // But wait, on the first Sunday we set winter = true no matter what time it is. This in incorrect on the first Sunday itself before 2 AM, so this line fixes that one special case.
 
  if(now.month()==3)                                     // In March
  { if((now.day()-now.dayOfWeek())>7)                     // On or after the second Sunday DST is in effect, so it's not winter
    { winter = false;
    }
    else
    {  winter = true;                                    // Otherwise DST is not in effect
    }
  }
  if((now.month()==3)&&(now.dayOfWeek()==0)&&(now.day()>7)&&(now.day()<15)&&(now.hour()<2)) winter = true; // But on the second Sunday itself we have to be careful that it's not before 2 AM.

void loop () {
    uint8_t hourvalue, minutevalue;
    uint8_t hourvoltage, minutevoltage;
    int hour_min = 20;
    int hour_max = 251;
    int minute_min = 20;
    int minute_max = 242;
   
   
// if you have calibration issues, you can change the min and max values(zero higher, 255 lower)
// to have the needle move less if your scale is not pasted on 100% straight.
   
    DateTime now = rtc.now();                                                                          // Get the RTC info
    if((now.hour()==2)&&(now.minute()==0))                                                             // At 2 AM when the shift to and from DST is made
    { if((now.month()==3)&&((now.day()-now.dayOfWeek())>7)&&(winter==true))                            // If it is on or after the second Sunday and we haven't change the clocks yet (winter==true)
      { int new_hour = now.hour()+1;
        rtc.adjust(DateTime(now.year(),now.month(),now.day(),new_hour,now.minute(),now.second()));     // Spring forward
        winter = false;                                                                                // Make sure to only do this once
      }
      if((now.month()==11)&&(now.day()-now.dayOfWeek()>0)&&(winter==false))                            // If it is on or after the fisrt Sunday and we haven't change the clocks yet (winter==false)
      { int new_hour = now.hour()-1;
        rtc.adjust(DateTime(now.year(),now.month(),now.day(),new_hour,now.minute(),now.second()));     // Fall back
        winter = true;                                                                                 // Make sure to only do this once
      }
    }
    hourvalue = now.hour();             // Get the hour
    if(hourvalue > 12) hourvalue -= 12; // This clock is 12 hour, is 13-24, convert to 1-12
    minutevalue = now.minute();         // Get the minutes
    hourvoltage = map(hourvalue, 0, 12, hour_min, hour_max);     // Convert hour to PWM duty cycle
    minutevoltage = map(minutevalue, 0, 59, minute_min, minute_max); // Convert minutes to PWM duty cycle. Note that the minutevuale will never reach 60, so setting mapping from 0 to 59 gives you a little more room to play with the needle setting.

/*
    // Uncomment this section to calibrate the needle positions.
    hourvoltage = map(0, 0, 12, hour_min, hour_max);     // Set the zero positions
    minutevoltage = map(0, 0, 59, minute_min, minute_max);   
    analogWrite(HOUR_PIN, hourvoltage);
    analogWrite4(minutevoltage);
    delay(10000);                                        // Extra delay here to allow time to use the adjustment screw on the meter to correct the zero position
    hourvoltage = map(6, 0, 12, hour_min, hour_max);     // Set the middle positions
    minutevoltage = map(30, 0, 59, minute_min, minute_max);   
    analogWrite(HOUR_PIN, hourvoltage);
    analogWrite4(minutevoltage);
    delay(10000);
    hourvoltage = map(12, 0, 12, hour_min, hour_max);     // Set the end positions
    minutevoltage = map(59, 0, 59, minute_min, minute_max);   
    analogWrite(HOUR_PIN, hourvoltage);
    analogWrite4(minutevoltage);
    delay(10000);
    hourvoltage = map(3, 0, 12, hour_min, hour_max);     // Set one quarter positions
    minutevoltage = map(15, 0, 59, minute_min, minute_max);   
    analogWrite(HOUR_PIN, hourvoltage);
    analogWrite4(minutevoltage);
    delay(10000);
    hourvoltage = map(9, 0, 12, hour_min, hour_max);     // Set three quarter positions
    minutevoltage = map(45, 0, 59, minute_min, minute_max);   
    analogWrite(HOUR_PIN, hourvoltage);
    analogWrite4(minutevoltage);
    delay(10000);
/*
/*   
    // Uncomment out this and other serial code to check that your clock is working.
    Serial.print(now.year(), DEC);
    Serial.print('/');
    Serial.print(now.month(), DEC);
    Serial.print('/');
    Serial.print(now.day(), DEC);
    Serial.print(' ');
    Serial.print(now.hour(), DEC);
    Serial.print(':');
    Serial.print(now.minute(), DEC);
    Serial.print(':');
    Serial.print(now.second(), DEC);
    Serial.print(" - ");
    Serial.print(hourvoltage, DEC);
    Serial.print(' ');
    Serial.print(minutevoltage, DEC);
    Serial.println();
*/ 

    analogWrite(HOUR_PIN, hourvoltage);
    analogWrite4(minutevoltage);
   
    // code to put the processor to sleep might be preferable - we will delay
    delay(5000);  // check time every 5 seconds.  You can change this.

}

void PWM4_init() {
  // Set up PWM on Trinket GPIO #4 (PB4, pin 3) using Timer 1
  TCCR1 = _BV (CS10);           // no prescaler
  GTCCR = _BV (COM1B1) | _BV (PWM1B);  //  clear OC1B on compare
  OCR1B = 127;                  // duty cycle initialize to 50%
  OCR1C = 255;                  // frequency
}

// Function to allow analogWrite on Trinket GPIO #4
void analogWrite4(uint8_t duty_value) { 
  OCR1B = duty_value;  // duty may be 0 to 255 (0 to 100%)
}


The only changes that I made, that i am aware of :), were to the minimum and maximum meter movements in this section:
Code: Select all | TOGGLE FULL SIZE
void loop () {
    uint8_t hourvalue, minutevalue;
    uint8_t hourvoltage, minutevoltage;
    int hour_min = 20;
    int hour_max = 251;
    int minute_min = 20;
    int minute_max = 242;


I will upload an entirely different sketch and see if i still have the problem.

Ratki
 
Posts: 20
Joined: Mon Jun 09, 2014 10:28 pm

Re: Analog Meter Clock

by Ratki on Wed Jun 11, 2014 9:05 pm

Using the following code, it still sets about 4 minutes fast. I'm using windows 7 and the 1.5.0-r2 of the arduino environment.

Code: Select all | TOGGLE FULL SIZE
// Adafruit Trinket analog meter clock
// Date and time functions using a DS1307 RTC connected via I2C and the TinyWireM lib

// Download these libraries from Adafruit's Github repository and
//    install in your Arduino Libraries directory
#include <TinyWireM.h>
#include <TinyRTClib.h>

//For debug, uncomment serial code, use a FTDI Friend with its RX pin connected to Pin 3
//   You will need a terminal program (such as freeware PuTTY for Windows) set to the
//   USB port of the FTDI friend at 9600 baud.  Uncomment out Serial commands to see what's up
//#include <SendOnlySoftwareSerial.h>  // See http://forum.arduino.cc/index.php?topic=112013.0
 
#define HOUR_PIN     1   // Hour display via PWM on Trinket GPIO #1
#define MINUTE_PIN   4   // Minute display via PWM on Trinket GPIO #4 (via Timer 1 calls)
 
//SendOnlySoftwareSerial Serial(3);  // Serial transmission on Trinket Pin 3
RTC_DS1307 rtc;                      // Set up real time clock

void setup () {
  pinMode(HOUR_PIN, OUTPUT);    // define PWM meter pins as outputs
  pinMode(MINUTE_PIN, OUTPUT);
  PWM4_init();                  // Set timer 1 to work PWM on Trinket Pin 4
 
  TinyWireM.begin();            // Begin I2C
  rtc.begin();                  // Begin DS1307 real time clock
  //Serial.begin(9600);           // Begin Serial Monitor at 9600 baud
  if  (!rtc.isrunning()) {
    //Serial.println("RTC is NOT running!");
    // following line sets the RTC to the date & time this sketch was compiled
    //rtc.adjust(DateTime(__DATE__, __TIME__));
  }
}

void loop () {
    uint8_t hourvalue, minutevalue;
    uint8_t hourvoltage, minutevoltage;
   
    DateTime now = rtc.now();           // Get the RTC info
    hourvalue = now.hour();             // Get the hour
    if(hourvalue > 12) hourvalue -= 12; // This clock is 12 hour, is 13-24, convert to 1-12
    minutevalue = now.minute();         // Get the minutes
// if you have calibration issues, you can change the last two values (zero higher, 255 lower)
// to have the needle move less if your scale is not pasted on 100% straight.
    hourvoltage = map(hourvalue, 0, 12, 20,251);     // Convert hour to PWM duty cycle
    minutevoltage = map(minutevalue, 0, 60, 20, 242); // Convert minutes to PWM duty cycle
/*   
    // Uncomment out this and other serial code to check that your clock is working.
    Serial.print(now.year(), DEC);
    Serial.print('/');
    Serial.print(now.month(), DEC);
    Serial.print('/');
    Serial.print(now.day(), DEC);
    Serial.print(' ');
    Serial.print(now.hour(), DEC);
    Serial.print(':');
    Serial.print(now.minute(), DEC);
    Serial.print(':');
    Serial.print(now.second(), DEC);
    Serial.print(" - ");
    Serial.print(hourvoltage, DEC);
    Serial.print(' ');
    Serial.print(minutevoltage, DEC);
    Serial.println();
*/ 
    analogWrite(HOUR_PIN, hourvoltage);
    analogWrite4(minutevoltage);
   
    // code to put the processor to sleep might be preferable - we will delay
    delay(5000);  // check time every 5 seconds.  You can change this.
}

void PWM4_init() {
  // Set up PWM on Trinket GPIO #4 (PB4, pin 3) using Timer 1
  TCCR1 = _BV (CS10);           // no prescaler
  GTCCR = _BV (COM1B1) | _BV (PWM1B);  //  clear OC1B on compare
  OCR1B = 127;                  // duty cycle initialize to 50%
  OCR1C = 255;                  // frequency
}

// Function to allow analogWrite on Trinket GPIO #4
void analogWrite4(uint8_t duty_value) { 
  OCR1B = duty_value;  // duty may be 0 to 255 (0 to 100%)
}

Ratki
 
Posts: 20
Joined: Mon Jun 09, 2014 10:28 pm

Re: Analog Meter Clock

by adafruit_support_bill on Thu Jun 12, 2014 5:43 am

Code: Select all | TOGGLE FULL SIZE
  if  (!rtc.isrunning()) {
    //Serial.println("RTC is NOT running!");
    // following line sets the RTC to the date & time this sketch was compiled
    //rtc.adjust(DateTime(__DATE__, __TIME__));
  }

That code will never set the RTC from your computer clock, since the rtc.adjust call is commented out. To always set the time, eliminate the 'if' and just use this code:

Code: Select all | TOGGLE FULL SIZE
    rtc.adjust(DateTime(__DATE__, __TIME__));

adafruit_support_bill
 
Posts: 78748
Joined: Sat Feb 07, 2009 10:11 am

Re: Analog Meter Clock

by Ratki on Thu Jun 12, 2014 8:20 pm

I would un-comment out the rtc.adjust call and it would set the time. Not sure why it would be fast. I did however remove the "if (!rtc.isrunning ())" line and the sketch compiles, loads and is the correct time, no longer fast. This is all very new to me so I was using the sketches as I found them. It still does not make since to me why removing that line would make this difference. Strange. Out of curiosity I put the "if" statement back in, loaded it again and it stayed at the correct time. The four minutes fast issue appears to be resolved. I did no other changes to the clock, wiring or meter scales. I really appreciate your time and help. If you can find the time, could you elaborate on why the "if" statement would be included in the code in the first place if it works fine without it? Again, this coding is all very new to me and I am trying to grasp all I can. Thanks again.

Would it be ok to post a couple of pics of the clocks in the clock photo thread? I browsed through but didn't see any analog meter clock pictures and didn't know if that was the right place.

Ratki
 
Posts: 20
Joined: Mon Jun 09, 2014 10:28 pm

Re: Analog Meter Clock

by adafruit_support_bill on Thu Jun 12, 2014 10:02 pm

Feel free to post your photos. We like to see customer projects.

The 'if' statement checks to see if the RTC clock is already running and only updates if it is not. I suspect that one of the clocks drifted a bit after the first upload. Both PC clocks and the DS1307 do have a tendency to drift. If they are drifting in opposite directions, that could explain the time difference.

adafruit_support_bill
 
Posts: 78748
Joined: Sat Feb 07, 2009 10:11 am

Re: Analog Meter Clock

by Ratki on Thu Jun 12, 2014 10:06 pm

Awesome! Thank you for the response. I will post a couple of pics too.

Ratki
 
Posts: 20
Joined: Mon Jun 09, 2014 10:28 pm

Please be positive and constructive with your questions and comments.