Turntable Digital Tachometer

Hi, I'm new and this is my first post.
I am going to acutely measure the speed of my turntable which I have just restored.
I used the code from Easy Peasy but I would have to adapt it for this new purpose.
I physically modified the two IR LEDs and placed them at 90 degrees to read the dots on the platter.
The turntable plat has 182 points.
What changes to the code should be changed?
Who helps me?

Thank You

Turntable mod:

//Easy Peasy Tachometer 2.0 (with updated library for SSD1306(128x64
#include <Adafruit_GFX.h>
#include <Adafruit_SPITFT.h>
#include <Adafruit_SPITFT_Macros.h>
#include <gfxfont.h>
#include <Adafruit_SSD1306.h>
#include <splash.h>
#include <Wire.h>
#define OLED_WIDTH 128
#define OLED_HEIGHT 64
#define OLED_ADDR 0x3C
Adafruit_SSD1306 display(128, 64);

float value = 0;
float rev = 0;
int rpm;
int oldtime = 0;
int time;
void isr()
{
  rev++;
}
void setup()
{
  display.begin(SSD1306_SWITCHCAPVCC, OLED_ADDR);
  display.clearDisplay();

  digitalWrite(HIGH, 2);
  attachInterrupt(0, isr, RISING);
}
void loop()
{
  //delay(3000);
  delay(1000);
  detachInterrupt(0);
  time = millis() - oldtime;
  rpm = (rev / time) * 60000;
  //rpm=(rev/time)*60000;
  oldtime = millis();
  rev = 0;

  display.clearDisplay();
  display.setTextSize(3);
  display.setTextColor(WHITE);
  display.setCursor(5, 20); // Vertical, Horizontal.
  display.println(rpm);
  display.setTextSize(2);
  display.setTextColor(WHITE);
  display.setCursor(15, 0);
  display.println("RPM");
  display.display();
  attachInterrupt(0, isr, RISING);
}

You're counting discrete events - why float?

Either way, the variable should be qualified "volatile" and read back in non-interrupt context with interrupts disabled - no need to detach and reattach the interrupt.

Please remember to use code tags when posting code

1 Like

I wonder why the time to manage the display shall contribute to speed calculation?
And where these 182 markers have been taking into account?

1 Like

Follow a windowing approach along with interrupt. This gives the general idea - not necessarily the correct code...

unsigned int lastMillis = 0;
unsigned int windowTimeMillis = 2000; //2 seconds - set anything from 1 to 10 seconds depending on no. of reflectors.

float numReflectors = 182; // No. of individual reflectors on the turntable.

unsigned int numPulses = 0;

void setup() {
    lastMillis = millis();
    numPulses = 0;

    //TO DO: Setup and enable interrupt pin
}

void loop() {
    unsigned int curMillis = millis();

    if(curMillis - lastMillis > windowTimeMillis) {
        //TO DO: Disable interrupt

       float revPerSec = (float)numPulses/(float)windowTimeMillis/numReflectors;

        float revPerMin = revPerSec * 60;

        //TO DO: Display revPerMin

        numPulses = 0;
        lastMillis = millis();
    } else {
        //TO DO: Enable interrupt, if disabled
    }
}

void interruptHandler() {
    numPulses++;
}
1 Like

Might be easier to make a strobe light at variable frequency and shine that at it .

2 Likes

Let's try some math.

An LP rotates at 33+1/3 RPM == 0.03 minutes per rotation == 1.8 seconds per rotation.

There are 182 dots, the expected frequency would be 182/1.8 == 101.1111111... Hz

Are you sure there are not 180 dots? That would make the dots frequency read 100.0 Hz, and a neon strobe would freeze that anywhere where there is a 50Hz line frequency.

Why do you attach and detach the interrupt every time through loop()? Not a good idea.

1 Like

You're referring to my code? Yes - its not the best way...it was just to convey the idea.

This is a better way - and most strobe discs are marked to work with 50/60 Hz mains lights anyways. The only requirement is that the mains frequency should be stable enough - it does vary but I guess a 1% variation would mean an error of 1% in the turntable speed...hardly recognisable by "ordinary" ears.

