Прошу помощи с ЕЕPROM

avgustdon
Offline
Зарегистрирован: 28.02.2016

Имеется устройство контроля влажности. Необходимо сделать возможность изменения настроек в процессе работы без участия компа. Менять нужно верхний и нижний порог влажности.

   Предполагаю, что должно быть так: нажимаем на кнопку входа в настройки, устройство переходит в режим настроек. При нажатии на кнопку увеличения или уменьшения, соответственно изменяются показания (можно одно изменение за одно нажатие, можно с заданной частотой до достижения нужного значения и при отпускании кнопки останавливается). При этом показания влажности, а также показания настроек выводятся на дисплей 1602. Главное, чтобы при выключении питания, настройки не забывались. Состояние кнопки настроек можно забывать. При повторном нажатии на кнопку входа в настройки, устройство выходит из режима настроек.

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


// ---------------------------- контроллер температуры и влажности -----------------------------------------
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x3F, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);
// -------------------------------------------------------- 
#include "stDHT.h" // подключаем библиотеку датчика
DHT sens(DHT22);
// ------------------- outputs ---------------------------------
#define Out2 5            // the output of the humidifier
  
// ---------------- inputs for control buttons ------------------------------------------
const int button1 = 8;       // кнопка входа в настройки. с этой кнопкой все понятно. два значения 0 - работаем, 1 - режим настроек   
const int button2 = 9;       // кнопка увеличения значения
const int button3 = 10;       // кнопка уменьшения значения
      
// -----------------------------------------------------------------------------------------------------
int count1 ;         // переменная для подсчета нажатий на кнопку
int button_old1 = 1;    // предыдущее значение входа для отлавливания момента нажатия

// ------------------------------- создаем переменные для работы кнопок --------------------------------
int hum_max   ;     // максимальный порог влажности      
int hum_min   ;     // минимальный порог влажности          

void setup() {
  Serial.begin(9600);
  pinMode(3, INPUT);      
  digitalWrite(3, HIGH);     // подключаем датчик
  pinMode(button1, INPUT_PULLUP);
  pinMode(Out2, OUTPUT);     // увлажнитель
  {lcd.begin(16, 2);} // Инициализируем LCD 1602
}

void loop() {
 // --------------- работа датчиков температуры и влажности ----------
  int t = sens.readTemperature(3); // чтение датчика на пине 3
  int h = sens.readHumidity(3);    // чтение датчика на пине 3
    delay(1000);

// -------------- работа с кнопками -----------------------------
  if ((digitalRead(button1) == LOW)&&(button_old1 == 1))
  { count1 = count1 + 1;    // увеличиваем значение на 1 при каждом нажатии на кнопку
  if (count1 > 1)
  {count1 = 0;}          // при втором нажатии обнуляем счетчик
    Serial.println(count1);  }
  button_old1 = digitalRead(button1); 








 // ------------------------------- работа увлажнителя ------------------------------------------
  // 1
 if (h < hum_min)                 // если влажность меньше минимальной заданной 
  {digitalWrite(Out2,HIGH); }     // включаем увлажнитель
  // 2
 if (h > hum_max)                 // если влажность больше максимальной заданной
  {digitalWrite(Out2,LOW); }      // выключаем увлажнитель   
 
  // ---------------------------------------------------------------------------------
  Serial.print("Hum_sens: ");
  Serial.print(h);   

  Serial.print("     hum_max: ");   
  Serial.print(hum_max);          //*/
  Serial.print("  hum_min: ");   
  Serial.print(hum_min);          //*/  
  Serial.print("        Hum: ");
  Serial.println(digitalRead(Out2));  



   // -------------Подпрограмма вывода на дисплей -------------------------------
    lcd.clear();                    // стираем показания
  lcd.home ();                      // В Начальную позицию дисплея
  lcd.print("t ");                  
  lcd.print(t);                     // выводим показания первого датчика
  lcd.setCursor(6,0);
  lcd.print(" h_max ");                    
  lcd.print(hum_max);               // верхний уровень влажности  
  lcd.setCursor(0,1);                         
  lcd.print("h ");                    
  lcd.print(h);                     // показания влажности
  lcd.setCursor(6,1);
  lcd.print(" h_min ");                    
  lcd.print(hum_min);               // нижний уровень влажности

  }

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

