Перейти к содержанию

Управление меню с помощью трёх кнопок (Си)


-=FISHER=-

Рекомендуемые сообщения

Всем здравствуйте!

В моем проекте потребовалось реализовать меню для настройки параметров и управлять им планирую с помощью трёх кнопок. Причем вход в меню и перемещение между пунктами, хотел реализовать длинным нажатием кнопки SET. А регулировку параметров короткими нажатиями на + и -. 

Подскажите пожалуйста какие есть варианты реализации такого меню на Си? Предполагаю, что лучше всего будет сделать через switch, однако в моем проекте в главном цикле уже есть один switch для выбора отображаемой информации (часы, температура, напряжение). В частности происходит путаница в голове где отслеживать нажатия кнопок? Отдельная функция или как-то внутри switch для меню?...

Скрытый текст

MENU.jpg.ab2ba9cfe562cc489c7edc5242a88286.jpg

 

Мы все учились по-немногу, чему-нибудь и как-нибудь...

Ссылка на комментарий
Поделиться на другие сайты

Реклама: ООО ТД Промэлектроника, ИНН: 6659197470, Тел: 8 (800) 1000-321

2 часа назад, -=FISHER=- сказал:

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

правильное решение... и что это меняет? в главном цикле по флагу системного тика опрашиваете кнопки , далее кася

часы =0, температура=2, напряжение=3, меню1=4, парам1.1=5, парам1.2=6, меню2=7, парам2.1=8, парам2.2=9 и тд

3 часа назад, -=FISHER=- сказал:

 А регулировку параметров короткими нажатиями на + и -. 

. при малом кол-ве кнопок обычно делается: вход/выход в меню/подменю/параметры Set , циклическое перемещение по пунктам Move,  циклическое изменение параметра Change

Ссылка на комментарий
Поделиться на другие сайты

20% скидка на весь каталог электронных компонентов в ТМ Электроникс!

Акция "Лето ближе - цены ниже", успей сделать выгодные покупки!

Плюс весь апрель действует скидка 10% по промокоду APREL24 + 15% кэшбэк и бесплатная доставка!

Перейти на страницу акции

Реклама: ООО ТМ ЭЛЕКТРОНИКС, ИНН: 7806548420, info@tmelectronics.ru, +7(812)4094849

8 часов назад, IMXO сказал:

при малом кол-ве кнопок обычно делается: вход/выход в меню/подменю/параметры Set , циклическое перемещение по пунктам Move,  циклическое изменение параметра Change

Я делал 3 кнопки так: SELECT - выбор пункта меню (выбор изменяемого параметра), UP и DN - изменение выбранного параметра в соответствующую сторону, подменю не предусматривалось. Длинные нажатия не требуются: после отсутствия нажатий любой кнопки в течение определенного времени режим меню отключается автоматически, и включается обычный режим - индикация того, чего надо. В обычном режиме кнопки UP/DN могут менять какой-то один оперативный параметр, например, яркость индикатора, чтобы по меню не лазить для этой функции, а могут и не работать вообще.

12 часов назад, -=FISHER=- сказал:

какие есть варианты реализации такого меню на Си?

Вариантов много. Например, последнее время я становлюсь сторонником максимального абстрагирования от "кнопок" и т.п. интерфейсов в "главном" коде: от кодов кнопок я уходу в "сообщения" или "события". Главный код содержит обращение к функции, возвращающей полученное событие. Если таковое событие получено, далее оно обрабатывается switch-ем. При этом событие "вход в меню" или "выбор другого пункта меню" отсутствует в принципе, зато есть событие "ПАРАМЕТР_1_БОЛЬШЕ" или "ПАРАМЕТР_3_МЕНЬШЕ".

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

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

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

Если забанить всех, кто набрался смелости думать независимо, здорово будет на форуме - как на кладбище: тишина, птички поют...

Ссылка на комментарий
Поделиться на другие сайты

