LCD I2C дисплей и обработка кнопок

BuonanotteMasha
BuonanotteMasha аватар
Offline
Зарегистрирован: 02.01.2018
Есть arduino, LCD I2C дисплей и 4 кнопки(up, down, next, set). Хочется сделать так чтобы при запуске на экран выводилось число допустим 000( объявил через массив byte dig[] = { 0, 0, 0 }). Здесь для удобства число разбито на цифры.  При нажатии на set должна мигать самая левая цифра. Затем при нажатии на next переходим к следующей цифре(мигает) и так по кругу(только одна мигает). Кнопками up, down можно +/-1 к выбранной цифре. Нужна помощь в настройке мигания цифры и с функциями кнопок set, next. Беда если значение цифры <0 или >9, выводит не понятные символы. Предложите идею как решить проблемы.
 
#include <Wire.h> // библиотека для управления устройствами по I2C 
#include <LiquidCrystal_I2C.h> // подключаем библиотеку для LCD 1602
#include "OneButton.h"
 
LiquidCrystal_I2C lcd(0x3F,20,4); // присваиваем имя lcd для дисплея 20х2
 
unsigned long prevmillis = 0; //счетчик прошедшего времени для мигания изменяемых значений.
#define interv 100UL     //интервал мигания изменяемых значений
boolean i=LOW; 
 
// кнопки
OneButton upPin(8, true); // Установить кнопку 1 на пин 8.  
OneButton downPin(9, true); // Установить кнопку 2 на пин 9. 
OneButton nextPin(10, true); // Установить кнопку 2 на пин 9. 
OneButton setPin(11, true); // Установить кнопку 2 на пин 9. 
  
byte dig[] = { 0, 0, 0 };
byte flag=0; byte state=0;  //byte c=2;
 
void IntToChar(byte d0, byte d1, byte d2, char *text)
{
  text[0] =  d0 + '0'; 
  text[1] =  d1 + '0'; 
  text[2] =  d2 + '0'; 
}
 
void setup() {
  lcd.begin(); // инициализация LCD дисплея
  lcd.backlight(); // включение подсветки дисплея 
  
  upPin.attachClick(click1); // Функции 1 кнопки
  downPin.attachClick(click2); // Функции 2 кнопки
  nextPin.attachClick(click3); // Функции 3 кнопки
  setPin.attachClick(click4); // Функции 4 кнопки
}
 
void loop() {
        
 
       /*   беда   */
     if(dig[0]<0 && dig[0]>9)
     {
      flag=1; // присваиваем пременной значение 1
      dig[0]=0; //обнуляем переменную таймера 
     }
 
      // Вызов функции, обрабатывающей состояния кнопки:
      setPin.tick();
      upPin.tick();
      downPin.tick();
      nextPin.tick();
     
     lcd.setCursor(0,0); // ставим курсор на 1 символ первой строки
     lcd.print("T=");
    
     char str[] = "   ";
     IntToChar(dig[0], dig[1], dig[2], &str[0]);
      
      if(millis() - prevmillis >= interv) {      //Если счетчик превысил интервал, 
      i = !i; prevmillis = prevmillis+interv; }  //меняем значение переменной i, добавляем к переменной интервал
      
      /* тут хотелось бы сделать мигание */
      if (i) { lcd.setCursor(2, 0); lcd.print(str); }
     // if (!i) { lcd.setCursor(2, 0); lcd.print(" "); } не работает как надо
 
   // В этом месте могут быть другие вызовы неблокирующих
   // функций и процедур, выполняющих какие-либо действия в
   // программе.
  delay(10);
}
 
