Instructables

Reading Digital Callipers with an Arduino / USB

Picture of Reading Digital Callipers with an Arduino / USB
How to use an Arduino to read the signal from a set of digital callipers and send the reading over USB.

Why?
This might be useful for accurate position sensing in home made / hacked computer aided manufacture systems. Adds USB functionality to your callipers.


A great reference on reading digital callipers can be found at:
http://www.shumatech.com/support/chinese_scales.htm

What this instructable adds to the shumatech tutorial is:
How to use an Arduino to read the callipers (using very few extra components).
Details of another protocol found to be in use on some callipers.
Basic Arduino code is provided.

To see more of my work please visit j44industries.


 
Remove these adsRemove these ads by Signing Up

Step 1: The Callipers

Picture of The Callipers
DSCF2303.JPG
The callipers I have been working with were the Electronic Digital Callipers by Precision Gold. I bought the callipers from Maplin (item code N48AA) in the UK for just under £20.

After some experimenting with a multi meter and a  jyetech oscilloscope (a very cheap basic oscilloscope that can be bought in kit form for under £40) I found the pins to be as shown in the diagram.


alaboz1 month ago

Hi J44,

Thanks for your share, really helped me a lot. But could you give me some clues about how to read the measurement once a day and store it, or send it via nrf24l01 to a station?

I even couldnt understand well the data type that is printed on serial.

ghoward78 months ago
Hi all,

I have done a little work on the protocol for my scales, I am trying to use a single Arduino and LCDkeypad as a DRO for my lathe.

In terms of the string format I have noticed that the last bit (bit 23) of the string is an output to determine whether the caliper is set to mm or inches. (You can only see this change though if you read the data line on the rising clock edge.) In my case 0 =mm 1= inches.

I hope this helps some of you, as by reading this bit correctly, the setting on the caliper can become irrelevant if you just want to change the units once via the DRO interface.
cs106611 months ago
And it reads 10 mm As

0,
0, 0,0, 0,
0, 0,
0, 0, 0,
0, 0,
0, 0, 0,
0, 0,
0, 0,
0,0,0, 0,
0,0,
0,

There is something wrong which i can't figure out. Please help
cs106611 months ago
I exactly used the same config and code but my compiler is not reading 1 at all instead it gives out put for 0 mm as 0, 0,0, 0,
0, 0,
0, 0,
0, 0,
0, 0, 0,
0, 0,
0, 0,
0, 0,
0,0,
0,


Which does not matches with the output in the instruction. kindly help
knudel1 year ago
I have found it.
The data must be converted backwards.
Now it works perfect.
knudel1 year ago
Thank you for this manual. It works great.
I do not understand how I convert the data output to a number.
could you please help me?
sizala1 year ago
and the WXWS's code does not show anything on the monitor at all.
sizala1 year ago
dear J44 and friends,

i have tried exactly everything same as J44 said....

but i am only getting "ready, 0 " on the serial monitor every-time i press the reset button ... no mater how much i move the caliper but it doesnt display the value which is on the caliper's display.

so what is wrong going on here?
jssussex1 year ago
any chance this could be out put to a blue tooth (USB) and linked to a pc or a laptop wirelessly? ANY Ideas on how to get this all to work. I have some digital readings but they are not practical to hardwire so I need to go wirelessly.rgans
j44 (author)  jssussex1 year ago
Bluetooth probably would be a reasonable choice for wireless, I think with the right set up the system would just behave as if it were connected via the normal USB cable. This page may help: http://www.sparkfun.com/tutorials/67
Belegnar1 year ago
shift register would help you
rhannemann1 year ago
Would it be possible to use an digital to analog converter to change the binary to an analog signal. I am trying to bring the data from a set of calipers in to an analog signal data acquisition unit (Dataq DI-145), but it does not accept digital signal.
j44 (author)  rhannemann1 year ago
I don't know of a digital to analog converter that would do it, sorry.
jmg32343 years ago
I'm attempting this as my first arduino project- which will be a learning experience. I have wired up my HF digital indicator (which I understand to be the same interface as the chinese calipers) using the same method shown here to convert the logic level. I have uploaded the script and appears everything is correct, I'm not sure how to start the data flow. What do i do to view the data on my PC coming from the arduino? I have launched the terminal viewer, but it is blank. Is a command needed?
TIA, -joe
j44 (author)  jmg32343 years ago
Hi Joe,

