Запись EEPROM

MacMillan
Offline
Зарегистрирован: 25.10.2016

Здравствуйте!

Собрал схему вольтметр/амперметр/измеритель ёмкости для LiPo 4S аккумулятора. Столкнулся впервые с EEPROM, и никак не могу понять как дописать код.

Мне нужно, что бы каждые 2 минуты значение ёмкости записывалось в память, а при напряжении в 16,78-16,80 Вольт (100% заряженая) значение обнулялось. При включении питания значение естественно должно считываться.

Скетч того, что я сделал ниже, как я понимаю в моём случае значение ёмкости записывается каждую секунду, а это плохо.

За любую помощь заранее огромное спасибо!

#include <LCD_1602_RUS.h>
#include <MsTimer2.h>
#include <EEPROM.h>
LCD_1602_RUS lcd(0x3F, 16, 2); //инициализация дисплея по адресу 0х27 (для 2004) и 0x3F (для 1602)
#define R1 560 //резистор делителя на +
#define R2 36 //резистор делителя на -
#define MEASURE_PERIOD 500  // время периода измерения
int timeCount;  // счетчик времени
long  sumVOLTAGE, sumCURRENT ; // переменные для суммирования кодов АЦП
long  averageVOLTAGE, averageCURRENT; // сумма кодов АЦП (среднее значение * 500)
boolean flagReady;  // признак готовности данных измерения
float voltage = 0;
float current = 0;
float capacity = 0;
int addr = 0;


void setup() {
  lcd.init(); //включаем дисплей
  lcd.backlight(); //включаем подсветку
  MsTimer2::set(1, timerInterupt); // прерывания по таймеру, период 1 мс 
  MsTimer2::start();              // разрешение прерывания
  EEPROM.get(addr, capacity);
}

void  timerInterupt() {
  timeCount++;  // +1 счетчик выборок усреднения
  sumVOLTAGE+= analogRead(A1);  // суммирование кодов АЦП для напряжения
  sumCURRENT+= analogRead(A3);  // суммирование кодов АЦП для тока
   // проверка числа выборок усреднения
  if ( timeCount >= MEASURE_PERIOD ) {
    timeCount= 0;
    averageVOLTAGE = sumVOLTAGE; // перегрузка среднего значения для напряжения
    averageCURRENT = sumCURRENT; // перегрузка среднего значения для тока
    sumVOLTAGE= 0;
    sumCURRENT= 0;
    flagReady= true;  // признак результат измерений готов
    }
}

void loop () {
  voltage = averageVOLTAGE / 500. * 5.113 / 1024. / R2 * (R1 + R2); //расчёт напряжения
  current = (.0264 * ((averageCURRENT / 500.) - 505));
     if (current<0.28) {
   current=0.0;// обнуляем нежелательное значение 
   }  
  capacity = capacity+current / 3600;
  EEPROM.put(addr, capacity);
    if (voltage>16.78){
    capacity = 0.0;
  }
  lcd.setCursor (0, 0);
  lcd.print(L"Бат:");
  lcd.print(voltage, 2);
  lcd.print(L"V  ");
  lcd.setCursor (11, 0);
  lcd.print(current, 2);
  lcd.print(L"A ");
  lcd.setCursor (2, 1);
  lcd.print((float)((averageVOLTAGE / 500. * 5.113 / 1024. / R2 * (R1 + R2) - 13.2) / 3.6) * 100, 0); //расчёт процентов
  lcd.print(L"%  ");
  lcd.setCursor (8, 1);
  lcd.print(capacity, 3);
  lcd.print(L"mAh ");
  delay(1000);
}
ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

ага - каждые 2 минуты - и жить этому процессору осталось 40 дней

MacMillan
Offline
Зарегистрирован: 25.10.2016

Ну хорошо, но даже если не думать о двух минутах, то как реализовать запись по времени?

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

if ((millis() - previousMillis) >= T1) {}

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

1- ЕЕPROM при заливке скетча перешивается. Так что надо выделить ячейку для  определения первый ли это проход после заливки или нет.

