replacing the crystal with a TCXO

Does anybody know if I could unsolder the crystal and replace it with a more stable TCXO like this one:

see attachment

it looks physically possible with a leftover pin connected to the 3.3V supply, would it work?
Thanks, p.-

EBAY TCXO.pdf (1.02 MB)

You can remove the ceramic resonator and related components and connect the TCXO to the external clock input - see the data sheets for details.

pepic:
Does anybody know if I could unsolder the crystal and replace it with a more stable TCXO like this one:

TCXO 16MHz 16.000M Temperature Compensated Crystal Oscillator DIP-14 OSC | eBay

see attachment

it looks physically possible with a leftover pin connected to the 3.3V supply, would it work?
Thanks, p.-

How can anyone possibly answer your question ???????

Replace which crystal on what ?

20 USD for a single oscillator? That's a very expensive part.
What are you planning to use it for? What application requires this precision?

I need to measure, with arduino limit precision, the separation and length of a succession of pulses to determine the properties of a precision pendulum clock, in particular the relationship between the clock period and the amplitude of the swing.
The pendulum motion is detected by a photo-interrupt sensor which intercepts the pendulum bob lower tip, shaped as a 4 mm cylinder.
The amplitude of the swing is deduced from the length of the pulse, of the order of 20 ms, inversely proportional to the max speed, itself proportional to the max angular swing.
The period, order of 2 s, is just the distance between the rising, or falling edge, of two photointerrupt pulses.
I developed a code, included, which makes use of both UNO interrupt inputs connected to the same photodetector output signal.
the question is: could one use a single interrupt arduino input instead of two?

PERIOD_and_DelT.ino (1011 Bytes)

The most precise approach to time pulses is to not use interrupts at all, and instead use Timer1 in the Input Capture mode, clocked at 16 MHz.

The overall accuracy will depend on the accuracy of the resonator or crystal in your Arduino, which can be calibrated to the GPS satellite system, if you are interested.

Excellent timer tutorial. Scroll down for Input Capture.

To measure a pendulum clock period (±4μs), the pendulum top speed (.01%), I assembled a very simple (~10$) but effective Arduino based timer.
2 hardware components:

  1. ARDUINO LEONARDO PRO MICRO - the arduino processor has to be a ATmega32U4, UNO is not suitable, the clock needs to be a quartz clock not a ceramic clock for accuracy
  2. PHOTOINTERRUPT DETECTOR + PHOTOINTERRUPTER BOARD to get a TTL signal out which interfaces with the Arduino interrupts
    I wrote a very simple sketch (attached) which works but occasionally misses a micros step, 4 micro s. why? Do you see any problem in my attached program? Any way to make it sturdier and more dependable
//////////////////////////////////////////////////////////////////////////////////////
/*
ARDUINO PROMICRO LEONARDO
measures the period and the optocoupler transit time (delT)
plug the photointerrupt TTL output to interrupt pin 0 & 1
*/
const byte perPin = 0;//interrupt pin assignement
const byte deltPin = 1;
unsigned long perms=0;//time variables declaration
unsigned long perms_1=0;
unsigned long period=0;
unsigned long deltms=0;
unsigned long deltms_1=0;
unsigned long delT=0;
volatile byte state = LOW;

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

 pinMode(perPin, INPUT_PULLUP);
 pinMode(deltPin, INPUT_PULLUP);
 
 attachInterrupt(digitalPinToInterrupt(perPin), perRead, RISING);
 attachInterrupt(digitalPinToInterrupt(deltPin), deltRead, FALLING);
 
 }

void loop(void)
{  
if(state==HIGH){

 period=perms-perms_1;
   //logfile.print(period);logfile.print(", ");
   Serial.print(period);Serial.print(", ");
 
 delT=deltms-deltms_1;
   //logfile.print(delT);logfile.print(", ");
   Serial.println(delT);

 state=LOW;
}
delay(900);// at 1500 it was missing recordings
}
 void perRead() {
 perms_1=perms;
 perms=micros();
}
 void deltRead() {
 deltms_1=perms;
 deltms=micros();
 state = !state;
}

////////////////////////////////////////////////////////////////////////////////////

The typical input is a 1 Hz, 20 ms long pulse.
The typical output is as follows

00:57:06.391 -> 1000000, 20000
00:57:07.237 -> 1000000, 20004
00:57:08.870 -> 1000000, 20000
00:57:09.720 -> 1000004, 19996
00:57:10.562 -> 999996, 20000
00:57:11.379 -> 1000000, 20000
00:57:13.023 -> 1000000, 20004
00:57:13.846 -> 1000000, 20000
00:57:14.709 -> 1000000, 20000
00:57:15.539 -> 1000000, 20000

