Программирование lcd дисплея с кнопками для управления

Ynkers
Offline
Зарегистрирован: 15.07.2019

ПРОЕКТ:

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

Суть проекта - В верхней строке находится постоянная надпись "Мне осталось:", в нижней строке показывается это время в днях и неделях. Чтобы поменять режим(дни или недели), нужно нажать на кнопку "BUTTON_ON_SWAP" , чтобы регулировать кол-во дней или недель есть две дополнительные кнопки - "BUTTON_DOWN" и "BUTTON_UP"(первая уменьшает кол-во, вторая повышает)

КОД:

Компилятор пишет непонятную ошибку. Перепроверил всё до иголочки. Код приведён ниже, заранее спасибо

#include <LiquidCrystal.h>

LiquidCrystal lcd(2,3,4,5,6,7);

const int BUTTON_DOWN = 9;
const int BUTTON_UP = 10;
const int BUTTON_ON_SWAP = 11;

// Переменные для хранения статусов кнопок
boolean currentDownButton = LOW;
boolean lastDownButton = LOW;

boolean currenUpButton = LOW;
boolean lastUpButton = LOW;

boolean lastOnSwapButton = LOW;
boolean currentOnSwapButton = LOW;

//Переменные кол-ва дней и недель
int days = 14000;
int weeks = 2000;

// Переменная значения статуса lcd(статус это режим дней или недель)
int ledMode = 0;

void setup()
{
  pinMode(BUTTON_DOWN, INPUT);
  pinMode(BUTTON_UP, INPUT);
  pinMode(BUTTON_ON_SWAP, INPUT);
  
  lcd.begin(16,2);
  
  lcd.print("Мне осталось:");
  
}

// ----------ПРОТИВО-ДРЕБЕЗГОВАЯ ЗАЩИТА--------------

boolean debounce(boolean last, int pin)
{
  boolean current = digitalRead(pin);
  if (last != current)
  {
    delay(5);
    current = digitalRead(pin);
  }
  return current;
}
// ------------------------------------------------


// ------------ПЕРЕКЛЮЧЕНИЕ РЕЖИМОВ С ПОМОЩЬЮ КНОПКИ BUTTON_ON_SWAP--------------
void setMode(int mode)
{ 
  // Дни
  if (mode == 1)
  {
    lcd.setCursor(0,1);
    lcd.print("DAYS:");
    lcd.setCursor(6,10);
    lcd.print("days");
  }
  // Недели
  else if (mode == 2)
  {
    lcd.setCursor(0,1);
    lcd.print("WEEKS:");
    lcd.setCursor(7,1);
    lcd.print("weeks");
  }
}
//------------------------------------------------------------------------------

void loop()
{
  currentDownButton = debounce(lastDownButton, BUTTON_DOWN);
  currentUpButton = debounce(lastUpButton, BUTTON_UP);
  
  // Регулировка дней с помощью кнопок 
  if (lastDownButton == LOW && currentDownButton == HIGH && mode == 1)
  {
    days--;
  }
  else if (lastUpButton == LOW && currentUpButton == HIGH && mode == 1)
  {
    days++;
  }
  
  // Регулировка недель с помощью кнопок
  else if(lastDownButton == LOW && currentDownButton == HIGH && mode == 2)
  {
    weeks--;
  }
  else if (lastUpButton == LOW && currentUpButton == HIGH && mode == 2)
  {
    weeks++;
  }
  
  // Переключение режимов с помощью кнопки BUTTON_ON_SWAP
  currentOnSwapButton = debounce(lastOnSwapButton, BUTTON_ON_SWAP);

  if (lastOnSwapButton == LOW && currentOnSwapButton == HIGH )
  {
    ledMode++;
  }
  
    currentOnSwapButton = debounce(lastOnSwapButton, BUTTON_ON_SWAP);
    currentDownButton = debounce(lastDownButton, BUTTON_DOWN);
    currentUpButton = debounce(lastUpButton, BUTTON_UP);
    
    // Если все режимы прошили сброс на начальный вариант
    if (ledMode == 3)
    {
      ledMode = 0;
      setMode(ledMode);
    }

    

}

 

nik182
Offline
Зарегистрирован: 04.05.2015

А ошибка то где? 

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

Боюсь даже предположить, что Вы там проверяли и какими иголочками, только переменные currentUpButton (строка №78) и mode (строка №81) нигде не описаны. Собственно компилятор Вам именно это и сказал - неясно почему Вы не поняли и не исправили.

