Jump to content

Banner.jpg.b89429c566825f6ab32bcafbada449c9.jpg

DIY Moon Phase Dial


Gina

Recommended Posts

No improvement to report - nothing has changed.  The seconds stepper is not working and nor is the minutes stepper once the clock reaches set time.  Except that the clock doesn't reach set time - the hour hand Hall sensor is still not working right and the clock is stopping at any hour when it's supposed to stop at 12 o'clock:(  The amount of time advance does seem to match that required though :)

I'm wondering if I'm missing something regarding interrupts.  The minutes stepper motor is working fine when turning the hands to set 12 o'clock and then advancing by tens or hundreds of steps to set the time but only making sounds when running from the ISR, not turning at all.

Link to comment
Share on other sites

  • Replies 1.1k
  • Created
  • Last Reply

Found it! :)

Quote

Note

Inside the attached function, delay() won't work and the value returned by millis() will not increment. Serial data received while in the function may be lost. You should declare as volatile any variables that you modify within the attached function. See the section on ISRs below for more information.

I'm using delay() in the moveforward routine to lengthen the pulses fed to the stepper motors to give them time to work.

Quote

Since delay() requires interrupts to work, it will not work if called inside an ISR. micros() works initially, but will start behaving erratically after 1-2 ms. delayMicroseconds() does not use any counter, so it will work as normal.

delayMicroseconds() should be used instead of delay() when called within an ISR then.

I'll try that.

Link to comment
Share on other sites

Yesssssssssss :hello2::)  Minutes motor is working from interrupt :)  But seconds one isn't - need to look at that sometime.  Also need to sort out the hour hand Hall sensor but another step in the right direction :)

Link to comment
Share on other sites

Added a couple of extra debugging code.

Here is the Serial Monitor

56d1f7a5e89a7_TestingRTCSerialMonitor04.

The time looks a bit funny - supposed to be synchronised with the 1Hz square wave and interrupt :icon_scratch:

Link to comment
Share on other sites

I've been running a test sketch to check operation of the Hall sensors and the hour one is not working in spite of showing as alright with DMM.  I'll have to do more testing tomorrow.

Link to comment
Share on other sites

Stripped down and modified a sketch to just advance the two stepper motors and turn the internal LED on if either Hall sensor is operated.  Result is that both Hall sensors work and that the magnets on the hands are strong enough to switch the sensors on at twice the working distance :)  The minutes motor works fine as expected but the seconds motor just vibrates and gets warm but doesn't turn.

// Filename :- Moon_Clock_Testing Hall sensors and Motors 01 - 2016-02-28 1130
// Arduino test sketch for moon clock Hall Sensors and motors only.
// LED turns on if either Hall sensor activated
//
int motorPins[] = {3, 4, 5, 6};       // motor pins for the minutes stepper
int motorPins2[] = {A0, A1, A2, A3};  // motor pins for the seconds stepper
int delayTime = 2000;  //  Time between steps (μs)
int mask = 0;          //  binary mask for minutes motor pins to select phase
int mask2 = 0;         //  binary mask for seconds motor pins to select phase
//
void setup() {
  pinMode(13, OUTPUT);
  for (int i = 0; i < 4; i++) { pinMode(motorPins[i], OUTPUT); pinMode(motorPins2[i], OUTPUT);}  // set motor pins for output
}
//
void moveForward(long steps) {  //  stepper motor "steps" forwards
  for (long i = steps; i >= 0; i--) {
    if ((mask == 0) || (mask == 1)) { mask = 16;}  // set/reset phase mask
    mask>>=1;  // binary shift phase mask one position right
    for (int i = 3; i >= 0; i--) { digitalWrite(motorPins[i], mask>>i&0x01);}  // 
    delayMicroseconds(delayTime);  // Allow time for motor to step
  }
}//
void moveForwardSecs(int steps) {  //  stepper motor "steps" forwards
  for (int i = steps; i >= 0; i--) {
    if ((mask2 == 0) || (mask2 == 1)) { mask2 = 16;}  // set/reset phase mask
    mask2>>=1;  // binary shift phase mask one position right
    for (int i = 3; i >= 0; i--) { digitalWrite(motorPins2[i], mask>>i&0x01);}  // 
    delayMicroseconds(delayTime);  // Allow time for motor to step
  } }
 //
//
void loop(){
  digitalWrite(13, ((analogRead(A6) < 500) || (analogRead(A7) < 500))); // Turn on internal LED if either Hall sensor operated
  moveForwardSecs(1);  //  Run minutes motor
  moveForward(1);      //  Run seconds motor
  }
// End

 

Link to comment
Share on other sites

I can do without the seconds hand for now though I do use my current digital clock seconds for timing sometimes so I shall eventually want seconds when I remove the digital clock in preference for my new analogue one.  Also, I shall need to change the design when I get round to adding the calendar display which will run off the RTC and Arduino.

The Nano has just barely sufficient pins to run the minutes and seconds in conjunction with the RTC and Hall sensors.  The calendar will require drivers for the day-of-week, day-of-month and month - I'm not displaying the year.  I have decided on split-flap displays for size and readability.

I've thought of three options to deal with the additional data outputs :-

  1. Replace Nano with Mega which has plenty of I/O pins - may be simplest conceptually but would mean a rebuild of the circuit board.
  2. Use micro servo motors for the seconds and 3 calendar drives using ratchet drive - means a mechanical redesign of the gearbox.
  3. Share Nano outputs between the two stepper motors and three servos - currently unproven and fiddly and would also need a new circuit board.

Anyway, first job is to get the clock actually working and showing the right time albeit hours and minutes only.

Link to comment
Share on other sites

Some progress! :)  The clock went to 12 o'clock and on to 1:31pm but seemed about 10s fast compared with my digital radio controlled clock but that's another step forward :)  After that the clock kept going at apparently normal rate for a couple of minutes then stopped!  Clock is showing 1:33. Here is a screenshot of the serial monitor.

56d2f87d396ef_TestingRTCSerialMonitor05.

So hit another strange problem - clock stopped after just a couple of minutes.  Also, the time keeping appears to leave a lot to be desired.  The RTC reading is creaping ahead of the clock and yet the clock is being driven by the RTC one second timing - I can't see how that can be.  How long do I keep at this head-banging before giving up??? :BangHead:

Link to comment
Share on other sites

If any clever person would like to take a look at my sketch, here it is.  This has been copied from the sketch I have just run with no changes.