Thanks, pepi

Moderator edit:
</mark> <mark>[code]</mark> <mark>

</mark> <mark>[/code]</mark> <mark>
tags added.



LEO_DELT.ino (1.12 KB)

Arduino Leonardo are truly quartzed, the PRO MICRO version is also very small. Would it be feasible to enclose the Arduino PCB inside a thermally insulated box and use some of the computing power of this board to control the temperature of the box and hence also of the crystal? Would the result be a true TCXO?
Would this be a practical way to improve on the stability of the clock? I would like to build a timer for pendulum precision clocks and the quartz as it is might not be stable enough in the long period. Does anybody see a way to improve also the resolution of a timer built on this processor? Do the higher frequency clocked Arduinos allow for a better resolution than the 4 micro s of the everyday micros() function? Arduino Nano 33 BLE ?
Thanks, pepi

Depending on your application, you could look at the DS323x RTC chips.
They are temperature compensated, and have an oscillator output if that suits your application.
They’re pretty good for stability.

You may have incremental timing issues adding up at a periodic rate.

I'd not use delay(), instead use Using millis() for timing. A beginners guide - Introductory Tutorials - Arduino Forum.

You can use micros() or millis() to get start time and end times of your code. Knowing the time it takes to run the code you can adjust, in code, the 'delay' time to be more precise.

Next you might want to see what is your opto-coupler response time, you might want to look for faster opto's.

If you want higher precision, use the Input Capture Register of Timer 1. That will give you times in 16ths of a microsecond:

// Measures the HIGH width, LOW width, frequency and duty-cycle of a pulse train
// on Arduino UNO Pin 8 (ICP1 pin).


// Note: Since this uses Timer1, UNO Pin 9 and UNO Pin 10 can't be used for
// analogWrite().


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


  // For testing on an UNO, uncomment one of these lines and connect
  // Pin 3 or Pin 5 to Pin 8
  // analogWrite(3, 64);  // 512.00, 1528.00, 2040.00, 25.10%, 490.20 Hz
  // analogWrite(5, 64);  // 260.00, 764.00, 1024.00, 25.39%, 976.56 Hz


  noInterrupts ();  // protected code
  // reset Timer 1
  TCCR1A = 0;
  TCCR1B = 0;
  TCNT1 = 0;
  TIMSK1 = 0;


  TIFR1 |= (1 << ICF1); // clear Input Capture Flag so we don't get a bogus interrupt
  TIFR1 |= (1 << TOV1); // clear Overflow Flag so we don't get a bogus interrupt


  TCCR1B = _BV(CS10) | // start Timer 1, no prescaler
           _BV(ICES1); // Input Capture Edge Select (1=Rising, 0=Falling)


  TIMSK1 |= _BV(ICIE1); // Enable Timer 1 Input Capture Interrupt
  TIMSK1 |= _BV(TOIE1); // Enable Timer 1 Overflow Interrupt
  interrupts ();
}


volatile uint32_t PulseHighTime = 0;
volatile uint32_t PulseLowTime = 0;
volatile uint16_t Overflows = 0;


ISR(TIMER1_OVF_vect)
{
  Overflows++;
}


ISR(TIMER1_CAPT_vect)
{
  static uint32_t firstRisingEdgeTime = 0;
  static uint32_t fallingEdgeTime = 0;
  static uint32_t secondRisingEdgeTime = 0;


  uint16_t overflows = Overflows;


  // If an overflow happened but has not been handled yet
  // and the timer count was close to zero, count the
  // overflow as part of this time.
  if ((TIFR1 & _BV(TOV1)) && (ICR1 < 1024))
    overflows++;


  if (PulseLowTime == 0)
  {
    if (TCCR1B & _BV(ICES1))
    {
      // Interrupted on Rising Edge
      if (firstRisingEdgeTime)  // Already have the first rising edge...
      {
        // ... so this is the second rising edge, ending the low part
        // of tghe cycle.
        secondRisingEdgeTime = overflows;
        secondRisingEdgeTime = (secondRisingEdgeTime << 16) | ICR1;
        PulseLowTime = secondRisingEdgeTime - fallingEdgeTime;
        firstRisingEdgeTime = 0;
      }
      else
      {
        firstRisingEdgeTime = overflows;
        firstRisingEdgeTime = (firstRisingEdgeTime << 16) | ICR1;
        TCCR1B &= ~_BV(ICES1); // Switch to Falling Edge
      }
    }
    else
    {
      // Interrupted on Falling Edge
      fallingEdgeTime = overflows;
      fallingEdgeTime = (fallingEdgeTime << 16) | ICR1;
      TCCR1B |= _BV(ICES1); // Switch to Rising Edge
      PulseHighTime = fallingEdgeTime - firstRisingEdgeTime;
    }
  }
}


