Установка значений с помощью кнопок для весового дозатора

Gexogyan
Offline
Зарегистрирован: 13.01.2020

Сделал весовой дозатор для воды, не без помощи форумчан (за что отдельная благодарность).

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

Все отлично работает.

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

Для этого я решил разбить значение (00.00 грамм)  на отдельные 4 цифры. Где, как вы уже наверняка догадались, первая цифра отвечает за значения кратные 10 грамм, вторая за кратные 1 грамму, третья за 0.1, четвертая цифра за 0.01 грамм. Но это так, легкое отступление. Если есть предложение лучше, буду только рад!

А для начала, я хочу разобраться как изменять значение хотя бы одной цифры.

void loop() {
  lcd.setCursor(7, 1);
  lcd.print(numb);

  if (digitalRead(butA) == HIGH) {
    countOn();
  }
}

int countOn() {
  if (digitalRead (butB) == HIGH && numb < 9) {
    numb = numb + 1;
    delay(300);
  }
  if (digitalRead(butB) == HIGH && numb == 9) {
    numb = 0;
    delay(300);
    lcd.clear();
  }
}

В данном отрезке кода на экран выводится цифра 0. Затем, пока я держу кнопку (butА), при каждом нажатии кнопки (butВ) цифра на экране изменяется на +1. Все замечательно, но менять эту цифру я могу только пока кнопка (butA) зажата.

Так вот, как сделать так, чтобы по одному нажатию кнопки (butA) включалась возможность изменения цифр кнопкой (butB), а по следующему отключалась?

 

P.S.: Опыт программирования меньше 10 дней, поэтому прошу отнестись с пониманием. 

 

svm
Offline
Зарегистрирован: 06.11.2016

Проще всего по длительности нажатия. Короткое-изменение параметра. Длинное - допустим 0,5-1 секунда переход к следующему.  Очень длинное > 2 секунд выход и запись в память.

Gexogyan
Offline
Зарегистрирован: 13.01.2020

Спасибо! Это отличный вариант!

А можете подсказать код, или где его поискать? Даже не знаю что у гугла спрашивать.

svm
Offline
Зарегистрирован: 06.11.2016

Gexogyan пишет:

Спасибо! Это отличный вариант!

А можете подсказать код, или где его поискать? Даже не знаю что у гугла спрашивать.

Поищите здесь на форуме, работа с кнопками. А может кто и готовый кусочек подкинет. Я у себя нашел только замороченные. Лучше их не смотреть. Вот примерно, что Вам нужно http://arduino.ru/forum/programmirovanie/rabota-s-knopkami-v-pomoshch-novichku?page=2#comment-48930  ну и дальше должны попадаться примеры, возможно более подходящие. Кроме того есть еще и библиотеки для кнопок.

trembo
trembo аватар
Offline
Зарегистрирован: 08.04.2011

4 кнопки.
Перебором по кругу.
Как во всех автомобильных приёмниках вводится код.

Gexogyan
Offline
Зарегистрирован: 13.01.2020

Спасибо большое! Тут нашел все что надо!

Gexogyan
Offline
Зарегистрирован: 13.01.2020

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

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

Подскажите пожалуйста.

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

Gexogyan пишет:
А вот как теперь сохранять значения в памяти контроллера, чтобы они не сбрасывались к 00.00 при каждой перезагрузки, не могу найти информацию.

Подскажите пожалуйста.

Ну этого в инете море, но раз вы ленивый, то разбирайтесь в этом ;))

/**/
#include "eeprom_Ref.h"
int* adr = (int*)0;
eeprom_int aaa(adr);
int i = 0;
//---------------------------------------
void setup() {
  Serial.begin(9600);
}

void loop() {
  Serial.print("\n Read=");// прочитать из EEPROM
  Serial.print(aaa[0]);
  Serial.print(" ");
  Serial.print(aaa[1]);
  aaa[0] = i; aaa[1] = i + 5; i++;// записать в EEPROM
  Serial.print("\n Write=");// проверить запись в  EEPROMе
  Serial.print(aaa[0]);
  Serial.print(" ");
  Serial.print(aaa[1]);
   delay(500);
}