...и вы хотите, чтобы Клапацуций вам остальное дописал - я правильно понял цель поста?

bwn
Offline
Зарегистрирован: 25.08.2014

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

avgustdon
Offline
Зарегистрирован: 28.02.2016

Да я в общем-то и пошел этим путем, но при выключении питания программа забывает настройки. Как я понимаю программа должна запомнить текущее состояние настроек, чтобы такого не случалось. Разве при помощи миллис такое возможно реализовать?

bwn
Offline
Зарегистрирован: 25.08.2014

Миллис обеспечит возможность вызова требуемых функций по мере надобности. А дальше все зависит от вашей фантазии. Опрос клавиш производим в каждый проход, температуру и ее вывод юзаем каждую секунду.
Заметили нажатие для входа в редактированиие, начали считать интервал, интервал достигнут - вывели ранее сохраненное значение и позволили его редактировать. После редактирования, если есть подтверждение, сохранили и вышли из режима, если подтверждения нет - отсчитали интервал и ушли назад без сохранения. Как то так. Все хотелки и сценарии сочиняете сами.

b707
Offline
Зарегистрирован: 26.05.2017

avgustdon у вас в одном вопросе минимум два - 1) установка настроек кнопками и 2) запоминание их

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

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

avgustdon пишет:

Предполагаю, что должно быть так: нажимаем на кнопку...

sadman41 пишет:

...и вы хотите, чтобы Клапацуций вам остальное дописал - я правильно понял цель поста?

...нажимаю на кнопку "СДЕЛАТЬ КОД" и ТС приковывается к батарее писать свои хотелки, а я ежесуточно хожу, проверяю результат и пижжу железной арматуриной.

когда код написан, то нажимаю на кнопку "СЛЕДУЮЩИЙ" - загорается зелёный фонарь над пытошной и входит ТС № 2.

так предполагаю(с) О_О

avgustdon
Offline
Зарегистрирован: 28.02.2016

Принимаю критику, виноват. Вот новый код где все работает кроме запоминания. Правда обошелся без миллис. 



// ---------------------------- контроллер температуры и влажности -----------------------------------------
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x3F, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);
// -------------------------------------------------------- 
#include "stDHT.h" // подключаем библиотеку датчика
DHT sens(DHT22);
// ------------------- outputs ---------------------------------
#define Out2 5            // the output of the humidifier
  
// ---------------- inputs for control buttons ------------------------------------------
const int button1 = 8;       // кнопка входа в настройки. с этой кнопкой все понятно. два значения 0 - работаем, 1 - режим настроек   
const int button2 = 9;       // кнопка увеличения значения
const int button3 = 10;       // кнопка уменьшения значения
      
// -----------------------------------------------------------------------------------------------------
int count1 ;         // переменная для подсчета нажатий на кнопку1
int button_old1 = 1;    // предыдущее значение входа для отлавливания момента нажатия кнопки1 
int count2 ;         // переменная для подсчета нажатий на кнопку2
int button_old2 = 1;    // предыдущее значение входа для отлавливания момента нажатия кнопки2 
int count3 ;         // переменная для подсчета нажатий на кнопку3
int button_old3 = 1;    // предыдущее значение входа для отлавливания момента нажатия кнопки3 // ------------------------------- создаем переменные для работы кнопок --------------------------------

// ------------------------------------------------------------------
//int hum_max   ;     // максимальный порог влажности      
   
// ------------------------------------------------------------------------------------------
void setup() {
  Serial.begin(9600);
  pinMode(3, INPUT);      
  digitalWrite(3, HIGH);     // подключаем датчик
  pinMode(button1, INPUT_PULLUP);
  pinMode(button2, INPUT_PULLUP);
  pinMode(button3, INPUT_PULLUP);
  pinMode(Out2, OUTPUT);     // увлажнитель
  {lcd.begin(16, 2);} // Инициализируем LCD 1602
}

