/* Reading Grizzly iGaging Digital Scales V2.5 Created 01 June 2014 Updated 01 June 2014 Based heavily on the work of Yuriy Krushelnytskiy *** Thanks Yuriy *** http://www.yuriystoys.com This version was written by Greg Dodd 05 June 2014. (greg@bettec.com) It has X, Y, Z, W and T outputed to the TouchDRO Android app via Bluetooth X cross slide, ie lathe radius Y diameter reading for a lathe, simply 2 x X reading Z lathe bed, ie length W display a 'random number' (raw data jump) if the scales (X or Z) seem to have a random jump, a common complaint A read alarm LED on the Arduino also display for 5 seconds to warn the operator not to trust the readings! T LM2917 based tacho input (I previously tried a pulsed digital input but there are too few per second for reliable readings) This version has 'jump detection' where it displays the jump as W-axis reading (Turn off summing in your TouchDRO settings!) This happens when this sketch thinks there has been an unreasonable jump since the last value read on X or Z axis. The purpose is to the machinist they should check their zero values again and not trust the DRO display. (You must have the W axis display activated on the Angroid software to see this, it is a display the raw count jump.) When I finaly solve the DRO jumping issue, I'll probably leave this feature here as an alarm feature. If you move an axis extremely fast, the led may light. The LED will auto-extinguish after 5 seconds. You can increae the jumpMaxRate to stop false triggering if you can move your X or Z axis faster tha I can. This example code is is licensed under a Creative Commons Attribution-ShareAlike 3.0 Unported License. */ //I can't use data pin 4 on my Arduino Droid board, it has other Droid related functions. int const clockPin = 2; int const xDataPin = 3; int const yDataPin = 5; int const zDataPin = 6; int const tDataPin = 7; int const LEDpin = 13; // LED positive lead connected to digital pin 13 int const analogPin = 0; int long jump = 0; //Store the value of the jump. int long unsigned jumpSize = 0; int long unsigned oldmillisX = millis(); int long unsigned oldmillisZ = millis(); int long ledReset = 5000; //miliSeconds before the red JUMP alarm LED goes off, ie 5 Seconds int firstRun = 1; int long jumpRate = 0; int long jumpMaxRate = 30; //if the count changes by more than this count per mSec, // 1 foot/sec = 2560x12 counts/sec (30,720) ie, approx 30 per mSec, //which is about 60 inches per second, and faster than most lathes ! //(assuming only 2 serials transmissions, as these take about 3 mSec each in the main loop) //Tacho variable needs to set outside 'loop' because it is not updated every read cycle, like the others int sensorValue = analogRead(analogPin); int long tacCount = 0; int long unsigned tacTemp = 0; int long unsigned time = millis(); int long unsigned tacTime1 = time; int long unsigned tacTime2 = time; // If you want to build a LM2917 tacho circuit, you can email me greg@bettec.com, or just use C1 = 0.2uF, R1 = 50K, C2 = 10uF // My lathe run 40 RPM to 1000 RPM and I used 4 pulses per rev. Otherwise at 40 RPM I get less than 1 pulse per second. // Too few pulse means a larger C2 (filering and averaging Capacitor) and the response time to RPM changes are way too slow. // These values will take about 2 seconds for the display to respond FUll Scale, ie 0 - 5 Volts, ie 0 - 1000 RPM in my case. //variables be used store the readout volatile long xCoord = 0; volatile long yCoord = 0; volatile long zCoord = 0; volatile long wCoord = 0; volatile long tCoord = 0; //variables that will store the previous readout, used by jump detection routines volatile long xCoordold = 0; volatile long yCoordold = 0; volatile long zCoordold = 0; volatile long xCoordTemp = 0; volatile long yCoordTemp = 0; volatile long zCoordTemp = 0; void setup() { //clock pin should be set as output jumpRate pinMode(clockPin, OUTPUT); //Data pins should be set as inputs, uses the scale to pull these low, use 10K pull resistors & diodes to improve noise margin. //I previoiusly tried using thr internal pull-up resistors, but it made the data input unstable as the inputs induced noise into one another. pinMode(xDataPin, INPUT); pinMode(yDataPin, INPUT); pinMode(zDataPin, INPUT); pinMode(tDataPin, INPUT); //LED pins should be set as output pinMode(LEDpin, OUTPUT); // sets the digital pin 13 as output, we will use this as teh jump alrm LED (Red) digitalWrite(LEDpin, LOW); // Set LED to OFF //initialize serial port Serial.begin(9600); } void loop() { xCoord = 0; //This reset each value to zero if the scale stops sending values yCoord = 0; zCoord = 0; wCoord = 0; int bitOffset; //read the first 20 bits for(bitOffset = 0; bitOffset<21; bitOffset++) { tickTock(); //read the pin state and shift it into the appropriate variables xCoord |= ((long)digitalRead(xDataPin)< xCoordTemp){jumpSize = (xCoordold - xCoordTemp);} else {jumpSize = (xCoordTemp - xCoordold);} jumpRate = jumpSize /(millis() - oldmillisX); if (jumpRate > jumpMaxRate) { digitalWrite(LEDpin, HIGH); time = millis(); // so you can turn the LED off after 3 seconds jump = jumpRate; } // jump = jumpRate; // Diagnostic: Un-comment this and move lathe, to see you normal maximum movement rate displayed on W-axis. xCoordold = xCoord; oldmillisX = millis(); } else {jump = 0; xCoordold = xCoord; } //set jump to 0 on the first run // Jump calculations Z-axis if (firstRun == 0) { if (zCoord <0){zCoordTemp = 0-zCoord;}else{zCoordTemp = zCoord;} // make it positive if (zCoordold <0){zCoordold = 0-zCoordold;} if (zCoordold > zCoordTemp){jumpSize = (zCoordold - zCoordTemp);} else {jumpSize = (zCoordTemp - zCoordold);} jumpRate = jumpSize /(millis() - oldmillisZ); if (jumpRate > jumpMaxRate) { digitalWrite(LEDpin, HIGH); time = millis(); // so you can turn the LED off after 3 seconds jump = jumpRate; } // jump = jumpRate; // Diagnostic: Un-comment this and move lathe, to see you normal maximum movement rate displayed on W-axis. zCoordold = zCoord; oldmillisZ = millis(); } else {jump = 0; xCoordold = xCoord; } //set jump to 0 on the first run firstRun = 0; //first run is now FALSE if (millis() - time > ledReset) { digitalWrite(LEDpin, LOW); //reset jump LED after 5 seconds, Red LED jump = 0; //reset jump display on W axis } //tacho calculations, sum multiple reading over time and divide by the number of samples taken tacTemp = tacTemp + analogRead(analogPin); tacCount = tacCount + 1; tacTime2 = millis(); if (tacTime2 - tacTime1 > 500) { // calc the average tacho analog voltage over the last 500 mSecs tCoord = tacTemp / tacCount ; tCoord = int((tCoord * (5.0 / 1023.0) * 200 + 5)/10) * 10 ; // volts * 200 = RPM & round off the units // tCoord = tCoord * (5.0 / 1023.0) *2 00; // or covert raw 0-1023 to RPM with no rounding of, just un-comment this line tacTime1 = tacTime2; // next sample starts here tacTemp = 0; tacCount = 0; } //print the measured data to the serial port, which can be a Bluetooth module. Serial.print("X"); Serial.print((long)xCoord); Serial.print(";"); yCoord = 2 * ((long)xCoord); //Not required by my lathe, so can be used for simultaneous diameter mode in this example Serial.print("Y"); //Just 'label' it in the Touch DRO settings Serial.print((long)yCoord); Serial.print(";"); Serial.print("Z"); Serial.print((long)zCoord); Serial.print(";"); Serial.print("W"); //used to display jumps greater than jumpMaxRate Serial.print(jump); Serial.print(";"); Serial.print("T"); Serial.print(tCoord); Serial.print(";\r\n"); //This carrage return & line feed just helps dumps to a computer, but does upset TouchDRO, so left in. // Diagnostic output to computer during debugging, useful to see how it was done, so left in code for explanatory purposes // This comes back out the same RS232 port used to program the Arduino, just use Teraterm or similar. // Remember to stop the terminal program when you upload new sketches or the port will be busy. //Serial.print((" Axis: tTime = ") + String(tTime) + ", " + "milliSecs = " +i String(millis()) + ", tCoord = " + String(tCoord) + ", tPulse = " + String(tPulse) + ", tDataPin = " + String(digitalRead(tDataPin))); //Serial.print(";\r\n"); //Carriage return and line feed //This is how often we will perform the read cycle, just for general understanding, and is derived from my measurements. //Yuriy says this gives the scales time to become ready again when set to 50, but scales are fine even with a delay of 0. //This is probably because the loop taks so long to complete a cycle, the scal are already 'ready'. //Real igaging display units have about 6 mSec between reads //this sketch seems to take 3 mSec to write each value to the serial port //even a delay of 0 seems to have about 15 mSec delay between reads (if 5 axis transmitted to Android) // a delay of 10 seems to have about 15 mSec delay between reads (if 5 axis transmitted to Android) // a delay of 20 seems to have about 26 mSec delay between reads (if 5 axis transmitted to Android) // a delay of 40 seems to have about 46 mSec delay between reads (if 5 axis transmitted to Android) // Therefore is seems there is an intrinsic delay between reads of time plus 6mSec, with a minimum of 15 mSec for 5 gauges //So set delay to 0, and only send the axis that you actually need to send. //Remember igauging are transmitting for one scale for each display, here we can have up to 5. //We are transmitting multiple scales to one display, at a leasurely 9600 baud. //delay(333); // Slows down RS232 enough to read debug display at about 333 mSec. } void tickTock() { //tick digitalWrite(clockPin, HIGH); //If the scale output is floating all over the place comment lines 99-102 and uncomment line 106. //Alternative 1: Use "software" delay (works better on UNO) //give the scales a few microseconds to think about it //This setting the data clock rate for reading the scale data //A value of 1 gives about 45 uSec between pules, or a freq of 22 kHz with a duty cycle 5 high, 40 low //A value of 20 gives about 50 uSec between pules, or a freq of 20 kHz with a duty cycle 5 high, 40 low //A value of 100 gives about 700 uSec between pules, or a freq of 1.4 kHz with a duty cycle 35 high, 35 low //igaging clock is about 105 uSec, 9 kHz(to 130 uSec, it varies, but high is constant) typically 25 high, 80 low //for(byte i = 0; i<20; i++) // Line 99 //{ // Line 100 // __asm__("nop\n\t"); // Line 101 //} // Line 102 //Alternative 2: Use proper delay //give the scales a few microseconds to think about it // Setting the number of uSec, based upon my own measurements. // 2 gives 50 uSec, 6 high, 44 low, if no low delay // 10 gives 56 uSec, 12 high, 44 low, if no low delay // 21 gives 67 uSec, 25 uSec high, 42 low, if no low delay // The combination of 21 and 54 gives 25 uSec high, 80 uSec low and looks like igaging on the oscilloscope. // I have not seen if other coding changes above impacts on these timing settings. delayMicroseconds(21); // Line 106 - default was 2, but trying to emulate scale's 9 kHz, //tock digitalWrite(clockPin, LOW); // Setting the number of uSec, based upon my own measurements. //60 gives 96 uSec low (seems about 26 uSec is inherent //54 gives 80 uSec low //40 gives 77 uSec low delayMicroseconds(54); }