Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Using Shahe scales with Arduino
Hello all!

So a few of you may be in the same situation as me, looking at some other Forum posts I'd guess there's a few of us.

So, you've got your Arduino, you've got the 'wrong' scales, what now?

Communication types

Shahe scales work differently than the iGaging type scales. The iGaging type scales are told what to do by the screen units attached to them, meaning once the screen is removed, it's easy to tell the scales what to do, or more specifically, how fast to send the data they're checking.

On the other hand, Shahe scales work at their own pace, they have an internal clock in the scale unit itself, meaning we have to wait patiently until the scales are ready to send the data they're reading.

Having an internal clock also means we are unable to use a single clock line to send signals to all scales at once, we need to check each scale's clock status to see if we're able to read a data packet. This means we need 1 pin on the Arduino per each scale we plan on using. Not a major issue for most Arduino boards in terms of pin count but definitely something to note as it will affect our coding and circuitry.


The data format used by the Shahe scales appears to be the standard 'Chinese Caliper' standard, this is referred to as BIN6 protocol. BIN6 protocol is a 24-bit protocol, meaning each data packet contains 24 'pulses' - either on or off. This is different than the iGaging type, which uses a 21-bit protocol. For our purposes, this doesn't matter too much but is important to note when looking at the code required to make the different types work.

What does this mean?

Basically, Shahe scales are slow. Not unusable though, so not all is lost, but from looking at videos of the proper iGaging scales being used, they look much smoother when paired with the TouchDRO application than the Shahe type scales. I've heard rumours of a 'fast read' mode but I've been unable to replicate this in my setup, if you are able to experiment with this, please feel free.

I've got my scales, soldering iron, and the will to use them

Great! But not so fast. There's a couple of extra things you need to know before wiring up your scales:
  • They operate on ~1.6v
  • They aren't wired up the same as the iGaging scales - You need to use a different circuit than shown in the Arduino circuit build
I did some googling research and found a wire colour code over at Caliper2PC

Green = GND[/url]

Vcc = Black
Clock = White
Data = Red

The lower voltage means we need to drop the voltage going to the Vcc pin to safely and reliably read data from our scales. I've accomplished this using the method described [url=]HERE

Essentially, hook up a red LED & ~100ohm resistor between your 3.3v output & Arduino ground, then a capacitor across the LED legs. Your ground rail for the scales then becomes the -ve leg of the LED, and your 1.6-ish V input is then taken from the +ve leg of your LED. This is difficult to describe without images, so I've attached one Big Grin

Your CLK and DATA lines are then just direct inputs to the Arduino. It's probably a good idea to add some pull-down resistors here but I haven't and my circuit seems to be OK, but that doesn't mean it's not a good idea. Do as I say, not as I do Smile

Once you have your voltage dropper circuit connected, you can use USB headers, or just solder directly to your circuit, USB headers are definitely the neater option, but they're able to be accidentally unplugged, but do what you want, I'm not your mom.


I am by no means a 'developer', I know enough to be dangerous and that's about it. Anyway, the code I've attached works, but only for 2 axis. If you want to add more, it's a case of duplicating all the values, loops & WHILE statements to check for another axis. There's probably a sleeker and faster way of doing this, but I refer you to my earlier comment about not being a developer. If you are, please feel free to modify this to your needs, and it would be grand if you'd share your work with the community.

Code stolen from here - Full credit goes to Mr Huang for the development of this, I've just modified it to attach both my X & Y scales.

Yuriy's TouchDRO application seems to require input in INCH format, so there's some calculations performed in my sketch to translate the measured values to inches, I'm not 100% on what magic is performed behind the scenes in the Android application, but this is Yuriy's secret to disclose Wink

All the usual disclaimers, I'm not responsible if your scales break, if you fry an Arduino, if your house burns down because you left your soldering iron on etc. Be safe, have fun.

ATB - n00bz.

Attached Files Thumbnail(s)

.txt   DROReadout__working.txt (Size: 3.97 KB / Downloads: 59)
There is no magic with the numbers, actually. You can pass anything to the app and set the scaling factor in the settings.
Shahe scales use 10 micron resolution (internally the app uses microns as base units); the UI uses counts-per-inch, so you can set the value to 2540 to start with and then calibrate.

I tried various ways to enable fast read mode to no avail either, so it might be a myth.

The scales I tested have a bit under 10 Hz refresh rate; this is slower than iGaging, but more than usable. They don't suffer as much from the last digit flicker, so you can disable the "Digital Filter" in the settings and get pretty decent responsiveness. In the MSP430 firmware I had to do some shennanigans with dynamic refresh rate to make them feel faster (i.e. I try to send the position as soon as it's processed rather than on a fixed clock).

