Страница 1 из 4
Обработка кнопок, EXTI[0]
Добавлено: Пн ноя 11, 2024 17:16:30
aleksey chilov
Добрый вечер кому как.
Подскажите пожалуйста варианты обработки кнопочек, для меню.
Спасибо.
Re: Обработка кнопок, EXTI[0]
Добавлено: Пн ноя 11, 2024 18:51:07
Аlex
Покажите свои варианты, а мы оценим

Re: Обработка кнопок, EXTI[0]
Добавлено: Пн ноя 11, 2024 19:36:46
BOB51
Вариантов огромное множество.
Зависит от схемы, компилятора и идеи самого устройства.

Re: Обработка кнопок, EXTI[0]
Добавлено: Вт ноя 12, 2024 07:34:19
aleksey chilov
Ну, тут просто флаги и переменные...
Добавлено after 4 minutes 5 seconds:
Потом просто хендлер с прерываниями по спаду и по фронту поднимает и опускает флажки при нажатии кнопок...
Нажата кнопка флаг true отжата false... Булий...
Добавлено after 5 minutes 38 seconds:
Дальше настроил таймер 3 на 100Гц и в прерывании с частотой 100 ГЦ идёт опрос кнопок и обработка ADC и если флаг
кнопки true тогда накапливаем переменную при каждом входе в прерывание если флаг позволяет. Это такакя у меня попытка была создать короткие и долгие нажатия кнопок. Ну и всё... Дальше я завис...
Добавлено after 5 minutes 6 seconds:
Хочу посмотреть другие решения, сколько людей столько и идей... Не хотелось бы прибегать к каким то библиотекам тем более всего 3 кнопки да и библиотеки все на HAL а я использую CMSIS, она меньше памяти хавает правда проблем в 1000.000 раз больше чем в HAL ..
Re: Обработка кнопок, EXTI[0]
Добавлено: Вт ноя 12, 2024 10:39:49
Martian
А что, в АРМах теперь для флагов один бит нельзя? И проверки битов больше нет?
Re: Обработка кнопок, EXTI[0]
Добавлено: Вт ноя 12, 2024 11:26:19
AlanDrakes
Кто как, а я опрашиваю кнопки в основном потоке, когда код ничего не делает (внутри while (1) { .... __WFI(); } ) обычно после выхода из сна, а флаг "пора проверить кнопки" выставляется таймером.
Но суть это не меняет. Логика примерно та же:
- Читаем состояние.
- Увеличиваем/уменьшаем переменную (софт-фильтр), если она в нормальных пределах. Если она в ОСОБЫХ значениях - то это нажатие или длительное нажатие (или даже повторы)
Псевдокод:
Код: Выделить всё
if (ButtonFilter[N] == BTN_PRESS_DURATION) {
DoPressCallback(N);
} else if (ButtonFilter[N] == BTN_LONG_PRESS_DURATION) {
DoLongPressCallback(N);
} else if (ButtonFilter[N] == BTN_LONG_PRESS_REPEAT_DURATION) {
DoPressRepeatCallback(N);
ButtonFilter[N] -= BTN_REPEAT_DURATION;
}
И условия:
0 < BTN_PRESS_DURATION < BTN_LONG_PRESS_DURATION < BTN_LONG_PRESS_REPEAT_DURATION
BTN_REPEAT_DURATION > 0
BTN_REPEAT_DURATION > (BTN_LONG_PRESS_REPEAT_DURATION - BTN_LONG_PRESS_DURATION)
Например, BTN_PRESS_DURATION = 50мс
BTN_LONG_PRESS_DURATION = 500мс
BTN_LONG_PRESS_REPEAT_DURATION = 800мс
BTN_REPEAT_DURATION = 200мс
Таким образом счётчик фильтра кнопки будет считать с нуля (у меня каждую милисекунду просыпается контроллер, ибо SysTickRate = 1kHz), на отметке 50мс после нажатия кнопки (считается, что антидребезг работает и устранил момент искрения контактов) сработает "Нажатие", затем через 450мс отработает "Длительное нажатие" (можно поднять до 1с), ещё через 300 запустятся повторы и счётчик будет сброшен на значение 600мс и продолжёт тикать вверх до 800, генерируя новый "повтор".
И так циклически, пока кнопку не отпустят.
Естественно, длительности нужно подбирать "под свои потребности"
Спойлер
Код: Выделить всё
#define BTN_FILTER 50
uint8_t Buttons_Tmr[3];
void ButtonsRd(void) {
// Power
if (GPIOA->IDR & GPIO_IDR_5) {
if (Buttons_Tmr[0] < BTN_FILTER * 5) {
Buttons_Tmr[0]++;
if (Buttons_Tmr[0] == BTN_FILTER * 5) {
Buttons_Tmr[0]++;
OnBtnPress(0);
}
}
} else {
if (Buttons_Tmr[0]) {
Buttons_Tmr[0]--;
}
}
// Next
if (GPIOA->IDR & GPIO_IDR_9) {
if (Buttons_Tmr[1] < BTN_FILTER) {
Buttons_Tmr[1]++;
if (Buttons_Tmr[1] == BTN_FILTER) {
Buttons_Tmr[1]++;
OnBtnPress(1);
}
}
} else {
if (Buttons_Tmr[1]) {
Buttons_Tmr[1]--;
}
}
// Mode
if (GPIOA->IDR & GPIO_IDR_10) {
if (Buttons_Tmr[2] < BTN_FILTER) {
Buttons_Tmr[2]++;
if (Buttons_Tmr[2] == BTN_FILTER) {
Buttons_Tmr[2]++;
timer = 0;
OnBtnPress(2);
}
}
} else {
if (Buttons_Tmr[2]) {
Buttons_Tmr[2]--;
}
}
}
int main(void) {
// Инициализация пропущена, оставлен только основной цикл
while(1) {
__WFI();
ButtonsRd();
Job();
}
}
Тут я НЕ использую длительные нажатия и прочие фокусы, но их можно добавить по желанию.
А тут - использую, но без повторов:
Код: Выделить всё
void ButtonFilfer(uint8_t ButtonNumber, uint8_t Direction) {
if (Direction) {
BtnFilter[ButtonNumber]++;
if (BtnFilter[ButtonNumber] == BUTTON_PRESS_DURATION) {
// OnPress()
OnButtonPress(ButtonNumber);
} else if (BtnFilter[ButtonNumber] == BUTTON_LONG_PRESS_DUR) {
// On LongPress()
OnButtonLongPress(ButtonNumber);
} else if (BtnFilter[ButtonNumber] > BUTTON_LONG_PRESS_DUR) {
BtnFilter[ButtonNumber] = BUTTON_LONG_PRESS_DUR;
}
} else {
if (BtnFilter[ButtonNumber]) {
BtnFilter[ButtonNumber] = 0;
OnButtonRelease(ButtonNumber);
} else {
BtnFilter[ButtonNumber] = 0;
OnButtonRelease(ButtonNumber);
}
}
}
Re: Обработка кнопок, EXTI[0]
Добавлено: Вт ноя 12, 2024 11:39:43
jcxz
[uquote="aleksey chilov",url="/forum/viewtopic.php?p=4648108#p4648108"]Потом просто хендлер с прерываниями по спаду и по фронту поднимает и опускает флажки при нажатии кнопок...[/uquote]1. Зачем сброс флагов - тремя операциями вместо одной?
2. Чтение GPIOA->IDR то же самое - зачем 6(!) чтений вместо одного???
3. Вместо прерывания EXTI лучше использовать периодическое прерывание.
При таком кривом обработчике прерываний иногда будут создаваться ситуации, когда кнопка оказывается залипшей в нажатом состоянии (или будут пропуски нажатий). Из-за того, что читаете GPIOA->IDR много раз вместо одного.
Подумайте - что будет, если кнопка изменит состояние между вашими чтениями?
PS: Для вставки кода здесь есть соответствующий тэг "Code". (вместо картинок)
Re: Обработка кнопок, EXTI[0]
Добавлено: Вт ноя 12, 2024 11:40:23
aleksey chilov
Обработчик у вас интересный. Пожалуй я его возьму к себе в проект. Только у меня контролер не спит но я могу поместить обработчик в хендлер по таймеру там у меня он на 100Гц настроен думаю этого вполне достаточно будет.
Re: Обработка кнопок, EXTI[0]
Добавлено: Вт ноя 12, 2024 11:52:54
jcxz
[uquote="aleksey chilov",url="/forum/viewtopic.php?p=4648108#p4648108"]Дальше настроил таймер 3 на 100Гц и в прерывании с частотой 100 ГЦ идёт опрос кнопок[/uquote]Зачем тогда EXTI, если уже есть периодическое прерывание?
Какой-то бурелом.....
Добавлено after 1 minute 55 seconds:
[uquote="Martian",url="/forum/viewtopic.php?p=4648152#p4648152"]А что, в АРМах теперь для флагов один бит нельзя? И проверки битов больше нет?[/uquote]Автор один и тот же порт, содержащий все кнопки, читает 6 раз! А вы про битовые переменные....
Он в принципе не понимает что такое "биты". Судя по коду.

