Millis, кнопки и меню
- Войдите на сайт для отправки комментариев
Всем добрый вечер.
Делаю скетч по выводу ардуиной меню на дисплей LCD 2004 I2C. Управляют всем 4 кнопки(5 пока не задействовал, в процессе).
Дисплей и упрощенный алгоритм работы скетча на рисунках.


Вся сложность работы в том, что по нажатию на UP и к обоим текущим числам + 1 , на DOWN к обоим - 1. Надо бы чтобы к определенному. Решил для этих целей задействвать кнопку LEFT. Она будет отвечать за выбор числа. Думаю добавить мигание(чтобы как то обозначить текущее число?) и разбить каждое число на сотни, десятки и еденицы и менять это кнопками, а то уж очень долго например если задано 200 а текущее 100 прибавлять по 1. Нужен ваш совет в реализации кода или доработке алгоритм. Заранее спасибо

Приложен код
// скетч меню
#include <Wire.h> // библиотека для управления устройствами по I2C
#include <LiquidCrystal_I2C.h> // подключаем библиотеку для LCD 1602
LiquidCrystal_I2C lcd(0x3f,20,4); // присваиваем имя lcd для дисплея 20х4
//Назначаем пины кнопок управления
#define BUTTON_OK 8
#define BUTTON_LEFT 9
#define BUTTON_RIGHT 12
#define BUTTON_UP 10
#define BUTTON_DOWN 11
//состояние кнопок по умолчанию
boolean State_Up = LOW;
boolean State_Down = LOW;
boolean State_Left = LOW;
boolean State_Right = LOW;
boolean State_Ok = LOW;
//переменные которые надо менять
byte t_bottom = 10; byte t_top = 90;
byte p_bottom = 20; byte p_top = 80;
byte kp1 = 50; byte kp2 = 50;
byte ki1 = 0; byte ki2 = 0;
byte kd1 = 0; byte kd2 = 0;
byte aaa = 0; byte AAA = 0;
byte bbb = 0; byte BBB = 0;
//переменные для кнопок
long ms_button = 0;
boolean button_state = false;
boolean button_long_state = false;
byte curMenu = 0; //текущий пункт меню,
bool b_ShowmMenu = 0; // флаг отображения меню
const byte CountMenu = 7; //количество пунктов меню
//массив элементов меню
struct MENU_1{ //
char name1[13];
byte *val1;
};
struct MENU_2{ //
char name2[13];
byte *val2;
};
//инициализация меню
//строковое имя, адрес переменной которую надо менять
MENU_1 mMenu[CountMenu] = {
" temp_t =", &t_bottom,
" power_t =", &p_bottom,
" kP1 =", &kp1,
" kI1 =", &ki1,
" kD1 =", &kd1,
" aa =", &aaa,
" bb =", &bbb
};
//инициализация меню
//строковое имя, адрес переменной которую надо менять
MENU_2 nMenu[CountMenu] = {
" temp_b =", &t_top,
" power_t =", &p_top,
" kP2 =", &kp2,
" kI2 =", &ki2,
" kD2 =", &kd2,
" AA =", &AAA,
" BB =", &BBB
};
//функция выполнения меню
void menu(){
//следующий пункт меню по кругу
if (State_Right == LOW && (millis() - ms_button)>200)
{
ms_button = millis();
if (curMenu == CountMenu - 1)
curMenu = 0;
else curMenu++;
}
// bOk выход из меню
if (State_Ok == LOW && ( millis() - ms_button)>200)
{
ms_button = millis();
// выход из меню
// переход к начальному меню
}
// bUp +1 значение
if (State_Up == LOW && ( millis() - ms_button)>200)
{
ms_button = millis();
(*mMenu[curMenu].val1)++;
(*nMenu[curMenu].val2)++;
}
// bDown -1 значение
if (State_Down == LOW && ( millis() - ms_button)>200)
{
ms_button = millis();
(*mMenu[curMenu].val1)--;
(*nMenu[curMenu].val2)--;
}
//вывод использую буфер
char ch1[16];
char ch2[16];
snprintf(ch1, 16, "%d ", *mMenu[curMenu].val1);
snprintf(ch2, 16, "%d ", *nMenu[curMenu].val2);
lcd.setCursor(0,2); lcd.print(mMenu[curMenu].name1);
lcd.setCursor(12,2); lcd.print(ch1);
lcd.setCursor(0,3); lcd.print(nMenu[curMenu].name2);
lcd.setCursor(12,3); lcd.print(ch2);
}
void setup() {
lcd.begin();
lcd.backlight();
lcd.setCursor(1, 1);
lcd.print("ARDUINO REWORK v0.3");
delay(1000); // wait for MAX chip to stabilize
lcd.clear();
pinMode (BUTTON_UP, INPUT); digitalWrite(BUTTON_UP, HIGH); //подключаем подтягивающий резистор
pinMode (BUTTON_DOWN, INPUT); digitalWrite(BUTTON_DOWN, HIGH); //подключаем подтягивающий резистор
pinMode (BUTTON_LEFT, INPUT); digitalWrite(BUTTON_LEFT, HIGH); //подключаем подтягивающий резистор
pinMode (BUTTON_RIGHT, INPUT); digitalWrite(BUTTON_RIGHT, HIGH); //подключаем подтягивающий резистор
pinMode (BUTTON_OK, INPUT); digitalWrite(BUTTON_OK, HIGH); //подключаем подтягивающий резистор
}
void loop() {
//Считываем состояние кнопок управления
State_Up = digitalRead(BUTTON_UP);
State_Down = digitalRead(BUTTON_DOWN);
State_Left = digitalRead(BUTTON_LEFT);
State_Right = digitalRead(BUTTON_RIGHT);
State_Ok = digitalRead(BUTTON_OK);
//-------------------------------------/
//вывод меню
if (b_ShowmMenu) {
menu();
} else {
//фиксируем момент нажатия кнопки "ОК" + защита от дребезга
if (State_Ok==LOW && !button_state && ( millis() - ms_button)>100)
{
ms_button = millis();
button_state = true;
button_long_state = false;
}
//держим "ОК" 3секунды и заходим в меню настроек
if (State_Ok==LOW && !button_long_state && ( millis() - ms_button)>3000)
{
button_long_state = true;
button_state = false;
b_ShowmMenu = 1;
lcd.clear();
}
}
}
Сделано 7 подменю для каждого числа, по нажатию на BUTTON_RIGHT переход к следущему.
Конкретно вот в этом месте запутался
// bUp +1 значение if (State_Up == LOW && ( millis() - ms_button)>200) { ms_button = millis(); (*mMenu[curMenu].val1)++; (*nMenu[curMenu].val2)++; } // bDown -1 значение if (State_Down == LOW && ( millis() - ms_button)>200) { ms_button = millis(); (*mMenu[curMenu].val1)--; (*nMenu[curMenu].val2)--; }Любой совет будет не лишним)
а вы не думали сначала научиться правильно работать с кнопками.
или какую то библиотеку для опроса кнопок прицепить...
Вначале пробывал с Bounce, но не получилось сделать длинное нажатие, поэтому сделал как видите. Да обработка кнопок кривая, подскажите как улучшить?
И похоже вы "потеряли" свою тему http://arduino.ru/forum/programmirovanie/lcd-i2c-displei-i-obrabotka-knopok#comment-332235
ПС: Я там в конце вариант скетча скидывал. #28 Нажатие в 3 сек - это что 33 утюга сидели на подоконике == "явка провалена"
if(State_Down == LOW && ( millis() - ms_button)>200) // сам знаю что это не решениеДа но я решил сделать по новому, qwone спасибо но буду уже этот код дорабатывать, а не писать заново
Я новичок в программировании , поэтому классы не осилил, буду дорабатывть уже созданный и отлаженный код
Нажатие в 3 сек - это что 33 утюга сидели на подоконике == "явка провалена"
Мне так проще, код будет дополняться новыми режимами, поэтому и нажатие в 3 сек
Любые идеи приветствуются, пишите
// это аналогично прежнему - тут есть защита от дребезга!!! if (State_Up == LOW) { if ( millis() - ms_button > 200) { ms_button = millis(); (*mMenu[curMenu].val1)++; (*nMenu[curMenu].val2)++; } }за счет millis() устраняется ложное срабатывание
.
// может так // изначально flag = 0 if (State_Left == LOW) { if ( millis() - ms_button > 200) { ms_button = millis(); // по нажатию флаг !flag // функция мигания blink разрешена } } // bUp +1 значение if (State_Up == LOW) { if ( millis() - ms_button > 200) { ms_button = millis(); // if (flag == TRUE && ???) (*mMenu[curMenu].val1)++; // flag = 1 // blink; ///////////////////////// // (flag == LOW && ???) (*nMenu[curMenu].val2)++; // flag = 0 // blink; } }используйте вел Клапы, что зря чтоли человек трудился.
У меня такой вопрос. Допустим имеется две кнопки и число(int, byte или другого целого типа). Нужен простой алгоритм чтобы задействуя эти кнопки можно было увеличивать число на 1,10,100. Думаю одной кнопкой такое не возможно, поэтому предлагая на двух.
Думаю организовать счетчик нажатий или чтото типа. Чтобы одна увеличивала число, а другая задавала предел(1,10...)
Лучше всего это.
Да и кнопки должно быть 3 :+ ,- и next
Был у меня такой кусочек. В часах время время и будильник устанавливает. Длинное нажатие на первую кнопку запускает цикл установки времени. Короткие нажатия - изменение цифры. Длинное нажатие - переход к следующей цифре. Последнее длинное нажатие - выход и сохранение результата. Если переменная ed или al отличны от нуля - в основном цикле моргает соответствующая позиция индикатора. Длинное нажатие на вторую кнопку вызывает значение будильника и меняет по тому же алгоритму. Было сделано на тиньке 25. Поэтому ноги используются и для индикации и для ввода - приходится переключать. Подавление дребезга присутствует, длинное короткое нажатие различаются.
...... tm=millis(); if(tm-tio > 20) { tio=tm; DDRB &= ~(1 << dataPin); // обработка кнопки 1 delayMicroseconds(100); if (k1cnt > 5){ if ((PINB & dataPin)==0) k1cnt++; else {if (k1cnt > 40) key=2; else key=1;} k1cnt=0;} else if ((PINB & dataPin)==0) k1cnt++; DDRB|= 1 << dataPin ; DDRB &= ~(1 << clockPin) ; // обработка кнопки 2 delayMicroseconds(100); if (k2cnt > 5){ if ((PINB & clockPin)==0) k2cnt++; else {if (k2cnt > 40) key=4; else key=3;} k2cnt=0;} else if ((PINB & clockPin)==0) k2cnt++; DDRB|= 1 << clockPin ; }; switch(key) { case 0: break; case 1: if (ed>0) switch (ed) { case 1: hour+=10;break; case 2: hour++;break; case 3: minute+=10;break; case 4: minute++;break; }; if (minute>59) minute-=60; if (hour>23) hour-=24; break; case 2: ed++; if (ed>3) { ed=0; setDS3231time(second, minute, hour, dayOfWeek, dayOfMonth, month,year);};break; case 3: if(al>0) switch (al) { case 1: alm++;break; case 2: alm+=10;break; case 3: alh++;break; case 4: alh+=10;break; }; if (alm>59) alm-=60; if (alh>23) alh-=24; break; case 4: al++; if (al>3) al=0; break; }; key=0; }У меня такой вопрос. Допустим имеется две кнопки и число(int, byte или другого целого типа). Нужен простой алгоритм чтобы задействуя эти кнопки можно было увеличивать число на 1,10,100. Думаю одной кнопкой такое не возможно, поэтому предлагая на двух.
Возможно, но будет неинтуитивно понятно: проверяете состояние кнопки каждые Xмс, если нажата - увеличиваете на единицу и считаете количество инкрементов. Если это кол-во > N, начинаете инкрементировать на десятку. Если > K - на сотню. Вместо прыжков по разрядам - можете уменьшать X (прибавляться будет быстрее). Как только на очередной итерации кнопка отжата - счетчик инкрементов на 0.
У меня такой вопрос. Допустим имеется две кнопки и число(int, byte или другого целого типа). Нужен простой алгоритм чтобы задействуя эти кнопки можно было увеличивать число на 1,10,100. Думаю одной кнопкой такое не возможно, поэтому предлагая на двух.
Возможно, но будет неинтуитивно понятно: проверяете состояние кнопки каждые Xмс, если нажата - увеличиваете на единицу и считаете количество инкрементов. Если это кол-во > N, начинаете инкрементировать на десятку. Если > K - на сотню. Вместо прыжков по разрядам - можете уменьшать X (прибавляться будет быстрее). Как только на очередной итерации кнопка отжата - счетчик инкрементов на 0.
Спасибо, буду пробовать. Позже прикреплю код
Не совсем то но вот
#include <Wire.h> // библиотека для управления устройствами по I2C #include <LiquidCrystal_I2C.h> // подключаем библиотеку для LCD 1602 LiquidCrystal_I2C lcd(0x3f,20,4); // присваиваем имя lcd для дисплея 20х4 unsigned long time_Pressed; // Переменные для работы со временем; unsigned long timeNow; byte i = 0; // мое число enum bottonVariants { // Определения для работы с кнопкой; BOTTON_CLICK, BOTTON_SHORT, BOTTON_LONG, BOTTON_NOT, }; bottonVariants botton = BOTTON_NOT; void setup() { lcd.begin(); lcd.backlight(); lcd.setCursor(1, 1); lcd.print("PROGRAM V1.0"); delay(1000); lcd.clear(); pinMode(9, INPUT); //пин для кнопки digitalWrite(9, HIGH); //подключаем подтягивающий резистор } void loop() { if (digitalRead(9) == 0) { // Стандартная проверка с антидребезгом; delay(50); // Ждем для устранения дребезга; if (digitalRead(9) == 0) { // Проверяем еще раз; time_Pressed = millis(); // Запоминаем время нажатия кнопки; lcd.clear(); lcd.print("+1"); delay(200); botton = BOTTON_CLICK; // однократное нажатие while (digitalRead(9) == 0) { // Ждем отпускания кнопки; timeNow = millis(); // И засекаем время; if (timeNow - time_Pressed > 1000 && timeNow - time_Pressed < 2000) { // Было долгое нажатие кнопки - больше 2 с. lcd.clear(); lcd.print("+10"); delay(200); botton = BOTTON_SHORT; } else if (timeNow - time_Pressed >2000) { // Было короткое нажатие - менее 2 с но более 1 с. lcd.clear(); lcd.print("+100"); delay(200); botton = BOTTON_LONG; } } } } switch (botton) { // Здесь выбираем что менять; case BOTTON_CLICK: // При одиночном нажатии, i++; lcd.setCursor(0, 1); lcd.print(i); botton = BOTTON_NOT; break; case BOTTON_SHORT: // При коротком нажатии; i+=10; lcd.setCursor(0, 1); lcd.print(i); botton = BOTTON_NOT; break; case BOTTON_LONG: // При долгом нажатии, i+=100; lcd.setCursor(0, 1); lcd.print(i); botton = BOTTON_NOT; break; case BOTTON_NOT: break; } }Может кто нибудь сталкивался с подобным. Как сделать чтобы по нажатию кнопки на 8 пине в переменную chislo записывалось первое chislo_One, затем по повторному нажатию второе chislo_Two, затем снова chislo_One ...
byte chislo_One = 0; // число 0-255 byte chislo_Two = 0; // число 0-255 byte chislo; // буфер enum bottonVariants { // Определения для работы с кнопкой; BOTTON_CLICK, BOTTON_NOT, }; bottonVariants botton = BOTTON_NOT; void setup() { pinMode(8, INPUT); //пин для кнопки выбора числа digitalWrite(9, HIGH); //подключаем подтягивающий резистор pinMode(9, INPUT); //пин для кнопки операций над числом digitalWrite(9, HIGH); //подключаем подтягивающий резистор } void loop() { if (digitalRead(8) == 0) { // Стандартная проверка с антидребезгом; delay(50); // Ждем для устранения дребезга; if (digitalRead(8) == 0) { // Проверяем еще раз; // этой кнопкой нужно выбрать из chislo_One и chislo_Two // chislo = присвоить переменной выбранное } } if (digitalRead(9) == 0) { // Стандартная проверка с антидребезгом; delay(50); // Ждем для устранения дребезга; if (digitalRead(9) == 0) { // Проверяем еще раз botton = BOTTON_CLICK; // однократное нажатие // редактирование числа } } switch (botton) { // Здесь выбираем что менять; case BOTTON_CLICK: // При одиночном нажатии, chislo++; botton = BOTTON_NOT; break; case BOTTON_NOT: //тут код вывода на ЖК break; } }Может кто нибудь сталкивался с подобным.
Может кто нибудь сталкивался с подобным. Как сделать чтобы по нажатию кнопки на 8 пине в переменную chislo записывалось первое chislo_One, затем по повторному нажатию второе chislo_Two, затем снова chislo_One ...
А в чем проблема то? Способов это сделать - тыщи. Можно через массивы, можно через указатели, можно по-простому, через пару условий if...
Заводите, к примеру, переменную, со значениями 1 и -1. Если в переменной "1" - значит переменная chislo соответствует chislo_One, если там "-1" - значит chislo_Two. А по нажатию кнопки 8 просто умножаете значение этой переменной на -1.
Все понятно, спасибо