Skip to content

Instantly share code, notes, and snippets.

@kesor
Last active April 18, 2024 01:09
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kesor/3577811486a4032baed0549bbc61c4df to your computer and use it in GitHub Desktop.
Save kesor/3577811486a4032baed0549bbc61c4df to your computer and use it in GitHub Desktop.
Digital Caliper / Digital Dial Indicator Arduino reader
/**
* Arduino Sketch for Digital Calipers and Dial Indicators Reading
*
* This sketch is designed to interface with digital calipers or dial indicators, reading measurements
* via a simple two-pin setup. It effectively handles data on both rising and falling edges of a clock signal,
* managing debouncing and differentiating between measurement units (inches or millimeters).
*
* Features:
* - Uses interrupts to capture data from clock signal changes.
* - Debouncing logic for accurate edge detection.
* - Detects measurement units and sign of the measurement.
* - Automatic reset after idle periods.
* - Debug output of bit patterns for verification.
*
* Pin Configuration:
* - PIN_CLOCK (Digital Pin 3): Clock signal input.
* - PIN_DATA (Digital Pin 2): Data signal input.
*
* Setup:
* Connect the clock and data outputs of your measuring tool to the respective Arduino pins.
* Upload this code to the Arduino and open the serial monitor at 115200 baud to see the measurements.
*
* Author: Evgeny Zislis
* License: MIT License
*
* Keywords: Arduino, Digital Caliper, Dial Indicator, Interrupts, Edge Detection, Debouncing
*/
#include <Arduino.h>
#include <avr/interrupt.h>
#define BITS 24
const int PIN_CLOCK = 3;
const int PIN_DATA = 2;
// keep track of the clock edge and timing
volatile unsigned long lastClock = 0;
volatile bool lastClockState = LOW;
// remember data values on each clock change
volatile byte dataBits[BITS];
volatile int bitCount = 0;
const unsigned long IDLE_TIME = 100000; // idle between reads is about 125kus, 8 times per second.
const unsigned long DEBOUNCE_US = 20; // clock falling edges are every ~175us
void tick() {
unsigned long currentUS = micros();
if (currentUS - lastClock < DEBOUNCE_US)
return; // debounce
if (currentUS - lastClock > IDLE_TIME)
bitCount = 0; // reset
bool state = digitalRead(PIN_CLOCK);
// rising edge for bit 24 :(
if (lastClockState == LOW & state == HIGH && bitCount == BITS) {
dataBits[bitCount - 1] = digitalRead(PIN_DATA);
bitCount++;
}
// falling edge for bits 0-23
if (lastClockState == HIGH & state == LOW && bitCount < BITS) {
dataBits[bitCount] = digitalRead(PIN_DATA);
bitCount++;
}
lastClockState = state;
lastClock = currentUS;
}
void setup() {
Serial.begin(115200);
pinMode(PIN_CLOCK, INPUT); // don't pullup the clock!
pinMode(PIN_DATA, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(PIN_CLOCK), tick, CHANGE);
}
void loop() {
if (bitCount > BITS)
decode();
}
void decode() {
static int signLast, unitLast, valueLast;
int sign = 1;
int unit = 0;
int value = 0;
if (dataBits[0] != 1)
return; // start bit error
for (int i = 0; i <= 20; i++)
if (dataBits[i + 1]) // ignore start bit
value += (1 << i);
sign = (dataBits[21] == 1) ? -1 : 1;
unit = dataBits[BITS - 1];
if (signLast == sign && unitLast == unit && valueLast == value)
return; // don't repeat the same output more than once
signLast = sign;
unitLast = unit;
valueLast = value;
// --- DEBUG the bits ---
// for (int i = 0; i < BITS; i++) {
// Serial.print(dataBits[i]);
// if ((i+1) % 4 == 0)
// Serial.print(" ");
// }
// Serial.print(" : ");
if (unit) { // inches
Serial.print(sign * value / 2000.0, 4);
Serial.println(" in");
} else { // millimeters
Serial.print(sign * value / 100.0, 2);
Serial.println(" mm");
}
Serial.flush();
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment