-
Notifications
You must be signed in to change notification settings - Fork 0
/
ADXL345.cpp
212 lines (195 loc) · 8.12 KB
/
ADXL345.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
/*
* ADXL345.cpp Created on: 17 May 2014
* Copyright (c) 2014 Derek Molloy (www.derekmolloy.ie)
* Made available for the book "Exploring Raspberry Pi"
* See: www.exploringrpi.com
* Licensed under the EUPL V.1.1
*
* This Software is provided to You under the terms of the European
* Union Public License (the "EUPL") version 1.1 as published by the
* European Union. Any use of this Software, other than as authorized
* under this License is strictly prohibited (to the extent such use
* is covered by a right of the copyright holder of this Software).
*
* This Software is provided under the License on an "AS IS" basis and
* without warranties of any kind concerning the Software, including
* without limitation merchantability, fitness for a particular purpose,
* absence of defects or errors, accuracy, and non-infringement of
* intellectual property rights other than copyright. This disclaimer
* of warranty is an essential part of the License and a condition for
* the grant of any rights to this Software.
*
* For more details, see http://www.derekmolloy.ie/
*/
#include "ADXL345.h"
#include <iostream>
#include <unistd.h>
#include <math.h>
#include <stdio.h>
using namespace std;
namespace exploringRPi {
//From Table 19. of the ADXL345 Data sheet
#define DEVID 0x00 //Device ID
#define THRESH_TAP 0x1D //Tap Threshold
#define OFSX 0x1E //X-axis Offset
#define OFSY 0x1F //Y-axis Offset
#define OFSZ 0x20 //Z-axis Offset
#define DUR 0x21 //Tap duration
#define LATENT 0x22 //Tap latency
#define WINDOW 0x23 //Tap window
#define THRESH_ACT 0x24 //Activity threshold
#define THRESH_INACT 0x25 //Threshold inactivity
#define TIME_INACT 0x26 //Inactivity time
#define ACT_INACT_CTL 0x27 //Axis enable control for activity and inactivity detection
#define THRESH_FF 0x28 //Free-fall threshold
#define TIME_FF 0x29 //Free-fall time
#define TAP_AXES 0x2A //Axis control for single tap/double tap
#define ACT_TAP_STATUS 0x2B //Source of single tap/double tap
#define BW_RATE 0x2C //Data rate and power mode control
#define POWER_CTL 0x2D //Power-saving features control
#define INT_ENABLE 0x2E //Interrupt enable control
#define INT_MAP 0x2F //Interrupt mapping control
#define INT_SOURCE 0x30 //Source of interrupts
#define DATA_FORMAT 0x31 //Data format control
#define DATAX0 0x32 //X-axis Data 0
#define DATAX1 0x33 //X-axis Data 1
#define DATAY0 0x34 //Y-axis Data 0
#define DATAY1 0x35 //Y-axis Data 1
#define DATAZ0 0x36 //Z-axis Data 0
#define DATAZ1 0x37 //Z-axis Data 1
#define FIFO_CTL 0x38 //FIFO control
#define FIFO_STATUS 0x39 //FIFO status
/**
* Method to combine two 8-bit registers into a single short, which is 16-bits on the Raspberry Pi. It shifts
* the MSB 8-bits to the left and then ORs the result with the LSB.
* @param msb an unsigned character that contains the most significant byte
* @param lsb an unsigned character that contains the least significant byte
*/
short ADXL345::combineRegisters(unsigned char msb, unsigned char lsb){
//shift the MSB left by 8 bits and OR with LSB
return ((short)msb<<8)|(short)lsb;
}
/**
* Method to calculate the pitch and roll state values. This calculation takes account of the scaling
* factors due to the resolution and gravity range to determine gravity weighted values that are used
* to calculate the angular pitch and roll values in degrees.
*/
void ADXL345::calculatePitchAndRoll(){
float gravity_range;
switch(ADXL345::range){
case ADXL345::PLUSMINUS_16_G: gravity_range=32.0f; break;
case ADXL345::PLUSMINUS_8_G: gravity_range=16.0f; break;
case ADXL345::PLUSMINUS_4_G: gravity_range=8.0f; break;
default: gravity_range=4.0f; break;
}
float resolution = 1024.0f;
if (this->resolution==ADXL345::HIGH) resolution = 8192.0f; //13-bit resolution
float factor = gravity_range/resolution;
float accXg = this->accelerationX * factor;
float accYg = this->accelerationY * factor;
float accZg = this->accelerationZ * factor;
float accXSquared = accXg * accXg ;
float accYSquared = accYg * accYg ;
float accZSquared = accZg * accZg ;
this->pitch = 180 * atan(accXg/sqrt(accYSquared + accZSquared))/M_PI;
this->roll = 180 * atan(accYg/sqrt(accXSquared + accZSquared))/M_PI;
}
/**
* Method used to update the DATA_FORMAT register and any other registers that might be added
* in the future.
* @return 0 if the register is updated successfully
*/
int ADXL345::updateRegisters(){
//update the DATA_FORMAT register
char data_format = 0x00; //+/- 2g with normal resolution
//Full_resolution is the 3rd LSB
data_format = data_format|((this->resolution)<<3);
data_format = data_format|this->range; // 1st and 2nd LSB therefore no shift
return this->writeRegister(DATA_FORMAT, data_format);
}
/**
* The constructor for the ADXL345 accelerometer object. It passes the bus number and the
* device address (with is 0x53 by default) to the constructor of I2CDevice. All of the states
* are initialized and the registers are updated.
* @param I2CBus The bus number that the ADXL345 device is on - typically 0 or 1
* @param I2CAddress The address of the ADLX345 device (default 0x53, but can be altered)
*/
ADXL345::ADXL345(unsigned int I2CBus, unsigned int I2CAddress):
I2CDevice(I2CBus, I2CAddress){ // this member initialisation list calls the parent constructor
this->I2CAddress = I2CAddress;
this->I2CBus = I2CBus;
this->accelerationX = 0;
this->accelerationY = 0;
this->accelerationZ = 0;
this->pitch = 0.0f;
this->roll = 0.0f;
this->registers = NULL;
this->range = ADXL345::PLUSMINUS_16_G;
this->resolution = ADXL345::HIGH;
this->writeRegister(POWER_CTL, 0x08);
this->updateRegisters();
}
/**
* Read the sensor state. This method checks that the device is being correctly
* read by using the device ID of the ADXL345 sensor. It will read in the accelerometer registers
* and pass them to the combineRegisters() method to be processed.
* @return 0 if the registers are successfully read and -1 if the device ID is incorrect.
*/
int ADXL345::readSensorState(){
this->registers = this->readRegisters(BUFFER_SIZE, 0x00);
if(*this->registers!=0xe5){
perror("ADXL345: Failure Condition - Sensor ID not Verified");
return -1;
}
this->accelerationX = this->combineRegisters(*(registers+DATAX1), *(registers+DATAX0));
this->accelerationY = this->combineRegisters(*(registers+DATAY1), *(registers+DATAY0));
this->accelerationZ = this->combineRegisters(*(registers+DATAZ1), *(registers+DATAZ0));
this->resolution = (ADXL345::RESOLUTION) (((*(registers+DATA_FORMAT))&0x08)>>3);
this->range = (ADXL345::RANGE) ((*(registers+DATA_FORMAT))&0x03);
this->calculatePitchAndRoll();
return 0;
}
/**
* Set the ADXL345 gravity range according to the RANGE enumeration
* @param range One of the four possible gravity ranges defined by the RANGE enumeration
*/
void ADXL345::setRange(ADXL345::RANGE range) {
this->range = range;
updateRegisters();
}
/**
* Set the ADXL345 resolution according to the RESOLUTION enumeration
* @param resolution either HIGH or NORMAL resolution. HIGH resolution is only available if the range is set to +/- 16g
*/
void ADXL345::setResolution(ADXL345::RESOLUTION resolution) {
this->resolution = resolution;
updateRegisters();
}
/**
* Useful debug method to display the pitch and roll values in degrees on a single standard output line
* @param iterations The number of 0.1s iterations to take place.
*/
void ADXL345::displayPitchAndRoll(int iterations){
int count = 0;
while(count < iterations){
cout << "Pitch:"<< this->getPitch() << " Roll:" << this->getRoll() << " \r"<<flush;
usleep(100000);
this->readSensorState();
count++;
}
}
///////////////////////////////////
float ADXL345::displayPitch(){
float pitchvalue;
this->readSensorState();
pitchvalue = this->getPitch();
return pitchvalue;
}
float ADXL345::displayRoll(){
float rollvalue;
this->readSensorState();
rollvalue = this->getRoll();
return rollvalue;
}
ADXL345::~ADXL345() {}
} /* namespace exploringRPi */