-
Notifications
You must be signed in to change notification settings - Fork 1
/
main.cpp
348 lines (313 loc) · 9.58 KB
/
main.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
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
#include <Arduino.h>
#include <Wire.h>
#include <SPI.h>
// #define BASIC_SD
#ifdef BASIC_SD
#include <SD.h> // https://www.arduino.cc/en/reference/SD
#else
#include "SdFat.h" // https://github.com/greiman/SdFat
#endif
#include <MemoryFree.h>
#include "SparkFun_ADXL345.h" // https://github.com/sparkfun/SparkFun_ADXL345_Arduino_Library/blob/master/examples/SparkFun_ADXL345_Example/SparkFun_ADXL345_Example.ino
#include "RTClib.h" // https://github.com/adafruit/RTClib/blob/master/examples/ds1307/ds1307.ino
// ADXL345 adxl = ADXL345(10); // USE FOR SPI COMMUNICATION, ADXL345(CS_PIN);
ADXL345 adxl = ADXL345(); // USE FOR I2C COMMUNICATION
const int VIBRATION_SAMPLES = 10;
const int MEASUREMENT_INTERVAL_MS = 1000; // log measure every x ms
RTC_DS1307 rtc;
const int SD_CS_PIN = 10;
#ifdef BASIC_SD
Sd2Card card;
#else
// Test with reduced SPI speed for breadboards. SD_SCK_MHZ(4) will select
// the highest speed supported by the board that is not over 4 MHz.
// Change SPI_SPEED to SD_SCK_MHZ(50) for best performance.
#define SPI_SPEED SD_SCK_MHZ(4)
// Note: Uno will not support SD_FAT_TYPE = 3.
// SD_FAT_TYPE = 0 for SdFat/File as defined in SdFatConfig.h,
// 1 for FAT16/FAT32, 2 for exFAT, 3 for FAT16/FAT32 and exFAT.
#define SD_FAT_TYPE 1 // 1 for the 128MB card
#if SD_FAT_TYPE == 0
SdFat sd;
typedef File file_t;
#elif SD_FAT_TYPE == 1
SdFat32 sd;
typedef File32 file_t;
#elif SD_FAT_TYPE == 2
SdExFat sd;
typedef ExFile file_t;
#elif SD_FAT_TYPE == 3
SdFs sd;
typedef FsFile file_t;
#else // SD_FAT_TYPE
#error Invalid SD_FAT_TYPE
#endif // SD_FAT_TYPE
#endif // BASIC_SD
// functions
void printSdCardInfo()
{
#ifdef BASIC_SD
SdVolume volume;
SdFile root;
// print the type of card
Serial.println();
Serial.print("Card type: ");
switch (card.type())
{
case SD_CARD_TYPE_SD1:
Serial.println("SD1");
break;
case SD_CARD_TYPE_SD2:
Serial.println("SD2");
break;
case SD_CARD_TYPE_SDHC:
Serial.println("SDHC");
break;
default:
Serial.println("Unknown");
}
// Now we will try to open the 'volume'/'partition' - it should be FAT16 or FAT32
if (!volume.init(card))
{
Serial.println("Could not find FAT16/FAT32 partition.\nMake sure you've formatted the card");
while (1)
;
}
Serial.print("Clusters: ");
Serial.println(volume.clusterCount());
Serial.print("Blocks x Cluster: ");
Serial.println(volume.blocksPerCluster());
Serial.print("Total Blocks: ");
Serial.println(volume.blocksPerCluster() * volume.clusterCount());
Serial.println();
// print the type and size of the first FAT-type volume
uint32_t volumesize;
Serial.print("Volume type is: FAT");
Serial.println(volume.fatType(), DEC);
volumesize = volume.blocksPerCluster(); // clusters are collections of blocks
volumesize *= volume.clusterCount(); // we'll have a lot of clusters
volumesize /= 2; // SD card blocks are always 512 bytes (2 blocks are 1KB)
Serial.print("Volume size (Kb): ");
Serial.println(volumesize);
Serial.print("Volume size (Mb): ");
volumesize /= 1024;
Serial.println(volumesize);
Serial.print("Volume size (Gb): ");
Serial.println((float)volumesize / 1024.0);
Serial.println("\nFiles found on the card (name, date and size in bytes): ");
root.openRoot(volume);
// list all files in the card with date and size
root.ls(LS_R | LS_DATE | LS_SIZE);
root.close();
#else
uint32_t size = sd.card()->sectorCount();
if (size == 0)
{
Serial.println(F("Can't determine the card size."));
// cardOrSpeed();
return;
}
uint32_t sizeMB = 0.000512 * size + 0.5;
Serial.print(F("Card size: "));
Serial.println(sizeMB);
Serial.println(F(" MB (MB = 1,000,000 bytes)"));
Serial.print(F("Volume is FAT"));
Serial.println((int(sd.vol()->fatType())));
Serial.print(F("Cluster size (bytes): "));
Serial.println(sd.vol()->bytesPerCluster());
Serial.println(F("Files found (date time size name):"));
sd.ls(LS_R | LS_DATE | LS_SIZE);
if ((sizeMB > 1100 && sd.vol()->sectorsPerCluster() < 64) || (sizeMB < 2200 && sd.vol()->fatType() == 32))
{
Serial.println(F("This card should be reformatted for best performance."));
Serial.println(F("Use a cluster size of 32 KB for cards larger than 1 GB."));
Serial.println(F("Only cards larger than 2 GB should be formatted FAT32."));
// reformatMsg();
return;
}
#endif
}
void i2cScanner()
{
byte error, address;
int nDevices;
Serial.println("Scanning...");
nDevices = 0;
for (address = 1; address < 127; address++)
{
// The i2c_scanner uses the return value of
// the Write.endTransmisstion to see if
// a device did acknowledge to the address.
Wire.beginTransmission(address);
error = Wire.endTransmission();
if (error == 0)
{
Serial.print("I2C device found at address 0x");
if (address < 16)
Serial.print("0");
Serial.print(address, HEX);
Serial.println(" !");
nDevices++;
}
else if (error == 4)
{
Serial.print("Unknown error at address 0x");
if (address < 16)
Serial.print("0");
Serial.println(address, HEX);
}
}
if (nDevices == 0)
Serial.println("No I2C devices found\n");
else
Serial.println("done\n");
}
void setup()
{
Serial.begin(115200); // Start the serial terminal
Serial.println(F("Vibration logger"));
Wire.begin();
// i2cScanner();
if (!rtc.begin())
{
Serial.println(F("Couldn't find RTC"));
Serial.flush();
while (1)
delay(10);
}
Serial.println(F("Initializing RTC"));
if (!rtc.isrunning())
{
Serial.println(F("RTC is NOT running, let's set the time!"));
// When time needs to be set on a new device, or after a power loss, the
// following line sets the RTC to the date & time this sketch was compiled
rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
// This line sets the RTC with an explicit date & time, for example to set
// January 21, 2014 at 3am you would call:
// rtc.adjust(DateTime(2014, 1, 21, 3, 0, 0));
}
// When time needs to be re-set on a previously configured device, the
// following line sets the RTC to the date & time this sketch was compiled
// rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
// This line sets the RTC with an explicit date & time, for example to set
// January 21, 2014 at 3am you would call:
// rtc.adjust(DateTime(2014, 1, 21, 3, 0, 0));
Serial.println(F("Initializing SD card..."));
// we'll use the initialization code from the utility libraries
// since we're just testing if the card is working!
#ifdef BASIC_SD
if (!card.init(SPI_HALF_SPEED, SD_CS_PIN))
{
Serial.println(F("initialization failed. Things to check:"));
// Serial.println("* is a card inserted?");
// Serial.println("* is your wiring correct?");
// Serial.println("* did you change the chipSelect pin to match your shield or module?");
while (1)
;
}
#else
if (!sd.begin(SD_CS_PIN, SPI_SPEED))
{
if (sd.card()->errorCode())
{
Serial.println(F(
"\nSD initialization failed.\n"
"Do not reformat the card!\n"
"Is the card correctly inserted?\n"
"Is chipSelect set to the correct value?\n"
"Does another SPI device need to be disabled?\n"
"Is there a wiring/soldering problem?"));
Serial.print(F("errorCode: "));
Serial.println(int(sd.card()->errorCode()));
Serial.print(F("ErrorData: "));
Serial.println(int(sd.card()->errorData()));
return;
}
Serial.println(F("Card successfully initialized."));
if (sd.vol()->fatType() == 0)
{
Serial.println(F("Can't find a valid FAT16/FAT32 partition."));
// reformatMsg();
return;
}
Serial.println(F("Can't determine error type"));
while (1)
;
}
#endif
else
{
Serial.println(F("Wiring is correct and a card is present."));
}
printSdCardInfo();
// accelerometer init
adxl.powerOn(); // Power on the ADXL345
adxl.setRangeSetting(2); // Give the range settings
// Accepted values are 2g, 4g, 8g or 16g
// Higher Values = Wider Measurement Range
// Lower Values = Greater Sensitivity
adxl.setSpiBit(0); // Configure the device to be in 4 wire SPI mode when set to '0' or 3 wire SPI mode when set to 1
// Default: Set to 1
// SPI pins on the ATMega328: 11, 12 and 13 as reference in SPI Library
Serial.println(F("Done setup"));
}
int calculateVibrationLevel()
{
// Accelerometer Readings
int x, y, z;
int px, py, pz; // previous measurement
int intensity = 0;
adxl.readAccel(&px, &py, &pz);
for (int i = 0; i < VIBRATION_SAMPLES; i++)
{
adxl.readAccel(&x, &y, &z);
intensity += abs(x - px);
intensity += abs(y - py);
intensity += abs(z - pz);
px = x;
py = y;
pz = z;
}
return intensity;
}
void loop()
{
// debug
// Serial.print("freeMemory()=");
// Serial.println(freeMemory());
// generate file name
DateTime now = rtc.now();
const int filenameLength = 8 + 1 + 3 + 1;
char filename[filenameLength];
snprintf(filename, filenameLength, "%d%02d%02d.csv", now.year(), now.month(), now.day());
// calculate vibration level
int vibrationLevel = calculateVibrationLevel();
// Serial.println(vibrationLevel);
// render data row
const int dataRowLength = 8 + 1 + 10 + 1;
char dataRow[dataRowLength];
snprintf(dataRow, dataRowLength, "%02d:%02d:%02d,%d", (int)now.hour(), (int)now.minute(), (int)now.second(), vibrationLevel);
// print to the serial port
Serial.println(dataRow);
// write to file
#ifdef BASIC_SD
File dataFile = SD.open(filename, FILE_WRITE | O_APPEND);
if (dataFile) // if the file is available, write to it:
#else
file_t dataFile;
if (dataFile.open(filename, O_RDWR | O_CREAT | O_APPEND | O_AT_END))
#endif
{
dataFile.println(dataRow);
dataFile.close();
}
else
{
Serial.print(F("Error opening file - "));
Serial.println(filename);
Serial.print(F("freeMemory()="));
Serial.println(freeMemory());
}
// wait until next measurement
delay(MEASUREMENT_INTERVAL_MS);
}