Reading Digital caliper with Arduino
#91
Trying to display 24 bits on an 8" screen is going to scrunch them for sure. I tried taking a picture with my camera but it's no better.
I've scaled up the attached image using GIMP. We'll see if that works better.

Ed

EDIT: Yup, that helps.


   
Reply
Thanks given by:
#92
Much easier. I see 0.333"
Reply
Thanks given by:
#93
(03-26-2015, 05:58 PM)Vinny Wrote: Much easier.  I see 0.333"

It's the metric conversion of .262" which is 6.66mm. That image is in metric mode.

Ed
Reply
Thanks given by:
#94
Try disconnecting the scale from the data line and then tie it high and see what the app thinks it is reading. Then tie it low and it had better think all the bits are the opposite.

If it doesn't change then ...
Reply
Thanks given by:
#95
I wasn't bothering with us/metric. I just figured all the remaining bits would be 0s. Using the same data that I read earlier when I came up with .333, yes it is 6.66 mm.
Reply
Thanks given by:
#96
(03-26-2015, 08:40 PM)arvidj Wrote: Try disconnecting the scale from the data line and then tie it high and see what the app thinks it is reading. Then tie it low and it had better think all the bits are the opposite.

If it doesn't change then ...

What I did before I went to bed last night was to use the diagnostic output pin and in the ISR right after reading the data bit in and storing it in the shift register I output that data bit to the diagnostic pin and the pin followed the data on the input pin so I know it's reading the data bit properly. It has to be something in the way we are storing the bits or displaying the bits. When I get home from work today, I'm going to try putting the serial.print inside the ISR and see if the data displays properly. I know it's advised not to do that but for a test it'll add one more bit of information to help solve this.

Ed
Reply
Thanks given by:
#97
I don't think you can put the print statement inside the interrupt because it uses inter ups to function. I'll look at the code tomorrow morning and fix it. I actually think I know what is wrong.
Reply
Thanks given by:
#98
Good because I'm running out of ideas. I did have a bit, no pun intended, of success by having the ISR just set a flag when a bit was available and then in the main routine I processed the bits. It worked, to a point anyway. I have to go into work tomorrow morning but I'll be able to access the forum from work.

Ed
Reply
Thanks given by:
#99
First thing to try ... and yes, this is one of those "DUH, where did that come from" moments.

In the main processing loop there is are these lines ...

Code:
   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;
   }

and I think we need to change it to ...

Code:
   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;
   }

I'm not exactly sure where the '= 0' came from but it is certainly wrong;

I also changed how the value of the data line is captured in the interrupt. Here is the code for the new, improved version [don't forget to remove the 'include' at the top of the file. Note the new define ... DATA_STATE_INDICATING_A_ONE ... which will allow us to easily set if a HIGH or a LOW on the data line means ONE.

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 DATA_STATE_INDICATING_A_ONE LOW          // Does a HIGH or LOW on the data line indicate a value of 1

#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_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 << 1;                      // Make room for the next data bit and then set it
      if (digitalRead(DATA_PIN) == DATA_STATE_INDICATING_A_ONE) {

        // We only need to do something if the data line indicates a ONE as the shift has already put in the ZERO value
        inProcessBurstData | DATA_BIT_ONE_VALUE;
      }
     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;
   }
   Serial.print(lastCapturedBurstCounter);
   Serial.print(", ");
   Serial.print(burstData, HEX);
   Serial.print(", ");
   Serial.println(burstData, BIN);
 }
}

Let me know if this is progress or ...,
Arvid
Reply
Thanks given by:
Arvid,

All that shows up in the serial monitor is "Ready:". No data.

One thing I haven't mentioned yet that I noticed a couple of days ago is that you're shifting the bits left which will put the least significant bit into the most significant bit position.

Ed
Reply
Thanks given by:




Users browsing this thread: 3 Guest(s)