Ruben Laguna’s blog

Arduino XBee Sensor (Temperature, Tilt, Compass, and Ambient Light)

I finally put together an Arduino Pro Mini, the XBee, the MMA7260Q, the HMC6352, the TEMT6000 and the DS1620.

This is how it looks like on the prototyping board (ugly, I know)

xbee sensors on protoboard

Hopefully it would look better when I move it to the PCB. But before doing that I need to get the battery power set up. (I’m waiting for a MAX756 DC-DC voltage regulator and CoilCraft inductors to arrive)

The XBee uses the API mode and I implemented a Zigbee Application Layer protocol stack in Arduino instead of using the Serial interface like the rest of Arduino-XBee project that I’ve seen.

I implemented the Temperature Measurement Cluster ID (0x0402) and the Illuminance Measurement Cluster ID (0x0400) (see Zigbee Cluster Library ). Then I also two non-standard cluster ids, the Tilt Measurement Cluster ID (0xFC00) and the Heading Measurement Cluster ID (0xFC01).

You can download the source code for the Arduino project.

Below you can find the main project file, from here I pass the control to the Xbee library and control the sleep cycle of the Arduino. The XBee library will invoke the callbacks (fgetTemperature, etc) when it needs the data. ie. it receives a read command. The callbacks(function pointers) point to functions in the main file (readDs1620, readTEMT6000, etc) and the callbacks are implemented in this main file which also contains the calls to ds1620 library, hmc6352 library and mma7260q library. To see the source files of the libraries download the sources. I also made independent libraries for ds1620, hmc6352 and mma7260q each one containing an example.

