Subversion Repositories FlightCtrl

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
1993 - 1
/**************************************************************************
2
 *                                                                         *
3
 * ADXL345 Driver for Arduino                                              *
4
 *                                                                         *
5
 ***************************************************************************
6
 *                                                                         *
7
 * This program is free software; you can redistribute it and/or modify    *
8
 * it under the terms of the GNU License.                                  *
9
 * This program is distributed in the hope that it will be useful,         *
10
 * but WITHOUT ANY WARRANTY; without even the implied warranty of          *
11
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the           *
12
 * GNU License V2 for more details.                                        *
13
 *                                                                         *
14
 ***************************************************************************/
15
 
16
#include "WProgram.h"
17
#include "ADXL345.h"
18
#include <Wire.h>
19
 
20
#define TO_READ (6)      // num of bytes we are going to read each time (two bytes for each axis)
21
 
22
ADXL345::ADXL345() {
23
  status = ADXL345_OK;
24
  error_code = ADXL345_NO_ERROR;
25
 
26
  gains[0] = 0.00376390;
27
  gains[1] = 0.00376009;
28
  gains[2] = 0.00349265;
29
}
30
 
31
void ADXL345::init(int address) {
32
  _dev_address = address;
33
  powerOn();
34
}
35
 
36
void ADXL345::powerOn() {
37
  //Turning on the ADXL345
38
  //writeTo(ADXL345_POWER_CTL, 0);      
39
  //writeTo(ADXL345_POWER_CTL, 16);
40
  writeTo(ADXL345_POWER_CTL, 8);
41
}
42
 
43
// Reads the acceleration into an array of three places
44
void ADXL345::readAccel(int *xyz){
45
  readAccel(xyz, xyz + 1, xyz + 2);
46
}
47
 
48
// Reads the acceleration into three variable x, y and z
49
void ADXL345::readAccel(int *x, int *y, int *z) {
50
  readFrom(ADXL345_DATAX0, TO_READ, _buff); //read the acceleration data from the ADXL345
51
 
52
  // each axis reading comes in 10 bit resolution, ie 2 bytes.  Least Significat Byte first!!
53
  // thus we are converting both bytes in to one int
54
  *x = (((int)_buff[1]) << 8) | _buff[0];  
55
  *y = (((int)_buff[3]) << 8) | _buff[2];
56
  *z = (((int)_buff[5]) << 8) | _buff[4];
57
}
58
 
59
void ADXL345::get_Gxyz(float *xyz){
60
  int i;
61
  int xyz_int[3];
62
  readAccel(xyz_int);
63
  for(i=0; i<3; i++){
64
    xyz[i] = xyz_int[i] * gains[i];
65
  }
66
}
67
 
68
// Writes val to address register on device
69
void ADXL345::writeTo(byte address, byte val) {
70
  Wire.beginTransmission(_dev_address); // start transmission to device
71
  Wire.send(address);             // send register address
72
  Wire.send(val);                 // send value to write
73
  Wire.endTransmission();         // end transmission
74
}
75
 
76
// Reads num bytes starting from address register on device in to _buff array
77
void ADXL345::readFrom(byte address, int num, byte _buff[]) {
78
  Wire.beginTransmission(_dev_address); // start transmission to device
79
  Wire.send(address);             // sends address to read from
80
  Wire.endTransmission();         // end transmission
81
 
82
  Wire.beginTransmission(_dev_address); // start transmission to device
83
  Wire.requestFrom(_dev_address, num);    // request 6 bytes from device
84
 
85
  int i = 0;
86
  while(Wire.available())         // device may send less than requested (abnormal)
87
  {
88
    _buff[i] = Wire.receive();    // receive a byte
89
    i++;
90
  }
91
  if(i != num){
92
    status = ADXL345_ERROR;
93
    error_code = ADXL345_READ_ERROR;
94
  }
95
  Wire.endTransmission();         // end transmission
96
}
97
 
98
// Gets the range setting and return it into rangeSetting
99
// it can be 2, 4, 8 or 16
100
void ADXL345::getRangeSetting(byte* rangeSetting) {
101
  byte _b;
102
  readFrom(ADXL345_DATA_FORMAT, 1, &_b);
103
  *rangeSetting = _b & B00000011;
104
}
105
 
106
// Sets the range setting, possible values are: 2, 4, 8, 16
107
void ADXL345::setRangeSetting(int val) {
108
  byte _s;
109
  byte _b;
110
 
111
  switch (val) {
112
  case 2:  
113
    _s = B00000000;
114
    break;
115
  case 4:  
116
    _s = B00000001;
117
    break;
118
  case 8:  
119
    _s = B00000010;
120
    break;
121
  case 16:
122
    _s = B00000011;
123
    break;
124
  default:
125
    _s = B00000000;
126
  }
127
  readFrom(ADXL345_DATA_FORMAT, 1, &_b);
128
  _s |= (_b & B11101100);
129
  writeTo(ADXL345_DATA_FORMAT, _s);
130
}
131
// gets the state of the SELF_TEST bit
132
bool ADXL345::getSelfTestBit() {
133
  return getRegisterBit(ADXL345_DATA_FORMAT, 7);
134
}
135
 
136
// Sets the SELF-TEST bit
137
// if set to 1 it applies a self-test force to the sensor causing a shift in the output data
138
// if set to 0 it disables the self-test force
139
void ADXL345::setSelfTestBit(bool selfTestBit) {
140
  setRegisterBit(ADXL345_DATA_FORMAT, 7, selfTestBit);
141
}
142
 
143
// Gets the state of the SPI bit
144
bool ADXL345::getSpiBit() {
145
  return getRegisterBit(ADXL345_DATA_FORMAT, 6);
146
}
147
 
148
// Sets the SPI bit
149
// if set to 1 it sets the device to 3-wire mode
150
// if set to 0 it sets the device to 4-wire SPI mode
151
void ADXL345::setSpiBit(bool spiBit) {
152
  setRegisterBit(ADXL345_DATA_FORMAT, 6, spiBit);
153
}
154
 
155
// Gets the state of the INT_INVERT bit
156
bool ADXL345::getInterruptLevelBit() {
157
  return getRegisterBit(ADXL345_DATA_FORMAT, 5);
158
}
159
 
160
// Sets the INT_INVERT bit
161
// if set to 0 sets the interrupts to active high
162
// if set to 1 sets the interrupts to active low
163
void ADXL345::setInterruptLevelBit(bool interruptLevelBit) {
164
  setRegisterBit(ADXL345_DATA_FORMAT, 5, interruptLevelBit);
165
}
166
 
167
// Gets the state of the FULL_RES bit
168
bool ADXL345::getFullResBit() {
169
  return getRegisterBit(ADXL345_DATA_FORMAT, 3);
170
}
171
 
172
// Sets the FULL_RES bit
173
// if set to 1, the device is in full resolution mode, where the output resolution increases with the
174
//   g range set by the range bits to maintain a 4mg/LSB scal factor
175
// if set to 0, the device is in 10-bit mode, and the range buts determine the maximum g range
176
//   and scale factor
177
void ADXL345::setFullResBit(bool fullResBit) {
178
  setRegisterBit(ADXL345_DATA_FORMAT, 3, fullResBit);
179
}
180
 
181
// Gets the state of the justify bit
182
bool ADXL345::getJustifyBit() {
183
  return getRegisterBit(ADXL345_DATA_FORMAT, 2);
184
}
185
 
186
// Sets the JUSTIFY bit
187
// if sets to 1 selects the left justified mode
188
// if sets to 0 selects right justified mode with sign extension
189
void ADXL345::setJustifyBit(bool justifyBit) {
190
  setRegisterBit(ADXL345_DATA_FORMAT, 2, justifyBit);
191
}
192
 
193
// Sets the THRESH_TAP byte value
194
// it should be between 0 and 255
195
// the scale factor is 62.5 mg/LSB
196
// A value of 0 may result in undesirable behavior
197
void ADXL345::setTapThreshold(int tapThreshold) {
198
  tapThreshold = min(max(tapThreshold,0),255);
199
  byte _b = byte (tapThreshold);
200
  writeTo(ADXL345_THRESH_TAP, _b);  
201
}
202
 
203
// Gets the THRESH_TAP byte value
204
// return value is comprised between 0 and 255
205
// the scale factor is 62.5 mg/LSB
206
int ADXL345::getTapThreshold() {
207
  byte _b;
208
  readFrom(ADXL345_THRESH_TAP, 1, &_b);  
209
  return int (_b);
210
}
211
 
212
// set/get the gain for each axis in Gs / count
213
void ADXL345::setAxisGains(float *_gains){
214
  int i;
215
  for(i = 0; i < 3; i++){
216
    gains[i] = _gains[i];
217
  }
218
}
219
void ADXL345::getAxisGains(float *_gains){
220
  int i;
221
  for(i = 0; i < 3; i++){
222
    _gains[i] = gains[i];
223
  }
224
}
225
 
226
 
227
// Sets the OFSX, OFSY and OFSZ bytes
228
// OFSX, OFSY and OFSZ are user offset adjustments in twos complement format with
229
// a scale factor of 15,6mg/LSB
230
// OFSX, OFSY and OFSZ should be comprised between
231
void ADXL345::setAxisOffset(int x, int y, int z) {
232
  writeTo(ADXL345_OFSX, byte (x));  
233
  writeTo(ADXL345_OFSY, byte (y));  
234
  writeTo(ADXL345_OFSZ, byte (z));  
235
}
236
 
237
// Gets the OFSX, OFSY and OFSZ bytes
238
void ADXL345::getAxisOffset(int* x, int* y, int*z) {
239
  byte _b;
240
  readFrom(ADXL345_OFSX, 1, &_b);  
241
  *x = int (_b);
242
  readFrom(ADXL345_OFSY, 1, &_b);  
243
  *y = int (_b);
244
  readFrom(ADXL345_OFSZ, 1, &_b);  
245
  *z = int (_b);
246
}
247
 
248
// Sets the DUR byte
249
// The DUR byte contains an unsigned time value representing the maximum time
250
// that an event must be above THRESH_TAP threshold to qualify as a tap event
251
// The scale factor is 625µs/LSB
252
// A value of 0 disables the tap/float tap funcitons. Max value is 255.
253
void ADXL345::setTapDuration(int tapDuration) {
254
  tapDuration = min(max(tapDuration,0),255);
255
  byte _b = byte (tapDuration);
256
  writeTo(ADXL345_DUR, _b);  
257
}
258
 
259
// Gets the DUR byte
260
int ADXL345::getTapDuration() {
261
  byte _b;
262
  readFrom(ADXL345_DUR, 1, &_b);  
263
  return int (_b);
264
}
265
 
266
// Sets the latency (latent register) which contains an unsigned time value
267
// representing the wait time from the detection of a tap event to the start
268
// of the time window, during which a possible second tap can be detected.
269
// The scale factor is 1.25ms/LSB. A value of 0 disables the float tap function.
270
// It accepts a maximum value of 255.
271
void ADXL345::setDoubleTapLatency(int floatTapLatency) {
272
  byte _b = byte (floatTapLatency);
273
  writeTo(ADXL345_LATENT, _b);  
274
}
275
 
276
// Gets the Latent value
277
int ADXL345::getDoubleTapLatency() {
278
  byte _b;
279
  readFrom(ADXL345_LATENT, 1, &_b);  
280
  return int (_b);
281
}
282
 
283
// Sets the Window register, which contains an unsigned time value representing
284
// the amount of time after the expiration of the latency time (Latent register)
285
// during which a second valud tap can begin. The scale factor is 1.25ms/LSB. A
286
// value of 0 disables the float tap function. The maximum value is 255.
287
void ADXL345::setDoubleTapWindow(int floatTapWindow) {
288
  floatTapWindow = min(max(floatTapWindow,0),255);
289
  byte _b = byte (floatTapWindow);
290
  writeTo(ADXL345_WINDOW, _b);  
291
}
292
 
293
// Gets the Window register
294
int ADXL345::getDoubleTapWindow() {
295
  byte _b;
296
  readFrom(ADXL345_WINDOW, 1, &_b);  
297
  return int (_b);
298
}
299
 
300
// Sets the THRESH_ACT byte which holds the threshold value for detecting activity.
301
// The data format is unsigned, so the magnitude of the activity event is compared
302
// with the value is compared with the value in the THRESH_ACT register. The scale
303
// factor is 62.5mg/LSB. A value of 0 may result in undesirable behavior if the
304
// activity interrupt is enabled. The maximum value is 255.
305
void ADXL345::setActivityThreshold(int activityThreshold) {
306
  activityThreshold = min(max(activityThreshold,0),255);
307
  byte _b = byte (activityThreshold);
308
  writeTo(ADXL345_THRESH_ACT, _b);  
309
}
310
 
311
// Gets the THRESH_ACT byte
312
int ADXL345::getActivityThreshold() {
313
  byte _b;
314
  readFrom(ADXL345_THRESH_ACT, 1, &_b);  
315
  return int (_b);
316
}
317
 
318
// Sets the THRESH_INACT byte which holds the threshold value for detecting inactivity.
319
// The data format is unsigned, so the magnitude of the inactivity event is compared
320
// with the value is compared with the value in the THRESH_INACT register. The scale
321
// factor is 62.5mg/LSB. A value of 0 may result in undesirable behavior if the
322
// inactivity interrupt is enabled. The maximum value is 255.
323
void ADXL345::setInactivityThreshold(int inactivityThreshold) {
324
  inactivityThreshold = min(max(inactivityThreshold,0),255);
325
  byte _b = byte (inactivityThreshold);
326
  writeTo(ADXL345_THRESH_INACT, _b);  
327
}
328
 
329
// Gets the THRESH_INACT byte
330
int ADXL345::getInactivityThreshold() {
331
  byte _b;
332
  readFrom(ADXL345_THRESH_INACT, 1, &_b);  
333
  return int (_b);
334
}
335
 
336
// Sets the TIME_INACT register, which contains an unsigned time value representing the
337
// amount of time that acceleration must be less thant the value in the THRESH_INACT
338
// register for inactivity to be declared. The scale factor is 1sec/LSB. The value must
339
// be between 0 and 255.
340
void ADXL345::setTimeInactivity(int timeInactivity) {
341
  timeInactivity = min(max(timeInactivity,0),255);
342
  byte _b = byte (timeInactivity);
343
  writeTo(ADXL345_TIME_INACT, _b);  
344
}
345
 
346
// Gets the TIME_INACT register
347
int ADXL345::getTimeInactivity() {
348
  byte _b;
349
  readFrom(ADXL345_TIME_INACT, 1, &_b);  
350
  return int (_b);
351
}
352
 
353
// Sets the THRESH_FF register which holds the threshold value, in an unsigned format, for
354
// free-fall detection. The root-sum-square (RSS) value of all axes is calculated and
355
// compared whith the value in THRESH_FF to determine if a free-fall event occured. The
356
// scale factor is 62.5mg/LSB. A value of 0 may result in undesirable behavior if the free-fall
357
// interrupt is enabled. The maximum value is 255.
358
void ADXL345::setFreeFallThreshold(int freeFallThreshold) {
359
  freeFallThreshold = min(max(freeFallThreshold,0),255);
360
  byte _b = byte (freeFallThreshold);
361
  writeTo(ADXL345_THRESH_FF, _b);  
362
}
363
 
364
// Gets the THRESH_FF register.
365
int ADXL345::getFreeFallThreshold() {
366
  byte _b;
367
  readFrom(ADXL345_THRESH_FF, 1, &_b);  
368
  return int (_b);
369
}
370
 
371
// Sets the TIME_FF register, which holds an unsigned time value representing the minimum
372
// time that the RSS value of all axes must be less than THRESH_FF to generate a free-fall
373
// interrupt. The scale factor is 5ms/LSB. A value of 0 may result in undesirable behavior if
374
// the free-fall interrupt is enabled. The maximum value is 255.
375
void ADXL345::setFreeFallDuration(int freeFallDuration) {
376
  freeFallDuration = min(max(freeFallDuration,0),255);  
377
  byte _b = byte (freeFallDuration);
378
  writeTo(ADXL345_TIME_FF, _b);  
379
}
380
 
381
// Gets the TIME_FF register.
382
int ADXL345::getFreeFallDuration() {
383
  byte _b;
384
  readFrom(ADXL345_TIME_FF, 1, &_b);  
385
  return int (_b);
386
}
387
 
388
bool ADXL345::isActivityXEnabled() {  
389
  return getRegisterBit(ADXL345_ACT_INACT_CTL, 6);
390
}
391
bool ADXL345::isActivityYEnabled() {  
392
  return getRegisterBit(ADXL345_ACT_INACT_CTL, 5);
393
}
394
bool ADXL345::isActivityZEnabled() {  
395
  return getRegisterBit(ADXL345_ACT_INACT_CTL, 4);
396
}
397
bool ADXL345::isInactivityXEnabled() {  
398
  return getRegisterBit(ADXL345_ACT_INACT_CTL, 2);
399
}
400
bool ADXL345::isInactivityYEnabled() {  
401
  return getRegisterBit(ADXL345_ACT_INACT_CTL, 1);
402
}
403
bool ADXL345::isInactivityZEnabled() {  
404
  return getRegisterBit(ADXL345_ACT_INACT_CTL, 0);
405
}
406
 