1 Like

Yes, exactly 182 dots/reflectors.
Frequency Strobe:
From the Turntable Sevice Manual:

  1. For this calibration, you need access to the component side of the drive control circuit board. Before you begin the calibration, you will need to set the main pitch control slider to "0", where the indicator lights up.
  2. Connect the frequency counter between test point (TP27) and earth.
  3. Adjust VR301 so that the frequency counter reads 262.08 kHz ±0.05 kHz

Thanks.
I tried different combinations,
unfortunately I am too ignorant of ARDUINO.
I also tried with the TimerOne.h library
but with no good results.
At this point, I'll first pay some of you via PayPal
for a well done script

Alright - try this code.

THIS IS UNTESTED - no guarantee that it will work. You need to directly connect the sensor that reads the light to the interrupt pin. It assumes that the interrupts generated will be regular as in reading a repeating sequence of markers.

Add/modify the code wherever applicable (such as TO DO).

Let us know if it works.

#define INTERRUPT_PIN 6 //TO DO: Give the correct pin number
#define windowIntervalSec 2 //2 seconds window - increase this if the no. of markers is less for better accuracy
#define INTERRUPT_MODE FALLING //Set this to one of FALLING, RISING, CHANGE, LOW
#define NUM_MARKERS 182 //TO DO: Check this as per your setup

unsigned int numPulses = 0;
unsigned int lastMillis = 0;
unsigned int curMillis = 0;

float revPerMin  = 0.0f;

void displayResults() {
    //TO DO: Display 'revPerMin' or use it for something...
}

void interruptRoutine() {    
     numPulses++;
}

void setup() {
    attachInterrupt(digitalPinToInterrupt(INTERRUPT_PIN), interruptRoutine, INTERRUPT_MODE);
    numPulses = 0;
    curMillis = lastMillis = millis();
    revPerMin  = 0.0f;
}

void loop() {
    curMillis = millis();

    if(curMillis >= lastMillis + (windowIntervalSec  * 1000)) {
        //Interval passed, time to calculate
        revPerMin = 60 * ((float)numPulses / (float)windowIntervalSec  / 182.0f);

        //Reset everything for a fresh calculation...
        lastMillis = curMillis;
        numPulses = 0;
    }
    
    displayResults();
}

It won't work. It breaks several ISR rules.

I won't work...as in millis() cannot be used? I have updated the code. As I mentioned I have no way of testing it, so the OP has to actually test it, after gathering inputs from others here...

Just use the interrupt to count
Nothing else.

I have updated the code to just count the pulses, and reset counts if the window time is passed. Hope this is fine.

Just use the interrupt to count
Nothing else.

And in most countries that's more accurate than the Arduino's clock, although the Arduino should be accurate-enough for this application.

It also requires a fluorescent (or neon) lamp. (Incandescent lamps don't flicker.)

Usually a turntable that has the dots also has a built-in strobe. These little neon lamps used to be common and I assume that's what's in my old turntable, but it could be an LED... I can't see what's behind the lens. The neon lamp just has to be connected to the AC power (with a series resistor) and no other electronics are required.

My turntable also has 4 sets of dots for 33 & 45 RPM and for 50 & 60Hz.

The number on your display is 97.6% of 6000. 33 1/3 * 180 = 6000.

1 Like

JCA34F

15h

The number on your display is 97.6% of 6000. 33 1/3 * 180 = 6000.

JCA34F,
I had noticed that too.

Also, as dsebastian pointed out, way back in reply #3, the original sketch does not take into account the number of dots on the platter.

The original Easy Peasy Tachometer project, on which the original sketch is based only used a single reflective tape on a motor shaft.

cicciobit, Have you tried the original sketch, modified to divide the result by 182 (or 180)?

Work! :slight_smile: :heart::heart::heart: Almost perfect!
Sometimes it flickers but I love it.
Now I would like to add the real percentage,
I try, am I see it hard

I thank you and I embrace you all, one by one,
FRANCESCO - ITALY

vid: