Home‎ > ‎Arduino‎ > ‎

Arduino reads digital caliper

Digital calipers have become available at very low prices. Some models even feature a serial port. For any passionate hacker this poses the immediate question: can Arduino read such calipers? The short answer is yes.

There is a type of digital caliper which is commonly sold on internet auctions for as little as 10-15€ and which features the required serial port. It hides behind a little plastic sliding cover on the upper side of the instrument. I bought one of these and after some testing luckily discovered that it uses a data protocol already described in detail on the net. I found this contribution particularly useful:


This is my caliper with the slide cover of the serial port opened


A close-up view of the serial port showing the four pins: 1.5V power supply, clock, data and ground.



 Here the most important facts about the caliper's data transmission:

  • Data are transmitted in a continuous data stream when the caliper is switched on
  • Each complete dataset consists of a series of 24 bits
  • The caliper uses a 1.5V logic level, which means that we need to amplify the signal to make it compatible with Arduino’s 5V logic
  • Data are transmitted by means of a data line and a clock line
  • The logic level of the data line needs to be read on the transition of the clock line from HIGH to LOW
  • Between each series of 24 bits there is a longer period during which CLK remains HIGH
  • The first bit is always high and does not have any proper meaning
  • The next bits codify the value of the caliper reading, starting with the least significant bit (LSB)
  • In mm–mode the resulting value corresponds to the caliper measurement multiplied by 100. E.g. 1,5mm will produce the readout 150
    • Bit 21 is the sign bit: if bit 21 is HIGH, the value is negative

    This is all we need to know to operate the caliper in the millimetre mode, in inch mode things are slightly different.

    Before decoding the caliper data, we need to raise the logic level of both data and clock lines from 1.5 to 5V. I have achieved this with the following simple transistor circuit:

    However, this little circuit which we need on both the data and clock line not only raises the voltage of the signal, but it also inverts the logic levels. This is not a major problem as we can easily deal with it by adjusting the Arduino code accordingly.


    Hardware setup:

    The caliper’s data and clock lines are connected to 2 Arduino digital pins via the described level shifting circuit.


    Arduino code:

    The code first identifies the longer period when clock is HIGH, which separates the consecutive series of 24 bits. Then it reads the logic level of the data line each time the clock changes from HIGH to LOW and assembles the individual bits to the resulting value, considering also the positive or negative sign as expressed by bit 21.

    Note that HIGH and LOW in this code are inverted since our interface circuit has inverted the original logic levels.

    With this code and the described setup you should be able to read the caliper data on the serial monitor of your PC.

    int i;

    int sign;

    long value;

    float result;

    int clockpin = 4;  

    int datapin = 5;

    unsigned long tempmicros;



    void setup() {


      pinMode(clockpin, INPUT);

      pinMode(datapin, INPUT);


     void loop () {

      while (digitalRead(clockpin)==HIGH) {} //if clock is LOW wait until it turns to HIGH


      while (digitalRead(clockpin)==LOW) {} //wait for the end of the HIGH pulse

      if ((micros()-tempmicros)>500) { //if the HIGH pulse was longer than 500 micros we are at the start of a new bit sequence

        decode(); //decode the bit sequence




    void decode() {



      for (i=0;i<23;i++) {

        while (digitalRead(clockpin)==HIGH) { } //wait until clock returns to HIGH- the first bit is not needed

        while (digitalRead(clockpin)==LOW) {} //wait until clock returns to LOW

        if (digitalRead(datapin)==LOW) {

          if (i<20) {

            value|= 1<<i;


          if (i==20) {






      Serial.println(result,2); //print result with 2 decimals