I am using a script on an Arduino to record BME280 data onto an SD card and to display it on a lcd display. To have a valid time stamp I am also using a DS3231 RTC module. I set the time succesfully and can manually read it and write it to the serial monitor. Writing the sensor data to the SD card works fine as well. But as soon as I try to include the time from the RTC into the file onto the SD card the script jumps back to the else statement in the setup() where I try to open the file for writing the header line.
Without using the RTC time it works fine, as soon as I put it in using the corresponding function, it fails.
Here is the script I am using:
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <SPI.h>
#include <SD.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_BME280.h>
#define BME_SCK 8
#define BME_MISO 6
#define BME_MOSI 7
#define BME_CS 5
#define SEALEVELPRESSURE_HPA (1013.25)
#define RTC_I2C_ADDRESS 0x68 // I2C Adresse des RTC DS3231
Adafruit_BME280 bme(BME_CS, BME_MOSI, BME_MISO, BME_SCK); // software SPI
unsigned long lastReadRTC = -1;
boolean sd_ok = 0, sensor_ok = 0;
File dataLog;
String dat_time;
LiquidCrystal_I2C lcd(0x27, 20, 4); //Hier wird das Display benannt (Adresse/Zeichen pro Zeile/Anzahl Zeilen)
void setup()
{
Wire.begin(); //Kommunikation über die Wire.h bibliothek beginnen.
Serial.begin(9600); // open serial communications and wait for port to open
// SD Card Initialization
if (SD.begin())
{
Serial.println("SD card is ready.");
sd_ok = true;
} else
{
Serial.println("SD card initialization failed");
return;
}
//if( SD.exists("test.txt") == 1 ){
dataLog = SD.open("test.txt", FILE_WRITE);
if(dataLog) { // if the file opened okay, write to it:
Serial.println("OK, writing header");
// write some texts to 'test.txt' file
dataLog.println("DATE | TEMPERATURE | HUMIDITY | PRESSURE");
dataLog.close(); // close the file
}
else {
Serial.println("error opening testfile.txt");
}
unsigned status;
status = bme.begin();
if (!status) {
Serial.println("Could not find a valid BME280 sensor, check wiring, address, sensor ID!");
Serial.print("SensorID was: 0x");
Serial.println(bme.sensorID(),16);
Serial.print(" ID of 0xFF probably means a bad address, a BMP 180 or BMP 085\n");
Serial.print(" ID of 0x56-0x58 represents a BMP 280,\n");
Serial.print(" ID of 0x60 represents a BME 280.\n");
Serial.print(" ID of 0x61 represents a BME 680.\n");
while (1) delay(10);
}else{
sensor_ok = true;
Serial.println("OK, sensor recognized");
}
lcd.init();
lcd.backlight();
lcd.setCursor(0,0);
lcd.print("Temp. = ");
lcd.print(bme.readTemperature());
lcd.print(" *C");
lcd.setCursor(0,1);
lcd.print("Press. = ");
lcd.print(bme.readPressure() / 100.0F);
lcd.print(" hPa");
lcd.setCursor(0,2);
lcd.print("Alti. = ");
lcd.print(bme.readAltitude(SEALEVELPRESSURE_HPA));
lcd.print(" m");
lcd.setCursor(0,3);
lcd.print("Hum. = ");
lcd.print(bme.readHumidity());
lcd.print(" %");
delay(1000);
}
//Reads the current datetime from rtc module
String rtcReadTime(){
Wire.beginTransmission(RTC_I2C_ADDRESS); //Connect to address 0x68
Wire.write(0);
Wire.endTransmission();
Wire.requestFrom(RTC_I2C_ADDRESS, 7);
int sekunde = bcdToDec(Wire.read() & 0x7f);
int minute = bcdToDec(Wire.read());
int stunde = bcdToDec(Wire.read() & 0x3f);
//weekday not included
/* wochentag =*/ bcdToDec(Wire.read());
int tag = bcdToDec(Wire.read());
int monat = bcdToDec(Wire.read());
int jahr = bcdToDec(Wire.read())+2000;
char timestamp[30];
sprintf(timestamp,"%02d.%02d.%4d %02d:%02d:%02d",tag,monat,jahr,stunde,minute,sekunde);
return timestamp;
}
//Converts binary to numeric
byte bcdToDec(byte val){
return ( (val/16*10) + (val%16) );
}
void loop()
{
unsigned long currentMilliseconds = millis();
if((lastReadRTC + 1000) < currentMilliseconds){
lastReadRTC = currentMilliseconds;
lcd.setCursor(0,0);
lcd.print("Temp. = ");
lcd.print(bme.readTemperature());
lcd.print(" *C");
lcd.setCursor(0,1);
lcd.print("Press. = ");
lcd.print(bme.readPressure() / 100.0F);
lcd.print(" hPa");
lcd.setCursor(0,2);
lcd.print("Alti. = ");
lcd.print(bme.readAltitude(SEALEVELPRESSURE_HPA));
lcd.print(" m");
lcd.setCursor(0,3);
lcd.print("Hum. = ");
lcd.print(bme.readHumidity());
lcd.print(" %");
//Serial.println(rtcReadTime());
if(sd_ok){
dataLog = SD.open("test.txt", FILE_WRITE);
//dataLog.print(rtcReadTime());
dataLog.print(" | ");
if(sensor_ok) {
dataLog.print(bme.readTemperature());
dataLog.print("°C | ");
dataLog.print(bme.readHumidity());
dataLog.print(" | ");
dataLog.println(bme.readPressure() / 100.0F);
dataLog.close();
}
else{
dataLog.println(" Error | Error | Error");
dataLog.close();
}
}
}
delay(1000);
}
So when I run the script without the RTC time included it gives me the output:
SD card is ready.
OK, writing header
If I include the line dataLog.print(rtcReadTime());
towards the end (in the script commented out) it jumps to the beginning of the setup section into the else statement giving me:
error opening testfile.txt
and nothing is written into the file on the SD card.
I tried to find the mistake for multiple hours yesterday and was hoping to find it today after a good night of sleep, but nope. It is probably an easy fix that i can't see. The code is probably far from perfect or good. I am a beginner in c++, so keep that in mind. :)
EDIT:
As I was not able to find a solution using rtcReadTime()
, I used the RTClib.h
directly and created the time manually in the writing process for the SD card:
void loop()
{
unsigned long currentMilliseconds = millis();
if((lastReadRTC + 1000) < currentMilliseconds){
lastReadRTC = currentMilliseconds;
lcd.setCursor(0,0);
lcd.print("Temp. = ");
lcd.print(bme.readTemperature());
lcd.print(" *C");
lcd.setCursor(0,1);
lcd.print("Press. = ");
lcd.print(bme.readPressure() / 100.0F);
lcd.print(" hPa");
lcd.setCursor(0,2);
lcd.print("Alti. = ");
lcd.print(bme.readAltitude(SEALEVELPRESSURE_HPA));
lcd.print(" m");
lcd.setCursor(0,3);
lcd.print("Hum. = ");
lcd.print(bme.readHumidity());
lcd.print(" %");
if(sd_ok){
dataLog = SD.open("test.txt", FILE_WRITE);
DateTime now = rtc.now();
dataLog.print(now.day(), DEC);
dataLog.print(' ');
dataLog.print(now.month(), DEC);
dataLog.print(' ');
dataLog.print(now.year(), DEC);
dataLog.print(" ");
dataLog.print(now.hour(), DEC);
dataLog.print(':');
dataLog.print(now.minute(), DEC);
dataLog.print(':');
dataLog.print(now.second(), DEC);
dataLog.print(" | ");
if(sensor_ok) {
dataLog.print(bme.readTemperature());
dataLog.print("°C | ");
dataLog.print(bme.readHumidity());
dataLog.print(" | ");
dataLog.println(bme.readPressure() / 100.0F);
dataLog.close();
}
else{
dataLog.println(" Error | Error | Error");
dataLog.close();
}
}
}
}
Probably far from ideal, but enough for me.