3 Simple Ways to
Share What You Make

With Instructables you can share what you make with the world — and tap into an ever-growing community of creative experts.

PhotosPhotos

Share one or more photos of a project, recipe, or whatever you've made, quickly and easily.

Step by StepStep-By-Step

Share your step-by-step photos with text instructions of what you made so others can do it too!

VideoVideo

Share your how-to video. You'll need your embed code from a video site such as YouTube.

Reading Digital Callipers with an Arduino / USB

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 1The Callipers

The Callipers
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.


« Previous StepDownload PDFView All StepsNext Step »
12 comments
Feb 15, 2011. 9:05 PMjmg3234 says:
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
Feb 18, 2011. 8:52 AMjmg3234 says:
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.
Feb 18, 2011. 8:53 AMjmg3234 says:
//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
}
Dec 21, 2010. 8:40 AMwxws says:
//5P:p
// gnd data clk vcc1.5
// from china

int dataIn = 3;
int clockIn = 2;

int isin=0; //inch=1 mm=0
int isfs=0; ///p
int index;

unsigned long xData,oData;//ȁpn

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 G
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 { //l6 mm

Serial.print(xData/100);
Serial.print('.');
if ((xData % 100)<10) //e0
Serial.print('0');
Serial.println(xData % 100);
};
}; //if l6
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) //,21M:&M -
isfs=digitalRead(dataIn);


if (index==23) //,24M:l6 1=6inch
isin=digitalRead(dataIn);

};

index++;
}

Nov 22, 2010. 11:07 PMring light says:
I'm seeing this as the basics of a linear encoder setup for motion control; i.e. x,y,z machines. Possible?
Dec 21, 2010. 8:40 AMwxws says:
//5P:p
// gnd data clk vcc1.5
// from china

int dataIn = 3;
int clockIn = 2;

int isin=0; //inch=1 mm=0
int isfs=0; ///p
int index;

unsigned long xData,oData;//ȁpn

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 G
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 { //l6 mm

Serial.print(xData/100);
Serial.print('.');
if ((xData % 100)<10) //e0
Serial.print('0');
Serial.println(xData % 100);
};
}; //if l6
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) //,21M:&M -
isfs=digitalRead(dataIn);


if (index==23) //,24M:l6 1=6inch
isin=digitalRead(dataIn);

};

index++;
}

Jun 30, 2010. 9:59 AMcpotoso says:
Nice work. How do these calipers transduce the linear displacement to numbers? is it a friction wheel or an optical pick-up?
Jun 29, 2010. 4:57 PMNerdz says:
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

Pro

Get More Out of Instructables

Already have an Account?

close

All Steps Viewing
View all steps of an Instructable on the same page when you're a Pro Member.

Upgrade to Pro today!
9
Followers
6
Author:j44(J44 Industries)