The code (also as gist):

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
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363

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
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
<span class='line'>/*
</span><span class='line'> XBee sensor
</span><span class='line'> ZCL Temperature Measurement Cluster
</span><span class='line'>*/
</span><span class='line'>
</span><span class='line'>#define ledPin 13
</span><span class='line'>
</span><span class='line'>#define lcdPin 6
</span><span class='line'>#define temt6000Pin 3
</span><span class='line'>
</span><span class='line'>
</span><span class='line'>#include &lt;stdlib.h>
</span><span class='line'>#include &lt;math.h>
</span><span class='line'>
</span><span class='line'>#include &lt;Stdio.h>
</span><span class='line'>#include &lt;SoftwareSerial.h>
</span><span class='line'>#include &lt;avr/power.h>
</span><span class='line'>#include &lt;avr/sleep.h>
</span><span class='line'>#include "XBeeLibrary.h"
</span><span class='line'>#include "ds1620.h"
</span><span class='line'>#include &lt;Wire.h>
</span><span class='line'>#include "hmc6352.h"
</span><span class='line'>#include &lt;math.h>
</span><span class='line'>#include &lt;float.h>
</span><span class='line'>#include &lt;limits.h>
</span><span class='line'> 
</span><span class='line'> 
</span><span class='line'>
</span><span class='line'>int xaxis = 0;
</span><span class='line'>int yaxis = 1;   
</span><span class='line'>int zaxis = 2;   
</span><span class='line'>
</span><span class='line'>float xa=0;
</span><span class='line'>float ya=0;
</span><span class='line'>float za=0;
</span><span class='line'>
</span><span class='line'>
</span><span class='line'>
</span><span class='line'>
</span><span class='line'>int minx = INT_MAX;
</span><span class='line'>int maxx = 0;
</span><span class='line'>int miny = INT_MAX;
</span><span class='line'>int maxy = 0;
</span><span class='line'>int minz = INT_MAX;
</span><span class='line'>int maxz = 0;
</span><span class='line'>
</span><span class='line'>float g0x = 0;
</span><span class='line'>float g0y = 0;
</span><span class='line'>float g0z = 0;
</span><span class='line'>
</span><span class='line'>//long time1 = 0;
</span><span class='line'>//long time2 = 0;
</span><span class='line'>
</span><span class='line'>
</span><span class='line'>// set up a new serial port
</span><span class='line'>SoftwareSerial lcdSerial = SoftwareSerial(lcdPin,lcdPin);
</span><span class='line'>byte pinState[16];
</span><span class='line'>byte backlightValue = 0x9D;
</span><span class='line'>
</span><span class='line'>// set up ds1620
</span><span class='line'>Ds1620 ds1620 = Ds1620(7/*rst*/,8/*clk*/,9/*dq*/);
</span><span class='line'>
</span><span class='line'>//set up hmc6352
</span><span class='line'>Hmc6352 hmc6352;
</span><span class='line'>
</span><span class='line'>  
</span><span class='line'>void setup()  {  
</span><span class='line'>  pinMode(ledPin, OUTPUT);
</span><span class='line'>  pinMode(lcdPin, OUTPUT);
</span><span class='line'>  pinMode(temt6000Pin,INPUT);
</span><span class='line'>  pinMode(xaxis,INPUT);
</span><span class='line'>  pinMode(yaxis,INPUT);
</span><span class='line'>  pinMode(zaxis,INPUT);  
</span><span class='line'>  
</span><span class='line'>  // set the data rate for the SoftwareSerial port
</span><span class='line'>  lcdSerial.begin(4800);
</span><span class='line'>  
</span><span class='line'>  Serial.begin(9600);
</span><span class='line'>  delay(100);
</span><span class='line'>  
</span><span class='line'>  // configure ds1620
</span><span class='line'>  ds1620.config();
</span><span class='line'>  
</span><span class='line'>  //initial calibration of the MMA7260q 
</span><span class='line'>  minx = 173.0;
</span><span class='line'>  miny = 192.0;  
</span><span class='line'>  minz = 258.0;
</span><span class='line'>  
</span><span class='line'>  maxx = 766.0;  
</span><span class='line'>  maxy = 720.0;  
</span><span class='line'>  maxz = 914.0;
</span><span class='line'>  
</span><span class='line'>  g0x = 469.0;
</span><span class='line'>  g0y = 456.0;
</span><span class='line'>  g0z = 586.0;
</span><span class='line'>  
</span><span class='line'>  lcdPrint("RST\r\n");delay(100);  
</span><span class='line'>}
</span><span class='line'>
</span><span class='line'>long start =0;
</span><span class='line'>
</span><span class='line'>void loop() 
</span><span class='line'>{ 
</span><span class='line'>  struct zigbee zb;
</span><span class='line'>  unsigned long time;
</span><span class='line'>  unsigned long time2;
</span><span class='line'>  
</span><span class='line'>  xbee_init(&zb);  
</span><span class='line'>  zb.fgetTemperature = &readDs1620;
</span><span class='line'>  zb.fprogress = &toggleLedPin;
</span><span class='line'>  zb.ferror = &lcdPrint;
</span><span class='line'>  zb.fprint = &lcdPrint;
</span><span class='line'>  zb.fprintHex = &lcdPrintBuffer;
</span><span class='line'>  zb.fgetHeading = &readHmc6352;
</span><span class='line'>  zb.fgetIlluminance = &readTEMT6000;
</span><span class='line'>  zb.fgetTilt = readMMA7260Q;
</span><span class='line'>  
</span><span class='line'>  
</span><span class='line'>  XBee xbee(&zb);  
</span><span class='line'>   
</span><span class='line'>  time = 0;
</span><span class='line'>  time2 = 0;
</span><span class='line'>  
</span><span class='line'>  //lcdPrintInt(millis());
</span><span class='line'>  while(1) 
</span><span class='line'>  {
</span><span class='line'>    xbee.serve();
</span><span class='line'>    if ((millis()-time) > 500) {
</span><span class='line'>      time = millis();
</span><span class='line'>      toggle(ledPin);
</span><span class='line'>      //lcdSerial.print("ab\r\n");
</span><span class='line'>    }
</span><span class='line'>    
</span><span class='line'>    
</span><span class='line'>    
</span><span class='line'>    int pfx /*valx*/ = analogRead(xaxis);    // read the value from the sensor
</span><span class='line'>    int pfy /*valy*/ = analogRead(yaxis);    // read the value from the sensor
</span><span class='line'>    int pfz /*valz*/ = analogRead(zaxis);    // read the value from the sensor
</span><span class='line'>  
</span><span class='line'>  
</span><span class='line'>    autoZeroCalibration(pfx,pfy,pfz);
</span><span class='line'>  
</span><span class='line'>    
</span><span class='line'>    
</span><span class='line'>    if ((millis()-time2) > 25000) {
</span><span class='line'>      goToSleep();
</span><span class='line'>      time2 = millis();
</span><span class='line'>    }
</span><span class='line'>    
</span><span class='line'>  }  
</span><span class='line'>}
</span><span class='line'>
</span><span class='line'>void goToSleep()
</span><span class='line'>{
</span><span class='line'>    /* Now is the time to set the sleep mode. In the Atmega8 datasheet
</span><span class='line'>     * http://www.atmel.com/dyn/resources/prod_documents/doc2486.pdf on page 35
</span><span class='line'>     * there is a list of sleep modes which explains which clocks and 
</span><span class='line'>     * wake up sources are available in which sleep modus.
</span><span class='line'>     *
</span><span class='line'>     * In the avr/sleep.h file, the call names of these sleep modus are to be found:
</span><span class='line'>     *
</span><span class='line'>     * The 5 different modes are:
</span><span class='line'>     *     SLEEP_MODE_IDLE         -the least power savings 
</span><span class='line'>     *     SLEEP_MODE_ADC
</span><span class='line'>     *     SLEEP_MODE_PWR_SAVE
</span><span class='line'>     *     SLEEP_MODE_STANDBY
</span><span class='line'>     *     SLEEP_MODE_PWR_DOWN     -the most power savings
</span><span class='line'>     * 
</span><span class='line'>     */  
</span><span class='line'>     
</span><span class='line'>  set_sleep_mode(SLEEP_MODE_IDLE);   // sleep mode is set here
</span><span class='line'>
</span><span class='line'>  sleep_enable();          // enables the sleep bit in the mcucr register
</span><span class='line'>                             // so sleep is possible. just a safety pin 
</span><span class='line'>  
</span><span class='line'>  power_adc_disable();
</span><span class='line'>  power_spi_disable();
</span><span class='line'>  power_timer0_disable();
</span><span class='line'>  power_timer1_disable();
</span><span class='line'>  power_timer2_disable();
</span><span class='line'>  power_twi_disable();
</span><span class='line'>  
</span><span class='line'>  digitalWrite(ledPin, 0);
</span><span class='line'>  lcdPrint("slp\r\n");
</span><span class='line'>  
</span><span class='line'>  sleep_mode();            // here the device is actually put to sleep!!
</span><span class='line'> 
</span><span class='line'>  digitalWrite(ledPin, 1);
</span><span class='line'> lcdPrint("wk\r\n");
</span><span class='line'>  
</span><span class='line'>                              // THE PROGRAM CONTINUES FROM HERE AFTER WAKING UP
</span><span class='line'>  sleep_disable();         // first thing after waking from sleep:
</span><span class='line'>                            // disable sleep...
</span><span class='line'>
</span><span class='line'>  power_all_enable();
</span><span class='line'>   
</span><span class='line'>}
</span><span class='line'>
</span><span class='line'>void toggleLedPin() {
</span><span class='line'>  toggle(ledPin);
</span><span class='line'>}
</span><span class='line'>
</span><span class='line'>float readDs1620()
</span><span class='line'>{
</span><span class='line'>  ds1620.start_conv();
</span><span class='line'>  int raw_data = ds1620.read_data();
</span><span class='line'>  ds1620.stop_conv();
</span><span class='line'>  float temp = raw_data / 2.0; 
</span><span class='line'>  return temp;
</span><span class='line'>}
</span><span class='line'>
</span><span class='line'>float readHmc6352()
</span><span class='line'>{
</span><span class='line'>  hmc6352.wake();
</span><span class='line'>  float a = hmc6352.getHeading();
</span><span class='line'>  hmc6352.sleep();
</span><span class='line'> 
</span><span class='line'>  return a;
</span><span class='line'> 
</span><span class='line'>}
</span><span class='line'>
</span><span class='line'>
</span><span class='line'>
</span><span class='line'>
</span><span class='line'>void toggle(int pinNum) {
</span><span class='line'>  // set the LED pin using the pinState variable:
</span><span class='line'>  digitalWrite(pinNum, pinState[pinNum]); 
</span><span class='line'>  // if pinState = 0, set it to 1, and vice versa:
</span><span class='line'>  pinState[pinNum] = !pinState[pinNum];
</span><span class='line'>}
</span><span class='line'>
</span><span class='line'>
</span><span class='line'>int readTEMT6000()
</span><span class='line'>{
</span><span class='line'>  int val = analogRead(temt6000Pin);   
</span><span class='line'>  return val;
</span><span class='line'>}
</span><span class='line'>
</span><span class='line'>
</span><span class='line'>float readMMA7260Q(int a)
</span><span class='line'>{
</span><span class='line'>    int pfx /*valx*/ = analogRead(xaxis);    // read the value from the sensor
</span><span class='line'>    int pfy /*valy*/ = analogRead(yaxis);    // read the value from the sensor
</span><span class='line'>    int pfz /*valz*/ = analogRead(zaxis);    // read the value from the sensor
</span><span class='line'>
</span><span class='line'>    autoZeroCalibration(pfx,pfy,pfz);
</span><span class='line'>  
</span><span class='line'>    int fx = (pfx - g0x);
</span><span class='line'>    int fy = (pfy - g0y);
</span><span class='line'>    int fz = (pfz - g0z);
</span><span class='line'>    
</span><span class='line'>    float ax = (fx*2.0)/((maxx-minx));    
</span><span class='line'>    float ay = (fy*2.0)/((maxy-miny));
</span><span class='line'>    float az = (fz*2.0)/((maxz-minz));
</span><span class='line'>    
</span><span class='line'> 
</span><span class='line'>    float rho =   atan(ax/sqrt(pow(ay,2)+pow(az,2)))*(57.2957795129); //57.2957795129 degrees per rad  
</span><span class='line'>    float phi =   atan(ay/sqrt(pow(ax,2)+pow(az,2)))*(57.2957795129);  
</span><span class='line'>    float theta = atan(sqrt(pow(ay,2)+pow(ax,2))/az)*(57.2957795129);  
</span><span class='line'>
</span><span class='line'>    switch (a)
</span><span class='line'>    {
</span><span class='line'>      case 1:
</span><span class='line'>        return rho;
</span><span class='line'>        break;
</span><span class='line'>      case 2:
</span><span class='line'>        return phi;
</span><span class='line'>        break;
</span><span class='line'>      case 3:
</span><span class='line'>        return theta;
</span><span class='line'>        break;
</span><span class='line'>      default:        
</span><span class='line'>        break;
</span><span class='line'>    }
</span><span class='line'>    return 0;
</span><span class='line'>  
</span><span class='line'>}
</span><span class='line'>
</span><span class='line'>
</span><span class='line'>
</span><span class='line'>void autoZeroCalibration(int pfx, int pfy, int pfz)
</span><span class='line'>{
</span><span class='line'>    //if ((pfx &lt; minx)||(pfy &lt; miny)||(pfz &lt; minz)||(pfx > maxx)||(pfy > maxy)||(pfz > maxz)) {
</span><span class='line'>     // autozero calibration
</span><span class='line'>     if (pfx &lt; minx) minx = pfx;
</span><span class='line'>     if (pfy &lt; miny) miny = pfy;
</span><span class='line'>     if (pfz &lt; minz) minz = pfz;
</span><span class='line'>  
</span><span class='line'>     if (pfx > maxx) maxx = pfx;
</span><span class='line'>     if (pfy > maxy) maxy = pfy;
</span><span class='line'>     if (pfz > maxz) maxz = pfz;
</span><span class='line'>    
</span><span class='line'>     g0x = ((maxx - minx)/2)+minx;
</span><span class='line'>     g0y = ((maxy - miny)/2)+miny;
</span><span class='line'>     g0z = ((maxz - minz)/2)+minz;
</span><span class='line'>     
</span><span class='line'>     //printValues();
</span><span class='line'>  //}
</span><span class='line'>}
</span><span class='line'>
</span><span class='line'>////////////////////////////////////
</span><span class='line'>//// Print functions
</span><span class='line'>//////////////////////////////////
</span><span class='line'>
</span><span class='line'>
</span><span class='line'>//void lcdPrintError(char *msg)
</span><span class='line'>//{
</span><span class='line'>//  lcdSerial.print("err:");
</span><span class='line'>//  lcdSerial.print(msg);
</span><span class='line'>//}
</span><span class='line'>
</span><span class='line'>void lcdPrint(char *msg)
</span><span class='line'>{
</span><span class='line'>  //lcdSerial.print(millis());
</span><span class='line'>  //lcdSerial.print(":");
</span><span class='line'> // lcdSerial.print(msg);
</span><span class='line'>  
</span><span class='line'>}
</span><span class='line'>
</span><span class='line'>//void lcdPrintInt(long i)
</span><span class='line'>//{
</span><span class='line'>//  lcdSerial.print(i, DEC);
</span><span class='line'>//}
</span><span class='line'>
</span><span class='line'>
</span><span class='line'>//void lcdPrintHex(byte *hex, int size) 
</span><span class='line'>//{
</span><span class='line'>//  for(int i=0;i&lt;size;i++)
</span><span class='line'>//  {
</span><span class='line'>    //lcdPrintHex(hex[i]);
</span><span class='line'>//  }
</span><span class='line'>//}
</span><span class='line'>
</span><span class='line'>void lcdPrintBuffer(byte *hex, int size)
</span><span class='line'>{
</span><span class='line'>  //lcdPrintHex(hex,size);
</span><span class='line'>  //lcdPrintBuffer(hex,size,"buf");
</span><span class='line'>}
</span><span class='line'>
</span><span class='line'>//void lcdPrintBuffer(byte *hex, int size, char *msg)
</span><span class='line'>//{
</span><span class='line'>  
</span><span class='line'>  //int i = 0;
</span><span class='line'>  //while (i&lt;size) {    
</span><span class='line'>    //lcdSerial.print(msg);
</span><span class='line'>    //lcdSerial.print(" ");
</span><span class='line'>    //lcdSerial.print(i);
</span><span class='line'>    //lcdSerial.print("-");
</span><span class='line'>    //lcdSerial.print(i+7);
</span><span class='line'>    //lcdSerial.print("\r\n");
</span><span class='line'>    //int len = min(size-i,8);
</span><span class='line'>    //lcdPrintHex(hex+i,len);
</span><span class='line'>    //lcdSerial.print("\r\n");
</span><span class='line'>    //i=i+8;
</span><span class='line'>  //}
</span><span class='line'> // lcdSerial.print("\r\n");
</span><span class='line'>//}
</span><span class='line'>
</span><span class='line'>//void lcdPrintHex(byte hex) 
</span><span class='line'>//{
</span><span class='line'>//  lcdSerial.print((hex&0xF0)>>4,HEX);
</span><span class='line'>//  lcdSerial.print((hex&0x0F),HEX);
</span><span class='line'>//}</span>

This is the java gui I built to test the implementation

java gui

The DEV-08165 is a Serial USB Board from Sparkfun. I use it to get logs from the Arduino, the logs are outputed in serial form on pin 6 , because the serial port (USART) on the ATmega is being used for the XBee communication. The DEV-8772 is the board to program the Arduino Pro Mini, the pro mini does have an USB connector on board like other Arduinos, you need the DEV-8722 to program it/power it

Reference

Comments

Copyright © 2015 - Ruben Laguna - Powered by Octopress