Выбираем схему BMS для заряда литий-железофосфатных (LiFePO4) аккумуляторов

Обязательным условием долгой и стабильной работы Li-FePO4-аккумуляторов, в том числе и производства EVE Energy, является применение специализированных BMS-микросхем. Литий-железофосфатные АКБ отличаются такими характеристиками, как высокая многократность циклов заряда-разряда, безопасность, возможность быстрой зарядки, устойчивость к буферному режиму работы и приемлемая стоимость. Но для этих АКБ очень важен контроль процесса заряда и разряда для избегания воздействия внешнего зарядного напряжения после достижения 100% заряда. Инженеры КОМПЭЛ подготовили список таких решений от разных производителей. Подробнее>>

Реклама: АО КОМПЭЛ, ИНН: 7713005406, ОГРН: 1027700032161

14 часов назад, IMXO сказал:

правильное решение... и что это меняет? в главном цикле по флагу системного тика опрашиваете кнопки , далее кася

часы =0, температура=2, напряжение=3, меню1=4, парам1.1=5, парам1.2=6, меню2=7, парам2.1=8, парам2.2=9 и тд

 В общем случае вот так получается?

Скрытый текст

       switch(mode)
        {
            case MODETIMEVIEW:
            {
  
                break;                
            }

            case MODETEMPVIEW:
            {

                break;
            }
            
            case MODEVOLTVIEW:
            {            

                break;    
            }   
           
            case MODE_MENU1_VIEW:
            {
  
                break;                
            }

            case MODE_PARAM1.1_VIEW:
            {

                break;
            }
            
            case MODE_PARAM1.2_VIEW:
            {            

                break;    
            } 
           
            case MODE_MENU2_VIEW:
            {
  
                break;                
            }

            case MODE_PARAM2.1_VIEW:
            {

                break;
            }
            
            case MODE_PARAM2.2_VIEW:
            {            

                break;    
            } 
        }

 

А опрос всех трех кнопок получается нужно будет вызывать из каждого CASE ? Я к тому что, как сделать чтобы кнопка понимала что в настройках минут, нужно менять только от 0 до 59, в часах от 0 до 23, а предположим в МЕНЮ2.ПАРАМЕТР2 только от 1 до 10.

Мы все учились по-немногу, чему-нибудь и как-нибудь...

Ссылка на комментарий
Поделиться на другие сайты

Сравнительное тестирование аккумуляторов EVE Energy и Samsung типоразмера 18650

Инженеры КОМПЭЛ провели сравнительное тестирование аккумуляторов EVE и Samsung популярного для бытовых и индустриальных применений типоразмера 18650. 

Для теста были выбраны аккумуляторы литий-никельмарганцевой системы: по два образца одного наименования каждого производителя – и протестированы на двух значениях тока разряда: 0,5 А и 2,5 А. Испытания проводились в нормальных условиях на электронной нагрузке EBD-USB от ZKEtech, а зарядка осуществлялась от лабораторного источника питания в режиме CC+CV в соответствии с рекомендациями в даташите на определенную модель. Подробнее>>

Реклама: АО КОМПЭЛ, ИНН: 7713005406, ОГРН: 1027700032161

38 минут назад, -=FISHER=- сказал:

Я к тому что, как сделать чтобы кнопка понимала что в настройках минут, нужно менять только от 0 до 59, в часах от 0 до 23, а предположим в МЕНЮ2.ПАРАМЕТР2 только от 1 до 10.

Я подобную задачу решал несколько иным способом, чем описывал давеча. Но в чем-то сходным.

Я создавал структуру меню, где каждому пункту меню сопоставлялись не только "наименования" пункта, но и указатель на данные, функция изменения этих данных и указатель на "края". Таким образом, при каждом нажатии кнопки в меню вызывалась функция изменения данных, которая получала направление изменения (про коду кнопки), указатель на данные, указатель на границы изменения данных. Эта же функция при необходимости отображала сами данные.

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

Обновления библиотечки: раз, два и три.