407
void ADXL345::setActivityX(bool state) {  
408
  setRegisterBit(ADXL345_ACT_INACT_CTL, 6, state);
409
}
410
void ADXL345::setActivityY(bool state) {  
411
  setRegisterBit(ADXL345_ACT_INACT_CTL, 5, state);
412
}
413
void ADXL345::setActivityZ(bool state) {  
414
  setRegisterBit(ADXL345_ACT_INACT_CTL, 4, state);
415
}
416
void ADXL345::setInactivityX(bool state) {  
417
  setRegisterBit(ADXL345_ACT_INACT_CTL, 2, state);
418
}
419
void ADXL345::setInactivityY(bool state) {  
420
  setRegisterBit(ADXL345_ACT_INACT_CTL, 1, state);
421
}
422
void ADXL345::setInactivityZ(bool state) {  
423
  setRegisterBit(ADXL345_ACT_INACT_CTL, 0, state);
424
}
425
 
426
bool ADXL345::isActivityAc() {
427
  return getRegisterBit(ADXL345_ACT_INACT_CTL, 7);
428
}
429
bool ADXL345::isInactivityAc(){
430
  return getRegisterBit(ADXL345_ACT_INACT_CTL, 3);
431
}
432
 
433
void ADXL345::setActivityAc(bool state) {  
434
  setRegisterBit(ADXL345_ACT_INACT_CTL, 7, state);
435
}
436
void ADXL345::setInactivityAc(bool state) {  
437
  setRegisterBit(ADXL345_ACT_INACT_CTL, 3, state);
438
}
439
 
440
bool ADXL345::getSuppressBit(){
441
  return getRegisterBit(ADXL345_TAP_AXES, 3);
442
}
443
void ADXL345::setSuppressBit(bool state) {  
444
  setRegisterBit(ADXL345_TAP_AXES, 3, state);
445
}
446
 
447
bool ADXL345::isTapDetectionOnX(){
448
  return getRegisterBit(ADXL345_TAP_AXES, 2);
449
}
450
void ADXL345::setTapDetectionOnX(bool state) {  
451
  setRegisterBit(ADXL345_TAP_AXES, 2, state);
452
}
453
bool ADXL345::isTapDetectionOnY(){
454
  return getRegisterBit(ADXL345_TAP_AXES, 1);
455
}
456
void ADXL345::setTapDetectionOnY(bool state) {  
457
  setRegisterBit(ADXL345_TAP_AXES, 1, state);
458
}
459
bool ADXL345::isTapDetectionOnZ(){
460
  return getRegisterBit(ADXL345_TAP_AXES, 0);
461
}
462
void ADXL345::setTapDetectionOnZ(bool state) {  
463
  setRegisterBit(ADXL345_TAP_AXES, 0, state);
464
}
465
 
466
bool ADXL345::isActivitySourceOnX(){
467
  return getRegisterBit(ADXL345_ACT_TAP_STATUS, 6);
468
}
469
bool ADXL345::isActivitySourceOnY(){
470
  return getRegisterBit(ADXL345_ACT_TAP_STATUS, 5);
471
}
472
bool ADXL345::isActivitySourceOnZ(){
473
  return getRegisterBit(ADXL345_ACT_TAP_STATUS, 4);
474
}
475
 
476
bool ADXL345::isTapSourceOnX(){
477
  return getRegisterBit(ADXL345_ACT_TAP_STATUS, 2);
478
}
479
bool ADXL345::isTapSourceOnY(){
480
  return getRegisterBit(ADXL345_ACT_TAP_STATUS, 1);
481
}
482
bool ADXL345::isTapSourceOnZ(){
483
  return getRegisterBit(ADXL345_ACT_TAP_STATUS, 0);
484
}
485
 
486
bool ADXL345::isAsleep(){
487
  return getRegisterBit(ADXL345_ACT_TAP_STATUS, 3);
488
}
489
 
490
bool ADXL345::isLowPower(){
491
  return getRegisterBit(ADXL345_BW_RATE, 4);
492
}
493
void ADXL345::setLowPower(bool state) {  
494
  setRegisterBit(ADXL345_BW_RATE, 4, state);
495
}
496
 
