Как сохранять переменные arduino, при reset

Тема в разделе "Arduino & Shields", создана пользователем Den Kiva, 4 дек 2019.

  1. ostrov

    ostrov Гуру

    Я за FRAM, стоит копейки, подключается элементарно, ресурс практически бесконечный.
     
  2. В дш atmel почемуто в фичах в параграфе Non-volatile Program and Data Memories перечислил как Non-volatile так Data Memories, а я-то понадеялся что она вся Non-volatile, читать дш надо мне тщательнее.

    П.С.
    Значит банку по питанию на тиньку поставить и в сон её, с микроамперами во сне на банке несколько секунд проспит.
     
  3. akl

    akl Гуру

    да, что-то около того. я так понял это надо ждать пока кондер зарядится.
    А еще функция AnalogReference мне показалось что не работает как надо, но это не точно.
     
  4. DetSimen

    DetSimen Guest

    Когда-то делал съем показаний с импульсных щёччиков воды. Если пригодится и разберёшься чо к чему - используй на здоровья.

    Код (C++):
    #pragma once
    #include <Arduino.h>
    #include <EEPROM.h>


    // щёччик, хранящийся в EEPROM
    // любого шаблонного типа, к которому можно применить операцию ++ (т.е. целочисленный byte - dword)
    // умеет только увеличиваться
    // при старте программы (или обьявлении) в конструкторе читает себя из EEPROM по адресу AAddr
    // при инкременте записывает себя в EEPROM
    // обьявление переменной
    //
    // TROMCounter < тип, адрес переменной в EEPROM> Variable;
    //
    // например, счетчик горячей воды, имеет тип uint32_t и
    // хранится в EEPROM по адресу 0x10, обьявляется так
    //
    // TROMCounter<uint32_t,0x10> HotCounter;
    //
    // после этого, операция ++ увеличит значение HotCounter и
    // срауже запишет его в EEPROM
    //
    // если при первом чтении щёччика его значение пустое (0xFFFFFFFF), то
    // принимает и записывает значение 0 взат, в ПЗУ


    #pragma pack(push,1)

    template<typename T, size_t AAddr>
    struct TROMCounter {
    protected:
        size_t        FROMAddress;
        T            FCounter;

        bool isEmpty(const T &AValue) {
            uint8_t *ptr = (uint8_t *)(&AValue);

            bool result = true;
            for (uint8_t i = 0; i < sizeof(T); i++) {
                result = result && ((*ptr++) == 0xFF);
            }
            return result;
        }

    public:
        TROMCounter() {
            FROMAddress = AAddr;
            EEPROM.get(FROMAddress, FCounter);

            if (isEmpty(FCounter)) SetCounter(0);
        }

        TROMCounter(const T AInitValue) : TROMCounter() {
            SetCounter(AInitValue);
        }

        T operator ++(int) {
            SetCounter(FCounter+1);
            return FCounter;
        }

        T operator +=(T AValue) {
            SetCounter(FCounter + AValue);
            return FCounter;
        }

        operator T() const {
            return FCounter;
        }

        inline T GetCounter() const { return FCounter; };

        void SetCounter(const T ANewValue) {
            if (FCounter == ANewValue) return;
            FCounter = ANewValue;
            EEPROM.put(FROMAddress, FCounter);
        }

    };

    #pragma pack(pop)
    использование примерна так

    Код (C++):
    const uint16_t HOT_COUNTER_ADDRESS = 0x20;
    const uint16_t COLD_COUNTER_ADDRESS = HOT_COUNTER_ADDRESS + sizeof(uint32_t);


    TROMCounter<uint32_t, HOT_COUNTER_ADDRESS> HotWaterCounter;
    TROMCounter<uint32_t, COLD_COUNTER_ADDRESS> ColdWaterCounter;
    Либо можешь сначала записать начальные показания в EEPROM прям в конструкторе

    Код (C++):
    const uint16_t HOT_COUNTER_ADDRESS = 0x20;
    const uint16_t COLD_COUNTER_ADDRESS = HOT_COUNTER_ADDRESS + sizeof(uint32_t);


    TROMCounter<uint32_t, HOT_COUNTER_ADDRESS> HotWaterCounter(100500);
    TROMCounter<uint32_t, COLD_COUNTER_ADDRESS> ColdWaterCounter(200500);
    Но потом перекомпилируй как выше, с пустым конструктором, иначе каждый рас при старте туда будут записываца начальные значения.
    Асилишь?
     
    Последнее редактирование модератором: 6 дек 2019
    Mestniy и ИгорьК нравится это.
  5. Из описания на приборы учета расхода воды "БЕТАР"
    Передаточный коэффициент на телеметрическом выходе счетчиков СВМ-25Д, СВМ-32Д, СВМ-40Д, СВМ-40СД - 0,001 м3/имп.
    Средний расход в неделю 3 куба (в доме проживают 4 человека), т.е. 3000 импульсов.
    Если записывать каждый импульс и количество циклов записи для ЕЕПРОМ 100000, то 100000/3000=33 недели, пичалька... даже на год не хватит.
     
  6. DetSimen

    DetSimen Guest

    а у меня 3 года шарашит, не зная об этом.
    Счетчик герконовый, Gerrida-15ГИ, импульс 1 на 10 литров.
    Ну и на самом деле, EEPROM гарантирует не менее 100000 перезаписей ячейки, это же не значить, что ровно на 100000-й записи она до дыры протрется.
     
  7. Ariadna-on-Line

    Ariadna-on-Line Гуру

    Полезную тему подняли. Буду применять. Уже есть куда. Разумно, чтоб от ресета данные не пропали - писАть их в неинициализируемый (фффух) участок ОЗУ. Не важно от чего ресет - береженого бог бережет. От падения питалова не спасешься, но это другая тема.
     
    Последнее редактирование: 5 дек 2019
  8. Asper Daffy

    Asper Daffy Иксперд

    Дело на в "поспать", а, например, в нажатии кнопки "Reset".

    В принципе это работает (если синтаксис подправить), но с ограничениями. Например, если запустить вот такой код:
    Код (C++):
    #define NO_INIT __attribute__((section(".noinit")))
    void setup(void) {
        static unsigned NO_INIT nonInitCounter;
        Serial.begin(57600);
        Serial.print("Setup counter: ");
        Serial.println(++nonInitCounter);
    }

    void loop(void){}
    и понажимать на ресет, то можно увидеть вот такую картинку:
    Код (C++):
    Setup counter: 1
    Setup counter: 2
    Setup counter: 3
    Setup counter: 4
    Setup counter: 5
     
    Andrey12, DetSimen и ИгорьК нравится это.
  9. ИгорьК

    ИгорьК Оракул Модератор

    Неспеша.
    Питание так и так иногда падает. У меня сегодня ночью - 2 раза!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
    Так нафига сначала решать проблему ресета а после - питания, если решение защиты по питанию обеспечивает защиту и по ресету?
    FRAM - наше все!
     
    ostrov и DetSimen нравится это.
  10. ИгорьК

    ИгорьК Оракул Модератор

    Это первое что на ум пришло. Ибо нафига такое устройство, что требует нажатие на кнопку ресет?
    А вот от пропажи питания защищать некоторые устройства надо.
     
    DetSimen нравится это.
  11. akl

    akl Гуру

    а если запилить алгоритм, который будет перемещать место записи при появлении сбоящих ячеек.
    типа например храним в нулевой ячейке число N, а переменную записываем в N, N+1, N+2, и когда одна из копия начинает отличаться - меняем N. Ну или прямо перед местом сохранения иметь ячейку-флажок, которую при появлении сбоев закрывать и открывать новую на новом месте.
    Короче если запилить ротацию ячеек - на сколько именно это продлит жизнь памяти? ведь там портится не только конкретная ячейка которую теребонькают, но и страница в целом? не получится ли что по исчерпании условных 100к циклов ячеек 0-9, а потом еще 100к 10-19, после этого 20-29 и т.д. тоже окажутся сломанными, хотя в них ничего не писали?
     
  12. Ariadna-on-Line

    Ariadna-on-Line Гуру

    У кого что болит, тот о том и говорит :>)))))))))))))))))
     
  13. parovoZZ

    parovoZZ Гуру

    Маловероятно, что бытовые электронные счетчики именно так и работают.

    Счетчики ресурсов (особенно бытовые) на батарейках. Поэтому там проблемы с питаловом нет.
     
  14. ИгорьК

    ИгорьК Оракул Модератор

    О, это очень глубокий пост, в сравнении с любым иным из этой темы.
     
  15. ostrov

    ostrov Гуру

    Когда я использкю EEPROM, записываю данные три (или пять) раз, а при считывании сравниваю эту информацию. Исхожу из того, что все три (или пять) ячеек сбиться сразу не могут, если две и более совпадают, а одна нет, значит было повреждение, о чем делается заметка, а данные восстанавливаются по большинству. RAID-1, лайт версия. Есть другие способы, но этот простой, надежный и нересурсоемкий.

    Ротация немного для другого, для многочисленных записей, тут только FRAM как радикальное решение.
     
    issaom, akl, Daniil и ещё 1-му нравится это.
  16. Ariadna-on-Line

    Ariadna-on-Line Гуру

    Уже и пошутить нельзя... :>(((((((((((((((((((((((((((((((
    ТС - то поднял тему именно про ресет, а не про питалово.
     
    Последнее редактирование: 5 дек 2019
  17. Den Kiva

    Den Kiva Нерд

    Добрый вечер.
    Помогите подправить ниже представленный код, чтобы сохранялась переменная ( pere ) ?! через добавление __no_init
    первично, она равна 0, после кнопками её выставляем, и вот это значение надо сохранять при сбое питания или ресет.



    Код (C++):
    #define PIN_PLUS 7    //обьявляем переменную и пин
    #define PIN_MINUS 6   //обьявляем переменную и пин
    int pere = 0;         //первично задаем чему равна pere
    void setup() {
    Serial.begin(9600);
    pinMode(PIN_PLUS, INPUT);  
    pinMode(PIN_MINUS, INPUT);
    }
    void loop() {
    int sensorVal = digitalRead(PIN_PLUS);
    int sensorVall = digitalRead(PIN_MINUS);

    if (sensorVal == HIGH) {pere=pere+1;delay(200); } // pere +1
    if (sensorVall == HIGH) {pere=pere-1;delay(200);} // pere -1

      Serial.println (pere); // печатаем в мониторе порта переменную
     
    }
     
  18. Den Kiva

    Den Kiva Нерд

  19. Asper Daffy

    Asper Daffy Иксперд

    Так вроде ж два примера выложили!
    Не выпендривайтесь, и делайте через еепром. Этот трюк только для ресета, при сбое питания чуть более долгом, чем какие-нибудь сраные наносекунды, всё благополучно сбросится.

    И вообще, это трюкачество, которым Вы не сумеете воспользоваться, уверяю Вас. Тут не Ваша квалификация нужна. У Вас такие глюки полезут, что мама не горюй. Память-то он сохраняет, а все регистры ввода/вывода - йок. Вы знаете, что с этим делать? Так что не выпендривайтесь.
     
    Daniil, SergeiL, parovoZZ и ещё 1-му нравится это.
  20. Маловероятно что? Что в эксплуатации есть вышеуказанные приборы учета или маловероятно что они дают импульс на один литр?
    На территории РФ к сожалению есть. И к сожалению с таким не очень приятным коэффициентом куб./имп.
    На сухой контакт (или намур) есть различные контроллеры ультра-лоу-повер, питаются от лития, срок службы в 2 раза превышает срок (6 лет) плановой поверки приборов учета воды.
    В основном спят, просыпаются от импульсов или раз в сутки для передачи показаний.
    Если-бы небыло такого многообразия приборов учета (в частности водосчетчиков), которое есть сейчас в эксплуатации, учитывать ресурсы было-бы куда проще.