Запись первоначальных данных в EEPROM

sashok
Offline
Зарегистрирован: 06.04.2019

Здравствуте.

Хочу сделать счетчик импульсов с выводом на двухстрочный дисплей на Arduino UNO. 

У водосчетчика, с которого получаю и считаю импульсы есть начальные показания. Эти показания необходимо при загрузки скетча прописать в EEPROM для дальнейшего использования и сохренения при отключении питания.

Самый простой способ, который нашел это сделать две загрузки скетча:

1. В Setup прописать команду записи в ячейку памати первоначальных значений и загрузить скетч;

2. Закоментировать строку с выше указанной записью и снова загрузить скетч.

При первой загрузке у меня все получается на дисплее выводится первоначальные данные счетчика, но после того как я удаляю из Setup строку с записью и загружаю скетч в контроллер, при чтении из EEPROM на дисплее получается нуль. Как-будто в прошлый раз данные не записались или стерлись при повторной загрузке.

#include <EEPROM.h>
#include <Wire.h> // библиотека для управления устройствами по I2C 
#include <LiquidCrystal_I2C.h> // подключаем библиотеку для LCD 1602
LiquidCrystal_I2C lcd(0x27,16,2); // присваиваем имя lcd для дисплея 16х2

volatile boolean lcdOnFlg = HIGH; //флаг включеного монитора
volatile long lcdOnTime = 0; //время включения монитора

int litrs = 110;
int address = 0;

void setup() 
{
  lcd.init(); // инициализация LCD дисплея
  lcd.backlight(); // включение подсветки дисплея
 lcd.setCursor(0,0);
 lcd.print("Litrs:");
 attachInterrupt(1, lcdOn, FALLING);
 Serial.begin(9600);
 <strong>//EEPROM.put(address,litrs);            // Записать первоначального значения счетчика 110  в ячейку с адресом 0
 //delay(100);</strong>
 
 //EEPROM.get(0, litrs);
}
//прерывание от кнопки включения дисплея
void lcdOn()
{
 if ((millis()-lcdOnTime) >200)
  {
    if(lcdOnFlg == LOW)     //если экран выключен, то поднимаем флаг и запоминаем время включения 
   {
     lcdOnTime = millis();   //запоминаем время сработки прерывания
     lcdOnFlg = !lcdOnFlg ;  //поднимаем флаг
   }
  }
   lcdOnTime = millis();
}

void loop() 
{
    // Получаем данные из EEPROM
  litrs = EEPROM.read(address);
  
  lcd.setCursor(0,1);  // ставим курсор на 1 символ второй строки
  lcd.print(litrs);
  if(lcdOnFlg == HIGH) //если флаг поднят - экран горит
  {  
    if ((millis()-lcdOnTime) >10000) //проверяем время которое горит экран не более 10 секунд
    {
     lcd.noBacklight();   //через 10 секнд гасим экран
     lcdOnFlg = !lcdOnFlg;  //опускаем флаг
    }
    else
    {
      lcd.backlight();
    }
  }
  Serial.println(litrs);  
}

Подскажите где ошибка в записи или в чтении и есть ли какой-то другой не сложный алгоритм записи первоначальных данных. Спасибо.

mykaida
mykaida аватар
Offline
Зарегистрирован: 12.07.2018

Подскажите, а где в Вашей программе идет запись в EEPROM?

asam
asam аватар
Offline
Зарегистрирован: 12.12.2018

У avrdude, которым заливается UNO есть параметр -е - стирать EEPROM. Надо его (-е) удалить из platform.txt который находится в Arduino\hardware\arduino\avr

tools.avrdude.erase.pattern="{cmd.path}" "-C{config.path}" {erase.verbose} -p{build.mcu} -c{protocol} {program.extra_params} -e -Ulock:w:{bootloader.unlock_bits}:m -Uefuse:w:{bootloader.extended_fuses}:m -Uhfuse:w:{bootloader.high_fuses}:m -

 

mykaida
mykaida аватар
Offline
Зарегистрирован: 12.07.2018

asam пишет:

У avrdude, которым заливается UNO есть параметр -е - стирать EEPROM. Надо его (-е) удалить из platform.txt который находится в Arduino\hardware\arduino\avr

tools.avrdude.erase.pattern="{cmd.path}" "-C{config.path}" {erase.verbose} -p{build.mcu} -c{protocol} {program.extra_params} -e -Ulock:w:{bootloader.unlock_bits}:m -Uefuse:w:{bootloader.extended_fuses}:m -Uhfuse:w:{bootloader.high_fuses}:m -

 

Да это я понимаю - а где записывают? Стереть каждый может...

asam
asam аватар
Offline
Зарегистрирован: 12.12.2018

mykaida пишет:

Да это я понимаю - а где записывают? Стереть каждый может...

 

см строку N20

asam
asam аватар
Offline
Зарегистрирован: 12.12.2018

Лично я бы не парился с двойной загрузкой скетча, а сделал бы считывание данных для записи из сериал. 

То есть при запуске программа проверяет не были ли данные записаны в EEPROM (сигнатуру,так какую придумать) и если нет, то ждать их ввода из сериал. Тогда при первой загрузке сразу можно и нужные данные ввести без перекомпиляции.  

sadman41
Offline
Зарегистрирован: 19.10.2016

#20 не прописывает для сохренения при отключении питания...

asam
asam аватар
Offline
Зарегистрирован: 12.12.2018

