Перезапускать переменную каждый день

rtc

Как я могу перезапускать переменную каждый день? У меня есть RTC 1307. Проблема в том, что я не могу использовать тревожное событие, потому что Arduino будет отключен в течение этого часа. Поэтому мне нужно более надежное решение.

Это сработает? Дата может быть целым числом?

#include <EEPROM.h>
#include "RTClib.h"

int  lastDay;
int EE_ADDR = 0;
int totalLitres;

void setup() {
  EEPROM.get(EE_ADDR, lastDay);
}

void loop() {
DateTime now;
  if (now.day() != lastDay) // это происходит ровно один раз в день.
    totalLitres = 0; // сбрасываем накопленный объем

  lastDay = now.day();
}

, 👍-1

Обсуждение

Почему ваш Arduino выключается? И намерены ли вы предотвратить отключение?, @Michel Keijzers

Arduino будет подключен к стене, поэтому он будет работать только при подключении. Мое намерение состоит не в том, чтобы предотвратить его отключение, но когда проходит день, переменная перезапустится до 0. Я делаю проект, который «чувствует» количество воды через расходомер, поэтому я хочу перезапустить переменную «количество воды» каждый день. С уважением, Сантьяго., @santilococo

Я до сих пор не понимаю проблемы... если Arduino выключить, он перезапустится, и переменная снова получит свое начальное значение., @Michel Keijzers

Да, ты должен быть немного более ясным. Вы хотите обнулять переменную каждый день, но есть вероятность, что Arduino не работает, когда начинается новый день? Одним из вариантов может быть сохранение переменной lastResetDay в EEPROM. Затем при запуске и периодически в своем коде вы будете извлекать их переменную из EEPROM, сверять ее с текущим дневным значением из RTC, если они совпадают - ничего не делать. Если они не совпадают, обнулите переменную расхода и сохраните текущий день обратно в EEPROM., @Chad G

Да! Я хотел бы сделать эту вещь «lastResetDay»?, @santilococo

@ChadG Я добавляю код. Это верно?, @santilococo

подумайте о том, что произойдет, если день изменится сразу после того, как оператор if сравнивает два значения, @jsotola

@jsotola: Ничего особенного не произойдет: now.day() не изменится сам по себе. DateTime - это не что иное, как контейнер для элементов меток времени (год, месяц, день, часы, минуты и секунды). Если вы не инициализируете его явно, он инициализируется по умолчанию 2000-01-01T00:00:00 (раньше по умолчанию было 2106-02-06T06:28:16, пока [этот запрос на включение](https:/ /github.com/adafruit/RTClib/pull/93) был принят)., @Edgar Bonet


1 ответ


2

Вот несколько предложений:

  • Поскольку ваш RTC имеет встроенную энергонезависимую память (NVRAM), вы можете используйте его вместо EEPROM. Таким образом, вам не придется беспокоиться о выносливости EEPROM.
  • Если есть вероятность, что устройство отключится в течение один день, вы, вероятно, хотите, чтобы он сохранил количество литров. Это может быть достигнуто путем периодического сохранения этого счетчика в NVRAM, и восстановление его при запуске. Вы можете сохраняться часто, так как у вас нет пределы выносливости.
  • Если устройство запускается после полного месяца простоя, следует ли обратите внимание, что прошло несколько дней, даже если номер дня совпадает с когда он был выключен. Вместо того, чтобы сохранять только номер дня, я бы сохранить общее количество дней, прошедших с 1 января 2000 года.

Непроверенная реализация приведенных выше предложений:

#include <Wire.h>
#include <RTClib.h>

const uint32_t NVRAM_UPDATE_PERIOD = 10000;  // 10 секунд

/* Addresses for data items saved in the RTC's NVRAM. */
const uint8_t ADDRESS_LITERS    = 0x00;
const uint8_t ADDRESS_RESET_DAY = 0x02;

RTC_DS1307 rtc;
uint16_t liters;
uint16_t reset_day;

/*
 * If `liters' has not been reset today, reset it now and update both
 * the RAM and NVRAM copies of `reset_day'.
 */
void reset_liters_if_needed()
{
    uint16_t current_day = rtc.now().secondstime() / 86400;
    if (current_day > reset_day) {
        liters = 0;
        reset_day = current_day;
        rtc.writenvram(ADDRESS_RESET_DAY,
                (uint8_t *) &reset_day, sizeof reset_day);
    }
}

void setup()
{
    /* Pull the initial `liters' and `rest_day' from NVRAM. */
    rtc.begin();
    rtc.readnvram((uint8_t *) &liters, sizeof liters,
            ADDRESS_LITERS);
    rtc.readnvram((uint8_t *) &reset_day, sizeof reset_day,
            ADDRESS_RESET_DAY);
    reset_liters_if_needed();
}

void loop()
{
    /* Periodically update the NVRAM. */
    static uint32_t last_nvram_update;
    if (millis() - last_nvram_update >= NVRAM_UPDATE_PERIOD) {
        reset_liters_if_needed();
        rtc.writenvram(ADDRESS_LITERS,
                (uint8_t *) &liters, sizeof liters);
    }
}

Для дополнительной безопасности вы можете добавить большой конденсатор, чтобы сохранить Arduino включался в течение нескольких миллисекунд после отключения. И схема, которая определяет, когда он отключается, чтобы немедленно сохранить данные и прекратите доступ к NVRAM до того, как она разрядится. Этот этот трюк уже обсуждался здесь, вы должны быть в состоянии найти соответствующие вопросы и ответы.

,

Большое спасибо! Я буду работать над этим кодом. У меня очень глупый вопрос: определяя нашу переменную литры как беззнаковое короткое, она не будет отображать десятичные дроби? Мне нужно, чтобы литры были плавающими. Это тот же процесс?, @santilococo

@santilococo: просто имейте в виду, что число с плавающей запятой составляет 4 байта. Если вы храните «литры» как число с плавающей запятой по адресу 0, вы можете поместить «reset_day» по адресу 4, но не по адресу 2., @Edgar Bonet

Поплавок не занимает всего 2 байта? Например, литры: 1,12., @santilococo

@santilococo: Нет, sizeof(float) равен 4., @Edgar Bonet