-
Notifications
You must be signed in to change notification settings - Fork 5
/
GenericDataLogger.ino
230 lines (198 loc) · 7.35 KB
/
GenericDataLogger.ino
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
/*
* Generic Data Logger example
* A starting framework to make easy-to-manage dataloggers.
*
* This exmaple uses sparkfun weather shield, but is simple to extend to other sensors.
* It will send data over Serial, using various formats (see the dump functions).
*
* Troubleshooting:
* - Check your paramters and constants. e.g., did you add or remove sensors or dumps?
* Is N_SENSORS and N_DUMPS still the correct size?
*
* Created by Ashley Gillman, 09/05/15
*/
#include<stdlib.h>
#include<string.h>
#include <Wire.h> // I2C
#include "DataLogger.h"
#include "MemoryFree.h" // https://github.com/maniacbug/MemoryFree
// Include any sensor libraries here
#include "MPL3115A2.h" // Pressure sensor
#include "HTU21D.h" // Humidity sensor
#define DEBUG 1
// pins
const byte STAT1 = 7;
const byte STAT2 = 8;
const byte LIGHT = A1;
const byte REFERENCE_3V3 = A3;
const byte SOUND = A0;
// parameters
const unsigned long UPDATE = 15500; // update interval, 15.5s (ThingSpeak preferred)
const unsigned int SOUND_UPDATE = 1000;
const short N_SENSORS = 5;
const short N_DUMPS = 2;
// Sensors
const ReadingFnPointer sensors[] =
{*getHumidityStr, *getTemperatureStr, *getPressureStr, *getLightStr, *getSoundStr};
const unsigned int channels[] =
{37372, 37372, 37372, 37372, 37372 };
const int fields[] =
{1, 2, 3, 4, 5 };
// other Constants
const char READING_WIDTH = 12; // xxxxxx.xxx
const char READING_PRECISION = 3;
// global vars
uint8_t * heapptr, * stackptr;
unsigned long lastUpdate; //The millis counter to see when a second rolls by
unsigned long lastSoundUpdate;
unsigned long soundSum;
unsigned int soundCount;
MPL3115A2 pressure;
HTU21D humidity;
DataLogger dataLogger;
unsigned long sound_pres = 0;
void setup() {
// General setup
Serial.begin(9600);
Serial.print("Beginning...");
pinMode(STAT1, OUTPUT); //Status LED Blue
pinMode(STAT2, OUTPUT); //Status LED Green
// Add custom sensor setup code to this function.
setupSensors();
// Configure DataLogger
dataLogger = DataLogger(N_SENSORS, READING_WIDTH, N_DUMPS);
// Configure data logger inputs
for (int i=0; i<N_SENSORS; ++i) {
dataLogger.addReading(sensors[i]);
}
// configure data logger outputs
dataLogger.addDump(*dumpToSerial);
dataLogger.addDump(*dumpToSerialJSON);
Serial.println(" done.");
}
void loop() {
// Every UPDATE milliseconds, or on millis overflow, update again
if ( (millis() - lastUpdate >= UPDATE) || (lastUpdate > millis()) ) {
digitalWrite(STAT1, HIGH); // Blink stat LED
lastUpdate += UPDATE; // update timer
lastSoundUpdate = lastUpdate;
dataLogger.takeReadings(); // update readings from sensors
dataLogger.dumpReadings(); // write out to XBee
//debugStats(); // Optional debugging
digitalWrite(STAT1, LOW); // Turn off stat LED
}
// Every SOUND_UPDATE milliseconds, or on millis overflow, update again
else if ((millis() - lastSoundUpdate >= SOUND_UPDATE) || lastSoundUpdate > millis() ) {
lastSoundUpdate += SOUND_UPDATE;
soundSum += analogRead(SOUND);
soundCount += 1;
}
}
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// SENSORS
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
void setupSensors() {
// Configure the pressure and temperature sensor
pressure.begin(); // Get sensor online
pressure.setModeBarometer(); // Measure pressure in Pascals from 20 to 110 kPa
pressure.setOversampleRate(7); // Set Oversample to the recommended 128
pressure.enableEventFlags(); // Enable all three pressure and temp event flags
// Configure the humidity sensor
humidity.begin();
}
// Sensor input functions should take a buffer, and save their value to
// that buffer. They must not have a return value.
void getHumidityStr(char *buf) {
dtostrf(humidity.readHumidity(), READING_WIDTH, READING_PRECISION, buf);
}
void getTemperatureStr(char *buf) {
dtostrf(pressure.readTemp(), READING_WIDTH, READING_PRECISION, buf);
}
void getPressureStr(char *buf) {
dtostre(pressure.readPressure(), buf, READING_WIDTH-6, 0);
}
void getLightStr(char *buf) {
float operatingVoltage = analogRead(REFERENCE_3V3);
float lightSensor = analogRead(LIGHT);
operatingVoltage = 3.3 / operatingVoltage; //The reference voltage is 3.3V
lightSensor = operatingVoltage * lightSensor;
dtostrf(lightSensor, READING_WIDTH, READING_PRECISION, buf);
}
void getSoundStr(char *buf) {
dtostrf((float)soundSum / (float)soundCount, READING_WIDTH, READING_PRECISION, buf);
soundSum = 0;
soundCount = 0;
}
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// DUMP
// Theses are the data output routines. They should take as input a string
// of data (char*), followed by two shorts which represent the
// two-dimensional shape of the data (no. sensors and size of each output
// value).
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Writes results to Serial.
// Start char: '!', end char: '\n', delimiter: ','.
void dumpToSerial(char* data, short height, short width) {
Serial.print('!');
for (int i=0; i<height; ++i) {
for (int j=0; j<width; ++j) {
//Serial.print(" ");
//Serial.print(i*width+j);
//Serial.print(":");
Serial.print(data[i*width+j]);
}
if (i<height-1)
Serial.print(',');
}
Serial.println();
}
// Writes to Serial for ThingSpeak uploading
// Start char: '^', end char: '\n', body is in JSON format.
void dumpToSerialJSON(char* data, short height, short width) {
Serial.print("^[");
for (int i=0; i<height; ++i) {
//debugStats();
delay(5);
Serial.print(F("{channel: "));
Serial.print(channels[i]);
Serial.print(F(",field: "));
Serial.print(fields[i]);
Serial.print(F(",data: "));
for (int j=0; j<width; ++j) {
if (data[i*width+j] != ' ') // optional: omit whitespace
Serial.print(data[i*width+j]);
}
if (i<height-1)
Serial.print("},");
else
Serial.print('}');
}
Serial.println(']');
}
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Debugging Code
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
void debugStats() {
if (DEBUG) {
Serial.print("FM: "); Serial.println(freeMemory());
check_mem();
Serial.print("HP: "); Serial.println((unsigned int) heapptr);
Serial.print("SP: "); Serial.println((unsigned int) stackptr);
}
}
/* This function places the current value of the heap and stack pointers in the
* variables. You can call it from any place in your code and save the data for
* outputting or displaying later. This allows you to check at different parts of
* your program flow.
* The stack pointer starts at the top of RAM and grows downwards. The heap pointer
* starts just above the static variables etc. and grows upwards. SP should always
* be larger than HP or you'll be in big trouble! The smaller the gap, the more
* careful you need to be. Julian Gall 6-Feb-2009.
*/
void check_mem() {
//uint8_t * heapptr, * stackptr; // I declared these globally
stackptr = (uint8_t *)malloc(4); // use stackptr temporarily
heapptr = stackptr; // save value of heap pointer
free(stackptr); // free up the memory again (sets stackptr to 0)
stackptr = (uint8_t *)(SP); // save value of stack pointer
}