03-31-2015, 07:10 PM
Updated the code to add displaying the actual digital caliper display.
Ed
Ed
Code:
// Do not remove the include below
#include <util/atomic.h>
#define INTERRUPT_NUMBER 0
#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 DATA_STATE_INDICATING_A_ONE HIGH // Does a HIGH or LOW on the data line indicate a value of 1
#define CLOCK_NOISE_FILTER 10 // How many microseconds long must the clock be stable for it to be consider 'good'
#define MINIMUM_BURST_START_PULSE_WIDTH 80000 // At a minimum, how many microseconds long is the pulse at the beginning of a burst
#define MAXIMUM_TIME_FOR_A_SINGLE_BURST 10000 // The maximum amount of time that a burst should take before considered invalid
#define DATA_BIT_ZERO_VALUE 0UL // For readability ...
#define DATA_BIT_ONE_VALUE 1UL // For readability ...
#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;
(digitalRead(DATA_PIN) == DATA_STATE_INDICATING_A_ONE) ? (inProcessBurstData = DATA_BIT_ONE_VALUE) : (inProcessBurstData = DATA_BIT_ZERO_VALUE);
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 = inProcessBurstData << 1; // Make room for the next data bit and then set it
if (digitalRead(DATA_PIN) == 1) // We only need to do something if the data line indicates a ONE as the shift has already put in the ZERO value
{
bitSet(inProcessBurstData, 0);
}
else
bitClear(inProcessBurstData, 0);
dataBitsReceived += 1;
if (dataBitsReceived == DATA_BITS_IN_A_VALID_BURST) // Are we done with this burst?
{
capturedBurstData = inProcessBurstData;
capturedBurstCounter = 24;
processingBurst = false;
}
}
}
}
// Variables used by the application loop
unsigned long burstData = 0;
unsigned long tempData = 0;
byte bitCount = 0;
float data[] = {.5, 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096};
float caliperData = 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(INTERRUPT_NUMBER, clockTransitioned, CLOCK_TRANSITION);
Serial.begin(115200);
Serial.println("Ready: ");}
// The loop function is called in an endless loop
void loop()
{
if (capturedBurstCounter == 24)
{ // If there is something new available then get it and print it
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;
bitCount = capturedBurstCounter;
capturedBurstCounter = 0;
}
burstData &= 0x00ffffff;
int y = 0;
caliperData = 0;
for(int x = 23; x >= 0; x--)
{
if (bitRead(burstData, x))
{
bitSet(tempData, y);
caliperData += data[y];
}
else
bitClear(tempData, y);
++y;
}
Serial.print(bitCount);
Serial.print(", ");
Serial.print(tempData, HEX);
Serial.print(", ");
Serial.print(tempData, BIN);
Serial.print(", ");
Serial.println((caliperData / 1000), 4);
}
}