MetalworkingFun Forum
Reading Digital caliper with Arduino - Printable Version

+- MetalworkingFun Forum (http://www.metalworkingfun.com)
+-- Forum: Machining (http://www.metalworkingfun.com/forum-5.html)
+--- Forum: Metrology (http://www.metalworkingfun.com/forum-33.html)
+--- Thread: Reading Digital caliper with Arduino (/thread-2564.html)

Pages: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16


RE: Reading Digital caliper with Arduino - EdK - 03-19-2015

(03-19-2015, 04:39 PM)Vinny Wrote: what did you use for a regulator?

A Texas Instruments TPS76316.

http://www.digikey.com/product-detail/en/TPS76316DBVR/296-11015-1-ND/477328

Ed


RE: Reading Digital caliper with Arduino - arvidj - 03-20-2015

My contribution is a start to the code ...

The .h file 

Code:
// Only modify this file to include
// - function definitions (prototypes)
// - include files
// - extern variable definitions
// In the appropriate section

#ifndef _scaleReader_H_
#define _scaleReader_H_
#include "Arduino.h"
//add your includes for the project scaleReader here

#include <util/atomic.h>

//end of add your includes here
#ifdef __cplusplus
extern "C" {
#endif
void loop();
void setup();
#ifdef __cplusplus
} // extern "C"
#endif

//add your function definitions for the project scaleReader here




//Do not add code below this line
#endif /* _scaleReader_H_ */

and the .cpp file

Code:
// Do not remove the include below
#include "scaleReader.h"

#define CLOCK_PIN 2                              // The pin associated with the clock pulse
#define CLOCK_TRANSITION FALLING                 // What will happen on the clock pulse that will want us to read the data pin
#define CLOCK_TERMINATION INPUT_PULLUP           // What kind of termination do we want on the clock pin

#define DATA_PIN 3                               // The pin associated with the data
#define DATA_TERMINATION INPUT_PULLUP            // What kind of termination do we want on the data pin

#define CLOCK_NOISE_FILTER 1000                  // How many microseconds long must the clock be stable for it to be consider 'good'
#define MINIMUM_BURST_START_PULSE_WIDTH 100000   // At a minimum, how many microseconds long is the pulse at the beginning of a burst
#define MAXIMUM_TIME_FOR_A_SINGLE_BURST 100000   // The maximum amount of time that a burst should take before considered invalid

#define DATA_BITS_IN_A_VALID_BURST 24            // The number of data bits that are expected in a complete burst of data
volatile boolean initialized = false;            // Lets the interrupt get set up right after application start up
volatile boolean processingBurst = false;        // Does the interrupt think it is processing a burst
volatile byte dataBitsReceived = 0;              // Data bit counter used by the interrupt routine
volatile unsigned long lastGoodClockTime = 0;    // The last time the interrupt saw what it thought was a valid clock pulse
volatile unsigned long burstStartTime = 0;       // The time when the interrupt thought the burst started
volatile unsigned long inProcessBurstData = 0;   // The burst of data as it is being captured by the interrupt routine

volatile unsigned long capturedBurstData = 0;    // A complete and validated burst of data
volatile byte capturedBurstCounter = 0;          // A rolling counter of the number of complete bursts we have seen. It must be a byte so increments will be atomic.

// This looks like a lot of code for an interrupt but the if statements should ensure that
// only a small portion of it actually runs during any given interrupt
void clockTransitioned() {
 unsigned long timeAtInterupt = micros();
 unsigned long intervalSinceLastInterrupt = timeAtInterupt - lastGoodClockTime;

 // If we do not have our ducks in a row so we will get organized
 if (!initialized) {
   lastGoodClockTime = timeAtInterupt;
   processingBurst = false;
   initialized = true;
 }

 // Is the interrupt because of noise?
 else if (intervalSinceLastInterrupt < CLOCK_NOISE_FILTER) {
   /*
    Note that we are going to do absolutely nothing in this case, not even update the last valid clock time.
    We are really waiting for a transition that is at least CLOCK_NOISE_FILTER later than the
    last transition that we thought was good.
    */
 }

 // Is the interrupt because of a 'beginning of burst' pulse?
 else if (intervalSinceLastInterrupt > MINIMUM_BURST_START_PULSE_WIDTH) {
   if (!processingBurst) {
     lastGoodClockTime = timeAtInterupt;
     burstStartTime = timeAtInterupt;
     inProcessBurstData = digitalRead(DATA_PIN);
     dataBitsReceived = 1;
     processingBurst = true;
   }

   // OK, we were in the process of receiving a burst but just got another 'beginning of burst' pulse.
   // We'll need to do something here but I will have to figure out exactly what after another cup of coffee.
   else {
   }
 }

 // OK, we are here because we are initialized and we do not think it is noise or a 'beginning of burst' pulse.
 // Let see if we believe it is a valid data bit.
 else {
  // If we are not in the process of reading a burst then we have a problem and need more coffee
   if (!processingBurst) {

   }

   // If it has taken longer than we thought is should to show up then we have a problem ... see the coffe issue mentined earlier
   else if ((timeAtInterupt - burstStartTime) > MAXIMUM_TIME_FOR_A_SINGLE_BURST) {

   }

   // We seem to be at the right place at the right time so grab what ever is on the data line.
   else {
     lastGoodClockTime = timeAtInterupt;
     inProcessBurstData << 1;                      // Make room for the next data bit
     inProcessBurstData | digitalRead(DATA_PIN);   // and then capture it
     dataBitsReceived += 1;

     if (dataBitsReceived == DATA_BITS_IN_A_VALID_BURST) { // Are we done with this burst?
       capturedBurstData = inProcessBurstData;
       capturedBurstCounter ++;
       processingBurst = false;
     }
   }
 }
}

// Variables used by the application loop
byte lastCapturedBurstCounter = 0;
unsigned long burstData = 0;

//The setup function is called once at startup of the sketch
void setup() {
 // Pin Set Up
 pinMode(DATA_PIN, INPUT_PULLUP);
 pinMode(CLOCK_PIN, INPUT_PULLUP);

 attachInterrupt(CLOCK_PIN, clockTransitioned, CLOCK_TRANSITION);

 Serial.begin(115200);
 Serial.println("Ready: ");}

// The loop function is called in an endless loop
void loop() {
 if ((lastCapturedBurstCounter - capturedBurstCounter) > 0) { // If there is something new available then get it and print it
   lastCapturedBurstCounter = capturedBurstCounter;           // This is a byte so it should be an atomic assignment
   ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {                        // Needs to be marked as atomic so the interrupt does not mess with it while we get a local copy of it
     burstData = capturedBurstData = 0;
   }
   Serial.print(lastCapturedBurstCounter);
   Serial.print(", ");
   Serial.print(burstData, HEX);
   Serial.print(", ");
   Serial.println(burstData, BIN);
 }
}

Submitted as a place to start the discussion, not as 'the last word'.

Arvid


RE: Reading Digital caliper with Arduino - Vinny - 03-20-2015

Are you reading on the falling edge of the clock pulse or just using it for the start notification?


RE: Reading Digital caliper with Arduino - arvidj - 03-20-2015

This defines which edge of the clock we use ...

Code:
#define CLOCK_TRANSITION FALLING

I put it in as a #define at the top of the code so it would be easy to change to RISING if that is what eventually shows up after the level shifting, etc.

The transition is used to determine the time component and it also defines when the data line is read.

Based on the time component ... i.e. how long has it been since we last saw a clock transition we care about ... we determine if it is a start of data stream and therefore need to set everything up to capture the first data bit and the rest of the stream or we thing the transition is noise or we think the transition indicates it is the next next bit of data or we are not exactly sure why it showed up and we need to forget about this stream and hope the next stream goes better.

Hopefully it is "edge direction agnostic". All we should need to do is look at the lines with a scope, define ...

Code:
#define CLOCK_PIN 2                              // The pin associated with the clock pulse
#define CLOCK_TRANSITION FALLING                 // What will happen on the clock pulse that will want us to read the data pin
#define CLOCK_TERMINATION INPUT_PULLUP           // What kind of termination do we want on the clock pin

#define DATA_PIN 3                               // The pin associated with the data
#define DATA_TERMINATION INPUT_PULLUP            // What kind of termination do we want on the data pin

#define CLOCK_NOISE_FILTER 1000                  // How many microseconds long must the clock be stable for it to be consider 'good'
#define MINIMUM_BURST_START_PULSE_WIDTH 100000   // At a minimum, how many microseconds long is the pulse at the beginning of a burst
#define MAXIMUM_TIME_FOR_A_SINGLE_BURST 100000   // The maximum amount of time that a burst should take before considered invalid

#define DATA_BITS_IN_A_VALID_BURST 24            // The number of data bits that are expected in a complete burst of data

... and hopefully have some binary output to look at.

Or that was what the [non-existent] requirements document said.


RE: Reading Digital caliper with Arduino - Vinny - 03-20-2015

I saw the #define which is why I asked. The Sparber document V1.3 says on the bottom of page 5 that the data is valid on the rising edge of the clock pulse. The data can very well have already changed by the falling edge.


RE: Reading Digital caliper with Arduino - EdK - 03-20-2015

(03-20-2015, 05:22 PM)Vinny Wrote: I saw the #define which is why I asked.  The Sparber document V1.3 says on the bottom of page 5 that the data is valid on the rising edge of the clock pulse.  The data can very well have already changed by the falling edge.

Which clock edge to look at is going to be dependent on the interface circuitry. I should have the cables done shortly and will set up the o-silly-scope to look at the signals.

Ed


RE: Reading Digital caliper with Arduino - Vinny - 03-20-2015

On a more positive note regarding my scope, it looks like two fets are bad (shorted) so I have some on order. Grabbed the one from the basement and no video. That appears to be the fuse for the HV supply so provided something didn't blow up there I should have that one back working tonite.


RE: Reading Digital caliper with Arduino - EdK - 03-20-2015

Arvid,

I'm a bit rusty on C programming since it's been a while. I'm getting this error when I try to "Verify" the project.

sketch_mar20a.ino:2:25: fatal error: scaleReader.h: No such file or directory

The .h file is in the project directory so I'm not sure why it's not finding it. Does the #include "scaleReader.h" need to have the complete path to the project directory? I didn't think it would need it but like I said, I'm a bit rusty with C programming.

Ed


RE: Reading Digital caliper with Arduino - EdK - 03-20-2015

Never mind Arvid, I got it to compile.

Ed


RE: Reading Digital caliper with Arduino - arvidj - 03-20-2015

Ed,


Short answer ... Under the Build Process headline here ... http://www.arduino.cc/en/Hacking/BuildProcess ... it says:

Quote:The include path includes the sketch's directory, the target directory (<ARDUINO>/hardware/core/<CORE>/) and the avr include directory (<ARDUINO>/hardware/tools/avr/avr/include/), as well as any library directories (in <ARDUINO>/hardware/libraries/) which contain a header file which is included by the main sketch file.

... which seems to suggest that if the .h file is in the sketch's directory it should find it.

 The slightly longer answer ... I use Eclipse C++ with and Arduino plugin [C++] rather than the Arduino IDE [IDE].

Some of the differences are:

The .cpp file [C++] is called .ino [IDE], but I am guessing you simply copied the code into a new [IDE] project so you automatically got the .ino file.

The [IDE] does some things 'automatically' so it is 'easier' to use. In doing so it hides some stuff that a normal C developer [which I am not] would normally need to do.

What you might want to do is forget about the .h file. The [IDE] will silently add the ...


Code:
#include "Arduino.h"
 
... line to your .ino file ... i.e. you will never see it but when the project is built "it is there". That takes care of part of what is in the .h file. The other line that is important ...

Code:
#include <util/atomic.h>

... you can put at the very top of your .ino file and remove these lines ...

Code:
// Do not remove the include below
#include "scaleReader.h"

... as they are only required when using the "less automatic" [C++] system that I am using.

Other than the include differences the two development environments should be compatible so we can share all of the code below the #include directives. Certainly not a big issue.

Arvid