Chinese Caliper Protocol (arbitrary serial stream)

Hi All,

I am trying to interface my Arduino with a digital caliper like this one:

These are available all over the world often very inexpensively, and can provide positioning data down to resolutions of better than .05mm/.001". What makes them really interesting is that they also have a serial output. I am trying to figure out whether it is practical to interface this to an Arduino.

A fairly deep description of the protocol they use is here:
http://www.shumatech.com/support/chinese_scales.htm#Chinese%20Scale%20Protocol

The basic idea is that approximately every 200ms, the data line sends out 2 24-bit data words containing the numbers I want to read. There is a clock line as well. The hi-lo swing is ~1.6V or whatever the battery is putting out.

While I understand the theory of all this, what I don't really know is the right way to implement it. My first thought was that I would need to use an interrupt to detect the clock pulses, and then when one of those occurs, check the data pin and get its value. This would all be wrapped up by some sort of state machine to get the two 24-bit words.

I am curious if:
a) this is a right way to do it, i.e., it will probably work
b) this is a smart way to do it
c) if there is a way that doesn't require interrupts, which would limit me to reading two of these devices with one Arduino (three would be ideal for X-Y-Z positioning purposes)

I have looked around a bit for howtos on using this type of arbitrary external serial stream, but all I could seem to find were tutorials on serial comms with a host PC. Any pointers or suggestions would be greatly appreciated.

It would be possible I think but the Arduino wouldnt be able to do too much else because it needs speed.

Just try it and see if it works.

Hi!
I don't know if I'm helping you, but, I'll try. I used serial to communicate with a ps/2 mouse, an already made code found on this site. Probably you could check if you find the datasheet of the IC on the caliper. Maybe it can communicate serial in different ways, and maybe you could write something on its register to get data, or to select the way or the time to get data. At least I've found out this from the serial mouse IC.

bye
G

Thanks for the suggestions. AFAICT there is no way to query the caliper for data, it simply broadcasts every 200ms. So, I have to be actively listening for it. If there are additional functions on the chip, they don't seem to be accessible from the data port, and the boards are nasty cheap SMD stuff that is hard to hack.

On the plus side, if I can figure out how to "catch" the bits, then all I need to do is turn them into a decimal, and that's not time-sensitive. Even if I can only read one caliper per Arduino, that's still much cheaper than the commercial solutions out there.

The thing I am trying to understand now is how to set an external interrupt. In other words, I want a procedure (an ISR I believe?) that gets called every time pin X (hooked to the clock line) goes from hi to lo. When that's triggered I will poll the data pin to see if it's hi or lo. Since the datagrams are sent as 2 fixed sequences of 24 bits, I figure I should be able to just accumulate the bits until I receive the right number of bits and then decode the number.

What I'm stuck on right now is that I'm not sure how to set up the interrupt servoice routine to fire on the change of pin state as described above. I've seen a lot of stuff about interrupt vectors and AVR and timers, but it's all still Greek to me. I was a liberal arts major, take it easy on me ;D

There is an explanation of external interrupts on the arduino here http://www.arduino.cc/en/Reference/AttachInterrupt including and example sketch. For your application you would replace the blink() function with one that used the state change to clock in the incoming data bit.

There is an explanation of external interrupts on the arduino here http://www.arduino.cc/en/Reference/AttachInterrupt including and example sketch. For your application you would replace the blink() function with one that used the state change to clock in the incoming data bit.

Thanks, that's the sort of "for dummies" intro I was looking for. For some reason when you google "arduino interrupts" that isn't coming up anywhere in the top 40-50 results and I never saw it referenced by any of the code refs. I will try that out as soon as I have time.

I don't think reading serveral bits of information every 200 mS is going to be a problem.

I made a setup with 16 slide potentiometeres that i read the value of through two 4051 multiplexer IC's, and then i send the information back to a PC program i have written.

I can easily read the 16 potentiometers and send the data to the PC every 10 mS, i could probably do it even faster.

The 10 mS include the time it takes to address the two 4051's 8 times, do 16 analog reads and send the 16 values over the serial line at 19200 Baud + a few other housekeeping routines.

Hi Guys,

Well the good news is that I think I figured out how to get the interrupt to work. I was having weird problems but I think it was due to having the USB plugged in at the same time I was trying to use interrupts. I forgot that digital pins 0 and 1 were used for serial comms too!

My problem for now is how to display the values. I have a parallel LCD display which works fine on its own, but I can't get it work with the program I wrote to read the values. As a start I was just trying to get the straight binary values out to see if everything was working. Naturally that's not working and I'm not sure where the problem lies.

Is there any way to use interrupts and serial to the monitor on the host PC? I'd like to keep the chain as simple as possible so that I can verify that the caliper reading part is working before figuring the rest of the mess out?

PS- MikMo- I'm getting a total of 48 bits sent to me every 200ms, or a nominal freq. of about 77Khz. So it should be able to handle this but from reading about interrupts, that will place a significant load on the processor. Fortunately, I don't really need to do much with the data once I get it.

Sound like you are making progress :slight_smile:

If you are using attchInterrupt, it enables interrupts 0 or 1 on digital pins 2 or 3. It should not be affected by serial on pins 0 and 1.

Does the LCD work if you comment out the code to get the binary data and replace it with some hard coded values to send to the LCD?

If you post your code it may be easier to help.

So, I've made just enough progress to reach the next impossible problem ;D

I think I am getting consistent readings from the data line. That brought up a new problem.

Every 200ms, the caliper sends out the current measurement as 2 24-bit packets. The first packet contains the absolute position, while the second is the relative position (relative to the last time the caliper was zeroed).

My original approach was to just count until I had received 48 bits, and then split it in the middle and decode the two words. The problem is that since there is no handshake, if I don't start reading at the right time, I'll get junk. The link in my original post at the top has the full detail, but's here's a basic version:

Clock: ++++____
Data: H_L_H_H
Time: 0123456789

In this case, I'd want to start reading at 3, since that's the start of the word. If I do that, I'll get words like "HLHH." If I start reading at 5, I'll get LHHH instead.

There are two things that define the boundaries of the data. The first is that the data and clock lines are both LO for >100ms in between words. The clock line will also go HI for ~50ms before, in between, and after each of the two words.

The only thing I've seen that rings a bell is using the pulseIn() function to time the length of the clock pulses and use that set a state machine. But this feels a little sketchy to me since I'm already using an interrupt.

Perhaps you can store the millis counter when the interrupt handler detects the data going low. Then each time you detect the data going high you can check if > 50 millis has elapsed and mark the start of a packet boundary if so.