void loop() {
 // --------------- работа датчиков температуры и влажности ----------
  int t = sens.readTemperature(3); // чтение датчика на пине 3
  int h = sens.readHumidity(3);    // чтение датчика на пине 3
    delay(100);

// -------------- работа с кнопками -----------------------------
  // кнопка входа в настройки
  if ((digitalRead(button1) == LOW) && (button_old1 == 1))
  { count1 = count1 + 1;    // увеличиваем значение на 1 при каждом нажатии на кнопку
  if (count1 > 1)
  {count1 = 0;}          // при втором нажатии обнуляем счетчик
    Serial.print(count1);  }
  button_old1 = digitalRead(button1); 
  
  // кнопка увеличения значения
  if ((digitalRead(button2) == LOW) && (button_old3 == 1) && (count1 == 1))
  { count2 = count2 + 1;    // увеличиваем значение на 1 при каждом нажатии на кнопку
  if (count2 > 99)
  {count2 = 0;}          // при достижении максимального значения обнуляем счетчик
    Serial.print(count2);  }
  button_old2 = digitalRead(button2);  
  
  // кнопка уменьшения значения
  if ((digitalRead(button3) == LOW) && (button_old3 == 1) && (count1 == 1))
  { count2 = count2 - 1;    // увеличиваем значение на 1 при каждом нажатии на кнопку
  if (count2 < 0)
  {count2 = 0;}          // при достижении максимального значения обнуляем счетчик
    Serial.print(count2);  }
  button_old2 = digitalRead(button2);







 // ------------------------------- работа увлажнителя ------------------------------------------

 if (h > count2)                 // если влажность больше максимальной заданной
  {digitalWrite(Out2,LOW); }      // выключаем увлажнитель   
  else
  {digitalWrite(Out2,HIGH); }      // включаем увлажнитель   
  
 
  // --------------------- проверка работы кнопок -----------------------------------------------
  Serial.print("count1: ");
  Serial.print(count1); 
  Serial.print("  count2: ");
  Serial.print(count2); 
    
  // -----------------------------------------------------------------------------------
  Serial.print("         Hum_sens: ");
  Serial.print(h);   

  Serial.print("     hum_max: ");   
  Serial.print(count2);          //*/

  Serial.print("        Hum: ");
  Serial.println(digitalRead(Out2));  



   // -------------Подпрограмма вывода на дисплей -------------------------------
    lcd.clear();                    // стираем показания
  lcd.home ();                      // В Начальную позицию дисплея
  lcd.print("t ");                  
  lcd.print(t);                     // выводим показания первого датчика
  lcd.setCursor(6,0);
  lcd.print(" h_max ");                    
  lcd.print(count2);               // верхний уровень влажности  
  lcd.setCursor(0,1);                         
  lcd.print("h ");                    
  lcd.print(h);                     // показания влажности


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

Клапауций 112 пишет:

 загорается зелёный фонарь над пытошной и входит ТС № 2.

Над скетчечной же.

ТС: на форуме есть тема "Запись и чтение EEPROM". довольно обширная и с нуля.

 

bwn
Offline
Зарегистрирован: 25.08.2014

avgustdon пишет:

Принимаю критику, виноват. Вот новый код где все работает кроме запоминания. Правда обошелся без миллис. 

Я фак его знает, как это все сделать в последовательном, бесконечном лупе. Если только нагородить такую кучу условий, что хрен кто разберется и в первую очередь разработчик. Почитайте про функции и пользуйтесь ими на здоровье. А лупу оставьте диспетчерские обязанности.

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

bwn пишет:

Я фак его знает, как это все сделать в последовательном, бесконечном лупе. Если только нагородить такую кучу условий, что хрен кто разберется и в первую очередь разработчик. Почитайте про функции и пользуйтесь ими на здоровье. А лупу оставьте диспетчерские обязанности.

кстати, интересно, в каком году подпрограммы стали называться функциями и как теперь функции называются?

ну, например - все эти синусы, косинусы?

bwn
Offline
Зарегистрирован: 25.08.2014

Клапауций 112 пишет:

кстати, интересно, в каком году подпрограммы стали называться функциями и как теперь функции называются?

ну, например - все эти синусы, косинусы?

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

b707
Offline
Зарегистрирован: 26.05.2017

Ну вообще-то изначально функции - это подпроограммы. имеющие возвращаемое значение, а процедуры - это все остальное. Но в современных книгах вс так перемешано. что это вопрос сроди "в/на Украину" и его лучше не касаться :)