Re: Обработка кнопок, EXTI[0]
Добавлено: Вт ноя 12, 2024 11:59:40
aleksey chilov
Чё вы несёте??? Какие 6 раз???
Там прерывание настроено по фронту и по спаду на каждый пин порта "А" который опрашивается. Порт в нуле флаг поднялся, второе прерывание когда порт в +3,3 когда кнопку бросил флаг сбросился чё не понятно какие 6 раз читайте внимательно что написанно
Re: Обработка кнопок, EXTI[0]
Добавлено: Вт ноя 12, 2024 12:01:54
jcxz
Примерно так:
Код: Выделить всё
enum {BUT_1, BUT_2, BUT_3, ...};
uint volatile buttons = 0;
void Isr()
{
EXTI->PR = EXTI_PR_PR5 | EXTI_PR_PR6 | EXTI_PR_PR7;
uint i = GPIOA->IDR, c = 0;
if (!(i & 1 << 7)) c += 1 << BUT_1;
if (!(i & 1 << 6)) c += 1 << BUT_2;
if (!(i & 1 << 5)) c += 1 << BUT_3;
buttons = c;
}
Также обращаем внимание на
volatile.
Re: Обработка кнопок, EXTI[0]
Добавлено: Вт ноя 12, 2024 12:02:08
aleksey chilov
EXTI настраивал дамал флагами как-то кнопки отслеживать но можно и без них я пробовал варианты какие лучше
Re: Обработка кнопок, EXTI[0]
Добавлено: Вт ноя 12, 2024 12:03:42
jcxz
[uquote="aleksey chilov",url="/forum/viewtopic.php?p=4648186#p4648186"]Чё вы несёте??? Какие 6 раз???[/uquote]"Несёте" это вы.
[uquote="aleksey chilov",url="/forum/viewtopic.php?p=4648186#p4648186"]чё не понятно какие 6 раз читайте внимательно что написанно[/uquote]Ясно. Гопник детектед.
Дальше в своём говнокоде бултыхайтесь сами.
Re: Обработка кнопок, EXTI[0]
Добавлено: Вт ноя 12, 2024 12:40:54
Martian
[uquote="aleksey chilov",url="/forum/viewtopic.php?p=4648190#p4648190"]EXTI настраивал думал флагами как-то кнопки отслеживать но можно и без них я пробовал варианты какие лучше[/uquote]
Это метод тыка. Даже если получите рабочий вариант, это не даст опыта и знаний.
Надо по науке: изучить язык, изучить контроллер, продумать алгоритм. И вот тогда идти на форум и спрашивать непонятное. Но, скорее всего, с таким вопросом уже не придёте - не будет непонятного, или же быстро разберётесь сами.
jcxz привёл код, так что, больше и говорить нечего.
Re: Обработка кнопок, EXTI[0]
Добавлено: Вт ноя 12, 2024 13:13:19
jcxz
[uquote="Martian",url="/forum/viewtopic.php?p=4648215#p4648215"]
jcxz привёл код, так что, больше и говорить нечего.[/uquote]По уму в той процедуре ещё хорошо бы после:
Код: Выделить всё
EXTI->PR = EXTI_PR_PR5 | EXTI_PR_PR6 | EXTI_PR_PR7;
добавить какую-то синхронизацию перед чтением IDR. Чтобы быть уверенным, что запись в EXTI->PR реально выполнилась к моменту чтения IDR.
Например так (обратным чтением):
Код: Выделить всё
EXTI->PR = EXTI_PR_PR5 | EXTI_PR_PR6 | EXTI_PR_PR7;
uint j = EXTI->PR;
uint i = GPIOA->IDR, c = 0;
...
Потому как EXTI и GPIO - разная периферия, а значит - может находиться на разных сегментах шин МК.
Иначе - есть вероятность сбросить событие переключения состояния кнопки до его чтения.
Но это уже - не для ТС. Ему - не читать. Иначе - есть опасность поумнеть.