// Filename :- Moon_Clock_with_RTC_11 - 2016-02-28 1230
// Arduino test sketch for moon clock with RTC v05
// Hardware interrupt from RTC on pin 2
// LED state changes on each interrupt so should be 1s on and 1s off
// Code included to turn stepper off between ticks
// Timing uses RTC interrupt
// Second stepper motor drive added to drive seconds hand. 
// Minutes driven every 5 interrupts (5s) on first stepper motor.
//
#include <DS3232RTC.h>    //http://github.com/JChristensen/DS3232RTC
#include <Time.h>         //http://www.arduino.cc/playground/Code/Time  
#include <Wire.h>         //http://arduino.cc/en/Reference/Wire (included with Arduino IDE)
//
int timeError = 50;  //  Amount of time setting error to be corrected
boolean timeIsSet = false;
int motorPins[] = {3, 4, 5, 6};  // motor pins for the minutes stepper
int motorPins2[] = {A0, A1, A2, A3};  // motor pins for the seconds stepper
int delayTime = 2000;  //  Time between steps (μs)
int mask = 0;       //  binary mask for minutes motor pins to select phase
int mask2 = 0;      //  binary mask for seconds motor pins to select phase
int secSteps = 64;  // motor steps for seconds
int fiveCount = 0;  // Count interrupts for minutes stepper
int gbCount = 0;    // Counts 5s units for gearbox correction
long steps, h, units, extra ; // time set variables;
//
void setup() {
  Serial.begin (9600);     // Enable Serial Monitor via USB
  for (int i = 0; i < 4; i++) { pinMode(motorPins[i], OUTPUT); pinMode(motorPins2[i], OUTPUT);}  // set motor pins for output
  pinMode(2,INPUT_PULLUP);   //  Interrupt pin
  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");
  RTC.squareWave(SQWAVE_1_HZ);    // 1 Hz square wave            
  attachInterrupt(digitalPinToInterrupt(2), timerIsr, FALLING);
}
//
void moveForward(long steps) {  //  stepper motor "steps" forwards
  for (long i = steps; i >= 0; i--) {
    if ((mask == 0) || (mask == 1)) { mask = 16;}  // set/reset phase mask
    mask>>=1;  // binary shift phase mask one position right
    for (int i = 3; i >= 0; i--) { digitalWrite(motorPins[i], mask>>i&0x01);}  // 
    delayMicroseconds(delayTime);  // Allow time for motor to step
  }
}//
void moveBackward(int steps) {  //  stepper motor "steps" backwards
  for (int i = steps; i >= 0; i--) {
    if ((mask == 0) || (mask == 1)) { mask = 16;}  // set/reset phase mask
    mask>>=1;  // binary shift phase mask one position right
    for (int i = 3; i >= 0; i--) { digitalWrite(motorPins[3 - i], mask>>i&0x01);}  // 
    delayMicroseconds(delayTime);  // Allow time for motor to step
  } }
//
void moveForwardSecs(int steps) {  //  stepper motor "steps" forwards
  for (int i = steps; i >= 0; i--) {
    if ((mask2 == 0) || (mask2 == 1)) { mask2 = 16;}  // set/reset phase mask
    mask2>>=1;  // binary shift phase mask one position right
    for (int i = 3; i >= 0; i--) { digitalWrite(motorPins2[i], mask>>i&0x01);}  // 
    delayMicroseconds(delayTime);  // Allow time for motor to step
  } }
 //
   void digitalClockDisplay(void)
{
    // digital clock display of the time
    Serial.print(' ');
    Serial.print(hour());
    printDigits(minute());
    printDigits(second());
    Serial.print(' ');
    Serial.print(day());
    Serial.print(' ');
    Serial.print(month());
    Serial.print(' ');
    Serial.print(year()); 
    Serial.print(" gbCount = ");
    Serial.print(gbCount);
    Serial.println(); 
}
//
void printDigits(int digits)
{
    // utility function for digital clock display: prints preceding colon and leading 0
    Serial.print(':');
    if(digits < 10)
        Serial.print('0');
    Serial.print(digits);
}

void timerIsr() {
  if (!timeIsSet) { return; } // Ignore the interrupt and return while setting the clock
  moveForwardSecs(secSteps);
  fiveCount ++; // Increment interrupt count
  if (fiveCount > 5) { fiveCount = 0;
    gbCount ++; // Increment gearbox count
    digitalClockDisplay();
    if (gbCount < 13 ) { moveForward(16); } else { moveForward(15); gbCount = 0; Serial.println(" gearbox correction"); }
//  moveForward(100);
//  Disable all motor pins to turn current off 
  for (int i = 3; i >= 0; i--) { digitalWrite(motorPins[i], 0); digitalWrite(motorPins2[i], 0);} 
  }
}
//
void loop(){
  // Main code loop - handles time set up
  if (timeIsSet) { return; } //  break out once time is set
  Serial.print(" RTC Time is "); digitalClockDisplay();
  Serial.println(" Setting hands to 12 o'clock");
  while ((analogRead(A6) > 500) || (analogRead(A7) > 500)) { moveForward(1); } // move fast forward until 12 o'clock sensed
  moveForward(timeError);   // correct error
  h = hour(); if (h > 12) { h = h - 12; }  // convert 24hr clock to 12hr
  units = h * 720;
  units += minute() * 12;
  units += second() / 5;
  steps = units * 16;
  extra = steps / 144;
  steps = steps + extra;
  Serial.print(" Moving hands to ");
  Serial.print(h); Serial.print(":");
  Serial.print(minute()); Serial.print(" using ");
  Serial.print(steps);
  Serial.println(" steps");
  moveForward(steps);
  timeIsSet = true;
}
// End

 