Ynkers
Offline
Зарегистрирован: 15.07.2019

Первую ошибку понял(строка №78), опечатался, а вторую ошибку понять не могу , я ведь описал mode в строке №57 и создал аргумент int mode в строке №54

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

главная ошибка - неправильно организована программа- очень сложно ловить в ней косяки.
побочная ошибка- неправильно организован опрос кнопок. Очень сложно переназначать их обработчик при переключении в меню.

ПС: #43

Ynkers
Offline
Зарегистрирован: 15.07.2019

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

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

Жевать эту тему долго. Особенно если у Вас маловато базовых знаний :(  Прежде всего меню надо расметривать как цифровой автомат. Каждая позиция экрана это состояние. И при переходе на новое состояние надо отразить новую информацию на экране и перезадать обработчики кнопок. Ведь при каждой позиции меню даже одна и таже кнопка делает различное действие.

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

Ynkers пишет:

 я ведь описал mode в строке №57 

Есть ощущение, что Вы не очень понимаете, что делаете или не знаете терминологии. В строке №57 нет никакого описания. Там эта переменная используется.

Ynkers пишет:

создал аргумент int mode в строке №54

Какое отнощение имеет аргумент функции setMode к функци loop в которой Вы эту переменную пытаетесь использовать (в строке 81)? Подсказка - никакого, от слова "совсем".

Ynkers
Offline
Зарегистрирован: 15.07.2019

Ой, да, я забыл что эта переменная локальная, переделал - добавил новые две глобальные переменные mode1 =1 и mode2 =2, компилятор доволен:

#include <LiquidCrystal.h>

LiquidCrystal lcd(2,3,4,5,6,7);

const int BUTTON_DOWN = 9;
const int BUTTON_UP = 10;
const int BUTTON_ON_SWAP = 11;

// Переменные для хранения статусов кнопок
boolean currentDownButton = LOW;
boolean lastDownButton = LOW;

boolean currentUpButton = LOW;
boolean lastUpButton = LOW;

boolean lastOnSwapButton = LOW;
boolean currentOnSwapButton = LOW;

//Переменные кол-ва дней и недель
int days = 14000;
int weeks = 2000;

// Переменная значения статуса lcd(статус это режим дней или недель)
int ledMode = 0;

int mode1 = 1;
int mode2 = 2;

void setup()
{
  pinMode(BUTTON_DOWN, INPUT);
  pinMode(BUTTON_UP, INPUT);
  pinMode(BUTTON_ON_SWAP, INPUT);
  
  lcd.begin(16,2);
  
  lcd.print("Мне осталось:");
  
}

// ----------ПРОТИВО-ДРЕБЕЗГОВАЯ ЗАЩИТА--------------

boolean debounce(boolean last, int pin)
{
  boolean current = digitalRead(pin);
  if (last != current)
  {
    delay(5);
    current = digitalRead(pin);
  }
  return current;
}
// ------------------------------------------------


// ------------ПЕРЕКЛЮЧЕНИЕ РЕЖИМОВ С ПОМОЩЬЮ КНОПКИ BUTTON_ON_SWAP--------------
void setMode(int mode)
{ 
  // Дни
  if (mode == mode1)
  {
    lcd.setCursor(0,1);
    lcd.print("DAYS:");
    lcd.setCursor(6,10);
    lcd.print("days");
  }
  // Недели
  else if (mode == mode2)
  {
    lcd.setCursor(0,1);
    lcd.print("WEEKS:");
    lcd.setCursor(7,1);
    lcd.print("weeks");
  }
}
//------------------------------------------------------------------------------

void loop()
{
  currentDownButton = debounce(lastDownButton, BUTTON_DOWN);
  currentUpButton = debounce(lastUpButton, BUTTON_UP);
  
  // Регулировка дней с помощью кнопок 
  if (lastDownButton == LOW && currentDownButton == HIGH && mode1)
  {
    days--;
  }
  else if (lastUpButton == LOW && currentUpButton == HIGH && mode1)
  {
    days++;
  }
  
  // Регулировка недель с помощью кнопок
  else if(lastDownButton == LOW && currentDownButton == HIGH && mode2)
  {
    weeks--;
  }
  else if (lastUpButton == LOW && currentUpButton == HIGH && mode2)
  {
    weeks++;
  }
  
  // Переключение режимов с помощью кнопки BUTTON_ON_SWAP
  currentOnSwapButton = debounce(lastOnSwapButton, BUTTON_ON_SWAP);

  if (lastOnSwapButton == LOW && currentOnSwapButton == HIGH )
  {
    ledMode++;
  }
  
    currentOnSwapButton = debounce(lastOnSwapButton, BUTTON_ON_SWAP);
    currentDownButton = debounce(lastDownButton, BUTTON_DOWN);
    currentUpButton = debounce(lastUpButton, BUTTON_UP);
    
    // Если все режимы прошили сброс на начальный вариант
    if (ledMode == 3)
    {
      ledMode = 0;
      setMode(ledMode);
    }

    

}

 

Ynkers
Offline
Зарегистрирован: 15.07.2019

Хорошо, я тогда попробую побольше углубится в этой теме  

 

 

Green
Offline
Зарегистрирован: 01.10.2015

Ynkers пишет:

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

В последнее время эта тема стала довольно популярной. Я, как минимум, 3-м делал подобное, в разных вариациях. В годах, месяцах, днях, часах, минутах, секундах. Кто то даже хотел и в десятках мс.) И кто то даже пытался на этом делать бизнес.)))

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016
/**/
//---кнопки-----------------------------
typedef void (*pDo)();
class Cl_btn {
  protected:
    byte pin;
    bool state;
    unsigned long past;
    void set(bool s) {
      state = s;
      past = millis();
      if (s == true) Do();
    }
  public:
    Cl_btn(byte p): pin(p) {}
    pDo Do = [] {};
    void init() {
      pinMode(pin, INPUT_PULLUP);
      set(false);
    }
    void run() {
      if (millis() - past >= 100)
        switch (state) {
          case false:
            if (!digitalRead(pin))set(true);
            break;
          case true:
            if (digitalRead(pin))set(false);
            if (millis() - past >= 300)set(false);
            break;
        }
    }
};
Cl_btn    BtnD(/*пин*/9);  //кнопка вниз
Cl_btn    BtnU(/*пин*/10);  //кнопка верх
Cl_btn    BtnS(/*пин*/11);  //кнопка селект

