чего то делаю не так

Prostovova
Offline
Зарегистрирован: 17.10.2017

Большая просьба помочь, не кидая камнями. Программированием не занимался никогда. Делаю счетчик для горячей и холодной воды. (ну еще семисегментный 8 рарядный индикатор показывает время и температуру)

Не работает функционал записи значений в память (для сохранения на случай пропадания питания).

Ниже код, все лишнее выбросил (про индикатор, время и температуру). Проблемный кусок про EEPROM откуда то списал не разобравшись как работает :-(  

И да... счетчик Cold работает как требовалось.


#include <Bounce2.h>  // библиотека обработки дребезга контактов
#include <avr/eeprom.h> // библиотека для работы с энергонезависимой памятью

int inputColdPin = 8; //назначаем вывод 8 для холодного счетчика
int inputHotPin  = 7;  //назначаем вывод 7 для горячего счетчика
unsigned long Cold;
unsigned long Hot;
Bounce bouncer = Bounce();
Bounce bouncer2 = Bounce();

void setup()
{
//если хотим присвоить начальные значения, активируем следующие 4 строки
           //Cold=77419;
           //Hot=69539; 
           //eeprom_write_block(&Cold, 0, 4);
           //eeprom_write_block(&Hot, 5, 4);
//послезагрузки, вновь их деактивируем начальные значения будут сохранены
eeprom_read_block(&Cold, 0, 4);
eeprom_read_block(&Hot, 5, 4);
// назначенные выводы для подсчета импульсов и подключаем их (с нагрузочными резисторами) к библиотеке антидребезга
    pinMode(inputColdPin, INPUT_PULLUP);
    pinMode(inputHotPin, INPUT_PULLUP);
    bouncer.attach(inputColdPin);
    bouncer2.attach(inputHotPin);
    bouncer.interval(10); // interval in ms
    bouncer2.interval(10); // interval in ms
    Serial.begin(9600);  // инициализируем порт, скорость 9600
}

void loop()
{
   if (bouncer.update() && bouncer.read() == LOW)
  {
   Cold=Cold+1;eeprom_write_block(&Cold, 0, 4); delay(5); //запись нового значения в память
  }
   if (bouncer2.update() && bouncer2.read() == LOW)
  {
   Hot=Hot+1;eeprom_write_block(&Hot, 5, 4); delay(5); //запись нового значения в память
  }
  Serial.print("Hot: "); Serial.print(Hot);Serial.print("\t");Serial.print("Cold: "); Serial.println(Cold);

}
DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

А надо-то чо?

Prostovova
Offline
Зарегистрирован: 17.10.2017

Добавлю: Считаю имульсы (1 на 10 литров), а на индикатор вывожу кубометры, а то разрядов не хватает.

Начальные, значения в коде - реальные, поэтому unsigned long

Prostovova
Offline
Зарегистрирован: 17.10.2017

В приведенном коде, после закомментирования начальных значений, значение "Hot", после перезагрузки получается 1126318, а должно было быть 69539 С переменной "Cold" все в порядке

b707
Онлайн
Зарегистрирован: 26.05.2017

В коде проблем не вижу. должно работать. Попробуйте сохранять Cold в еепроме по другому адресу, например  10. Может у вас первые ячейки еепром "битые"

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

b707 пишет:

Попробуйте сохранять Cold в еепроме по другому адресу, например  10. Может у вас первые ячейки еепром "битые"

Это ненадолго с таким режимом записи.

2ТС: если бы вы свои Serial.print-ы воткнули сразу после считывания блока с eeprom, то всем было бы проще.

Prostovova
Offline
Зарегистрирован: 17.10.2017

Ну Serial.print-ы воткнул в конце, что бы убедиться, счетчик считает и после сброса питания восстанавливаются именно насчитанные значения

А что с режимом записи не так? одна единичка счета на 10 литров это не особо много и часто. на 100 000 циклов это должно быть 1000 кубов (сейчас на счетчиках - 700 кубов)

Проблема не в "битых" ячейках - проверял на разных экземплярах Nano

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

Prostovova пишет:

Ну Serial.print-ы воткнул в конце, что бы убедиться, счетчик считает и после сброса питания восстанавливаются именно насчитанные значения

#include <avr/eeprom.h> // библиотека для работы с энергонезависимой памятью

unsigned long Cold;
unsigned long Hot;

void setup()
{
  Serial.begin(9600);  // инициализируем порт, скорость 9600
  //если хотим присвоить начальные значения, активируем следующие 4 строки
 /*          Cold=77419;
           Hot=69539; 
           eeprom_write_block(&Cold, 0, 4);
           eeprom_write_block(&Hot, 5, 4);
*/
//послезагрузки, вновь их деактивируем начальные значения будут сохранены
eeprom_read_block(&Cold, 0, 4);
eeprom_read_block(&Hot, 5, 4);
 Serial.print("Hot: "); Serial.print(Hot);Serial.print("\t");Serial.print("Cold: "); Serial.println(Cold);
}
void loop()
{
 
}
Hot: 69539 Cold: 77419
Hot: 69539 Cold: 77419
 
Тоже Nano. Два раза даже ребутнул.
 
Prostovova
Offline
Зарегистрирован: 17.10.2017

Проверил

Все работает, то есть счетчики после перезагрузки питания начинают считать с того места где остановились.

НО! "Нот" - со своих непойми откуда взявшихся 1126318

 

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

Что тут посоветовать... пытайтесь локализовать проблемное место - например, втыкайте Serial.print("Hot: "); Serial.print(Hot); туда, где у вас +1 делается. 

 

Prostovova
Offline
Зарегистрирован: 17.10.2017

sadman41 пишет:

Hot: 69539 Cold: 77419

Hot: 69539 Cold: 77419
 
Тоже Nano. Два раза даже ребутнул.
 

А начальные значения закоменнтировали?

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

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

Prostovova пишет:

А начальные значения закоменнтировали?

Я даже вставил в сообщение то, что заливал, чтобы сомнений не возникло. Но это не помогло...

b707
Онлайн
Зарегистрирован: 26.05.2017

Prostovova пишет:

А что с режимом записи не так? одна единичка счета на 10 литров это не особо много и часто. на 100 000 циклов это должно быть 1000 кубов (сейчас на счетчиках - 700 кубов)

Проблема не в "битых" ячейках - проверял на разных экземплярах Nano

Вы уверены. что ваш код пишет в епром только изменяющиеся данные? Я бы на всякий случай писал функцией update(). И что 700 кубов -  их этот код уже "натикал", а потом начал глючить? тогда точно битые ячейки. 

Чтобы сохранить епром подольше, не пишите все время в одно место, пишите со смещением при каждой записи. Если надо - распишу алгоритм подробно. Можно продлить жизнь епром в десятки раз.

Prostovova
Offline
Зарегистрирован: 17.10.2017

Нет этот код не  натикал 700 кубов, я с Ардуиной живу последний месяц только и у меня не бассейн :-).