Link to comment
Share on other sites

What's the matter with me?  Am I getting past it? :(  Programming was my profession in addition to electronics and computer hardware.

Interrupt programming depends on having everything finished from one interrupt before the next one arrives otherwise it can get missed.  I think I need to get these problems separated.  I can test the operation without concerning myself with the gearbox error.  ATM the clock just stops - best to get it going first and then worry about the timekeeping I think.

Link to comment
Share on other sites

Not quite a six count.  If you look at the screenshot it seems it's about a 5.5 count. 

I think you could be right about the serial.println causing problems - thank you for that :)

I know the time setting part works so I can try taking out all the serial debugging code.

Link to comment
Share on other sites

Hi Gina,

You are not alone with interrupt problems!! My problem is too many interrupts, not too few. All I am trying to do is read one channel from an optical rotary encoder. The channel output is connected to pin D12 on an Arduino Nano. So far so good and when I rotate the encoder the count increases nicely (I have to divide the count by two as I'm using a Pin Change interrupt that is triggered by both falling and rising edges). The problem is that sometimes the Nano generates interrupts without me touching the encoder and when I turn on a step motor that uses the same power supply I always get false triggering. Just EMI but it is proving very difficult to get rid of it. I have rebuilt to enclose all the step motor circuitry in a shielded enclosure, The rotary encoder is also in a shielded enclosure although the Nano that does the pulse counting isn't shielded.

What is even more irritating is that the rotary encoder is also connected to another board that is right next to the Nano and that board counts the pulses perfectly!

I have already used pull-up resistors to reduce the sensitivity to spikes but I guess I need to add yet more decoupling capacitors. 

So, what started out as a nice, simple circuit board is now up to Rev. 11 with yet more changes to come.

Good luck with your own, heroic efforts!

Regards, Hugh

Link to comment
Share on other sites

30 minutes ago, Gina said:

void moveForward(long steps) { // stepper motor "steps" forwards for (long i = steps; i >= 0; i--) { if ((mask == 0) || (mask == 1)) { mask = 16;} // set/reset phase mask mask>>=1; // binary shift phase mask one position right for (int i = 3; i >= 0; i--) { digitalWrite(motorPins, mask>>i&0x01);} // delayMicroseconds(delayTime); // Allow time for motor to step } }// void moveBackward(int steps) { // stepper motor "steps" backwards for (int i = steps; i >= 0; i--) { if ((mask == 0) || (mask == 1)) { mask = 16;} // set/reset phase mask mask>>=1; // binary shift phase mask one position right for (int i = 3; i >= 0; i--) { digitalWrite(motorPins[3 - i], mask>>i&0x01);} // delayMicroseconds(delayTime); // Allow time for motor to step } }

Hi Gina,

I'm a bit confused - you are decrementing  i, your 'steps' counter for both forward stepping and backward stepping.

Is this right?

Regards, Hugh

Link to comment
Share on other sites

The clock is running :)  So it looks like the serial comms were the problem

11 minutes ago, hughgilhespie said:

Hi Gina,

You are not alone with interrupt problems!! My problem is too many interrupts, not too few. All I am trying to do is read one channel from an optical rotary encoder. The channel output is connected to pin D12 on an Arduino Nano. So far so good and when I rotate the encoder the count increases nicely (I have to divide the count by two as I'm using a Pin Change interrupt that is triggered by both falling and rising edges). The problem is that sometimes the Nano generates interrupts without me touching the encoder and when I turn on a step motor that uses the same power supply I always get false triggering. Just EMI but it is proving very difficult to get rid of it. I have rebuilt to enclose all the step motor circuitry in a shielded enclosure, The rotary encoder is also in a shielded enclosure although the Nano that does the pulse counting isn't shielded.

What is even more irritating is that the rotary encoder is also connected to another board that is right next to the Nano and that board counts the pulses perfectly!

I have already used pull-up resistors to reduce the sensitivity to spikes but I guess I need to add yet more decoupling capacitors. 

So, what started out as a nice, simple circuit board is now up to Rev. 11 with yet more changes to come.

Good luck with your own, heroic efforts!

Regards, Hugh

Thank you Hugh :)  I feel your problem - the sort of thing that has troubled me plenty in the past :(

Link to comment
Share on other sites

7 minutes ago, hughgilhespie said:

Hi Gina,

I'm a bit confused - you are decrementing  i, your 'steps' counter for both forward stepping and backward stepping.

Is this right?

Regards, Hugh

Yes, that is right - the direction is determined a bit later in the code with - [3 - i] versus

digitalWrite(motorPins[3 - i]
Link to comment
Share on other sites

Hi Gina,

I don't understand how the clock works so I'm probably barking up the wrong tree but doesn't that fivecount go 0,1,2,3,4,5,6/0,1,2,3,4,5,6/0 so that is 6 counts per cycle not 5. Would that make the clock run slow? If it was counting clock pulses then your time would be out by a factor of 6/5

Cheers

Steve

 

Link to comment
Share on other sites

I think I'll apply my experience in getting code timings as low as possible at the expense of more code - I'm not short of space.  I think there could still be a problem with some code parts taking too long to execute.

I have run the sketch again having done some pruning and the set time is a minute fast.  I can easily correct for this in the "extra" steps that allow for the time taken to set the time.  The time to set the time seems to be about half what I have allowed so I'll up the 144 divisor to 288 and see what's what.

A bit later... Now stopping just under half a minute fast so upping the divisor to 400 and trying again.

Anda again... That's about it - within about 10s - I can do more tittivating later when there are more hours of time setting.

Link to comment
Share on other sites

Now to code time saving...  The most time consuming part is the moveForward function, the rest is just a bit of logic.

void moveForward(long steps) {  //  stepper motor "steps" forwards
  for (long i = steps; i >= 0; i--) {
    if ((mask == 0) || (mask == 1)) { mask = 16;}  // set/reset phase mask
    mask>>=1;  // binary shift phase mask one position right
    for (int i = 3; i >= 0; i--) { digitalWrite(motorPins[i], mask>>i&0x01);}  // 
    delayMicroseconds(delayTime);  // Allow time for motor to step
  }
}

I would have thought the slowest part of this was the delay of 2ms with the time to execute the code being much less.  Now the number of steps is usually 16 every 5s.  16 x 2ms = 32ms - far far less than 5s.  Actually, that should have been obvious because the stepper motor runs much faster when setting the time.  So the problem is NOT execution time and nothing can be achieved by code pruning.

I'll start trying to find where there may be a calculation error by removing the gearbox correction.  This will assume 2048 steps per revolution of the motor shaft and with 8t pinion and 45t minutes wheel the number of steps every 5s is 16.  Checking this yet again for the umpteenth time...

16x8 = 128 so 128 teeth.steps per 5s and there are 45t on the minutes wheel so we have a ratio of 128 to 5x45=225.  Minutes wheel wants to take 3600 seconds per revolution (one hour).  Now we have 128t.s in 5s so the minutes wheel takes (5x45 / 128 ) x 2048 = 3600 seconds Q.E.D.  That's for a gearbox ratio of 1:64 and ignores the correction required.

I will now remove the gearbox correction and see what we get.

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.