2 "каждые 2 минуты значение ёмкости" Это как. У вас что за две минуты аккум заряжается и разряжается . И по этому вы определяете есмкость?

3- косяки в ТЗ(техническом задании)  => косяки в ПО(программном обеспечении)

MacMillan
Offline
Зарегистрирован: 25.10.2016

qwone пишет:

2 "каждые 2 минуты значение ёмкости" Это как. У вас что за две минуты аккум заряжается и разряжается . И по этому вы определяете есмкость?

Запись нужна только для того, что бы знать сколько мА/ч было потрачено за всё время использования на одной зарядке. Т.е попользовался я аккумулятором полчаса, выключил, потом через какое то время опять включаю и счёт мА/ч продолжается.  Поэтому я хотел, что бы значение мА/ч записывалось каждые пару минут, в случае, если я отключаю ардуину. А обнулять значение не кнопками, а по принципу - если напряжение составляет 100% от заряда, значит обнулить значение. Расчёт мА/ч мне не нужен супер точный, а лишь приблизительный.

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

У вас Ардуина стоит на устройстве зарядке или же как на смартфоне индикатор заряда батареи.

negavoid
Offline
Зарегистрирован: 09.07.2016

qwone пишет:
ЕЕPROM при заливке скетча перешивается

ЕЕPROM при заливке скетча по кнопке из arduino ide НЕ перезаписывается.

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

negavoid пишет:

qwone пишет:
ЕЕPROM при заливке скетча перешивается

ЕЕPROM при заливке скетча по кнопке из arduino ide НЕ перезаписывается.

не знал. я пишу без кнопки. 

MacMillan
Offline
Зарегистрирован: 25.10.2016

qwone пишет:

У вас Ардуина стоит на устройстве зарядке или же как на смартфоне индикатор заряда батареи.

Только как индикатор заряда и растраченой ёмкости

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

Понятно. Тогда когда у вам напряжение максимум. Точнее напряжение выше порога , то растрачено 0. А если ниже напряжение то в ЕЕPROM писать расход. Каковы единицы расхода byte,int,float,long ? Если ток обратный (зарядка) ничего не писать. Достиг максимума (выше порога) обнулился расход. 

Курите это http://radioprog.ru/post/117  , особенно это EEPROM.update(address, value)ВместоEEPROM.write(address, value)

MacMillan
Offline
Зарегистрирован: 25.10.2016

qwone пишет:

Понятно. Тогда когда у вам напряжение максимум. Точнее напряжение выше порога , то растрачено 0. А если ниже напряжение то в ЕЕPROM писать расход. Каковы единицы расхода byte,int,float,long ? Если ток обратный (зарядка) ничего не писать. Достиг максимума (выше порога) обнулился расход. 

Напряжение максимум - любое предыдущее значение должно обнулиться.

Расход - записывать, скажем каждые 2 минуты.

Расход считается как float, поэтому я применил EEPROM.get и EEPROM.put.

Зарядки через ардуину не будет, т.к аккумулятор литиевый с балансирным входом. Поэтому счёт в этом случае вообще не требуется.

EEPROM.update...опять таки перезаписывается изменившееся значение, а т.к изменение ежесекундное, то и запись будет ежесекундная. 

MacMillan
Offline
Зарегистрирован: 25.10.2016

ua6em пишет:

if ((millis() - previousMillis) >= T1) {}

Нужно только понять как использовать и как это работает)

Jeka_M
Jeka_M аватар
Offline
Зарегистрирован: 06.07.2014

MacMillan пишет:

Нужно только понять как использовать и как это работает)

http://arduino.ru/tutorials/BlinkWithoutDelay

http://robocraft.ru/blog/arduino/385.html

Клапауций 112
Онлайн
Зарегистрирован: 01.03.2017

qwone пишет:

negavoid пишет:

qwone пишет:
ЕЕPROM при заливке скетча перешивается

ЕЕPROM при заливке скетча по кнопке из arduino ide НЕ перезаписывается.

не знал. я пишу без кнопки. 

