Jump to content

Banner.jpg.b83b14cd4142fe10848741bb2a14c66b.jpg

DIY Moon Phase Dial


Gina

Recommended Posts

For adjusting the time there are 3 controls :-

  1. M+  Go forward in minutes
  2. M-   Go backwards in minutes
  3. Sw  If changed go forward or backwards one hour

These are two mechanical push buttons and one switch fed to 3 analogue inputs via an RC circuit to remove switch bounce.  Each analogue input is read producing a numerical value of 0-1023.  The ON state can be anything over two thirds ie. 682 and the OFF state anything below 341.  This will ensure the control state is never in doubt.

To cover the switch change a flag is needed to hold the previous switch state (ON or OFF).  An if statement will test if the new switch state is different from the flagged previous state and if different the current switch state will determine whether the hour wants advancing or retarding and the switch flag is set to the new state.

Link to comment
Share on other sites

  • Replies 1.1k
  • Created
  • Last Reply

As mentioned earlier, a flag is needed to remember the mode from last time viz. is the clock being adjusted or not.  If it is and there is minute change, a counter is incremented and used to check if the button is still pressed after a timeout period (about a second) further code will be applied accordingly (I'll go into that later).  If OTOH it's during an hour change a flag is tested to see if this process has finished.  If not the interrupt flag remains set otherwise the interrupt flag is cleared.  Then the interrupt flah itself is tested and if clear normal clock operation resumes.

PHEW...  I think my brain battery has run down...

Link to comment
Share on other sites

I'm not sure I can get my brain round all of this at the same time.  I think I'll leave the GMT/BST switch for now and just do the miniute adjust bits.  In fact I think I need to build the hardware first and check that the clock runs correctly from the interrupts when changed to the new higher rate.

Link to comment
Share on other sites

I've made up the new clock driver unit - well most of it.  I have yet to connect the RGB LED strip and the wires to the LED in the moon.  The sketch just runs the minutes stepper from the timer interrupt set to 156,250 μs and sending one step for each interrupt - I haven't added the seconds stepper motor drive code yet.  I am now running the clock to see if it's working right.  So far the minute hand seems to be turning at about the right rate but I'll know better in the morning when it's had a night's run.

56afcd6869297_ArduinoNanoDriveUnit01.thu

Link to comment
Share on other sites

Gosh Gina I see what you mean about the timing control being complicated.  There is no way I could get my mechanical head around the nuances of what you described above.  In retrospect, would using the radio time chip thing you mentioned previously not have taken care of all of this, or would that have just added further complexity?

 

Jim

Link to comment
Share on other sites

I'm not sure how much more complicated it would be to use the RTC or radio time data receiver but the timing principles would be similar I think.  It would have the advantage that everything could be automatic though, with suitable code.  As I see it, the clock would run off the internal timer interrupt most of the time and then at say 2am, read the RTC and apply correction as required.  One extra complication is that the Arduino would need to know where the hands are.  In my earlier radio controlled clock design I had magnets and hall effect devices detecting when the hands were at a particular position.  Alternatively, optical sensors could be used.

I might have another look at what's involved in using radio control or maybe just the Real Time Clock chip though I don't think the latter handles the BST problem.

Link to comment
Share on other sites

Looks like I need to check my calculations again - the clock is a long way out :(  It's showing 11:15 and the time is 9:50 - that's about one and a half hours fast over about 10 hours or around 15% too fast :Envy::icon_scratch:

Link to comment
Share on other sites

I've checked up on which RTC unit I have for the clock and it's a DS3231 with battery backup.  Accuracy is quoted as within ±2 minutes per year which is good enough for me.  It doesn't change time for BST/DST so I would either have to add a manual time change or work out how to use the radio time data receiver.  For manual time change I could use computer and USB connection.  That would set the RTC date/time to computer date/time and not only switch to BST or back but correct any time error.

Quote
The DS3231 is a serial RTC driven by a temperature-
compensated 32kHz crystal oscillator. The TCXO provides
a stable and accurate reference clock, and maintains the
RTC to within ±2 minutes per year accuracy from -40°C
to +85°C. The TCXO frequency output is available at the
32kHz pin. The RTC is a low-power clock/calendar with
two programmable time-of-day alarms and a programmable
square-wave output. The INT/SQW provides either an
interrupt signal due to alarm conditions or a square-wave
output. The clock/calendar provides seconds, minutes,
hours, day, date, month, and year information. The date at
the end of the month is automatically adjusted for months
with fewer than 31 days, including corrections for leap
year. The clock operates in either the 24-hour or 12-hour
format with an AM/PM indicator. The internal registers are
accessible though an I2C bus interface. A temperature
compensated voltage reference and comparator circuit
monitors the level of VCC to detect power failures and to
automatically switch to the backup supply when necessary

 

Link to comment
Share on other sites

I think the clocks change from GMT to/from BST always at the same time each year - the last Sunday in March & October at 2am. I could be wrong but I remember reading it somewhere. That should be easy enough to work out from the current date.

According to Wikipedia: https://en.wikipedia.org/wiki/Daylight_saving_time_by_country

Link to comment
Share on other sites

Thanks Dave :)  Yes, that's a good idea :)

I think I would prefer not to mess with the TCD receiver both to give me less to do and because radio reception can be a problem - sometimes my commercial radio controlled clocks fail to update correctly.  If I were using a less accurate RTC unit it would be worthwhile.  Checking the date and day should be pretty trivial. 

I have another use for the RTC as well as accurate clock timing - I plan to add a calendar below the present clock as mentioned earlier.  Whether everything could be handled by one Arduino Nano I rather doubt but I'll have to see.  Maybe two Nanos or one Mega.  But in any event, one control unit will drive both clock and calendar.

I need to study the DS3231 datasheet but it looks like I could use it to provide an external interrupt for clock timing :)