Если забанить всех, кто набрался смелости думать независимо, здорово будет на форуме - как на кладбище: тишина, птички поют...

Ссылка на комментарий
Поделиться на другие сайты

Литиевые аккумуляторы EVE Energy и решения для управления перезаряжаемыми источниками тока (материалы вебинара)

Опубликованы материалы вебинара Компэл, посвященного литиевым аккумуляторам EVE Energy и решениям для управления перезаряжаемыми источниками тока.

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

Реклама: АО КОМПЭЛ, ИНН: 7713005406, ОГРН: 1027700032161

1 час назад, -=FISHER=- сказал:

 В общем случае вот так получается?

Я к тому что, как сделать чтобы кнопка понимала что в настройках минут, нужно менять только от 0 до 59, в часах от 0 до 23, а предположим в МЕНЮ2.ПАРАМЕТР2 только от 1 до 10.

Опрос кнопок - это одна функция, возвращающая код "нажатия виртуальной кнопки".

Реакция на "нажатую виртуальную кнопку" - другая  функция.

В функциях реакции выполняется вся нужная валидизация: в функции изменения минут контролируется что бы минут не было больше 59, в функции часов  что бы не более 12/24,  а в функции работы с   Х -сколько нужно для него.

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

 

Изменено пользователем dasZebra
Ссылка на комментарий
Поделиться на другие сайты

Литиевые батарейки и аккумуляторы от мирового лидера  EVE в Компэл

Компания Компэл, официальный дистрибьютор EVE Energy, бренда №1 по производству химических источников тока (ХИТ) в мире, предлагает продукцию EVE как со склада, так и под заказ. Компания EVE широко известна в странах Европы, Америки и Юго-Восточной Азии уже более 20 лет. Недавно EVE была объявлена поставщиком новых аккумуляторных элементов круглого формата для электрических моделей «нового класса» компании BMW.

Продукция EVE предназначена для самого широкого спектра применений – от бытового до промышленного. Подробнее>>

Реклама: АО КОМПЭЛ, ИНН: 7713005406, ОГРН: 1027700032161

1 час назад, dasZebra сказал:

Опрос кнопок - это одна функция, возвращающая код "нажатия виртуальной кнопки".

А почему вы пишите виртуальной кнопки? 

1 час назад, dasZebra сказал:

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

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

Мы все учились по-немногу, чему-нибудь и как-нибудь...

Ссылка на комментарий
Поделиться на другие сайты

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

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

Мы все учились по-немногу, чему-нибудь и как-нибудь...

Ссылка на комментарий
Поделиться на другие сайты

Вы для какого девайса меню делаете? Перемещение по пунктам долгим нажатием явно неудобно будет для большинства случаев...

Далее: индикатор какой? ЖКИ символьный или 7-сегментный ? 

Я столько вариантов меню делал, что наверняка смогу подсказать удобный в эксплуатации и программировании вариант. Был даже опыт с ОДНОКНОПОЧНЫМ управлением :)

Если забанить всех, кто набрался смелости думать независимо, здорово будет на форуме - как на кладбище: тишина, птички поют...

Ссылка на комментарий
Поделиться на другие сайты

В прошлом своем "однокнопочном" проекте, правда без меню, я применил вот такую функцию опроса длинного и короткого кнопки. Этот код хорошо работал. Но вот как применить его в этом проекте с меню, ума не приложу. Пока на ум пришла вот такая конструкция. Но что правильнее делать дальше?

Скрытый текст

 


#define PORT_BTN		PORTD
#define DDR_BTN			DDRD
#define PIN_BTN			PIND

#define BIT_PLUS_BTN    _BV(0)
#define BIT_MINUS_BTN   _BV(1)
#define BIT_SET_BTN     _BV(2) 