Запись в EEPROM стоит после изменения значения счетчика (то есть нет изменения - нет записи)

Запись со смещением - интересная мысль, но пока должно хватать того что есть.

Последовал совету b707 - перенес начальный адрес с 5 на 10:  eeprom_write_block(&Hot, 10, 4);

Вроде получилось !!!

 

 

b707
Онлайн
Зарегистрирован: 26.05.2017

Prostovova пишет:

Вроде получилось !!!

тогда точно битые ячейки...

Может вы их при тестировании "поджарили"?

Prostovova
Offline
Зарегистрирован: 17.10.2017

b707 пишет:

тогда точно битые ячейки...

Может вы их при тестировании "поджарили"?

Видимо

Был момент, когда чтобы кнопку не нажимать я счетчик в цикл поставил

А уже потом вычитал про 100 000 ограничение

А 100 000 - это на ячейку или на весь модуль?

Я сейчас снесу начальные адреса, это должно помочь?

b707
Онлайн
Зарегистрирован: 26.05.2017

Prostovova пишет:

А 100 000 - это на ячейку или на весь модуль?

Я сейчас снесу начальные адреса, это должно помочь?

на ячейку.

счетчик в цикле - это круто. Где-то читал. что при записи в цикле флеш убивается за 7 секунд, а епром за минуту.

Сдвиньте адреса записи куда-нибудь подальше, например за сотню адресов , должно помочь.

Prostovova
Offline
Зарегистрирован: 17.10.2017

b707 пишет:

Где-то читал. что при записи в цикле флеш убивается за 7 секунд, а епром за минуту.

Сдвиньте адреса записи куда-нибудь подальше, например за сотню адресов , должно помочь.

Спасибо сдвину :-)

Я ж новичок. Всех познаний програмировании: иф, зен, гоу ту. Мне про это в институте рассказывали, лет 30 назад :-)

Prostovova
Offline
Зарегистрирован: 17.10.2017

Ну вроде все заработало.

Вот только индикатор заметно мерцает на температуре и времени, в чем может быть дело?

Я выложу весь скетч скопом, не судите строго. Вернее судите, но не строго:

