bcd_caliper.ino


1
/*
2
        Reading data from digital calipers with 6 digit BCD protocol
3
4
        Data format as it appears on the serial line.
5
        The first nibble holds 1/100mmm, the next 1/10mm, then 1mm and so on.
6
      If the unit is inches, it starts with 1/1000 inch.
7
        Nibble_1 Nibble_2 Nibble_3 Nibble_4 Nibble_5 Nibble_6 Nibble_7
8
        -------- -------- -------- -------- -------- -------- --------
9
        xxxx.xN  xxxx.Nx  xxxN.xx  xxxNx.xx  xNxx.xx Nxxx.xx  bitvalues  # mm
10
        xxx.xxN  xxx.xNx  xxx.Nxx  xxxN.xxx  xNx.xxx Nxx.xxx  bitvalues  # inches
11
      
12
        Nibble 1-6 : BCD (binary coded decimal)
13
        Timing:
14
          1 bit               ca.  12 µsec
15
          1 nibble with sync  ca. 100 µsec
16
            example 1, first nibble : 1010 = 5
17
                 _____   _   _   _   ______
18
            ____|     |_| |_| |_| |_|         clock (falling edge = data valid , rising edge = data change)
19
20
                      1   2   4   8           bit value
21
                 _______     ___ 
22
            ____|       |___|   |___N         data; N = set to value of first bit in NEXT nibble
23
24
            example 2, first nibble : 0010 = 4
25
                 _____   _   _   _   ______
26
            ____|     |_| |_| |_| |_|         clock (falling edge = data valid , rising edge = data change)
27
28
                      1   2   4   8           bit value
29
                             ___ 
30
            ________________|   |___N         data; N = set to value of first bit in NEXT nibble
31
  
32
        Nibble 7   : Bit 0: sign; 0=plus,1=minus
33
                     Bit 1: 5/10000-inch (if unit is inch), 0=off, 1=on
34
                     Bit 2: unit,  0=inch, 1=mm
35
                     Bit 3: (?, always 1)
36
37
        whole packet ca. 750 µsec, pause between packets ca. 300 ms
38
39
        references:
40
        http://www.mikrocontroller.net/articles/Me%C3%9Fschieber_auslesen
41
        http://www.mikrocontroller.net/topic/30219
42
        http://www.roboternetz.de/community/threads/45869-digitale-schieblehre-auslesen
43
      http://www.pcbheaven.com/exppages/Digital_Caliper_Protocol/
44
        http://code.google.com/p/digitalwritefast/
45
46
        BL, 2015-aug-14
47
*/
48
49
50
#include <LiquidCrystal.h>
51
// ------------- LCD pin declarations
52
// initialize the library with the interface pin numbers
53
//                RS  EN  D4 D5 D6 D7
54
LiquidCrystal lcd(12, 11, 7, 6, 5, 4);
55
56
// library from http://code.google.com/p/digitalwritefast/
57
#include <digitalWriteFast.h>
58
59
#define BITS 28         // data bits in one burst
60
#define STARTUP BITS+2  // value which is not reached during sync'ed transfer. used to identify startup
61
#define DATAIN 3        // data in pin number
62
63
// ------------- global variables
64
int           clockIn = 2;   // clockIn pin number
65
volatile int  bitVal[30];    // bit read buffer
66
volatile int  bitCount = STARTUP;
67
unsigned int  timer;         // used to detect pause between data bursts
68
69
// ------------- setup
70
void setup() {
71
  pinMode (DATAIN, INPUT);
72
  pinMode(clockIn, INPUT);
73
  attachInterrupt (0, getBit, FALLING);
74
  // Serial.begin(115200);
75
}
76
77
// ------------- interupt service routine
78
void getBit(){
79
  if ( bitCount <= BITS ){
80
  /*
81
   * read data bit
82
   * needs 'fast' variant, 'digitalRead' too slow
83
   */
84
  bitVal[bitCount] = digitalReadFast2(DATAIN);
85
  bitCount++;
86
  }
87
}
88
89
// ------------- loop
90
void loop(){
91
  int  bc;          // bit counter
92
  int  sc;          // shift counter
93
  int  dc;          // digit counter
94
  int  nibble;      // 4 bit buffer
95
  int  bcdDigit[7]; // BCD + bitmask in [6]
96
  // display data
97
  char sign;
98
  int ftt;           // 5/10000 inch
99
  char* units;       // mm or inch
100
  char* displayText = "1234567890123456";  // display buffer
101
102
  // ------------- sync with pause between data bursts
103
104
  if ( bitCount > BITS ){
105
    if ( bitCount < STARTUP){      // startup done, now synced
106
    // process data bits
107
    // Serial.println(bitCount);
108
    
109
    // bit decoding to BCD
110
    sc = 0;
111
    dc = 0;
112
    nibble=0;
113
    for ( bc = 0; bc < BITS; bc++ ){
114
      nibble |=  bitVal[bc] << sc;
115
      // Serial.print(bitVal[bc]);
116
      if ( bc %4 == 3 ){
117
        // Serial.print("(");
118
        // Serial.print(nibble,HEX);
119
        // Serial.print(") ");
120
        
121
        bcdDigit[dc] = nibble;
122
        nibble = 0;
123
        sc = 0;
124
        dc++;
125
      }else{
126
        sc++;
127
      }
128
    }
129
130
    // ------------- format output
131
    // check sign bit
132
    if ( bcdDigit[6] & 0x1 ){
133
      sign = '-';
134
    }else{
135
      sign = '+';
136
    }
137
    // check 5/10000 bit
138
    if ( bcdDigit[6] & 0x2 ){
139
      ftt = 5;
140
    }else{
141
      ftt = 0;
142
    }
143
    // check units bit
144
    if ( bcdDigit[6] & 0x4 ){
145
      units = "mm";
146
      sprintf(displayText, "%c%d%d%d.%d%d %s",
147
        sign,
148
        bcdDigit[4], bcdDigit[3], bcdDigit[2], bcdDigit[1], bcdDigit[0],
149
        units);
150
        // Serial.println(" ");
151
        // Serial.print(displayText);
152
        // Serial.println(" ");
153
    }else{
154
      units = "inch";
155
          sprintf(displayText, "%c %d%d.%d%d%d%d %s",
156
      sign,
157
      bcdDigit[4], bcdDigit[3], bcdDigit[2], bcdDigit[1], bcdDigit[0],ftt,
158
      units);
159
      // Serial.println(" ");
160
      // Serial.print(displayText);
161
      // Serial.println(" ");
162
      }
163
    }
164
165
    // display caliper value on LCD
166
    lcd.clear();
167
    //          col,row
168
    lcd.setCursor(0,0);
169
    lcd.print(displayText);
170
    
171
    // display done, now sync with next data burst
172
    
173
    // Serial.println("syncing");
174
    // wait for clock becoming low
175
    while ( digitalRead(clockIn) == 1 ){}
176
    // record time of falling edge
177
    timer = millis();
178
    // wait for clock becoming high
179
    while ( digitalRead(clockIn) == 0 ){}       
180
    // verify time of rising edge
181
    if ( millis() - timer > 200 ){
182
      // enable bit capture in ISR getBit
183
      bitCount = 0;
184
    }
185
  }
186
  delay(20);
187
}
188
189
/*
190
 serial debug output:
191
syncing
192
0100(2) 1001(9) 1010(5) 1110(7) 0000(0) 0000(0) 0011(C)  
193
+075.92 mm   
194
syncing
195
0100(2) 1001(9) 1010(5) 1110(7) 0000(0) 0000(0) 0011(C)  
196
+075.92 mm   
197
 */