void Read_Button_State(unsigned char b) //функция опроса кнопки
{
	if(!(PIN_BTN&b)) //проверяем нажатие кнопки
	{
		if(but_count<10){but_count++;} //считаем время антидребезга ~10 мс
		else
		{
			if(but_long_press<500){but_long_press++;} //считаем время длительного нажатия ~0.5 с
			else
			{
				//делаем то, что хотели после длительного нажатия
				but_trig=1; //устанавливаем флаг длительного нажатия
			}
		}
	}
	else
	{
		if((but_long_press>0)&&(but_trig==0)) //если нажатие было, и оно НЕ было длинным, то
		{
			//делаем то, что хотели после короткого нажатия
		}
		if(but_trig){but_trig=0;} //если до этого было длинное нажатие, сбрасываем его флаг
		but_long_press=0; //сбрасываем счетчик длительного нажатия
	}	
}  
  
  
ISR (TIMER0_OVF_vect) //в прерывании по переполнению, примерно 1 раз в 1 мс
{
	Read_Button_State(BIT_SET_BTN); //опрашиваем кнопку SET
	Read_Button_State(BIT_MINUS_BTN ); //опрашиваем кнопку "-"
	Read_Button_State(BIT_MINUS_BTN ); //опрашиваем кнопку "+"
}

 

 

5 минут назад, ARV сказал:

Вы для какого девайса меню делаете? Перемещение по пунктам долгим нажатием явно неудобно будет для большинства случаев...

Далее: индикатор какой? ЖКИ символьный или 7-сегментный ? 

1. Часы, термометр, вольтметр;

2. 7-сегментный индикатор.

 

P.S. понятное дело, что в моем варианте, у каждой кнопки должны быть свои переменные:

but_count, but_long_press, but_trig

Изменено пользователем -=FISHER=-

Мы все учились по-немногу, чему-нибудь и как-нибудь...

Ссылка на комментарий
Поделиться на другие сайты

Для часов с 7-сегментным индикатором меню, как таковое, не требуется: мигание разрядов будет информировать о том или ином режиме настроек. Если часы не наручные, то долгих нажатий не надо: первое нажатие SET включает мигание часов, второе минут, третье секунд, затем либо переход к календарю, либо выключение мигания. 

Автомат состояний определяет диапазон изменения настраиваемого значения. При переходе между состояниями эти границы меняются. Все очень просто...

Что настраивать в вольтметре и термометре, я не знаю.

Если забанить всех, кто набрался смелости думать независимо, здорово будет на форуме - как на кладбище: тишина, птички поют...

Ссылка на комментарий
Поделиться на другие сайты

12 минут назад, ARV сказал:

Что настраивать в вольтметре и термометре, я не знаю.

1.       Настройка времени:

           1.1.    Настройка минут (моргают минуты);

           1.2.    Настройка часов (моргают часы).

2.       Настройка яркости:

          2.1.    Дневная яркость;

          2.2.    Ночная яркость.

3.       Оповещения:

          3.1.    Температура за бортом ниже -4;

          3.2.    Возможно, ещё что-то добавлю.

4.       Анимация включения:

          4.1.    Вариант 1;

          4.2.    ***;

          4.3.    Вариант n.

5.       Анимация смены отображения (Часы <=> t в салоне <=> t за бортом <=> Вольтметр)

         5.1.    Вариант 1;

         5.2.    ***;

         5.3.    Вариант n.

Изменено пользователем -=FISHER=-

Мы все учились по-немногу, чему-нибудь и как-нибудь...

Ссылка на комментарий
Поделиться на другие сайты

А вы себе чётко представляете, как именно это многообразие вариантов будет показано на 7-сегментах?!

То есть как отличать один пункт от другого?

Если забанить всех, кто набрался смелости думать независимо, здорово будет на форуме - как на кладбище: тишина, птички поют...

Ссылка на комментарий
Поделиться на другие сайты

8 минут назад, ARV сказал:

А вы себе чётко представляете, как именно это многообразие вариантов будет показано на 7-сегментах?!