eeprom_Ref.h

/* eeprom_Ref.h */
#ifndef EEPROM_REF_H
#define EEPROM_REF_H
//Ref.h-----------------------
#include <Arduino.h>
#include <avr/eeprom.h>
template <typename T>
class Ref {
  protected:
    T* pointer;
    void set(T data);
    T get();
  public:
    ~Ref();
    Ref() = delete;
    Ref(T* a);
    Ref(const Ref& other) = delete;
    Ref(Ref&& other);
    Ref& operator=(const Ref& other) = delete;
    Ref& operator=(Ref&& other);
    //
    operator T();
    Ref& operator=(T&& d);
    Ref& operator=(const T& d);
    Ref operator[] (const int index);
    Ref& operator +=(T&& d);
    Ref& operator -=(T&& d);
};
//Ref.cpp-----------------------
/* uint8_t */
template <>
void Ref<uint8_t>::set(uint8_t data) {
  eeprom_write_byte(pointer, data);
}
template <>
uint8_t Ref<uint8_t>::get() {
  return eeprom_read_byte(pointer);
}
/* int */
template <>
void Ref<int>::set(int data) {
  eeprom_write_word((uint16_t*)pointer, (uint16_t)data);
}
template <>
int Ref<int>::get() {
  return eeprom_read_word((uint16_t*)pointer);
}
/* uint16_t*/
template <>
void Ref<uint16_t>::set(uint16_t data) {
  eeprom_write_word(pointer, data);
}
template <>
uint16_t Ref<uint16_t>::get() {
  return eeprom_read_word(pointer);
}
/* uint32_t*/
template <>
void Ref<uint32_t>::set(uint32_t data) {
  eeprom_write_dword(pointer, data);
}
template <>
uint32_t Ref<uint32_t>::get() {
  return eeprom_read_dword(pointer);
}
/* float*/
template <>
void Ref<float>::set(float data) {
  eeprom_write_float(pointer, data);
}
template <>
float Ref<float>::get() {
  return eeprom_read_float(pointer);
}
/*общее*/
template <typename T>
Ref<T>::~Ref() {}
template <typename T>
Ref<T>::Ref(T* a): pointer(a) {}
template <typename T>
Ref<T>::Ref(Ref<T>&& other) {
  pointer = other.pointer;
}
template <typename T>
Ref<T>& Ref<T>::operator=(Ref<T>&& other) {
  if (pointer != other.pointer)
    set(other.get());
  return *this;
}
template <typename T>
Ref<T>::operator T() {
  return get();
}
template <typename T>
Ref<T>& Ref<T>::operator=(T&& d) {
  set(d);
  return *this;
}
template <typename T>
Ref<T>& Ref<T>::operator=(const T& d) {
  set(d);
  return *this;
}
template <typename T>
Ref<T> Ref<T>::operator[] (const int index) {
  return Ref<T>(pointer + index);
}
template <typename T>
Ref<T>& Ref<T>::operator +=(T&& d) {
  set(get() + d);
  return *this;
}
template <typename T>
Ref<T>& Ref<T>::operator -=(T&& d) {
  set(get() - d);
  return *this;
}
using eeprom_int      = Ref<int> ;
using eeprom_uint8_t  = Ref<uint8_t>;
using eeprom_uint16_t = Ref<uint16_t>;
using eeprom_uint32_t = Ref<uint32_t>;
using eeprom_float    = Ref<float>;
//pRef.h-----------------------------
#include <avr/pgmspace.h>
template <typename T>
class pRef {
  protected:
    const T* pointer;
    T get();
  public:
    ~pRef();
    pRef() = delete;
    pRef(const T* a);
    pRef(const pRef& other) = delete;
    pRef(pRef&& other);
    pRef& operator=(const pRef& other) = delete;
    pRef& operator=(pRef&& other);
    //
    operator T();
    pRef operator[] (const int index);
};
//pRef.cpp-----------------------------
/*uint8_t*/
template <>
uint8_t pRef<uint8_t>::get() {
  return pgm_read_byte(pointer);
}
/* int */
template <>
int pRef<int>::get() {
  return pgm_read_word((uint16_t*)pointer);
}
/* uint16_t*/
template <>
uint16_t pRef<uint16_t>::get() {
  return pgm_read_word(pointer);
}
/* uint32_t*/
template <>
uint32_t pRef<uint32_t>::get() {
  return pgm_read_dword(pointer);
}
/* float*/
template <>
float pRef<float>::get() {
  return pgm_read_float(pointer);
}
/*String*/
template <>
String pRef<String>::get() {
  return String(reinterpret_cast<const __FlashStringHelper *>(pointer));
}
template <>
pRef<String> pRef<String>::operator[] (const int index) {
  char *p = (char*)pointer;
  int i = index;
  while (i != 0) {
    p = (char*)strchrnul_P(p, 0);
    p++;
    i--;
  }
  return pRef<String>((String*)p);
}
/*общее*/
template <typename T>
pRef<T>::~pRef() {}
template <typename T>
pRef<T>::pRef(const T* a): pointer(a) {}
template <typename T>
pRef<T>::pRef(pRef<T>&& other)
  : pointer(other.pointer) {}

