//==========================================================
/* https://github.com/grmis-fr
SD card datalogger
Arduino UNO
SD card attached to SPI bus:
MOSI - pin 11
MISO - pin 12
CLK - pin 13
CS - pin 4
I2C SSD1306 Oled DISPLAY:
SCL = A5 , SDA = A4
RTC module:
SCL = A5 , SDA = A4
*/
//==========================================================
#include <SdFat.h> //Library SD Card
#include <Wire.h>// Library for I2C bus communication (with the RTC module)
#include "DS3231.h" //Real-time clock (RTC) RTC module library
#include <SPI.h> // Library for SPI bus communication (with the SD card reader)
//ASCII-only (uses less memory than graphical versions) OLED display library
#include "SSD1306Ascii.h"
#include "SSD1306AsciiWire.h"
// 0X3C+SA0 - 0x3C or 0x3D
#define I2C_ADDRESS 0x3C
// Define proper RST_PIN if required.
#define RST_PIN -1
SSD1306AsciiWire oled;
SdFat SD;
//==========================================================
#define chipSelect 4
#define signal_PIN 2 //Data pin connected to the input signal
#define filename "data.txt"
#define date_filename "setdate.txt"
// Minimum time between two successive change of the input (in ms). Usefull to "de-bounce" the input.
// You may reduce the delay belo if you expect faster changes on the input pin.
#define minimum_time 200
RTClib rtc;
DS3231 Clock;
uint8_t state, last_state;
unsigned long last_change_time = 0;
//==========================================================
String time2string() {
DateTime now = rtc.now();
String d = String(now.unixtime())// number of seconds elapsed since Jan. 1st 1970.
+ ", " + now.year() + ", " + now.month() + ", " + now.day() + ", " + now.hour() + ", " + now.minute() + ", " + now.second();
return d;
}
//==========================================================
void Println(const String s) {
Serial.println(s);
oled.println(s);
}
void Print(const String s) {
Serial.print(s);
oled.print(s);
}
void Println(const int s) {
Serial.println(s);
oled.println(s);
}
void Print(const int s) {
Serial.print(s);
oled.print(s);
}
//--------------------------------------------------------
void PrintDate() {
DateTime now = rtc.now();
Print(now.day()); Print(" ");
switch (now.month()) {
case 1: Print(F("Jan.")); break;
case 2: Print(F("Fev.")); break;
case 3: Print(F("Mar.")); break;
case 4: Print(F("Avr.")); break;
case 5: Print(F("Mai.")); break;
case 6: Print(F("Juin")); break;
case 7: Print(F("Juil.")); break;
case 8: Print(F("Aout")); break;
case 9: Print(F("Sept.")); break;
case 10: Print(F("Oct.")); break;
case 11: Print(F("Nov.")); break;
case 12: Print(F("Dec.")); break;
}
Print(" ");
Print(now.hour()); Print("h"); if (now.minute() < 10) Print("0"); Println(now.minute());
}
//--------------------------------------------------------
void Print2file(const String s) {
if (SD.exists(filename)) {
File myFile = SD.open(filename, FILE_WRITE);
if (myFile) {
myFile.println(s); myFile.close();
} else {
Println(F("file error."));
}
} else {
Println(F("file error."));
}
}
//==========================================================
void switch_detected() {
String m = (state == 1) ? ("ON, ") : ("OFF, ");
Print(m); PrintDate();
m = m + time2string() + ", " + String(Clock.getTemperature(), 1);
Print2file(m);
}
//==========================================================
void GetDateFromFile(byte& Year, byte& Month, byte& Day, byte& Hour, byte& Minute, byte& Second,
File& f) {
// The date in the file should be in
// the order YYMMDDHHMMSS, with an 'x' at the end.
boolean GotString = false;
char InChar;
byte Temp1, Temp2;
char InString[20];
byte j = 0;
while (!GotString) {
if (f.available()) {
InChar = f.read();
InString[j] = InChar;
j += 1;
if (InChar == 'x') GotString = true;
}
}
uint8_t c = 0;
// Year first
Temp1 = (byte)InString[c++] - 48;
Temp2 = (byte)InString[c++] - 48;
Year = Temp1 * 10 + Temp2;
// Month
Temp1 = (byte)InString[c++] - 48;
Temp2 = (byte)InString[c++] - 48;
Month = Temp1 * 10 + Temp2;
// Date
Temp1 = (byte)InString[c++] - 48;
Temp2 = (byte)InString[c++] - 48;
Day = Temp1 * 10 + Temp2;
// Hour
Temp1 = (byte)InString[c++] - 48;
Temp2 = (byte)InString[c++] - 48;
Hour = Temp1 * 10 + Temp2;
// Minute
Temp1 = (byte)InString[c++] - 48;
Temp2 = (byte)InString[c++] - 48;
Minute = Temp1 * 10 + Temp2;
// Second
Temp1 = (byte)InString[c++] - 48;
Temp2 = (byte)InString[c++] - 48;
Second = Temp1 * 10 + Temp2;
}
//==========================================================
void setup() {
pinMode(signal_PIN, INPUT_PULLUP);
Serial.begin(9600);
//--------------------------------------------------------
Wire.begin(); // Initialize the I2C
Wire.setClock(400000L); // I2C speed
#if RST_PIN >= 0
oled.begin(&Adafruit128x64, I2C_ADDRESS, RST_PIN);
#else // RST_PIN >= 0
oled.begin(&Adafruit128x64, I2C_ADDRESS);
#endif // RST_PIN >= 0
oled.setFont(System5x7);
oled.clear();
#if INCLUDE_SCROLLING == 0
#error INCLUDE_SCROLLING must be non-zero. Edit SSD1306Ascii.h
#endif // INCLUDE_SCROLLING
// Set auto scrolling at end of window.
oled.setScrollMode(SCROLL_MODE_AUTO);
Println(F("================="));
Println(F("== DATA LOGGER =="));
Println(F("================="));
PrintDate(); Print(F("Temp. ")); Print(String(Clock.getTemperature(), 1)); Println(" C");
//--------------------------------------------------------
Println(F("SD card init"));
// Wait until the card is present and can be initialized:
while (!SD.begin(chipSelect)) {
Print(F("."));
delay(200);
}
Println("Card Ok");
//--------------------------------------------------------
if (SD.exists(date_filename)) {
Print(date_filename); Println(F(" found"));
byte Year, Month, Date, Hour, Minute, Second;
File myFile = SD.open(date_filename);
GetDateFromFile(Year, Month, Date, Hour, Minute, Second, myFile);
if (Year < 18 || Year > 99 || Month > 12 || Date > 31 || Hour > 24 || Minute > 59 || Second > 59) {
Println(F("Date/time error"));
} else {
Clock.setClockMode(false); // set to 24h
Clock.setYear(Year); Clock.setMonth(Month);
Clock.setDate(Date); //Clock.setDoW(DoW);
Clock.setHour(Hour); Clock.setMinute(Minute);
Clock.setSecond(Second);
//myFile.close();
Println(F("Date set to:"));
PrintDate();
Println(rtc.now().year());
String new_filename = "NO"; new_filename += date_filename;
if (myFile.rename(SD.vwd(), new_filename.c_str()))
Println(F("file renamed."));
else
Println(F("rename error"));
}
}
//--------------------------------------------------------
String m;
if (SD.exists(filename)) {
Print(F("File "));
Println(filename); Println(F("exists"));
File myFile = SD.open(filename, FILE_WRITE);
m = "RESTART, "; m = m + time2string();
Print2file(m);
myFile.close();
} else {
Print(filename); Println(F(" doesn't exist."));
Println(F("->creating it."));
File myFile = SD.open(filename, FILE_WRITE);
m = "CREATED,"; m = m + time2string();
Print2file(m);
myFile.close();
}
//--------------------------------------------------------
state = digitalRead(signal_PIN);
}
//==========================================================
unsigned long last_print = 0;
void loop() {
uint8_t input = digitalRead(signal_PIN);
if (input != last_state) {
// memorize the time of this input change
last_change_time = millis();
}
if (input != state)
if ((millis() - last_change_time) > minimum_time) {
// the new state has been here for >minimum_time, so it should be considered as the new state
state = input;
switch_detected();
}
last_state = input;
}