Я уверен что что-нибудь придумаю, а тем кто (если ВДРУГ) захотят повторить, обязательно напишу подробную инструкцию по настройке.

Вот кстати как я себе представляю навигацию по меню:

Скрытый текст

1371828905_.JPG.4d379e2849a8f3382565668535bf6616.JPG

 

Мы все учились по-немногу, чему-нибудь и как-нибудь...

Ссылка на комментарий
Поделиться на другие сайты

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

А после продумывания того, как ОДНОТИПНО отображать и редактировать разное, станет понятно, какими функциями это реализовывать. Имхо...

Изменено пользователем ARV

Если забанить всех, кто набрался смелости думать независимо, здорово будет на форуме - как на кладбище: тишина, птички поют...

Ссылка на комментарий
Поделиться на другие сайты

18 минут назад, ARV сказал:

А после продумывания того, как ОДНОТИПНО отображать и редактировать разное, станет понятно, какими функциями это реализовывать. Имхо...

Я думаю например вот так:

Скрытый текст

1687426858_.JPG.70cabb4316623dfeb46a44a26e15cbc8.JPG

И кстати, чтобы зайти в меню из любого режима отображения (Часы - термометр - вольтметр), тоже зажимаем долго кнопку SET

Изменено пользователем -=FISHER=-

Мы все учились по-немногу, чему-нибудь и как-нибудь...

Ссылка на комментарий
Поделиться на другие сайты

4 часа назад, -=FISHER=- сказал:

А почему вы пишите виртуальной кнопки? 

Изделие имеет всего например 3 физические кнопки. По сути ваша задача эмулировать этими тремя кнопками необходимое количество кнопок - виртуальных кнопок. Ну например:

Минуты+; Минуты-; Часы+; Часы-; .... PараметряN+; PараметрN-.

4 часа назад, -=FISHER=- сказал:

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

Код вы сами  прекрасно напишите. А парпдигму я поясню.

1. У вас три физические кнопки. Значит прежде всего вам нужно детектировать их нажатие.  Пишите функцию GetRealButton(), которая слушает ноги и возвращает (присваивает глобальной переменной) код нажатой кнопки. Эта функцию вы  вызывете  в главном цикле с заданным вами интервалом. То есть если была нажата кнопка 1 то переменная chRealButtonMem будет равна 1. Если нажата кнопка 2 то 2, если было длительное нажатие кнопки 3 то 46, а если кнопки 1 и 2 были нажаты одновременно то код 69.

2. Теперь нужно развернуть логику вложенности.   В главном цикле вызывается фунция GetMenu(), слушающая переменную chRealButtonMem и в зависимости от её значения, текущего состояния и логики изделия присваивающая переменной chVirtualButtonMem  нужный код.  

3. Теперь обработка децствиц меню. В главном цикле вызываются нужные обработчики, слушающие переменную chVirtualButtonMem, и при обнаружении что эта переменная равна определенному значению, выполняющие нужное действие.

do while(1)

 {

 chRealButtonMem=GetRealButton(); //слушаем ноги

chVirtualButtonMem=GetMenu(chRealButtonMem); //слушаются три реальные кнопки без дребезга но с блэкджеком и шлюхами

Обработчик1(chVirtualButtonMem); // выполняется запрошенное действие

Обработчик2(chVirtualButtonMem); //выполняется запрошенное действие

....

DisplayShow1(chVirtualButtonMem); // отображается нужное на дисплее

DisplayShow2(chVirtualButtonMem); //отображается нужное на дисплее

....

chRealButtonMem=0; // нажатие отработанно

chVirtualButtonMem=0; // запрошенное действие отработанно

ОстальныеДействия();

}

 

В итоге у вас  разделены физический уровень, логический уровень и уровень  функционирования устройства.

 

Ссылка на комментарий
Поделиться на другие сайты

7 часов назад, dasZebra сказал:

chVirtualButtonMem=GetMenu(chRealButtonMem); //слушаются три реальные кнопки без дребезга но с блэкджеком и шлюхами

