Проблема с SD-картой Arduino RTC
Я использую скрипт на Arduino для записи данных BME280 на SD-карту и отображения их на ЖК-дисплее. Чтобы иметь действительную отметку времени, я также использую модуль DS3231 RTC. Я успешно установил время и могу вручную прочитать его и записать на последовательный монитор. Запись данных датчика на SD - карту также работает нормально. Но как только я пытаюсь включить время из RTC в файл на SD-карту, скрипт возвращается к оператору else в setup (), где я пытаюсь открыть файл для записи строки заголовка.
Без использования времени RTC он работает нормально, как только я вставляю его с помощью соответствующей функции, он терпит неудачу.
Вот сценарий, который я использую:
#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); // программное обеспечение 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-карта готова.");
sd_ok = true;
} else
{
Serial.println("Не удалось инициализировать SD-картуd");
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);
}
Поэтому, когда я запускаю скрипт без учета времени RTC, он выдает следующий результат:
SD-карта готова.
Хорошо, пишу заголовок
Если я включаю строку dataLog.print(rtcReadTime());
ближе к концу (в закомментированном скрипте) она переходит к началу раздела setup в оператор else, дающий мне:
ошибка открытия testfile.txt
и ничего не записывается в файл на SD-карте.
Вчера я несколько часов пытался найти эту ошибку и надеялся найти ее сегодня после хорошего ночного сна, но нет. Вероятно, это простое решение, которое я не вижу. Код, вероятно, далек от совершенства или хорошего. Я новичок в c++, так что имейте это в виду. :)
ПРАВКА:
Поскольку я не смог найти решение с помощью rtcReadTime()
, я использовал RTClib.h
напрямую и создал время вручную в процессе записи для SD-карты:
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();
}
}
}
}
Вероятно, далеко не идеал, но для меня достаточно.
@Kj Ell, 👍0
1 ответ
метка
времени в rtcReadTime ()
- это локальная переменная. Когда вы возвращаетесь из этой функции, она перестает существовать - так что то, что вы вернули, есть ничто. Вы не можете ничего напечатать, поэтому Arduino падает.
Вам нужно либо сделать переменную timestamp
статической
, чтобы она не терялась при выходе из функции, либо сделать ее глобальной переменной, которая имеет аналогичный эффект, либо передать переменную буфера в rtcReadTime ()
, которая затем заполняется вместо того, чтобы возвращать указатель на символ.
Самый простой из них-просто сделать временную метку
статичной. Кроме того, вы должны использовать snprintf
вместо sprintf
, чтобы избежать возможности переполнения буфера:
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;
static char timestamp[30];
snprintf(timestamp, 30, "%02d.%02d.%4d %02d:%02d:%02d",tag,monat,jahr,stunde,minute,sekunde);
return timestamp;
}
- Звук перестает воспроизводиться после подключения rtc
- Режимы открытия файлов на SD-карте Arduino добавление/перезапись
- Какие контакты можно использовать для выбора микросхемы (CS, CC) на Arduino Nano Every?
- RtcDateTime' не называет тип
- Не удалось выделить SSD1306 при добавлении константы
- Печать содержимого файла SD - карты на ЖК-дисплее
- RTC и SD работают отдельно, а не вместе
- Ошибка модуля часов реального Времени-DS3231
Спасибо за ввод, к сожалению, это не работает. Не спрашивай меня, почему, хотя^^, @Kj Ell
Даже вынимание содержимого из функции и помещение его непосредственно в оператор "if(sd_ok)" дает мне тот же результат, @Kj Ell
Кстати. Я могу распечатать время на последовательном мониторе, используя
Serial.println(rtcReadTime());
. Я бы подумал, что это означает, что возврат переменной из функции работает?, @Kj EllЭто "работает", потому что у вас есть другие переменные во фрейме стека функции, действующие в качестве буфера для переменной метки времени - последующие функции, которые вы вызываете, не совсем пересекают свои фреймы стека достаточно далеко через этот буфер старых переменных в памяти, чтобы повредить строку. Чисто случайно., @Majenko