/*
работающая программа
Считает замыкания на землю по 2-м выводам (D7 и D8)
Результат хранится в энергонезависимой памяти (на случай пропадания питания)
Первоначальные значения можно внести с копьютера
Запись новых значений производится при их изменении, дабы не вырабатывать циклы записи/чтения
Вывод производится на 8 разрядный индикатор (на чипе MAX72XX), подключенный к выводам 10 (Load) 11(CLK) 12(DataIn)
Имеются часы на базе чипа DS3231 модуль подключается к аппаратным выводам I2C
Есть датчик температуры и влажности DHT11, подключенный к выводу D2
Данные счетчиков, времени и температуры выводятся последовательно с задержкой на 150 - 200 циклов программы (примерно по 4 секунды на Arduino Nano v3)
*/


#include <Bounce2.h>  // библиотека обработки дребезга контактов
#include "LedControl.h"  //подключаем библиотеку работы с многоразрядным семимегментным индикатором
#include <avr/eeprom.h> // библиотека для работы с энергонезависимой памятью
#include <RTC.h>         //подключаем библиотеку работы с часами реального времени RTC
RTC  time;
#include <DHT_U.h>       //подключаем библиотеку работы с датчиком температуры и влажности
#define DHTPIN      2  // Датчик температуры подключен выводу 2
#define DHTTYPE DHT11  // указываем тип датчика, бывает еще DHT22 - более точный и с большим диапазоном включая отрицательные температуры   
DHT_Unified dht(DHTPIN, DHTTYPE);

/*
указываем к каким пинам контролера какие пины модуля подключаем.
***** These pin numbers will probably not work with your hardware *****
pin 12 is connected to the DataIn
 pin 11 is connected to the CLK
 pin 10 is connected to LOAD
 We have only a single MAX72XX.
*/
LedControl lc=LedControl(12,11,10,2);
const int inputColdPin = 8; //назначаем вывод 8 для холодного счетчика
const int inputHotPin  = 7;  //назначаем вывод 7 для горячего счетчика
unsigned long Cold;
unsigned long Hot;
unsigned long printCold;
unsigned long printHot;
int NN=0;
int Light = 0;
int Temper;
Bounce bouncer = Bounce();
Bounce bouncer2 = Bounce();

void setup()
{
//если хотим присвоить начальные значения, активируем следующие 4 строки
           //Cold=77419;
           //Hot=69539; 
           //eeprom_write_block(&Cold, 20, 4);
           //eeprom_write_block(&Hot, 30, 4);
//послезагрузки, вновь их деактивируем начальные значения будут сохранены
eeprom_read_block(&Cold, 20, 4);
eeprom_read_block(&Hot, 30, 4);

    time.begin(RTC_DS3231);     //инициализация модуля RTC на базе чипа DS3231
    dht.begin(); // инициализируем датчик температуры
    sensor_t sensor;
    dht.temperature().getSensor(&sensor);
    dht.humidity().getSensor(&sensor);

    lc.shutdown(0,false); //инициализируем индикатор
    lc.setIntensity(0,8); // устанавливаем значение яркости индикатора от 0 до 15
    lc.clearDisplay(0); // очищаем дисплей
// назначенные выводы для подсчета импульсов и подключаем их (с нагрузочными резисторами) к библиотеке антидребезга
    pinMode(inputColdPin, INPUT_PULLUP);
    pinMode(inputHotPin, INPUT_PULLUP);
    bouncer.attach(inputColdPin);
    bouncer2.attach(inputHotPin);
    bouncer.interval(10); // interval in ms
    bouncer2.interval(10); // interval in ms
    Serial.begin(9600);  // инициализируем порт, скорость 9600
    Serial.print("Hot: "); Serial.print(Hot);  Serial.print("   Cold: "); Serial.println(Cold);
}

void loop()
{
   if (bouncer.update() && bouncer.read() == LOW)
  {
     Cold=Cold+1;
     eeprom_write_block(&Cold, 20, 4); //запись нового значения в память
     Serial.print("Cold: "); Serial.println(Cold);
  }
   if (bouncer2.update() && bouncer2.read() == LOW)
  {
     Hot=Hot+1;
     eeprom_write_block(&Hot, 30, 4); //запись нового значения в память
     Serial.print("Hot: "); Serial.println(Hot);
  }
//округляем выводимые значения
                printCold=okrugGl(Cold/10)*10;
                printHot=okrugGl(Hot/10)*10;
                Light=0;
  if ( NN==100)
                {
                sensors_event_t event; 
                dht.temperature().getEvent(&event);
                Temper = event.temperature;
                }
    Filer( Temper, printCold , printHot );
}

// функция округления с уменьшением разрядности
int okrugGl(unsigned long x)
{
int Delta; 
unsigned long outPut;
Delta=x%10;
if (Delta>4) {outPut=x/10+1;} else {outPut=x/10;}
return outPut;
}