Ворота
Ворота аватар
Offline
Зарегистрирован: 10.01.2016

Если возвращаемый тип void, то подпрограмма, если что-то другое, то функция. Подпрограмма всегда вызывается только ради побочного эффекта, а функция - как получится.

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

Ворота пишет:

пшёл нах, "оральный гей"

зачем ты так? - он же не виноват, что у него президент-хуйло.

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

avgustdon пишет:

Принимаю критику, виноват. Вот новый код где все работает

Ну, раз принимаете, то держите:

1. Переменная count1 объявлена без инициализации (стр. 17), а затем используется как уже имеющая значение (стр. 48).  Тоже самое count2 (строки 19, 56 и 64)

2. Строки 30-31 и 32, 33, 34 делают одно и тоже, но в разной стилистике. Зачем? Чтобы читателя запутать?

3. Неясно для чего фигурные скобки в строке 36

4. В описаниях DHT рекомендуется не читать данные с датчиков чаще, чем полгерца, а строки 41-42 выполняются гораздо чаще

5. В строка 47 и 52 дважды читается состояние кнопки, хотя, по логике это одна величина. Если вдруг случится так, что состояние кнопки изменится в короткий промежуток времени между строкой 47 и строкй 52, у Вас сломается логика программы. Конечно, промежуток небольшой и вероятность невелика, но вот именно из таких ошибок и вылазят "редкие и необъяснимые глюки". То же касается и строк 55,60 и 63,68

6. Строки 78-81 - когда влажность окажется в пограничном состоянии (практически равно границе) увлажнитель будет включаться и выключаться как авиационный пулемёт. Здесь просится гистерезис.

b707
Offline
Зарегистрирован: 26.05.2017

ЕвгенийП пишет:

1. Переменная count1 объявлена без инициализации (стр. 17), а затем используется как уже имеющая значение (стр. 48).  Тоже самое count2 (строки 19, 56 и 64)

Евгений, удивительно слышать такое от вас. Во всех учебниках написано. что стандарт языка ГАРАНТИРУЕТ инициализацию глобальных переменных нулевым значением.

Я тоже часто не инициализирую счетчики... Не прав?

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

мало того, оно еще все храница в сегменте глобальных данных во флэше и при старте программы пишеца в ОЗУ.  Почему строки и выгоднее как PROGMEM обьявлять а не как глобальные константы (иначе, и там и там память жруть). 

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

b707 пишет:

Я тоже часто не инициализирую счетчики... Не прав?

Да, как сказать "прав - не прав". Инициализировать переменные - это просто хорошая, правильная практика. 

GarryC
Offline
Зарегистрирован: 08.08.2016

Евгений, неужели Вы допускаете, что не все в MISAR плохо ?

Это так, шутка, а насчет инициализации - даже если стандарт гарантирует нулевые значения, то написав =0, Вы никоим образом стандарту не помешаетет, код не расширите, время выполнения не увеличите, а понятнее станет - так почему бы это и не делать, неужели Вам настолько жалко 2 символа?

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Да мне как-то без разницы всё в мисаре плохо или не всё :)))

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

Клапауций 112 пишет:

кстати, интересно, в каком году подпрограммы стали называться функциями и как теперь функции называются?

ну, например - все эти синусы, косинусы?

1. В 1989г.

2. Так же.

3. В том числе.

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

andriano пишет:

1. В 1989г.

2. Так же.

3. В том числе.

мда. такую страну пиндосы кацапам развалили... достаточно было переименовать подпрограммы в функции

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

Клапауций 112 пишет:

достаточно было переименовать подпрограммы в функции

точнее - объединить две родственные сущности в одну.

 

PS. Первоначально предполагалось, что функции возвращают значение, но не имеют побочного эффекта, а подпрограммы имеют побочный эффект, но не возвращают значения. На деле оказалось, что функции могут иметь побочный эффект. Когда стало очевидным, что подпрограммы и функции различаются только тем, возвращают они значение или нет, по принципу бритвы Оккама было решено использовать для них единственную сущность, отражая особенность квалификатором типа возвращаемого значения.