-
Notifications
You must be signed in to change notification settings - Fork 17
/
Copy pathQMC5883L.cpp
208 lines (171 loc) · 4.38 KB
/
QMC5883L.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
#include <Wire.h>
#include <math.h>
#include "QMC5883L.h"
/*
* QMC5883L
* http://wiki.epalsite.com/images/7/72/QMC5883L-Datasheet-1.0.pdf
*/
/* The default I2C address of this chip */
#define QMC5883L_ADDR 0x0D
/* Register numbers */
#define QMC5883L_X_LSB 0
#define QMC5883L_X_MSB 1
#define QMC5883L_Y_LSB 2
#define QMC5883L_Y_MSB 3
#define QMC5883L_Z_LSB 4
#define QMC5883L_Z_MSB 5
#define QMC5883L_STATUS 6
#define QMC5883L_TEMP_LSB 7
#define QMC5883L_TEMP_MSB 8
#define QMC5883L_CONFIG 9
#define QMC5883L_CONFIG2 10
#define QMC5883L_RESET 11
#define QMC5883L_RESERVED 12
#define QMC5883L_CHIP_ID 13
/* Bit values for the STATUS register */
#define QMC5883L_STATUS_DRDY 1
#define QMC5883L_STATUS_OVL 2
#define QMC5883L_STATUS_DOR 4
/* Oversampling values for the CONFIG register */
#define QMC5883L_CONFIG_OS512 0b00000000
#define QMC5883L_CONFIG_OS256 0b01000000
#define QMC5883L_CONFIG_OS128 0b10000000
#define QMC5883L_CONFIG_OS64 0b11000000
/* Range values for the CONFIG register */
#define QMC5883L_CONFIG_2GAUSS 0b00000000
#define QMC5883L_CONFIG_8GAUSS 0b00010000
/* Rate values for the CONFIG register */
#define QMC5883L_CONFIG_10HZ 0b00000000
#define QMC5883L_CONFIG_50HZ 0b00000100
#define QMC5883L_CONFIG_100HZ 0b00001000
#define QMC5883L_CONFIG_200HZ 0b00001100
/* Mode values for the CONFIG register */
#define QMC5883L_CONFIG_STANDBY 0b00000000
#define QMC5883L_CONFIG_CONT 0b00000001
/* Apparently M_PI isn't available in all environments. */
#ifndef M_PI
#define M_PI 3.14159265358979323846264338327950288
#endif
static void write_register( int addr, int reg, int value )
{
Wire.beginTransmission(addr);
Wire.write(reg);
Wire.write(value);
Wire.endTransmission();
}
static int read_register( int addr, int reg, int count )
{
Wire.beginTransmission(addr);
Wire.write(reg);
Wire.endTransmission();
Wire.requestFrom(addr,count);
int n = Wire.available();
if(n!=count) return 0;
return n;
}
void QMC5883L::reconfig()
{
write_register(addr,QMC5883L_CONFIG,oversampling|range|rate|mode);
}
void QMC5883L::reset()
{
write_register(addr,QMC5883L_RESET,0x01);
reconfig();
}
void QMC5883L::setOversampling( int x )
{
switch(x) {
case 512:
oversampling = QMC5883L_CONFIG_OS512;
break;
case 256:
oversampling = QMC5883L_CONFIG_OS256;
break;
case 128:
oversampling = QMC5883L_CONFIG_OS128;
break;
case 64:
oversampling = QMC5883L_CONFIG_OS64;
break;
}
reconfig();
}
void QMC5883L::setRange( int x )
{
switch(x) {
case 2:
range = QMC5883L_CONFIG_2GAUSS;
break;
case 8:
range = QMC5883L_CONFIG_8GAUSS;
break;
}
reconfig();
}
void QMC5883L::setSamplingRate( int x )
{
switch(x) {
case 10:
rate = QMC5883L_CONFIG_10HZ;
break;
case 50:
rate = QMC5883L_CONFIG_50HZ;
break;
case 100:
rate = QMC5883L_CONFIG_100HZ;
break;
case 200:
rate = QMC5883L_CONFIG_200HZ;
break;
}
reconfig();
}
void QMC5883L::init() {
/* This assumes the wire library has been initialized. */
addr = QMC5883L_ADDR;
oversampling = QMC5883L_CONFIG_OS512;
range = QMC5883L_CONFIG_2GAUSS;
rate = QMC5883L_CONFIG_50HZ;
mode = QMC5883L_CONFIG_CONT;
reset();
}
int QMC5883L::ready()
{
if(!read_register(addr,QMC5883L_STATUS,1)) return 0;
uint8_t status = Wire.read();
return status & QMC5883L_STATUS_DRDY;
}
int QMC5883L::readRaw( int16_t *x, int16_t *y, int16_t *z, int16_t *t )
{
while(!ready()) {}
if(!read_register(addr,QMC5883L_X_LSB,6)) return 0;
*x = Wire.read() | (Wire.read()<<8);
*y = Wire.read() | (Wire.read()<<8);
*z = Wire.read() | (Wire.read()<<8);
return 1;
}
void QMC5883L::resetCalibration() {
xhigh = yhigh = 0;
xlow = ylow = 0;
}
int QMC5883L::readHeading()
{
int16_t x, y, z, t;
if(!readRaw(&x,&y,&z,&t)) return 0;
/* Update the observed boundaries of the measurements */
if(x<xlow) xlow = x;
if(x>xhigh) xhigh = x;
if(y<ylow) ylow = y;
if(y>yhigh) yhigh = y;
/* Bail out if not enough data is available. */
if( xlow==xhigh || ylow==yhigh ) return 0;
/* Recenter the measurement by subtracting the average */
x -= (xhigh+xlow)/2;
y -= (yhigh+ylow)/2;
/* Rescale the measurement to the range observed. */
float fx = (float)x/(xhigh-xlow);
float fy = (float)y/(yhigh-ylow);
int heading = 180.0*atan2(fy,fx)/M_PI;
if(heading<=0) heading += 360;
return heading;
}