Malawi Production Quality
 All Files Functions Variables Macros Pages
Malawi_001.ino
Go to the documentation of this file.
1 /**
2  * @file Malawi_001.ino
3  * @author Nico Verduin
4  * @date 30-12-2013
5  *
6  * @mainpage Malawi_001
7  * This project measures time between pulses generated from a photo sensor. The time between each
8  * rising and falling edge is measured as well as the time between the falling and rising edge.
9  * The time measured in both cases is stored on an SD Card.
10  * \n\n
11  * The given estimations of the HIGH time vs LOW time is 150 milli Seconds (variation = 120-170) and
12  * 30 milli seconds (variation = 10-50).
13  *
14  * @par Important information
15  * SD cards are sold in different qualities. The most important is the so called latency time
16  * This can influence the delay on the write operation.
17  *
18  * @par Workings
19  * An interrupt service routine (ISR) is called every time the edge changes. The difference between
20  * the time now and the time before is the time between edges. \n
21  * These values are stored in an array. Each array can contain a maximum of BUFFER_ENTRIES (=max 100) bytes.\n
22  * The program has 2 buffers once a buffer is full, the buffer pointer is switched to the other allowing
23  * the ISR to keep storing data. \n
24  * Meanwhile the filled buffer is written to the SD card as a 2 column CSV format with a Long and short pulse time.
25  *
26  * @par Usage instructions
27  * a) Make sure a standard FAT32 formatted SD card is inserted in the card Holder\n
28  * b) Switch the Arduino on\n
29  * c) The LED should light constant\n
30  * d) recording will start as soon as pulses arrive from the Opto
31  *
32  * @par LED flashes
33  * a) 2 seconds on / 2 seconds off : There is no SD card inserted or card not usable\n
34  * b) 1 seconds on / 2 seconds off : The card already contains 99 MALAWIxx files. Either clean up the card or use another\n
35  * c) 250 milliseconds on / 250 milliseconds off : a buffer overrun has happened.\n
36  * In all cases above recording has terminated or not even started\n
37  * \n
38  * If a very short flash happens once every 3-4 seconds the data is being recorded on the card and the system is operating perfectly.
39  *
40  * @par Version Control
41  * $Revision: 5 $
42  * $Author: Nico $
43  * $Date: 2013-12-31 14:55:38 +0100 (di, 31 dec 2013) $
44  *
45  * @par License info
46  *
47  * Malawi_001 measuring time between pulses
48  *
49  * Copyright (C) 2013 Nico Verduin
50  *
51  * This program is free software: you can redistribute it and/or modify
52  * it under the terms of the GNU General Public License as published by
53  * the Free Software Foundation, either version 3 of the License, or
54  * (at your option) any later version.
55  *
56  * This program is distributed in the hope that it will be useful,
57  * but WITHOUT ANY WARRANTY; without even the implied warranty of
58  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
59  * GNU General Public License for more details.
60  *
61  * You should have received a copy of the GNU General Public License
62  * along with this program. If not, see <http://www.gnu.org/licenses/>.
63  *
64  * Program : Malawi_001 Copyright (C) 2013 Nico Verduin
65  * This is free software, and you are welcome to redistribute it.
66  *
67  */
68 
69 #include "Arduino.h"
70 
71 #include <SD.h> // SD Card functions
72 //
73 // file name specifics
74 //
75 char fileName[13]; // we will use msDos files here(8 + . + 3 +\0)
76 char fileType[] = ".csv"; // just plain text file
77 char fileNameStart[] = "MALAWI"; // files will start with MALAWI
78 File dataFile; // file object to write to
79 
80 //#define DEBUG // DEBUG purposes
81 #define FIELD_SEPARATOR ";" // for CSV file
82 //
83 // Pin definitions
84 //
85 #define LED 6 // LED turns on if no buffer full
86 #define CS 10 // Chip select for SD card
87 #define INTERRUPT_INPUT 2 // digital pin for interrupt 0
88 //
89 // variables used between the ISR and the loop
90 //
91 #define BUFFER_ENTRIES 50 // currently we have 50 entries per buffer
92 #define FLASH_OVERRUN 150 // flash on/off every 150 milli seconds buffer overrun
93 #define FLASH_CARD 2000 // flash on/off every 2000 milli seconds no Card
94 #define FLASH_100 1000 // flash on/off every 1000 milli seconds no Card
95 #define NO_CARD 1 // no card inserted or unreadable
96 #define OVERRUN 2 // buffer overrun
97 #define FILE100 3 // we have reached a 100 files
98 
99 volatile bool firstValue = true; // ignore the first value as we need 2 values to start with
100 volatile unsigned long oldValue; // contains the previous millis value
101 volatile unsigned long currentValue; // current millis value
102 volatile int buffer[2][BUFFER_ENTRIES]; // we use 2 buffer for writing (each is 512 bytes in size)
103 volatile int *ptrBuffer; // points to first empty address in buffer
104 volatile uint8_t bufferIndex; // references correct buffer
105 volatile unsigned int entryIndex; // keeps track of entry in buffer
106 volatile boolean bufferFull; // indicates if a buffer can be written to SD card
107 volatile unsigned int error = 0; // an error occured
108 
109 /**
110  * @name flash(unsigned long flashTime)
111  * @param flashTime sets the time the LED is on and off
112  * flashes the Led
113  */
114 void flash(unsigned long flashTime) {
115 
116  unsigned long flashCtr;
117 
118  flashCtr = millis() + flashTime; // set the timer
119  digitalWrite(LED, !digitalRead(LED)); // flip the LED
120  while (millis() < flashCtr){}; // wait until done
121 }
122 /**
123  * @name HandleEdgeChange()
124  * This is the Interrupt Service Routine called every time the pulse edge changes
125  */
127  //
128  // get the time in any case
129  //
130  currentValue = millis();
131  //
132  // check if this is the first value
133  //
134  if (firstValue) {
135  //
136  // we start with the rising edge
137  //
138  if (digitalRead(INTERRUPT_INPUT) == LOW) {
139  //
140  // this is the start
141  //
142  oldValue = currentValue; // first value will be 0
143  firstValue = false; // we will do this only once
144  }
145  } else {
146  //
147  // calculate the difference
148  //
149  *ptrBuffer = currentValue - oldValue; // calculate the difference and put it in the buffer
150  ptrBuffer++; // pointer to next integer position
151  //
152  // now increment the Entry index and check for buffer full. if not we are done
153  //
154  entryIndex++;
155  if (entryIndex == BUFFER_ENTRIES) {
156  //
157  // buffer is full so switch to other buffer but first check if other buffer is empty
158  //
159  if (bufferFull) {
160  //
161  // not emptied yet so set error flag
162  //
163  error = OVERRUN;
164  }
165  bufferIndex = !bufferIndex; // index can only be 0 or 1
166  entryIndex = 0; // reset the entry ctr
167  ptrBuffer = &buffer[bufferIndex][0]; // pointer to first entry in current buffer
168  bufferFull = true; // previous buffer can be written
169  }
170  }
171  //
172  // save the current value as old for the next interrupt
173  //
175 }
176 
177 /**
178  * @name writeBuffer(uint8_t index)
179  * @param index pointer to writable buffer
180  * Writes a buffer of integer values to the file
181  */
182 void writeBuffer(uint8_t index) {
183  //
184  // copy the data to the file in readable format
185  //
186 #ifdef DEBUG
187  Serial.print("Write Buffer");
188  unsigned long start = millis(); // needed to determine writing time
189 #endif
190  for (unsigned int i = 0; i < BUFFER_ENTRIES; i++) {
191 
192  dataFile.print(buffer[index][i]);
193  dataFile.print(FIELD_SEPARATOR);
194  i++;
195  dataFile.println(buffer[index][i]);
196  }
197  dataFile.flush();
198 
199 #ifdef DEBUG
200  Serial.print("Duration = ");
201  Serial.println(millis() - start);
202 #endif
203 }
204 
205 /**
206  * @name setup()
207  * initialize the program
208  */
209 void setup()
210 {
211 #ifdef DEBUG
212  Serial.begin(9600); // for debug purposes
213 #endif
214 
215  //
216  // setup inputs and outputs
217  //
218  pinMode(LED , OUTPUT); // Led will indicate if Buffer is empty
219  pinMode(CS , OUTPUT); // SD card select
220  //
221  // turn LED off
222  //
223  pinMode(LED, HIGH);
224  //
225  // initialize buffers and pointers
226  //
227  ptrBuffer = &buffer[0][0]; // Points to first index in first buffer
228  entryIndex = 0; // references first entry in buffer
229  bufferIndex = 0; // references the first buffer
230  bufferFull = false; // nothing to write yet
231 
232  //
233  // Initialize the SD card
234  //
235  if (!SD.begin(CS)) {
236 #ifdef DEBUG
237  Serial.println("Card failed, or not present");
238 #endif
239  //
240  // set error code
241  //
242  error = NO_CARD;
243  return;
244  }
245 #ifdef DEBUG
246  Serial.println("card initialized.");
247 #endif
248 
249  //
250  // find the first free file name to use
251  //
252  strcpy(fileName, fileNameStart);
253  //
254  // currently set for max 999 files
255  //
256  for (unsigned int i = 1; i < 99; i++) {
257  //
258  // build the number range
259  //
260  sprintf(&fileName[sizeof(fileNameStart)-1], "%02d", i);
261  strcat(fileName, fileType);
262 
263  if (SD.exists(fileName)) {
264 #ifdef DEBUG
265  //
266  // just let us know the file was created earlier
267  //
268  Serial.print(fileName);
269  Serial.println(" Exists");
270 #endif
271  //
272  // No more files allowed on this card
273  //
274  if (i == 99) {
275  error = FILE100;
276  break;
277  }
278  } else {
279  //
280  // create the new file and let us know
281  //
282  dataFile = SD.open(fileName, FILE_WRITE);
283 #ifdef DEBUG
284  Serial.print(fileName);
285  Serial.println(" Created");
286 #endif
287  //
288  // we found the file so exit loop
289  //
290  i = 100;
291  }
292  }
293  //
294  // print a dummy to dataFile as the first write takes about 10x as long as normal
295  //
296  dataFile.println("Short;Long");
297  dataFile.flush();
298  //
299  // now attach the interrupt to the ISR so it can respond to pulses
300  //
301  attachInterrupt(0, HandleEdgeChange, CHANGE);
302 }
303 
304 /**
305  * @name loop()
306  * main loop of program and runs endlessly
307  */
308 void loop()
309 {
310  //
311  // first check if there is an error
312  //
313  if (error != 0) {
314  //
315  // remove interrupt vector, no use continuing
316  //
317  detachInterrupt(0);
318  //
319  // flash determined on error type
320  //
321  switch (error) {
322 
323  case NO_CARD: // no card detected or unusable
324  flash(FLASH_CARD);
325  break;
326 
327  case OVERRUN: // buffer overrun
329  break;
330 
331  case FILE100: // we have 99 files from this sketch on the SD card
332  flash(FLASH_100);
333  break;
334 
335  default:
336  break;
337  }
338  } else {
339  //
340  // write to the SD card only if there is something to write
341  //
342  if (bufferFull) {
343  //
344  // we have to write a buffer away
345  //
346  digitalWrite(LED, !bufferFull); // if buffers are empty, it is a false so reverse it
347  writeBuffer(!bufferIndex); // we have to write the other buffer as this one
348  // is filling
349  bufferFull = false;
350  }
351  //
352  // check if buffers are still empty
353  //
354  digitalWrite(LED, !bufferFull); // if buffers are empty, it is a false so reverse it
355  }
356 }
char fileNameStart[]
Definition: Malawi_001.ino:77
volatile unsigned int error
Definition: Malawi_001.ino:107
#define INTERRUPT_INPUT
Definition: Malawi_001.ino:87
void setup()
Definition: Malawi_001.ino:209
volatile int buffer[2][BUFFER_ENTRIES]
Definition: Malawi_001.ino:102
#define LED
Definition: Malawi_001.ino:85
#define FLASH_100
Definition: Malawi_001.ino:94
#define BUFFER_ENTRIES
Definition: Malawi_001.ino:91
void HandleEdgeChange()
Definition: Malawi_001.ino:126
#define OVERRUN
Definition: Malawi_001.ino:96
char fileType[]
Definition: Malawi_001.ino:76
File dataFile
Definition: Malawi_001.ino:78
void flash(unsigned long flashTime)
Definition: Malawi_001.ino:114
volatile boolean bufferFull
Definition: Malawi_001.ino:106
volatile unsigned long currentValue
Definition: Malawi_001.ino:101
#define FILE100
Definition: Malawi_001.ino:97
void loop()
Definition: Malawi_001.ino:308
char fileName[13]
Definition: Malawi_001.ino:75
void writeBuffer(uint8_t index)
Definition: Malawi_001.ino:182
#define CS
Definition: Malawi_001.ino:86
#define FIELD_SEPARATOR
Definition: Malawi_001.ino:81
volatile bool firstValue
Definition: Malawi_001.ino:99
volatile uint8_t bufferIndex
Definition: Malawi_001.ino:104
volatile unsigned long oldValue
Definition: Malawi_001.ino:100
volatile int * ptrBuffer
Definition: Malawi_001.ino:103
#define FLASH_OVERRUN
Definition: Malawi_001.ino:92
volatile unsigned int entryIndex
Definition: Malawi_001.ino:105
#define NO_CARD
Definition: Malawi_001.ino:95
#define FLASH_CARD
Definition: Malawi_001.ino:93