Reading a digital Indicator's value and convert it to decimal

Hello guys, I finally got my digital indicator to work. I used the code provided from this link : http://www.instructables.com/id/Reading-Digital-Callipers-with-an-Arduino-USB/
This is the only code which worked for me, unfortunately it is in binary and I'm having a hard time converting it to decimal. I tried using string but didn't worked.

Here's the actual code from the site:

// Pin Declarations
int dataIn = 11;
int clockIn = 12;

// Variables
int clock = 1;
int lastClock = 1;
unsigned long time = 0;
unsigned long timeStart = 0;
int out = 0;


void setup() {
  // Pin Set Up
  pinMode(dataIn, INPUT);     
  pinMode(clockIn, INPUT);  


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


void loop(){

  lastClock = clock;
  clock = digitalRead(clockIn);

  if (lastClock == 1 && clock == 0){
    out = digitalRead(dataIn)+digitalRead(dataIn)+digitalRead(dataIn); // Tripple sampling to remove glitches
    if((micros() - time) > 800){
      Serial.println(" ");
    }
    else if((micros() - time) > 400){
      Serial.print("  ");
    }

    if (out > 1){
      Serial.print("1");
    }
    else{
      Serial.print("0");
    }
    Serial.print(",");
    time = micros();
  }
}

Here's an example of the output i get from the serial monitor: 1,1,0,1, 0,1,0,1, 1,1,1,0, 0,0,0,0, 0
(11010101111000000)

What I want to do is to take only the first 17 digits, reverse it, remove the last digit, convert it to decimal then insert a dot "." just before the last 2 digits and store it to a variable and display to serial monitor (Maybe there's a better Idea).

please add line comments so I can study it :slight_smile:
Any help is very much appreciated.

Collect enough bits in an int variable, then use Serial.print() to output the value in decimal.

So these 17 bits (1,1,0,1, 0,1,0,1, 1,1,1,0, 0,0,0,0, 0) should be reversed (00000011110101011) and the 'last' bit thrown out (0000001111010101) then converted to decimal (0000001111010101 -> 0x03D5 -> 981) and insert a decimal point before the last two digits (divide by 100). So the example value is 9.81?

Or did you mean to take the first 16 bits (ignoring the 'last' bit), reverse them (0000 0111 1010 1011) and convert to decimal (-> 0x07AB -> 1963) so the example value is 19.63? That would be easier and would seem to fit the (1,1,0,1, 0,1,0,1, 1,1,1,0, 0,0,0,0, 0) format better.

johnwasser:
So these 17 bits (1,1,0,1, 0,1,0,1, 1,1,1,0, 0,0,0,0, 0) should be reversed (00000011110101011) and the 'last' bit thrown out (0000001111010101) then converted to decimal (0000001111010101 -> 0x03D5 -> 981) and insert a decimal point before the last two digits (divide by 100). So the example value is 9.81?
.....

Yes , that is exactly what I want to do.. it should be 16 bit but the 1st bit is some kind of a constant value and seems not to be ( should not be) included in the conversion process.. IDK why but that's the way it is reading my indicator. I took that method from one of the comment in the above link.

Try this. Instead of printing out the bit values it accumulates the 16 bits of data into an unsigned integer and displays the value when all of the bits have arrived.

// Pin Declarations
const byte DataPin = 11;
const byte ClockPin = 12;


byte BitCount = 0;
unsigned long ReceivedValue = 0;


void setup()
{
  Serial.begin(115200);
  Serial.println("Ready: ");


  // Pin Set Up
  pinMode(DataPin, INPUT);
  pinMode(ClockPin, INPUT);
}




void loop()
{
  boolean currentClockState = digitalRead(ClockPin);
  static boolean lastClockState = HIGH;


  unsigned long currentMicros = micros();
  static unsigned long lastFalingEdgeTime = 0;


  // Detect faling edge of clock
  if (lastClockState == HIGH && currentClockState == LOW)
  {
    // Get three samples of the DataPin
    int data = digitalRead(DataPin) + digitalRead(DataPin) + digitalRead(DataPin);


    // If the gap is larger then 800 microseconds it's the start of a new message
    if ((currentMicros - lastFalingEdgeTime) > 800)
    {
      BitCount = 0;
      ReceivedValue = 0;
      lastClockState = LOW;
      lastFalingEdgeTime = currentMicros;
      return;  // Ignore this first bit.
    }


    ReceivedValue >>= 1;  // Move all the bits to the right by one bit


    // If two or more of the three samples were HIGH:
    if (data > 1)
      ReceivedValue |= 0x80000000UL;  // Set the high bit


    BitCount++;


    if (BitCount == 16)
    {
      Serial.println(ReceivedValue / 100.0);
    }
    lastFalingEdgeTime = currentMicros;
  }
  lastClockState = currentClockState;
}

Thank you sir! I got to try this tomorrow evening. This seems a lot easier to understand.

I just tested in and it is giving me this weird result:

0.00 <--should be 0.00
0.00
98.30
1245.18
2555.90
16482.31
44302.33
69402.63
86441.99
86441.99 <--should be 26.39

Anyway, It's all ok now and I won't bother you too much sir. I found a better code from here and it works great:

I'm about to finish this project and I have to say thank you sir johnwasser for allocating some of your time.

It's weird but I cant copy the code from that site, so just in case someone need it,
Here's the code:

int bit_array[25]; // For storing the data bit. bit_array[0] = data bit 1 (LSB), bit_array[23] = data bit 24 (MSB).
unsigned long time_now; // For storing the time when the clock signal is changed from HIGH to LOW (falling edge trigger of data output).
int CLOCK_PIN = 2;
int DATA_PIN = 3;
void setup() {
Serial.begin(9600);
pinMode(CLOCK_PIN, INPUT);
pinMode(DATA_PIN, INPUT);
}
void loop() {
while (digitalRead(CLOCK_PIN) == LOW) {} // If clock is LOW wait until it turns to HIGH
time_now = micros();
while (digitalRead(CLOCK_PIN) == HIGH) {} // Wait for the end of the HIGH pulse
if ((micros() - time_now) > 500) { // If the HIGH pulse was longer than 500 micros we are at the start of a new bit sequence
decode(); //decode the bit sequence
}
}
void decode() {
int sign = 1;
int i = 0;
float value = 0.0;
float result = 0.0;
bit_array[i] = digitalRead(DATA_PIN); // Store the 1st bit (start bit) which is always 1.
while (digitalRead(CLOCK_PIN) == HIGH) {};
for (i = 1; i <= 24; i++) {
while (digitalRead(CLOCK_PIN) == LOW) { } // Wait until clock returns to HIGH
bit_array[i] = digitalRead(DATA_PIN);
while (digitalRead(CLOCK_PIN) == HIGH) {} // Wait until clock returns to LOW
}
for (i = 0; i <= 24; i++) { // Show the content of the bit array. This is for verification only.
Serial.print(bit_array[i]);
Serial.print(" ");
}
Serial.println();
for (i = 1; i <= 20; i++) { // Turning the value in the bit array from binary to decimal.
value = value + (pow(2, i-1) * bit_array[i]);
}
if (bit_array[21] == 1) sign = -1; // Bit 21 is the sign bit. 0 -> +, 1 => -
if (bit_array[24] == 1) { // Bit 24 tells the measureing unit (1 -> in, 0 -> mm)
result = (value*sign) / 2000.00;
Serial.print(result,3); // Print result with 3 decimals
Serial.println(" in");
} else {
result = (value*sign) / 100.00;
Serial.print(result,2); // Print result with 2 decimals
Serial.println(" mm");
}
//delay(500);
}
  • 0.00 = 0x0000
  • 98.30 = 0x2666
  • 1245.18 = 0x1E666
  • 2555.90 = 0x3E666

Looks like I forgot to clear something between reads. Oh well, looks like the code that works is a completely different protocol (24 bits instead of 17).