Link to comment
Share on other sites

I have found some info on setting the registers in the RTC HERE so I should be able to do something.  The default setting is to use the interrupt output for one or other of the time-of-day alarms, which are OFF by default.  Clearing a bit in one of the registers sets the interrupt to a square wave.  Now to see what frequency or period I can set this to.

Link to comment
Share on other sites

Now to look at the timing...  The intermediate wheel to minute wheel ratio is 6:1 and the stepper motor to intermediate wheel is 16:30.  Stepper motor does 2048 steps per revolution.  So one revolution of the intermediate wheel takes 2048 x 30 / 16 = 3840 and one revolution of the minute wheel = 3840 x 6 = 23040.  That's for one hour so for one second that's 23040 / 3600 = 6.4 steps.  Hmmm...  Needs a whole number.  Three options :-

  1. Update minutes every 5s with 32 steps.
  2. Try other interrupt frequencies viz. 1.024 Hz, 2.048 Hz or 8.192 Hz. 
  3. Change the gearing.

I guess a minutes advance every 5s might be alright.  I can change the current clock sketch to try it with the internal timer set to 1s.  If that seems alright I can set the RTC to provide a 1Hz square wave and connect it to one of the Arduino external interrupts.  Since the external interrupt needs to be on either D2 or D3 I shall need to change the wiring for the first stepper driver.

 

Link to comment
Share on other sites

I've set the timer to 5,000,000 μs = 5s and the step count per interrupt to 32.  It seems to be fine :(  Been running for 10m now.  Of course I shall want to use 1Hz for the interrupt from the RTC so I'll count 5 interrupts for each burst of steps.  The seconds can be driven from the same interrupt by sending 64 steps each interrupt.

Here's the sketch.