чуть не так - перезаписывать ЕЕPROM или нет, за это отвечает фьюз контроллера EESAVE

MacMillan
Offline
Зарегистрирован: 25.10.2016

Всё, задача решена) Большое спасибо!

if ((millis() - previousMillis) >= T1) {} - реально рабочая штука)

#include <LCD_1602_RUS.h>
#include <MsTimer2.h>
#include <EEPROM.h>
LCD_1602_RUS lcd(0x3F, 16, 2); //инициализация дисплея по адресу 0х27 (для 2004) и 0x3F (для 1602)
#define R1 560 //резистор делителя на +
#define R2 36 //резистор делителя на -
#define MEASURE_PERIOD 500  // время периода измерения
int timeCount;  // счетчик времени
long  sumVOLTAGE, sumCURRENT ; // переменные для суммирования кодов АЦП
long  averageVOLTAGE, averageCURRENT; // сумма кодов АЦП (среднее значение * 500)
boolean flagReady;  // признак готовности данных измерения
float voltage = 0;
float current = 0;
float capacity = 0;
int addr = 0;
long previousMillis = 0;
long T1 = 60000;


void setup() {
  lcd.init(); //включаем дисплей
  lcd.backlight(); //включаем подсветку
  MsTimer2::set(1, timerInterupt); // прерывания по таймеру, период 1 мс 
  MsTimer2::start();              // разрешение прерывания
  EEPROM.get(addr, capacity);
}

void  timerInterupt() {
  timeCount++;  // +1 счетчик выборок усреднения
  sumVOLTAGE+= analogRead(A1);  // суммирование кодов АЦП для напряжения
  sumCURRENT+= analogRead(A3);  // суммирование кодов АЦП для тока
   // проверка числа выборок усреднения
  if ( timeCount >= MEASURE_PERIOD ) {
    timeCount= 0;
    averageVOLTAGE = sumVOLTAGE; // перегрузка среднего значения для напряжения
    averageCURRENT = sumCURRENT; // перегрузка среднего значения для тока
    sumVOLTAGE= 0;
    sumCURRENT= 0;
    flagReady= true;  // признак результат измерений готов
    }
}

void loop () {
  voltage = averageVOLTAGE / 500. * 5.113 / 1024. / R2 * (R1 + R2); //расчёт напряжения
  current = (.0264 * ((averageCURRENT / 500.) - 505));
     if (current<0.28) {
   current=0.0;// обнуляем нежелательное значение 
   }  
  capacity = capacity+current / 3600;
  if ((millis() - previousMillis) >= T1) {
     EEPROM.put(addr, capacity);
    }
    if (voltage>16.78){
    capacity = 0.0;
  }
  lcd.setCursor (0, 0);
  lcd.print(L"Бат:");
  lcd.print(voltage, 2);
  lcd.print(L"V  ");
  lcd.setCursor (11, 0);
  lcd.print(current, 2);
  lcd.print(L"A ");
  lcd.setCursor (2, 1);
  lcd.print((float)((averageVOLTAGE / 500. * 5.113 / 1024. / R2 * (R1 + R2) - 13.2) / 3.6) * 100, 0); //расчёт процентов
  lcd.print(L"%  ");
  lcd.setCursor (8, 1);
  lcd.print(capacity, 3);
  lcd.print(L"mAh ");
  delay(1000);
}

 

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016
 if ((millis() - previousMillis) >= T1) {
     EEPROM.put(addr, capacity);
previousMillis=millis();
    }

Каждый жеж отрезок времени проверяем, а если нужны точные отрезки времени, то:

 if ((millis() - previousMillis) >= T1) {
     EEPROM.put(addr, capacity);
previousMillis=previousMillis+T1;
    }

 

MacMillan
Offline
Зарегистрирован: 25.10.2016

ua6em пишет:

 if ((millis() - previousMillis) >= T1) {
     EEPROM.put(addr, capacity);
previousMillis=millis();
    }

Каждый жеж отрезок времени проверяем, а если нужны точные отрезки времени, то:

Спасибо большущее, исправил)