I'm attempting to connect a digital caliper to a duemilanove, software wise I can read the pin and work with interrupts etc. My problem is I have the electrical skills of a chipmunk. I realize I have to boost the 1.5v signals from the caliper's clock and data pins to ~5 volts (3.3 or higher? unsure what the andruino threshold is for high vs low).
I've tried following something similar to this: Robocombo - Robotic and Electronic Experiments: Interfacing TI Launchpad to Digital Caliper and it makes a reasonable amount of sense to me in theory, but I can't execute on it. I have mucked around on a breadboard and in multisim some and I've come up with the attached setup. If I power V1 with an AA battery instead of the data/clock pins I can see the transistor changing states and I can measure it with my multimeter. If I had an oscilliscope I could look at the state when the clock/data pins are on, but sadly I only have a multimeter so I need to test with a steady that will stay in a given state for more than a few ms.
The crux of the problem is once I lay this all out on the breadboard, there is no where to successfully connect a digital pin to and see the state change. I can measure 4.5v across R2 with a voltmeter, but that doesnt really help me as to where to put pin 2.
Perhaps the fundamental issue is the 2 seperate grounds/negatives? I don't really know.
If anyone can help me out with this, that'd be great.
Edit, a quick note that I relaize I really need to do this for each data/clock pin. Simplified the example for troubleshooting purposes. If I can make it work for one pin I will move on to the second.
You're pretty close (for a chipmunk). First, make sure you connect the grounds together (of the 1.5V battery and the +5V source), negative terminals that is.
For pin 2, connect to the collector terminal of Q1 (the one at the top in your drawing). You should be able to see that vary from 5V (when the 1.5V battery is disconnected) to near 0V when the 1.5V battery is connected.
--
The Ruggeduino: compatible with Arduino UNO, 24V operation, all I/O's fused and protected
I have the circuit working now I believe. I am getting interrupts firing from either the data or clock pin depending on what I plug in where.
The trouble now seems to be that I only get one interrupt from the clock pin every 290ms or so. Not sure if I've done something wrong or if this is an issue with my caliper. Scope traces I've seen online from other people who have done this show that the clock pin should fall from high to low every time a new bit is ready to be read on the data line. As there are 24? or 48? or some arbitrarily large number of bits involved and it is reported that most of these units send their complete data ~3 times a second. So every second I should see 24 * 3 interrupts from the clock pin.
I've modified my function called by attachInterrupt to simply print the time in millis() and the output now looks like:
millis: 1695
millis: 1695
millis: 2014
millis: 2014
millis: 2332
millis: 2332
millis: 2651
millis: 2651
millis: 2969
millis: 2969
based on that I can see that the clock interrupt is firing in pairs every ~300ms. If I look at the time as micro the time between the pairings is approximately 800microseconds, or .8milliseconds.
So, Is it possible my circuit is too slow and its only catching the first interrupt and then another (the last?) or are the calipers only sending 2 interrupts every 300ms and I should look for new calipers. Or other possibilities...
I've modified my function called by attachInterrupt to simply print the time in millis()
It is a bad idea to use a print statement in an interrupt. Not only does it take quite a long time but the millis() counter does not advance in an ISR so the results are a bit meaningless.
It would appear that putting print statements in my interrupt function was a real bad idea, once I cut down my interrupt function to the bare bones and applied some software smarts it turns out the calipers I was attempting to use spit out a 48/49 bit pulse pattern which I'm sure is a totally different standard than I initially intended.
I moved to a new set of calipers and everything is fine now.
along with a few tweaks and merged them all to get:
// code by mbconfuse 29/05/11
#include <avr/interrupt.h>
// Arduino as load cell amplifier
// by Christian Liljedahl
// christian.liljedahl.dk
// Load cells are linear. So once you have established two data pairs, you can interpolate the rest.
// Step 1: Upload this sketch to your arduino board
// You need two loads of well know weight. In this example A = 10 kg. B = 30 kg
// Put on load A
// read the analog value showing (this is analogvalA)
// put on load B
// read the analog value B
// Enter you own analog values here
float loadA = 0; // kg
int analogvalA = 18.75; // analog reading taken with load A on the load cell
float loadB = 210; // kg
int analogvalB = 150; // analog reading taken with load B on the load cell
int analogValue=0;
float analogValueAverage = 0;
float load=0;
// How often do we do readings?
long timeloadcell = 0; //
volatile int bumper;
int clockPin = 2;
int dataPin = 4;
int counter = 0;
const int numberBits = 24;
int data[numberBits];
int usedData[numberBits];
int decimalVal = 0;
int oldDecimalVal = 0;
int passedSync=0;
float oldLoad=0;
void setup()
{
Serial.begin(115200);
pinMode(clockPin, INPUT);
pinMode(dataPin, INPUT);
attachInterrupt(0, bumperISR, FALLING);
interrupts();
bumper = 0;
}
void bumperISR()
{
char sample = 0;
if(digitalRead(clockPin) == LOW) sample++;
if(digitalRead(clockPin) == LOW) sample++;
if(digitalRead(clockPin) == LOW) sample++;
if(sample > 2)
bumper = 1;
}
void loop()
{
// make sure loop starts at the begining of the data set
syncronization();
//start that data conversion
if (bumper == 1 && passedSync ==1)
{
//sample the reading 3 times
// Serial.println("sampling");
data[counter] = sampleData (digitalRead(dataPin), 1);
bumper = 0;
counter++;
if(counter >=numberBits)
{
// tick the syncronisatoin button
passedSync = 1;
counter =0;
analogValue = analogRead(0);
analogValueAverage = 0.9*analogValueAverage + 0.1*analogValue;
analogValue = analogRead(0);
analogValueAverage = 0.9*analogValueAverage + 0.1*analogValue;
analogValue = analogRead(0);
analogValueAverage = 0.9*analogValueAverage + 0.1*analogValue;
analogValue = analogRead(0);
analogValueAverage = 0.9*analogValueAverage + 0.1*analogValue;
analogValue = analogRead(0);
analogValueAverage = 0.9*analogValueAverage + 0.1*analogValue;
analogValue = analogRead(0);
analogValueAverage = 0.9*analogValueAverage + 0.1*analogValue;
analogValue = analogRead(0);
analogValueAverage = 0.9*analogValueAverage + 0.1*analogValue;
load = analogToLoad(analogValueAverage);
//reverse the order of the binary bits
reverseData();
//printBinary();
//convert the binary to decimal
binaryToDecimal(usedData, numberBits);
}
}
}
// convert a binary string to a decimal number, returns decimal value
void binaryToDecimal(int TheArray[], int numBits)
{
int b, k, m, n;
int len;
//start bit and end bit are chosen to chop out the unwanted bits
int startBit = 9;
int endBit = 23;
len = numBits;
for(k = startBit; k <= endBit; k++)
{
n = TheArray[k];
// Serial.print("n: ");
// Serial.print(n);
if ((n > 1) || (n < 0))
{
Serial.println("non_binary number!!");
}
for(b = 1, m = endBit; m > k; m--)
{
// 1 2 4 8 16 32 64 ... place-values, reversed here
b *= 2; //same as b = b * 2
}
decimalVal = decimalVal + n * b;
}
// decimalVal = decimalVal + n;
decimalVal=32768-decimalVal;
decimalVal= decimalVal/2;
// the 3rd bit is the positive/negative bit. if it is 1 then value is negative.
if(TheArray[3] == 0)
{
decimalVal=decimalVal * -1;
}
//only print if the decimal value has changed
float tempload=oldLoad-load;
float absload=abs(tempload);
if ( (decimalVal != oldDecimalVal) || ( absload > 1) )
{
double temp=0;
temp=(decimalVal)*.001;
Serial.print(temp,3);
Serial.print(",");
Serial.println(load,5);
oldDecimalVal = decimalVal;
oldLoad=load;
}
decimalVal = 0;
}
//sample data three times
int sampleData(int readData, int highLow)
{
char sample = 0;
if(readData == highLow) sample++;
if(readData == highLow) sample++;
if(readData == highLow) sample++;
if(sample > 2)
{
return(highLow);
}
else return((1-highLow));
}
//reverse all the binary bits
void reverseData()
{
int k=0;
for(int j = (numberBits-1) ; j >= 0; j--)
{
usedData[k] = data[j];
k++;
}
}
//print the binary
void printBinary()
{
for (int i = 0 ; i < numberBits; i++)
{
Serial.print(usedData[i]);
}
Serial.println("");
Serial.print(" ");
for (int i = 4 ; i < 24; i++)
{
Serial.print(usedData[i]);
}
Serial.println("");
}
//sync so we start at the begining of a data set
//130 is approx lenght of gap between data sets
void syncronization()
{
if(bumper == 1 && passedSync == 0)
{
int time;
do
{
time = pulseIn(clockPin, HIGH);
}
while(time < 130);
passedSync = 1;
Serial.print("time - ");
Serial.println(time);
delay (130);
bumper =0;
}
}
float analogToLoad(float analogval){
// using a custom map-function, because the standard arduino map function only uses int
float load = mapfloat(analogval, analogvalA, analogvalB, loadA, loadB);
return load;
}
float mapfloat(float x, float in_min, float in_max, float out_min, float out_max)
{
return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}
Note: I'm terrible at electronics, verify before you build/test this, in particular the transistors may be reversed...
This allows me to bring a digital caliper in on digital pins 2 and 4, and a load cell on analog pin 0 (note the diagram says pin 1 but that should be corrected). So I can measure force vs displacement/travel.
Likely just how I drew it then. The direction of the symbols doesn't mean much to me. I guess just flipping those transistors positive/negative or collector/whatever its called around fixes the issue. When I measure my circuit the arduino pins from the DRO see 5v until the base goes high then the arduino sees something like .4v, but as it's a digital in thats 0, which is exactly what is needed. When I measure the output to the load cell excitation I get 10v, so I believe the issue is with my ability to translate what I actually did to a drawing.