// Filename :- Moon_Clock_04 - 2016-02-02 1730
// Arduino test sketch v04 for moon clock
// Code included to turn stepper off between ticks
// Timing uses timer interrupt (Timer1)
//
#include <TimerOne.h>
int motorPins[] = {2, 3, 4, 5};  // motor pins for the stepper
int stepSize = 32;  // how many motor steps correspond to one second
int count = 0;
int mask = 0; //  binary mask for motor pins to select phase
//
void setup() {
  for (count = 0; count < 4; count++) {
    pinMode(motorPins[count], OUTPUT);  // set the motor pins for output
  }
  Timer1.initialize(5000000); // set a timer of length 5,000,000 microseconds = 5s
  Timer1.attachInterrupt( timerIsr ); // attach the interrupt service routine here
}
//
void moveForward() {  //  move one stepper motor phase forwards
  if ((mask == 0) || (mask == 1)) {
    mask = 16;  // set/reset phase mask  10000
  }
  mask>>=1;  // binary shift phase mask one position right  1000, 0100, 0010, 0001                                      
  for (count = 3; count >= 0; count--) {
    digitalWrite(motorPins[3 - count], mask>>count&0x01);  // 
  }
  delay(150);
}
//
void moveBackward() {  //  move one stepper motor phase backwards - for use later for time correction
  if ((mask == 0) || (mask == 1)) {
    mask = 16;
  }
  mask>>=1;
  for (count = 3; count >= 0; count--) {
    digitalWrite(motorPins[count], mask>>count&0x01);
  }
}
//
void timerIsr() {  //  Ths was previously the loop - now called by the interrupt
  int c = 0;
  for (c = 0; c < stepSize; c++) {
    moveForward();
  }
//  Disable all motor pins to turn current off 
//  mask is not touched and phase shift continues where it left off on next tick
  for (count = 3; count >= 0; count--) {
    digitalWrite(motorPins[count], 0);  
  } 
}
//
void loop()
{
  // Main code loop
  // TODO: Put regular (non-ISR) logic here
}

// End

 

Link to comment
Share on other sites

Sketch modified to add drive for second stepper motor which drives the second hand.  This used 64 steps every second.  The minutes drive wants 32 steps every 5s so 5 interrupts are counted for each burst of 32 steps to the minutes motor.  This is still using the internal Timer1 to produce the interrupts and this is set to 1s.

// Filename :- Moon_Clock_05 - 2016-02-02 2200
// Arduino test sketch v05 for moon clock
// Code included to turn stepper off between ticks
// Timing uses timer interrupt (Timer1)
// Second stepper motor drive added to drive seconds hand. 
// Minutes driven every 5 interrupts (5s) on first stepper motor.
//
#include <TimerOne.h>
int motorPins[] = {2, 3, 4, 5};  // motor pins for the minutes stepper
int motorPins2[] = {6, 7, 8, 10};  // motor pins for the seconds stepper
int stepSize = 32;  // motor steps for minutes
int stepSize2 = 64;  // motor steps for seconds
int count = 0;
int mask = 0; //  binary mask for motor pins to select phase
int mask2 = 0; //  binary mask for motor pins to select phase
int intCount = 0; // Count interrupts for minutes stepper
//
void setup() {
  for (count = 0; count < 4; count++) {
    pinMode(motorPins[count], OUTPUT);  // set the motor pins for output
    pinMode(motorPins2[count], OUTPUT);  // set the motor pins for output
  }
  Timer1.initialize(1000000); // set a timer of length 1,000,000 microseconds = 1s
  Timer1.attachInterrupt( timerIsr ); // attach the interrupt service routine here
}
//
void moveForward() {  //  move one stepper motor phase forwards
  if ((mask == 0) || (mask == 1)) {
    mask = 16;  // set/reset phase mask  10000
  }
  mask>>=1;  // binary shift phase mask one position right  1000, 0100, 0010, 0001                                      
  for (count = 3; count >= 0; count--) {
    digitalWrite(motorPins[3 - count], mask>>count&0x01);  // 
  }
  delay(150);
}
//
void moveForwardSecs() {  //  move one stepper motor phase forwards
  if ((mask2 == 0) || (mask2 == 1)) {
    mask2 = 16;  // set/reset phase mask  10000
  }
  mask2>>=1;  // binary shift phase mask one position right  1000, 0100, 0010, 0001                                      
  for (count = 3; count >= 0; count--) {
    digitalWrite(motorPins2[3 - count], mask2>>count&0x01);  // 
  }
  delay(150);
}
//
void moveBackward() {  //  move one stepper motor phase backwards - for use later for time correction
  if ((mask == 0) || (mask == 1)) {
    mask = 16;
  }
  mask>>=1;
  for (count = 3; count >= 0; count--) {
    digitalWrite(motorPins[count], mask>>count&0x01);
  }
}
//
void timerIsr() {  //  Ths was previously the loop - now called by the interrupt
  int c = 0;
  for (c = 0; c < stepSize2; c++) {
    moveForwardSecs();
  }
  intCount ++; // Increment interrupt count
  if (intCount > 4) 
  {
    intCount = 0; 
    for (c = 0; c < stepSize; c++) 
    { moveForward(); }
  } // move minuter forward
//  Disable all motor pins to turn current off 
//  mask is not touched and phase shift continues where it left off on next tick
  for (count = 3; count >= 0; count--) {
    digitalWrite(motorPins[count], 0);  
    digitalWrite(motorPins2[count], 0);  
  } 
}
//
void loop()
{
  // Main code loop
  // TODO: Put regular (non-ISR) logic here
}