Но, почему без обработки дребезга?

Мы все учились по-немногу, чему-нибудь и как-нибудь...

Ссылка на комментарий
Поделиться на другие сайты

Потому что там работа ведется уже не с физическими дребезжащими кнопками. а с их кодами, полученными ранее

Если забанить всех, кто набрался смелости думать независимо, здорово будет на форуме - как на кладбище: тишина, птички поют...

Ссылка на комментарий
Поделиться на другие сайты

4 минуты назад, ARV сказал:

а с их кодами, полученными ранее

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

Мы все учились по-немногу, чему-нибудь и как-нибудь...

Ссылка на комментарий
Поделиться на другие сайты

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

Действие пункта - это то, что выполняется при активации какой-то кнопки, в вашем случае SET.

Главная проблема в том, что потоки команд разделяются на 2 варианта: для "основного режима" и для "хождения по меню". В каждом из потоков приходится делать отдельную функцию вывода на индикатор, отдельную реакцию на кнопки и т.п. Это, конечно, портит стройность алгоритма...

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

Если не гнаться за этой стройностью, то самый тривиальный switch с кучей case, под которыми тоже switch с кучей case, под которыми... ну вы поняли :) 

Если забанить всех, кто набрался смелости думать независимо, здорово будет на форуме - как на кладбище: тишина, птички поют...

Ссылка на комментарий
Поделиться на другие сайты

вообще для такой простой задачи меню не нужно в полноценном понимании этого слова.

я бы назвал это списком.

и я бы предложил такой список:

1. Часы.      SET -> (мигают минуты - установка минут кнопками "+/-") -> SET -> (мигают часы - установка часов кнопками "+/-")  -> SET -> (закончили установку времени - убрали мигание).

                     также нажатие кнопки SET выводит из настройки времени досрочно после установки минут.

2. t в салоне.      SET не воспринимается.

3.  t за бортом.      SET не воспринимается.

4. Вольтметр.      SET не воспринимается.

5. Яркость.      SET -> (мигает значение яркости - установка яркости кнопками "+/-")  -> SET -> (закончили установку яркости - убрали мигание).

6. Анимация включения.     SET -> (мигает значение анимации - выбор анимации кнопками "+/-")  -> SET -> (закончили выбор анимации - убрали мигание).

7. Оповещения.     SET -> (переходим к перелистыванию оповещений кнопками "+/-")  -> SET -> (закончили перелистывание оповещений).

 

навигация по этому списку производится кнопками "+/-" - вперед/назад, по кольцу, с последнего пункта на первый или с первого на последний.

длинное нажатие кнопки SET тоже не потребуется.

Мудрость приходит вместе с импотенцией...

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

Ссылка на комментарий
Поделиться на другие сайты

4 часа назад, ARV сказал:

Если не гнаться за этой стройностью, то самый тривиальный switch с кучей case, под которыми тоже switch с кучей case, под которыми... ну вы поняли :) 

В целом понял, но всё же меня интересует, вот эта функция имеет право на жизнь или есть более красивый способ отлавливания коротких и длинных нажатий?

Скрытый текст

void Read_Button_State(unsigned char b) //функция опроса кнопки
{
	if(!(PIN_BTN&b)) //проверяем нажатие кнопки
	{
		if(but_count<10){but_count++;} //считаем время антидребезга ~10 мс
		else
		{
			if(but_long_press<500){but_long_press++;} //считаем время длительного нажатия ~0.5 с
			else
			{
				//делаем то, что хотели после длительного нажатия
				but_trig=1; //устанавливаем флаг длительного нажатия
			}
		}
	}
	else
	{
		if((but_long_press>0)&&(but_trig==0)) //если нажатие было, и оно НЕ было длинным, то
		{
			//делаем то, что хотели после короткого нажатия
		}
		if(but_trig){but_trig=0;} //если до этого было длинное нажатие, сбрасываем его флаг
		but_long_press=0; //сбрасываем счетчик длительного нажатия
	}	
}  

 

 