Re: Обработка кнопок, EXTI[0]
Добавлено: Вт ноя 12, 2024 13:17:30
aleksey chilov
За код спасибо!
Меня и интересовали методы реализации опроса кнопок.
Хотел посмотреть кто как делает чтоб не придумывать то что давно придумано.
Ну ничего, разберёмся по маленьку...
Re: Обработка кнопок, EXTI[0]
Добавлено: Вт ноя 12, 2024 13:20:41
Adrift
[uquote="jcxz",url="/forum/viewtopic.php?p=4648189#p4648189"]
Код: Выделить всё
uint i = GPIOA->IDR, c = 0;
if (!(i & 1 << 7)) c += 1 << BUT_1;
if (!(i & 1 << 6)) c += 1 << BUT_2;
if (!(i & 1 << 5)) c += 1 << BUT_3;
buttons = c;
}
[/uquote]
Тут напрашивается функция которая будет битики переносить:
Код: Выделить всё
uint32_t i = GPIOA->IDR;
buttons = moveBit(i, 7, BUT_1) | moveBit(i, 6, BUT_2) | moveBit(i, 5, BUT_3);
Re: Обработка кнопок, EXTI[0]
Добавлено: Вт ноя 12, 2024 13:22:46
jcxz
[uquote="Adrift",url="/forum/viewtopic.php?p=4648233#p4648233"]Тут напрашивается функция которая будет битики переносить:
Код: Выделить всё
uint32_t i = GPIOA->IDR;
buttons = moveBit(i, 7, BUT_1) | moveBit(i, 6, BUT_2) | moveBit(i, 5, BUT_3);
[/uquote]Конечно, так лучше. Но для начинающих может быть уже сложно. Не все они знают - что такое
макросы.
Ещё лучше описать пины кнопок в хидере:
Код: Выделить всё
#define PIN_BUTTON1 A, 7
#define PIN_BUTTON2 A, 6
#define PIN_BUTTON3 A, 5
...
и ссылаться через них, а не через "магические числа".
PS: Это для тех, кто знает - что такое "макрос".

Re: Обработка кнопок, EXTI[0]
Добавлено: Вт ноя 12, 2024 13:35:34
Martian
buttons = GPIOA->IDR & mask;

Re: Обработка кнопок, EXTI[0]
Добавлено: Вт ноя 12, 2024 13:43:24
Adrift
[uquote="jcxz",url="/forum/viewtopic.php?p=4648234#p4648234"]Ещё лучше описать пины кнопок в хидере:
Код: Выделить всё
#define PIN_BUTTON1 A, 7
#define PIN_BUTTON2 A, 6
#define PIN_BUTTON3 A, 5
...
[/uquote]
Пины в хедере - это уже дикий оверхед, придется читать с порта по разу на каждую кнопку )