//Переменные кол-ва дней и недель
int days = 14000;
int weeks = 2000;

#include <LiquidCrystal.h>
LiquidCrystal lcd(2, 3, 4, 5, 6, 7);
// Переменная значения статуса lcd(статус это режим дней или недель)
const byte page0 = 0;// главный экран
const byte page1 = 1;// регулировка дней
const byte page2 = 2;//регулировка недель

byte page;// текущий экран

// ------------ПЕРЕКЛЮЧЕНИЕ РЕЖИМОВ С ПОМОЩЬЮ КНОПКИ BUTTON_ON_SWAP--------------
void goPage(byte p) {
  if (p > page2) p = page0 ;
  page = p;
  lcd.clear();
  switch (page) {
    case  page0 : {
        lcd.print("Мне осталось:");
        lcd.print(days);
      }
      BtnU.Do = [] {};
      BtnD.Do = [] {};
      BtnS.Do = [] {
        goPage(page1);
      };
      break;
    case  page1 :
      {
        lcd.setCursor(0, 1);
        lcd.print("DAYS:");
        lcd.print(days);
        lcd.setCursor(6, 10);
        lcd.print("days");
      }
      BtnU.Do = [] {
        days++;
        goPage(page1);
      };
      BtnD.Do = [] {
        days--;
        goPage(page1);
      };
      BtnS.Do = [] {
        goPage(page2);
      };
      break;
    case  page2 :
      {
        lcd.setCursor(0, 1);
        lcd.print("WEEKS:");
        lcd.print(weeks);
        lcd.setCursor(7, 1);
        lcd.print("weeks");
      }
      BtnU.Do = [] {
        weeks++;
        goPage(page2);
      };
      BtnD.Do = [] {
        weeks--;
        goPage(page2);
      };
      BtnS.Do = [] {
        goPage(page0);
      };
      break;
  }
}
void setup() {
  BtnU.init();
  BtnD.init();
  BtnS.init();

  lcd.begin(16, 2);
  goPage(page0);
}

void loop() {
  BtnU.run();
  BtnD.run();
  BtnS.run();
}

Разумеется в железе не проверял. И да косяки в программе связаны с тем что ТС невнятно написал ТЗ.

Ynkers
Offline
Зарегистрирован: 15.07.2019

Спасибо, попробую проанализировать Ваш код