Мы все учились по-немногу, чему-нибудь и как-нибудь...

Ссылка на комментарий
Поделиться на другие сайты

Только что, -=FISHER=- сказал:

эта функция имеет право на жизнь или

Вы же знаете мой принцип: имеет право на жизнь всё, что приводит к нужному результату :)

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

Второй вопрос, это поведение самого устройства. Возможно 2 принципиальных варианта: реагирование на нажатие и реагирование на отпускание. При реагировании на отпускание проще отличать долгое нажатие от короткого, но это не всегда удобно с точки зрения интерфейса пользователя. Реагирование на нажатие более сложно в реализации, но более "привычно" для потребителя. 

Ваша функция называется "считать состояние кнопки", но внутри себя содержит участки "делать при долгом или кратком нажатии" - это не правильно с точки зрения алгоритма: внутри функции не должно выполняться никакой работы, кроме выяснения состояния кнопок, которое и должно быть возвращено.

Я всегда делаю так.

Создаю функцию get_pressed_keys(void), которая возвращает код, соответствующий всем возможным комбинациям нажатых кнопок. 0 - ничего не нажато, 1 - нажата одна кнопка и т.д. Конечно, каждой комбинации я присваиваю символьный идентификатор.

Затем я создаю функцию get_command(int), которая получает в качестве параметра код комбинации и возвращает уже команду, которая должна быть исполнена. Вот именно в этой функции я отделяю долгие нажатия от коротких, разрешенные комбинации от запрещенных и т.д. Функция вернет CMD_NONE, если на вход поступило что-то не то, иначе вернет конкретную команду, например, CMD_SET_SHORT или CMD_SET_LONG. Главное, постараться отойти от кнопок в сторону абстрактных команд. Это разумно сделать именно с точки зрения перфекционизма и перспективы: наличие абстрактных команд позволит легко и просто внедрить в девайс дистанционное управление любым способом, ведь для программы не будет никакой разницы, как появилась команда - с клавиатуры, из USART или с IR-датчика.

Ну а далее уже дело техники.

Если забанить всех, кто набрался смелости думать независимо, здорово будет на форуме - как на кладбище: тишина, птички поют...

Ссылка на комментарий
Поделиться на другие сайты

4 часа назад, ARV сказал:

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

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

#define LEFT_IN _BV(PB0) //(1<<PB0)
#define COM _BV(PB1) //(1<<PB1)
#define RIGHT_IN _BV(PB2) //(1<<PB2)
#define SET_BTN _BV(PB3) //(1<<PB3) кнопка настройки
#define ANY_K (RIGHT_IN|COM|LEFT_IN|SET_BTN) //маска для комбинации входных сигналов
  
#define command_Setup_Pause 0x7
#define command_Setup_StandBy 0x5
#define command_Setup_Left 0x4
#define command_Setup_Right 0x1
#define command_Setup_All 0x0

#define ERROR 10

uint8_t get_button(void)
{
	return PINB & ANY_K;
}

uint8_t get_code(void) //опрос портов
{
	code=get_button();
	_delay_ms(3);
	if(code!=get_button()){code=ERROR;}
	return code;
}

//*****************************************

command=get_code();

но я совсем не могу придумать, как при таком подходе мне отловить длительно нажатие?

Изменено пользователем -=FISHER=-

Мы все учились по-немногу, чему-нибудь и как-нибудь...

Ссылка на комментарий
Поделиться на другие сайты

Присоединяйтесь к обсуждению

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

Гость
Unfortunately, your content contains terms that we do not allow. Please edit your content to remove the highlighted words below.
Ответить в этой теме...

×   Вставлено с форматированием.   Восстановить форматирование

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

Загрузка...
  • Последние посетители   0 пользователей онлайн

    • Ни одного зарегистрированного пользователя не просматривает данную страницу

×
×
  • Создать...