I use the serial monitor part of the arduino software (button next to upload).
It does not need any commands, and even if you have go the wiring wrong you should still get the" ready" message from the code. If you are having problems with my code try using the Graph example sketch which can be found in the communications section of the examples to test getting data from the arduino.

J44
jmg3234 j443 years ago
J44, thank you for the reply. I found the error, I left the battery in the gauge and used the logic level hack which caused the arduino to not see a high/low change.

I learned quite a bit playing with your script, and one from another forum. My goal was to have the arduino convert the binary to a decimal value. I could not figure a way to change your script to capture the 1 and 0 (sent via serial.print.) to a string or array. Is there a command so that you can append a string with bits as they are read in a loop?

Anyways, I now have a script that mostly works; the binary string is truncated properly and converted. I need work and find a way to set the value to be divided by 1000- so that is shows inchs with a decimal place rather than thousanths of a inch (it now rounds to 1 if divided by 1000). Also, I need mod it so that it will display negative readings.
jmg3234 jmg32343 years ago
//I modified this script from link below:
//http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1235853702/0

volatile int count = 0;
int total = 0;
char data[14];
int dataPin = 4;
int gauge = 0; // display of calipers reading
int factor = 0;
unsigned long sec;


void setup(){
pinMode(dataPin, INPUT); //DATA line goes to Arduino digital pin 4
Serial.begin(9600);
delay(500);
//attachInterrupt(0,getBit,FALLING); //CLOCK line goes to Arduino digital pin 2

}

void loop(){
int i,time;
for(i=2;i<14;i++){ //initialize array of bits to 0
data[i]=0;
}
do{time = pulseIn(2, LOW);} //repeatedly get the length of LOW pulses until one is longer than 130uS
while(time < 130);

attachInterrupt(0,getBit,FALLING); //start watching data line

while(count < 14){} //wait till all bits are filled in

detachInterrupt(0);
count = 0;
for(i=2;i<14;i++){


}

gauge = 0; //the following is code for converts least significant bit first binary to decminal, units are thousandths of an inch
factor = 1;
for(i=2; i<14; i++){
gauge += data[i]*factor;
factor = factor*2;
}

Serial.print("Time (sec):");
sec = millis();
Serial.print(sec/1000);
Serial.print(" Inches:");
Serial.print(gauge);

delay(1000);
Serial.println();
}


void getBit(){
char sample = 0; //variable used for "triple sampling"
if(digitalRead(dataPin) == HIGH) //here the dataPin is checked three times for a HIGH value.
sample++;
if(digitalRead(dataPin) == HIGH)
sample++;
if(digitalRead(dataPin) == HIGH)
sample++;
if(sample > 1) //if the pin was HIGH at least twice, a 1 is recorded
data[count] = 1;
count++; //increment count so main() knows when the entire string of bits is ready
}
wxws3 years ago
//电子尺读数
// gnd data clk vcc1.5
// from china

int dataIn = 3;
int clockIn = 2;

int isin=0; //英寸inch=1,mm=0
int isfs=0; //是负数
int index;

unsigned long xData,oData;//最终要输出的数据

int ledPin = 13; // the number of the LED pin
int ledState = LOW; // ledState used to set the LED
long previousMillis = 0; // will store last time LED was updated
long interval = 500; // interval at which to blink (milliseconds)

long previousGetMillis = 0; //上次中断发生时间
long Timeout = 8; //超时时间 8ms



void setup(){
digitalWrite(dataIn, 1);
digitalWrite( clockIn, 1);
pinMode(dataIn, INPUT); //DATA line goes to Arduino digital pin 4
pinMode(clockIn, INPUT);
Serial.begin(9600);
delay(500);
attachInterrupt(0,getBit,RISING); //CLOCK line goes to Arduino digital pin 2 上升沿触发
index =0;
xData=0;
oData=999;
}