Now a bit of feedback on your code:
your approsh should work reasonably well for two slow-ish scales, but if you're curious, look into GPIO interrupts. The code becomes more tricky, and there are some gotchas, but it eill be more robust and will handle arbitrary pulse frequency. Also, if at all possible you want to avoid mutliplication or division, expecially any sort of floating point division. Arduino doesn't have any floating point hardware, so these two lines probably take the bulk of CPU time:
result = (value*sign);
result = (result/25.4);

The first line might be optimized out by the compiler (not sure); a simple approach would be to do this using bit manipulation (look into how negative number are represented in binary)
The second line you simply don't need; just pass the value as is.

Hope this helps.

Thanks Yuriy!

I did mention I'm not a developer, right Wink

I've taken another look at the code and removed the conversion to inches, I hadn't even considered using the CPI multiplier to do this, working great now!

Wei-Hsiung Huang does mention it would be possible to use pin interrupts to do this, I just need to noodle out the logic behind capturing the start of a new packet. I also can't quite figure out how it would be possible to monitor multiple pins with this approach, as in, what happens if an interrupt is triggered while in the middle of receiving a packet from another axis? Then what happens if that interrupting pin gets interrupted? Too many interruptions for my head to handle Smile I'll do some googling on this topic and see what rocks I can look under.

I'm not 100% on using bit manipulation to set the sign of a number, I'll need to do some research on this, seems complicated  Huh

It's getting late here, I'll do some investigation tomorrow with fresh eyes, but thank you for your input, it is greatly appreciated Smile

ATB - n00bz.
Interrupts are a bit hard to wrap your brain around at first. The general idea is to "listen" to the port instead of polling it. When an interrupt fires, look at which pin changed and handle the event that way. In this case you want to listen on the clock line and read data line in the ISR (interrupt service routine). There are two gotchas:
1. You need to detect the start of the bit stream. I would have a variable for each axis that gets incremented each time your main loop runs and reset to 0. In the while loop, if the value is larger than X, assume you haven't gotten clock interrupts, so you must be between data streams.
2. You will be getting into multithreaded programming paradigm, so "race conditions" become real. Arduino is an 8-bit MCU, so reading a 32-bit number takes 4 separate reads. If an ISR fires and change the data inbetween the reads, you will have issues. There are ways to deal with that; on Arduino you woll likely need to disable interrupts for a brief moment while reading shared data and re-enable them right away. This is no fun to do or debug, though.

Hey all, I'm back!

I'm just now getting back into this project after a couple of months of it gathering dust.

So, I've got some rudimentary code working with interrupts rather than pollers, see attached.

I've not yet looked into the bit manipulation part as mentioned by Yuriy but it works well enough for my use.

The only issue I've found is there seems to be an odd flicker in the values received to the TouchDRO app after about 3 seconds. Not a major issue as it's only a small flicker, but still slightly annoying. If anyone has any ideas why this is happening, please do let me know.

I'll continue to work on this when I have time, hopefully I can get the code up to a good standard given enough poking.

ATB, n00bz0rz.

EDIT: This code (or my scales) are unusable, the values flicker and reset far too much.

EDIT EDIT: One of my scales was faulty, it appears the metal bars are 'directional' and the moving piece was on upside down... Anyway, the flicker is still present and the value read by the long scales eventually flips to a negative number, work continues...

Attached Files
.txt   ReadScales.txt (Size: 2.98 KB / Downloads: 44)
The negative number likely means that you are using integer size that is too small (i.e. use int_32 instead of int_16).
Can you describe what the flicker looks like?
Hi Yuriy.

Yes that's certainly what the issue appears to be, the scales flip to a negative when going above 32768 which suggests that the value variable is somehow being converted to an int instead of a long as defined at the start of the sketch.

Oddly, this doesn't seem to be an issue when using the polling method, only when the code is copied into the interrupt method sketch does this become an issue.

I'm still working on this and will try to post an update as I have any.

ATB, n00bz0rz,.

I just thought I'd post my Arduino code for shahe scales here. As this thread was one of my starting points.

.txt   ShaheDRO_arduino.txt (Size: 3.1 KB / Downloads: 85)

I went for a different approach in that I deal with one bit of the scale data at a time rather than read the whole packet of data at once. This hopefully allows multiple scales to be read simultaneously without using interrupts.
It certainly appears to work fine so far.

I also had a problem my 'long' value being converted to an int and values flipping at 32768, it turned out to be the bitwise operation :
  value |= 1 << x;
the 1 needs to be explicitly cast as a long i.e.:
  value |= long(1) << x;

The scales I have are ones that although powered with 3v, the data signals are only 1.5v. So I had to do some level conversion for arduino inputs. 

.pdf   TouchDRO v8.pdf (Size: 16.22 KB / Downloads: 68)

I hope this may be of help to anyone trying to work with these scales on an Arduino.


Forum Jump:

Users browsing this thread: 1 Guest(s)