template <typename T>
pRef<T>& pRef<T>::operator=(pRef<T>&& other) {
  pointer = other.pointer;
  return *this;
}
template <typename T>
pRef<T>::operator T() {
  return get();
}
template <typename T>
pRef<T> pRef<T>::operator[] (const int index) {
  return pRef<T>(pointer + index);
}
//-------------------------------------------------
using pgm_int      = pRef<int>;
using pgm_uint8_t  = pRef<uint8_t>;
using pgm_uint16_t = pRef<uint16_t>;
using pgm_uint32_t = pRef<uint32_t>;
using pgm_float    = pRef<float>;
using pgm_String   = pRef<String>;
#endif

 

Gexogyan
Offline
Зарегистрирован: 13.01.2020

На самом деле не знал куда копать. Много натыкался на "запись на внешнюю память", но ничего того что нужно (на первый взгляд) не мог найти. А потом уже увидел "EEPROM", понял что это такое и после этого уже достаточно быстро разобрался.

Но тем не менее, за ответ спасибо! 

Kakmyc
Offline
Зарегистрирован: 15.01.2018

Gexogyan пишет:

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

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

Подскажите пожалуйста.

Гугли "Ардуино EEPROM"

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

Gexogyan пишет:

Спасибо! Это отличный вариант!

А можете подсказать код, или где его поискать? Даже не знаю что у гугла спрашивать.

Пробовал код QWONE

/*** Обработчик кнопки ***/
//------Cl_Btn----------------------
enum {sbNONE = 0, sbClick, sbLong}; /*состояние не изменилось/клик/долгое нажатие*/
class Cl_Btn {
  protected:
    const byte pin;
    byte state;
    bool bounce = 0;
    bool btn = 1, oldBtn;
    unsigned long past;
    const uint32_t time = 500 ;
    bool flag = 0;
    uint32_t past_flag = 0 ;
  public:
    Cl_Btn(byte p): pin(p) {}
    /*инициализация-вставить в setup()*/
    void init() {
      pinMode(pin, INPUT_PULLUP);
    }
    /*работа-вставить в loop()*/
    void run() {
      state = sbNONE;
      bool newBtn = digitalRead(pin);
      if (!bounce && newBtn != btn) {
        bounce = 1;
        past = mill;
      }
      if (bounce && mill - past >= 10) {
        bounce = 0 ;
        oldBtn = btn;
        btn = newBtn;
        if (!btn && oldBtn) {
          flag = 1;
          past_flag = mill;
        }
        if (!oldBtn && btn && flag && mill - past_flag < time ) {
          flag = 0;
          state = sbClick;
        }
      }
      if (flag && mill - past_flag >= time ) {
        flag = 0;
        state = sbLong;
      }
    }
    byte read() {
      return state;
    }
};
#ifdef GYVER
GButton Btn1(BUTTON);
#else
Cl_Btn Btn1(/*пин*/BUTTON); //Экземпляр обработчика для кнопки
#endif

и библиотеку Алекса Гайвера, зачёт для этих целей