// End

 

Link to comment
Share on other sites

After a touch of debugging the sketch is working fine and seems to be keeping time.  Because the hour hand is keyed to its drive tube I have stopped the clock and will restart it when the real time is what the clock says.  ATM that's the only way I have of getting the clock to show the right time :D  Only 10m to go :) 

Link to comment
Share on other sites

Been looking at auto detecting the position of the hands for setting the time.  For detecting the minute, I think a reflective optical sensor behind the minute wheel attached to the frame and either a reflecting foil spot or a black spot on the minute wheel and for the hour a magnet on the back of the hour hand and a hall effect device on the frame detecting when the hour is at 3 o'clock.  There's too much in the way at 12 o'clock.  The wires can go down the frame and out the back to the electronics box.

Link to comment
Share on other sites

Clock has been running overnight on the Arduino internal timer and it's 5m slow.  Seems to me that the sketch and gearing are right but the crystal is nowhere near accurate enough for clock use.  A correction could be applied to the number of microseconds between interrupts to improve timekeeping but the very accurate, temperature compensated crystal oscillator in the RTC is clearly the best solution.

Link to comment
Share on other sites

Whilst using the RTC is the ideal and will be the final solution, this will take some time to set up, both regarding the sketch and physical construction.  The current unit doesn't lend itself to adding the RTC module as the stripboard is too small and cramped, so I shall build a new unit.  Meanwhile, I'll look at the temporary alternative of using the internal Timer1.  The clock can be regulated by adjusting the interrupt timing, which can be set to one part in a million.

Looking at the arithmetic, one million minutes is 1,000,000 / 60 hours or 1,000,000 / (60 x 24) days = 694.4 days or nearly two years.  That accuracy is quite adequate but the crystal oscillator is temperature sensitive and liable to frequency drift.  I could play with adjusting Timer1 taking the error in timekeeping as a start and applying this correction.  I could repeat the operation after a further period, getting the timekeeping better and better until frequency drift is the limiting factor.  I can do this by updating the sketch and re-uploading.

Taking the current clock time of 10 minutes slow after running for 12 hours, that's 10 minutes in 720m or 1 in 72 = 1.389%  Thus the interrupt time want to be 1.4% less to speed up the clock = 986111 μs

Link to comment
Share on other sites

That's strange - three quarters of my post above has disappeared :(   Can't be bothered to post it again...

Anyway, time to sum up what needs doing on this project, I think.  The timekeeping correction was a bit out and it's now gaining a bit but that's by the way really.  I don't intend to use this method in the end but...

Here is a list of jobs - not necessarily in any particular order :-

  1. Sort out the code for setting the RTC registers.
  2. Build new circuit including Arduino Nano, RTC module, 2 stepper driver chips and a few odd discrete components.
  3. Experiment with optical sensor and hall effect device to determine best way to use these and find a suitable resistor to convert phototransistor current to voltage to feed an analogue input.
  4. Add the hand sensors to the clock.
  5. Make the curved top for the case to shield the moon globe from light.
  6. Fit clock in case and arrange the RGB LED strip lighting.

I have a sneeking suspicion that this list is not exhaustive :icon_scratch:  I may well have fogotten something.  There is also the addition of the calendar unit beneath the main clock case.  This will want controlling from the RTC so I'm wondering if I ought to consider this rather than just pushing ahead with the new clock circuit knowing that this will want re-building before long.  I'm afraid it looks like this clock will not be finished any day soon :(  So It becomes a question of what order I do things in.  I can get the clock working and maybe even usable by fiddling with the internal timer and add accurate timekeeping a bit later.

One thing I want to avoid is getting bogged down in this project so I think I'll just use the internal timer for now and sort out some of the mechanical stuff as light relief from the mind-boggling coding and circuit layout design :D

Link to comment
Share on other sites

Archived

This topic is now archived and is closed to further replies.

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue. By using this site, you agree to our Terms of Use.