// функция вывода на индикатор поразрядно с нулевого знакоместа
// v- входное 4-х разрядное значение
// n- номер начального знакоместа
// l включать или нет подсветку для десятков и сотен
// l2 - то же для тысяч

void printNumber(int v,int n, int l, int l2)
{ 
    int ones; 
    int tens; 
    int hundreds;
    int tausends;

    if(v > 9999)  return; 
    ones=v%10;
    v=v/10; 
    tens=v%10;
    v=v/10;
    hundreds=v%10;
    v=v/10; 
    tausends=v;
    /*

    Now print the number digit by digit
    первый аргумент отвечает за НЕотображение в указанном разряде
    "0" - отображать, "1" - не отображать
    последний аргумент в функции отвечает за отображение символа "точки"
    "1" - отображать, "0" - не отображать
    */

    lc.setDigit(l2,(n+3),tausends,0);
    lc.setDigit(l,(n+2),hundreds,0);
    lc.setDigit(l,(n+1),tens,0); 
    lc.setDigit(1,n,ones,0); //последнюю цифру не показываем
    }

void Filer(int Temper, unsigned long printCold,unsigned long printHot )
{
  int l2=1;
  NN=NN+1;
  if (NN>=1 && NN<=200)       //ПЕРВЫЕ 200 ЦИКЛОВ ПОКАЗЫВАЕМ СЧЕТЧИКИ
   {
                               printNumber(printCold,0,Light,0); // 0 - данные по холодному счетчику сначала
                               printNumber(printHot,4,Light,0);  // 4 - данные по горячему счетчику потом
                               lc.setChar(0,4,'-',false);        // дефис между показаниями
   }
  else { lc.clearDisplay(0);
  if (NN>200 && NN<=350)       //ВТОРЫЕ 150 ЦИКЛОВ ПОКАЗЫВАЕМ ТЕМПЕРАТУРУ
   {
                                printNumber(Temper*10,3,0,l2);
                                lc.setRow(0,3,B01100011); //знак градуса
                                lc.setRow(0,2,B01001110); //буква "С"
   }
   else { lc.clearDisplay(0);
 if (NN>350&& NN<=500)       //ТРЕТЬИ 150 ЦИКЛОВ ПОКАЗЫВАЕМ ВРЕМЯ
   {
                               printNumber(time.minutes*10,1,0,l2);
                               printNumber(time.Hours*10,4,0,l2);
                               lc.setChar(0,4,'-',false); 
   }
   else { lc.clearDisplay(0);  NN=0; }}}
  }

 

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

может быть в LedControl.h

проблема?

что за индикаторы кстати?

Prostovova
Offline
Зарегистрирован: 17.10.2017

Индикатор такой:

MAX7219 LED Dot Matrix 8-Digit Digital Tube Display Control Module

https://ru.aliexpress.com/item/MAX7219-LED-Dot-Matrix-8-Digit-Digital-Tube-Display-Control-Module/32654195774.html?spm=a2g0v.10010108.1000016.1.41fcc028CGYQCk&isOrigTitle=true

По идее не должно быть делло в библиотеке. Температуру я отдаю ей так же как и значения счетчиков.

T.Rook
Offline
Зарегистрирован: 05.03.2016

Так у Вас lc.clearDisplay(0) на каждом прогоне loop (вызове Filer) для температуры и времени. Зачем??

inspiritus
Offline
Зарегистрирован: 17.12.2012

b707 пишет:

Чтобы сохранить епром подольше, не пишите все время в одно место, пишите со смещением при каждой записи. Если надо - распишу алгоритм подробно. Можно продлить жизнь епром в десятки раз.

интересно , распишите, как Вы это делаете.

Я делал испыталку на вкл/выкл, и каждый факт срабатывания надо было хранить. А тестов в одном запуске 40000 раз.

Потому храню в ячейке с аддр 0 номер запуска (int), а текущий адрес для записи результатов тестов каналов (4*unsigned int)  в запуске вычисляю каждый раз, как :

текущий_адрес=базовый_адрес+количество_запусков*длина_записи(+смещение_канала)

если результат больше 1023, то текущий_адрес=базовый_адрес

Prostovova
Offline
Зарегистрирован: 17.10.2017

T.Rook пишет:

Так у Вас lc.clearDisplay(0) на каждом прогоне loop (вызове Filer) для температуры и времени. Зачем??

Если не чистить каша получается.

Но Вы правы. Поставил очистку на конкретные номера заходов на филер и все получилось :-)

Prostovova
Offline
Зарегистрирован: 17.10.2017

Вот, получилось

Всем ОГРОМНОЕ спасибо.