void loop(){

//超时处理
if ((index !=0) && (millis() - previousGetMillis > Timeout) ) {
index=0;
xData=0;
};

//输出
if (index >23) {
if (oData !=xData) {
if (isfs==1)
Serial.print('-');

if (isin==1){ //英寸 inch
xData *=5;
Serial.print(xData/10000);
Serial.print('.');
if ((xData % 10000)<1000){
if ((xData % 10000)<100){
if ((xData % 10000)<10){
Serial.print('0');
};
Serial.print('0');
};
Serial.print('0');
};
Serial.println(xData % 10000);
}else { //公制 mm

Serial.print(xData/100);
Serial.print('.');
if ((xData % 100)<10) //补0
Serial.print('0');
Serial.println(xData % 100);
};
}; //if 公英制
oData =xData;
index=0;
xData=0;
};


if (millis() - previousMillis > interval) {
previousMillis = millis();
if (ledState == LOW)
ledState = HIGH;
else
ledState = LOW;
digitalWrite(ledPin, ledState);
}

}



void getBit(){
previousGetMillis=millis();
if(index < 20){
if(digitalRead(dataIn)==1){
xData|= 1<<index;

};
} else {

if (index==20) //第21位为符号位 -
isfs=digitalRead(dataIn);


if (index==23) //第24位为公英制 1=英制inch
isin=digitalRead(dataIn);

};

index++;
}

j44 (author)  wxws3 years ago
Hmm interesting.

Sadly I do not have my arduinos at hand, but when I do I will try this code out.
ring light3 years ago
I'm seeing this as the basics of a linear encoder setup for motion control; i.e. x,y,z machines. Possible?
j44 (author)  ring light3 years ago
I expect it is possible, it is the kind of use I had in mind when I started the hack.
wxws3 years ago
//电子尺读数
// gnd data clk vcc1.5
// from china

int dataIn = 3;
int clockIn = 2;

int isin=0; //英寸inch=1,mm=0
int isfs=0; //是负数
int index;

unsigned long xData,oData;//最终要输出的数据

int ledPin = 13; // the number of the LED pin
int ledState = LOW; // ledState used to set the LED
long previousMillis = 0; // will store last time LED was updated
long interval = 500; // interval at which to blink (milliseconds)

long previousGetMillis = 0; //上次中断发生时间
long Timeout = 8; //超时时间 8ms



void setup(){
digitalWrite(dataIn, 1);
digitalWrite( clockIn, 1);
pinMode(dataIn, INPUT); //DATA line goes to Arduino digital pin 4
pinMode(clockIn, INPUT);
Serial.begin(9600);
delay(500);
attachInterrupt(0,getBit,RISING); //CLOCK line goes to Arduino digital pin 2 上升沿触发
index =0;
xData=0;
oData=999;
}

void loop(){

//超时处理
if ((index !=0) && (millis() - previousGetMillis > Timeout) ) {
index=0;
xData=0;
};

//输出
if (index >23) {
if (oData !=xData) {
if (isfs==1)
Serial.print('-');

if (isin==1){ //英寸 inch
xData *=5;
Serial.print(xData/10000);
Serial.print('.');
if ((xData % 10000)<1000){
if ((xData % 10000)<100){
if ((xData % 10000)<10){
Serial.print('0');
};
Serial.print('0');
};
Serial.print('0');
};
Serial.println(xData % 10000);
}else { //公制 mm

Serial.print(xData/100);
Serial.print('.');
if ((xData % 100)<10) //补0
Serial.print('0');
Serial.println(xData % 100);
};
}; //if 公英制
oData =xData;
index=0;
xData=0;
};


if (millis() - previousMillis > interval) {
previousMillis = millis();
if (ledState == LOW)
ledState = HIGH;
else
ledState = LOW;
digitalWrite(ledPin, ledState);
}

}



void getBit(){
previousGetMillis=millis();
if(index < 20){
if(digitalRead(dataIn)==1){
xData|= 1<
};
} else {

if (index==20) //第21位为符号位 -
isfs=digitalRead(dataIn);


if (index==23) //第24位为公英制 1=英制inch
isin=digitalRead(dataIn);

};

index++;
}

carlos66ba4 years ago
Nice work. How do these calipers transduce the linear displacement to numbers? is it a friction wheel or an optical pick-up?
j44 (author)  carlos66ba4 years ago
I think the callipers work with capacitance.
Nerdz4 years ago
from your timing diagrams it *looks* like I2C. From your schematic it also Looks like I2C (2 lines, one for clock one for data)..hmmm interesting