sadman41 пишет:

#20 не прописывает для сохренения при отключении питания...

А что же, по вашему, EEPROM.put() делает?

sadman41
Offline
Зарегистрирован: 19.10.2016

Записывает какие-то первоначальные показания, но не производит сохренение при отключении питания.

asam
asam аватар
Offline
Зарегистрирован: 12.12.2018

sadman41 пишет:

Записывает какие-то первоначальные показания, но не производит сохренение при отключении питания.

То есть, опять же по-вашему, EEPROM не сохраняет данные при отключении питания?

sadman41
Offline
Зарегистрирован: 19.10.2016

Сохраняет, конечно. Но, полагаю, что ценность прибора, который при случайной перезагрузке не сохраняет текущие показание водомера, а начинает считать каждый раз со 110 - стремится к нулю.

sashok
Offline
Зарегистрирован: 06.04.2019

sadman41 пишет:

Сохраняет, конечно. Но, полагаю, что ценность прибора, который при случайной перезагрузке не сохраняет текущие показание водомера, а начинает считать каждый раз со 110 - стремится к нулю.


Я пока не дописал код, который записывает изменённые показания, я застрял с начальными :)
Ем слона по частям.
Спасибо всем за советы буду пробовать.

Pyotr
Offline
Зарегистрирован: 12.03.2014

В СЕТАП() 
если в ячейке № значение не равно контрольному (например 85 или другое кроме 255)
1) записать стартовые значения счетчика
2) записать в ячейку № контрольное число

mykaida
mykaida аватар
Offline
Зарегистрирован: 12.07.2018

Pyotr пишет:

В СЕТАП() 
если в ячейке № значение не равно контрольному (например 85 или другое кроме 255)
1) записать стартовые значения счетчика
2) записать в ячейку № контрольное число

Не получится - сработает 1 раз. Тут надо привязаться к чему-то конкретному, например ко времени, но это потребует аппаратных доработок.

andycat
andycat аватар
Offline
Зарегистрирован: 07.09.2017

mykaida пишет:

Pyotr пишет:

В СЕТАП() 
если в ячейке № значение не равно контрольному (например 85 или другое кроме 255)
1) записать стартовые значения счетчика
2) записать в ячейку № контрольное число

Не получится - сработает 1 раз. Тут надо привязаться к чему-то конкретному, например ко времени, но это потребует аппаратных доработок.

Всё получится, оно и должно сработать один раз, а в другое место eeprom уже пишется счётчик из loop, а выводится уже сумма начального значения и счетчикал

mykaida
mykaida аватар
Offline
Зарегистрирован: 12.07.2018

Да, логично, ступил. Но тогда это значение и надо писать 2 раза в EEPROM и сравнивать их.

Pyotr
Offline
Зарегистрирован: 12.03.2014

Мой вариант работает. Скажу больше - после загрузки скетча нужен один старт программы (он происходит без нашего участия). Дальше коментируем условие и снова загружаем скетч. При этом в фузах должен быть установлен бит EESAVE. При больших объемах данных исключение функции начальной записи еепром позволит уменьшить размер скетча. ТС-у это конечно не нужно.

Pyotr
Offline
Зарегистрирован: 12.03.2014

Вот пример для записи массива

#include <avr/eeprom.h>
uint8_t EEMEM ee_write;//по этому адресу (0) лежит контрольное 
uint16_t EEMEM ee_val_w[22];//с адреса "1" лежит массив из 22 значений типа word

void writeEEPROM(){
  word val[22] = {/*.......*/};//заполнить массив
  eeprom_write_block ((const void*) &val, (void*) &ee_val_w, sizeof(val));
}

void setup() {
  if(eeprom_read_byte(&ee_write) != 85){ 
    writeEEPROM();
    eeprom_write_byte ((uint8_t *) &ee_write, 85);
  } 
} 
void loop() {
  word temp = eeprom_read_word(&ee_val_w[3]); //читаем четвертый элемент массива
}

 

mykaida
mykaida аватар
Offline
Зарегистрирован: 12.07.2018

Pyotr пишет:

Мой вариант работает. Скажу больше - после загрузки скетча нужен один старт программы (он происходит без нашего участия). Дальше коментируем условие и снова загружаем скетч. При этом в фузах должен быть установлен бит EESAVE. При больших объемах данных исключение функции начальной записи еепром позволит уменьшить размер скетча. ТС-у это конечно не нужно.

Поздравляю, уважаемый, но в изначальном ТЗ этого не озвучивалось. Короче - Вы сами не знали, чего хотели.

sashok
Offline
Зарегистрирован: 06.04.2019

Что конкретно нужно удалить просто два символа -e?

sashok
Offline
Зарегистрирован: 06.04.2019

Pyotr пишет:

Мой вариант работает. Скажу больше - после загрузки скетча нужен один старт программы (он происходит без нашего участия). Дальше коментируем условие и снова загружаем скетч. При этом в фузах должен быть установлен бит EESAVE. При больших объемах данных исключение функции начальной записи еепром позволит уменьшить размер скетча. ТС-у это конечно не нужно.

Как установить бит EESAVE?

sashok
Offline
Зарегистрирован: 06.04.2019

Поменял я платы, была у меня такая:

Перепрошил в такую

И все заработало! 

Знатоки в чем может быть отличие?

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

Отличие в том, что Вы неверно выставили тип платы в настройках.