// Эта функция будет вызвана, когда setPin был нажат в 1 раз
void click1() {
 
 
// Эта функция будет вызвана, когда upPin был нажат в 1 раз
void click2() {  
        dig[0]++;
 
// Эта функция будет вызвана, когда downPin был нажат в 1 раз
void click3() {   
        dig[0]--;
 
// Эта функция будет вызвана, когда nextPin был нажат в 1 раз
void click4() {
  lcd.setCursor(0,2);
  lcd.print("nextPin click");
 
BuonanotteMasha
BuonanotteMasha аватар
Offline
Зарегистрирован: 02.01.2018

Программирую arduino год, подскажите что  не так делаю

BuonanotteMasha
BuonanotteMasha аватар
Offline
Зарегистрирован: 02.01.2018

 Еще хотелось бы избавиться в процессе от delay(10)

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

BuonanotteMasha пишет:
Предложите идею как решить проблемы.

Это чё? Типа нам такое задание? Ты препод? Или сержант? А чего не сапоги почистить?

BuonanotteMasha
BuonanotteMasha аватар
Offline
Зарегистрирован: 02.01.2018

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

 

BuonanotteMasha
BuonanotteMasha аватар
Offline
Зарегистрирован: 02.01.2018

Мне бы идейку подкинул кто

BuonanotteMasha
BuonanotteMasha аватар
Offline
Зарегистрирован: 02.01.2018

Сапоги еще начищу 

BuonanotteMasha
BuonanotteMasha аватар
Offline
Зарегистрирован: 02.01.2018

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

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

Спасибо, но код не совсем верный, постоянно отображается 9, при нажатии на кнопки+/- ничего не меняется.

BuonanotteMasha
BuonanotteMasha аватар
Offline
Зарегистрирован: 02.01.2018

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

BuonanotteMasha
BuonanotteMasha аватар
Offline
Зарегистрирован: 02.01.2018
#include <Wire.h> // библиотека для управления устройствами по I2C 
#include <LiquidCrystal_I2C.h> // подключаем библиотеку для LCD 1602
#include "OneButton.h"

LiquidCrystal_I2C lcd(0x3F,20,4); // присваиваем имя lcd для дисплея 20х4

unsigned long prevmillis = 0; //счетчик прошедшего времени для мигания изменяемых значений.
#define interv 100UL     //интервал мигания изменяемых значений
boolean i=LOW; 

// кнопки
OneButton upPin(8, true); // Установить кнопку 1 на пин 8.  
OneButton downPin(9, true); // Установить кнопку 2 на пин 9. 
OneButton nextPin(10, true); // Установить кнопку 2 на пин 10. 
OneButton setPin(11, true); // Установить кнопку 2 на пин 11. 
  
byte dig[] = { 0, 0, 0 };
byte flag=0; byte state=0;  //byte c=2;

void IntToChar(byte d0, byte d1, byte d2, char *text)
{
  text[0] =  d0 + '0';
  text[1] =  d1 + '0'; 
  text[2] =  d2 + '0';
}

void setup() {
  lcd.begin(); // инициализация LCD дисплея
  lcd.backlight(); // включение подсветки дисплея 
  
  upPin.attachClick(click1); // Функции 1 кнопки
  downPin.attachClick(click2); // Функции 2 кнопки
  nextPin.attachClick(click3); // Функции 3 кнопки
  setPin.attachClick(click4); // Функции 4 кнопки
}

void loop() {
        
       /****/
     //if(val>=0 && val<10)
     /*if(dig[0]<0 && dig[0]>9)
     {
      flag=1; // присваиваем переменной значение 1
      dig[0]=0; //обнуляем переменную таймера 
     }*/
      if (dig[0] < 9) { dig[0]++; } 
      // Вызов функции, обрабатывающей состояния кнопки:
      setPin.tick();
      upPin.tick();
      downPin.tick();
      nextPin.tick();
     
    lcd.setCursor(0,0); // ставим курсор на 1 символ первой строки
    lcd.print("T=");
    
      
      
      char str[] = "   ";
      IntToChar(dig[0], dig[1], dig[2], &str[0]);
      
      if(millis() - prevmillis >= interv) {      //Если счетчик превысил интервал, 
      i = !i; prevmillis = prevmillis+interv; }  //меняем значение переменной i, добавляем к переменной время интервала.
      
      if (i) { lcd.setCursor(2, 0); lcd.print(str); }
     // if (!i) { lcd.setCursor(2, 0); lcd.print(" "); }



  // В этом месте могут быть другие вызовы неблокирующих
  // функций и процедур, выполняющих какие-либо действия в
  // программе.
  delay(10);
}


// Эта функция будет вызвана, когда setPin был нажат в 1 раз
void click1() {
  //state = 1;
  lcd.setCursor(0,1);
  lcd.print("setPin click");
}

// Эта функция будет вызвана, когда upPin был нажат в 1 раз
void click2() {  
        dig[0]++;
} 

// Эта функция будет вызвана, когда downPin был нажат в 1 раз
void click3() {   
        dig[0]--;
} 

// Эта функция будет вызвана, когда nextPin был нажат в 1 раз
void click4() {
  lcd.setCursor(0,2);
  lcd.print("nextPin click");
} 

 

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

BuonanotteMasha пишет:
Есть arduino, LCD I2C дисплей и 4 кнопки(up, down, next, set). Хочется сделать так чтобы при запуске на экран выводилось число допустим 000( объявил через массив byte dig[] = { 0, 0, 0 }). Здесь для удобства число разбито на цифры.  При нажатии на set должна мигать самая левая цифра. Затем при нажатии на next переходим к следующей цифре(мигает) и так по кругу(только одна мигает). Кнопками up, down можно +/-1 к выбранной цифре. Нужна помощь в настройке мигания цифры и с функциями кнопок set, next. Беда если значение цифры <0 или >9, выводит не понятные символы. Предложите идею как решить проблемы.
Ну здесь очень просто. У вас уровень программирования не подходит для этой задачи. Как апнете +100% то можете начать писать.

BuonanotteMasha
BuonanotteMasha аватар
Offline
Зарегистрирован: 02.01.2018
Да с этим вообще печаль - беда

     /*if(dig[0]<0 && dig[0]>9)
     {
      flag=1; // присваиваем переменной значение 1
      dig[0]=0; //обнуляем переменную таймера
      }

 

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

BuonanotteMasha пишет:

Спасибо, но код не совсем верный, постоянно отображается 9, при нажатии на кнопки+/- ничего не меняется.

В каком месте он неверный? Он не исправляет всю вашу программу, а не дает счетчику уйти за цифру 9, чтобы ваша беда не проявлялась.

BuonanotteMasha
BuonanotteMasha аватар
Offline
Зарегистрирован: 02.01.2018

Не пинайте так сильно, программировать научусь, да и arduino и хороший програмист две разные вещи

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

У вас должны быть 5 (ПЯТЬ) переменных- обработчиков функций - 4 на кнопки и 1 на экран. При переходе с одной позицию на другую им должны присваиваться новые . И так по кругу. Опять же что бы не гемороить надо организовать целую структуру.

BuonanotteMasha пишет:
Не пинайте так сильно, программировать научусь, да и arduino и хороший програмист две разные вещи
Так не по Сеньке шапка. Это как первокласнику задать решение линейных(или нелинейных) уровнений. :)

BuonanotteMasha
BuonanotteMasha аватар
Offline
Зарегистрирован: 02.01.2018
Как я вас правильно понял, для каждой из этих функций должна задаваться своя переменная, и 
еще одна для обновления lcd

// Эта функция будет вызвана, когда setPin был нажат в 1 раз
void click1() {

} 

// Эта функция будет вызвана, когда upPin был нажат в 1 раз
void click2() {  
        dig[0]++;
} 

// Эта функция будет вызвана, когда downPin был нажат в 1 раз
void click3() {   
        dig[0]--;
} 

// Эта функция будет вызвана, когда nextPin был нажат в 1 раз
void click4() {

} 

Так не по Сеньке шапка - но я не поставил невыполнимую задачу

BuonanotteMasha
BuonanotteMasha аватар
Offline
Зарегистрирован: 02.01.2018
#include <Wire.h> // библиотека для управления устройствами по I2C 
#include <LiquidCrystal_I2C.h> // подключаем библиотеку для LCD 1602

LiquidCrystal_I2C lcd(0x3F,20,4); // присваиваем имя lcd для дисплея 20х2

long previousMillisTime = 0; //счетчик прошедшего времени для мигания изменяемых значений.
long intervalTime = 1000;     //интервал мигания изменяемых значений
double i=0;

void setup() {
  lcd.begin(); // инициализация LCD дисплея
  lcd.backlight(); // включение подсветки дисплея 
}

void loop() {
        lcd.setCursor(1,0); // ставим курсор на 1 символ первой строки 
        if(millis() - previousMillisTime >= intervalTime) {                 //Если счетчик превысил интервал, 
        i = !i; previousMillisTime = previousMillisTime+intervalTime; }  //меняем значение переменной i, добавляем к переменной время интервала.
        if (i) lcd.print(1); 
        if (!i) lcd.print(" "); 
}

 

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

Ну скорее всего так начал ;)

/**/
unsigned long mill; // переменная под millis()
typedef (*pDo)();
//--------------------------------
// класс кнопка
class Cl_btm {
  protected:
    byte pin;
  public:
    pDo Do;//обработчик
    /*конструктор*/
    Cl_btm(byte p): pin(p) {}
    /*инициализация-вставить в setup()*/
    void init() {}
    /*работа-вставить в loop()*/
    void run() {}
};
//---------------------
// класс кнопка
class Cl_viev {
  protected:
  public:
    pDo Do;//обработчик
    /*конструктор*/
    Cl_viev() {}
    /*инициализация-вставить в setup()*/
    void init() {}
    /*работа-вставить в loop()*/
    void run() {}
};
//---Компоновка-----------------------------
Cl_btm Btn1(/*пин*/2);
Cl_btm Btn2(/*пин*/3);
Cl_btm Btn3(/*пин*/4);
Cl_btm Btn4(/*пин*/5);
Cl_viev viev;
//---main-----------------------------
void setup() {
  Btn1.init();
  Btn2.init();
  Btn3.init();
  Btn4.init();
  viev.init();
}

void loop() {
  mill = millis();
  Btn1.run();
  Btn2.run();
  Btn3.run();
  Btn4.run();
  viev.run();
}
/*Скетч использует 544 байт (1%) памяти устройства. Всего доступно 30720 байт.
  Глобальные переменные используют 25 байт (1%) динамической памяти, оставляя 2023 байт для локальных переменных. Максимум: 2048 байт.
*/

 

BuonanotteMasha
BuonanotteMasha аватар
Offline
Зарегистрирован: 02.01.2018

Скетч мигания символа на дисплее

BuonanotteMasha
BuonanotteMasha аватар
Offline
Зарегистрирован: 02.01.2018

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

BuonanotteMasha
BuonanotteMasha аватар
Offline
Зарегистрирован: 02.01.2018

Для мигания цифры вполне подойдет эта конструкция, но я думаю добавить в условие дополнительную переменную типа boolean flag для условия !i для запуска мигания только при нажатии set

        lcd.setCursor(1,0); // ставим курсор на 1 символ первой строки 
        if(millis() - previousMillisTime >= intervalTime) {                 //Если счетчик превысил интервал, 
        i = !i; previousMillisTime = previousMillisTime+intervalTime; }  //меняем значение переменной i, добавляем к переменной время интервала.
        if (i) lcd.print(1); 
        if (!i) lcd.print(" ");

 

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

Есть библиотека micromenu. Поищите в интернете. Она заточена под управление меню с помощью кнопок. Работает и с четырьмя кнопками и i2c lcd1602. Позволяет легко написать и меню и в нем изменение параметров. Вот только строк получается много. Но работает. 

BuonanotteMasha
BuonanotteMasha аватар
Offline
Зарегистрирован: 02.01.2018

Да я видел  называется Menu Backend

https://pandauino.com/en/one-button-menu-arduino/

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016
/**/
unsigned long mill; // переменная под millis()
typedef (*pDo)();
//--------------------------------
// класс кнопка
class Cl_btm {
  protected:
    byte pin;
  public:
    pDo Do;//обработчик
    /*конструктор*/
    Cl_btm(byte p): pin(p) {}
    /*инициализация-вставить в setup()*/
    void init() {}
    /*работа-вставить в loop()*/
    void run() {}
    /*записать*/
    void write(pDo Do_) {
      Do = Do_;
    }
};
//---------------------
// класс кнопка
class Cl_viev {
  protected:
  public:
    pDo Do;//обработчик
    /*конструктор*/
    Cl_viev() {}
    /*инициализация-вставить в setup()*/
    void init() {}
    /*работа-вставить в loop()*/
    void run() {}
    /*записать*/
    void write(pDo Do_) {
      Do = Do_;
    }
};
//---------------------------
typedef struct MenuUnit {
  pDo up;
  pDo down;
  pDo left;
  pDo right;
  pDo viev;
};
//---Компоновка-----------------------------
void up1() {}
void up2() {}
void up3() {}
void up4() {}
void up5() {}
void down1() {}
void down2() {}
void down3() {}
void down4() {}
void down5() {}
void left1() {}
void left2() {}
void left3() {}
void left4() {}
void left5() {}
void right1() {}
void right2() {}
void right3() {}
void right4() {}
void right5() {}
void viev1() {}
void viev2() {}
void viev3() {}
void viev4() {}
void viev5() {}
MenuUnit MN[] = {
  {up1, down1, left1, right1, viev1},
  {up2, down2, left2, right2, viev2},
  {up3, down3, left3, right3, viev3},
  {up4, down4, left4, right4, viev4},
  {up5, down5, left5, right5, viev5}
};
Cl_btm Btn1(/*пин*/2);
Cl_btm Btn2(/*пин*/3);
Cl_btm Btn3(/*пин*/4);
Cl_btm Btn4(/*пин*/5);
Cl_viev viev;
//---main-----------------------------
void setup() {
  Btn1.init();
  Btn2.init();
  Btn3.init();
  Btn4.init();
  viev.init();
}

void loop() {
  mill = millis();
  Btn1.run();
  Btn2.run();
  Btn3.run();
  Btn4.run();
  viev.run();
}
/*Скетч использует 544 байт (1%) памяти устройства. Всего доступно 30720 байт.
  Глобальные переменные используют 25 байт (1%) динамической памяти, оставляя 2023 байт для локальных переменных. Максимум: 2048 байт.
*/

 

BuonanotteMasha
BuonanotteMasha аватар
Offline
Зарегистрирован: 02.01.2018

Меню я собирался отдельно реализовать в помощью switch 

BuonanotteMasha
BuonanotteMasha аватар
Offline
Зарегистрирован: 02.01.2018

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

http://mypractic.ru/urok-7-klassy-v-programmax-arduino-knopka-kak-obekt....

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

Что бы не жевать много раз одно и тоже. Вот мои идеи http://arduino.ru/forum/programmirovanie/klassy-arduino-po-qwone-dlya-chainikov

Но это так самая малость.

BuonanotteMasha пишет:

Меню я собирался отдельно реализовать в помощью switch 

Можно но это так глубоко устаревший способ. Можно запутаться в скетче.

ПС:

/**/
unsigned long mill; // переменная под millis()
typedef (*pDo)();
//--------------------------------
// класс кнопка
class Cl_btm {
  protected:
    byte pin;
  public:
    pDo Do;//обработчик
    /*конструктор*/
    Cl_btm(byte p): pin(p) {}
    /*инициализация-вставить в setup()*/
    void init() {}
    /*работа-вставить в loop()*/
    void run() {}
    /*записать*/
    void write(pDo Do_) {
      Do = Do_;
    }
};
//---------------------
// класс показ
class Cl_viev {
  protected:
    unsigned long past;
  public:
    pDo Do;//обработчик
    /*конструктор*/
    Cl_viev() {}
    /*инициализация-вставить в setup()*/
    void init() {    
    }
    /*работа-вставить в loop()*/
    void run() {
      if (mill - past >= 1000)// выводить раз в 1 сек
        past = mill;
      Do();
    }
    /*записать*/
    void write(pDo Do_) {
      Do = Do_;
    }
};
//---------------------------
typedef struct MenuUnit {
  pDo up;
  pDo down;
  pDo next;
  pDo set;
  pDo viev;
};
//---Компоновка-----------------------------
void up1() {}
void up2() {}
void up3() {}
void up4() {}
void up5() {}
void down1() {}
void down2() {}
void down3() {}
void down4() {}
void down5() {}
void next1() {}
void next2() {}
void next3() {}
void next4() {}
void next5() {}
void set1() {}
void set2() {}
void set3() {}
void set4() {}
void set5() {}
void viev1() {}
void viev2() {}
void viev3() {}
void viev4() {}
void viev5() {}
int screen = 0; //номер позиции
MenuUnit MN[5] = {
  {&up1, &down1, &next1, &set1, &viev1},
  {&up2, &down2, &next2, &set2, &viev2},
  {&up3, &down3, &next3, &set3, &viev3},
  {&up4, &down4, &next4, &set4, &viev4},
  {&up5, &down5, &next5, &set5, &viev5}
};
Cl_btm upBtn(/*пин*/2);
Cl_btm downBtn(/*пин*/3);
Cl_btm nextBtn(/*пин*/4);
Cl_btm setBtn(/*пин*/5);
Cl_viev viev;
//---main-----------------------------
void setup() {
  screen = 0;
  upBtn.init();
  upBtn.write(MN[screen].up);
  downBtn.init();
  downBtn.write(MN[screen].down);
  nextBtn.init();
  nextBtn.write(MN[screen].next);
  setBtn.init();
  setBtn.write(MN[screen].set);
  viev.init();
  viev.write(MN[screen].viev);
}

void loop() {
  mill = millis();
  upBtn.run();
  downBtn.run();
  nextBtn.run();
  setBtn.run();
  viev.run();
}
/*Скетч использует 836 байт (2%) памяти устройства. Всего доступно 30720 байт.
  Глобальные переменные используют 83 байт (4%) динамической памяти, оставляя 1965 байт для локальных переменных. Максимум: 2048 байт.
*/