497
float ADXL345::getRate(){
498
  byte _b;
499
  readFrom(ADXL345_BW_RATE, 1, &_b);
500
  _b &= B00001111;
501
  return (pow(2,((int) _b)-6)) * 6.25;
502
}
503
 
504
void ADXL345::setRate(float rate){
505
  byte _b,_s;
506
  int v = (int) (rate / 6.25);
507
  int r = 0;
508
  while (v >>= 1)
509
  {
510
    r++;
511
  }
512
  if (r <= 9) {
513
    readFrom(ADXL345_BW_RATE, 1, &_b);
514
    _s = (byte) (r + 6) | (_b & B11110000);
515
    writeTo(ADXL345_BW_RATE, _s);
516
  }
517
}
518
 
519
void ADXL345::set_bw(byte bw_code){
520
  if((bw_code < ADXL345_BW_3) || (bw_code > ADXL345_BW_1600)){
521
    status = false;
522
    error_code = ADXL345_BAD_ARG;
523
  }
524
  else{
525
    writeTo(ADXL345_BW_RATE, bw_code);
526
  }
527
}
528
 
529
byte ADXL345::get_bw_code(){
530
  byte bw_code;
531
  readFrom(ADXL345_BW_RATE, 1, &bw_code);
532
  return bw_code;
533
}
534
 
535
byte ADXL345::getInterruptSource() {
536
  byte _b;
537
  readFrom(ADXL345_INT_SOURCE, 1, &_b);
538
  return _b;
539
}
540
 
541
bool ADXL345::getInterruptSource(byte interruptBit) {
542
  return getRegisterBit(ADXL345_INT_SOURCE,interruptBit);
543
}
544
 
545
bool ADXL345::getInterruptMapping(byte interruptBit) {
546
  return getRegisterBit(ADXL345_INT_MAP,interruptBit);
547
}
548
 
549
// Set the mapping of an interrupt to pin1 or pin2
550
// eg: setInterruptMapping(ADXL345_INT_DOUBLE_TAP_BIT,ADXL345_INT2_PIN);
551
void ADXL345::setInterruptMapping(byte interruptBit, bool interruptPin) {
552
  setRegisterBit(ADXL345_INT_MAP, interruptBit, interruptPin);
553
}
554
 
555
bool ADXL345::isInterruptEnabled(byte interruptBit) {
556
  return getRegisterBit(ADXL345_INT_ENABLE,interruptBit);
557
}
558
 
559
void ADXL345::setInterrupt(byte interruptBit, bool state) {
560
  setRegisterBit(ADXL345_INT_ENABLE, interruptBit, state);
561
}
562
 
563
void ADXL345::setRegisterBit(byte regAdress, int bitPos, bool state) {
564
  byte _b;
565
  readFrom(regAdress, 1, &_b);
566
  if (state) {
567
    _b |= (1 << bitPos);  // forces nth bit of _b to be 1.  all other bits left alone.
568
  }
569
  else {
570
    _b &= ~(1 << bitPos); // forces nth bit of _b to be 0.  all other bits left alone.
571
  }
572
  writeTo(regAdress, _b);  
573
}
574
 
575
bool ADXL345::getRegisterBit(byte regAdress, int bitPos) {
576
  byte _b;
577
  readFrom(regAdress, 1, &_b);
578
  return ((_b >> bitPos) & 1);
579
}
580
 
581
// print all register value to the serial ouptut, which requires it to be setup
582
// this can be used to manually to check the current configuration of the device
583
void ADXL345::printAllRegister() {
584
  byte _b;
585
  Serial.print("0x00: ");
586
  readFrom(0x00, 1, &_b);
587
  print_byte(_b);
588
  Serial.println("");
589
  int i;
590
  for (i=29;i<=57;i++){
591
    Serial.print("0x");
592
    Serial.print(i, HEX);
593
    Serial.print(": ");
594
    readFrom(i, 1, &_b);
595
    print_byte(_b);
596
    Serial.println("");    
597
  }
598
}
599
 
600
void print_byte(byte val){
601
  int i;
602
  Serial.print("B");
603
  for(i=7; i>=0; i--){
604
    Serial.print(val >> i & 1, BIN);
605
  }
606
}
607
 
608