void loop()
{
  noInterrupts();
  uint32_t pulseHighTime = PulseHighTime;
  uint32_t pulseLowTime = PulseLowTime;
  interrupts();


  // If a sample has been measured
  if (pulseLowTime)
  {
    // Display the pulse length in microseconds
    Serial.print("High time (microseconds): ");
    Serial.println(pulseHighTime / 16.0, 2);
    Serial.print("Low time (microseconds): ");
    Serial.println(pulseLowTime / 16.0, 2);


    uint32_t cycleTime = pulseHighTime + pulseLowTime;
    Serial.print("Cycle time (microseconds): ");
    Serial.println(cycleTime / 16.0, 2);


    float dutyCycle = pulseHighTime / (float)cycleTime;
    Serial.print("Duty cycle (%): ");
    Serial.println(dutyCycle * 100.0, 2);


    float frequency = (float)F_CPU / cycleTime;
    Serial.print("Frequency (Hz): ");
    Serial.println(frequency, 2);
    Serial.println();


    delay(1000);  // Slow down output


    // Request another sample
    noInterrupts();
    PulseLowTime = 0;
    interrupts();
  }
}

Double posted under a different title - naughty!

All things clock / pendulum related merged.

@pepic, please stop cross-posting.

You could get an ARM board with clock 48MHz to 600Mhz. A 48MHz TeensyLC runs about $12 plus shipping.

responding to IDAHOWALKER I dont understand why I shousldnt use delay()
You say "its stops all activity on the Arduino until the delay is finished" isn't it exactly what I want? I want to prevent the program to respond to a spurious interrupt while I know there are no useful signals coming in. There might be abetter way of doing it though, that is a way to make the non responsive period longer, hence the time the processor is listenting to legitimate pulses shorter, any idea?

Johnwasser your suggestion is really interesting but I find very difficult to understand your program, iis there a location where I could learn about using timer1 as a counter? Simpler exercises to practice the needed information?
It’s really frustrating how hard is to find my own posts on this forum.
I understand they are under my name but how do I locate my name in the first place without locating a post?

pepic:
Johnwasser your suggestion is really interesting but I find very difficult to understand your program, iis there a location where I could learn about using timer1 as a counter?

It's a feature of Timer1 on the Arduino UNO. Probably also available on every other AVR processor. Look at the datasheet for the ATmega328P processor for details. It's fairly simple: You turn on "Input Capture" by setting a bit in a register. This will load the current timer value into the Input Capture Register when the Input Capture Pin changes to a specified state. The state change (Rising or Falling) is set by another bit in a register. If you enable the corresponding interrupt by setting another bit you will get an interrupt every time the ICR has a new value. Because the register gets loaded by hardware it doesn't matter much how long it takes you to service the interrupt and read the register.

Enabling the timer overflow interrupt allows you to keep 32-bit timer values.

pepic:
It's really frustrating how hard is to find my own posts on this forum.

Click on your username anywhere in the forums. Then click the "Show Posts" link on the left. The "Messages" tab will show you every reply you ever posted in reverse chronological order. The "Posts" tab will show you every topic you ever created.

Johnwasser your program works really well but when I try to use it on a leonardo board it doesn’t any more. I tried to conside the differences between the two boards but I didn’t find the issue, thanks, p.-

I used Google to find a pinout diagram of the Leonardo and it says that the ICP1 function is on Pin 4 9not Pin 8 like on the UNO). Move your signal to Pin 4 and see if that works.

The Leonardo also has an ICP3 pin (Pin 13) so you could probably use that by changing over to Timer3.

Fantastic, at Pin 4 it worked immediately. Thank you very much Johnwasser excellent help. Where should I go for a novice, 72 years old, intro about timers? Incidentally my arduino project has been very successful, it allowed me to experiment with a precision pendulum clock at a level I would have never dreamt before. Here an incomplete web page of my measurements
https://sites.google.com/s/1ZHKM-ebTNo_Pj-PY2Vm0a2aI9H7lffr7/p/1uz1DPdYI6brbn3zNRAnm7-cB_ieyUTDK/edit
I would love to add a TCXO quartz to my arduino (I imagine Leonardo since it's already quatzed as opposed to a UNO). It's easy and inexpensive to buy such a quartz with the right freq, 16 MHz, and dimensions 3.5 x 2.5 mm, see for example ASTX-H11-16.000MHZ-T ABRACON | Mouser Europe, but they are all 3.3 V instead of 5V.
Does anybody know if they are compatible Voltage wise? It doesn't look too difficult to replace the original by soldering the new one. Any other arduino solution?
Greetings from Venice, Italy, in between a flood and a coronavirus outbreak.