Например TDA7294

Форум РадиоКот :: Просмотр темы - Обработка кнопок, EXTI[0]
Форум РадиоКот
https://radiokot.ru/forum/

Обработка кнопок, EXTI[0]
https://radiokot.ru/forum/viewtopic.php?f=59&t=195560
Страница 1 из 4

Автор:  aleksey chilov [ Пн ноя 11, 2024 17:16:30 ]
Заголовок сообщения:  Обработка кнопок, EXTI[0]

Добрый вечер кому как.
Подскажите пожалуйста варианты обработки кнопочек, для меню.
Спасибо.

Автор:  Аlex [ Пн ноя 11, 2024 18:51:07 ]
Заголовок сообщения:  Re: Обработка кнопок, EXTI[0]

Покажите свои варианты, а мы оценим :)

Автор:  BOB51 [ Пн ноя 11, 2024 19:36:46 ]
Заголовок сообщения:  Re: Обработка кнопок, EXTI[0]

Вариантов огромное множество.
Зависит от схемы, компилятора и идеи самого устройства.
8)

Автор:  aleksey chilov [ Вт ноя 12, 2024 07:34:19 ]
Заголовок сообщения:  Re: Обработка кнопок, EXTI[0]

Ну, тут просто флаги и переменные...

Изображение

Добавлено 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 ..

Автор:  Martian [ Вт ноя 12, 2024 10:39:49 ]
Заголовок сообщения:  Re: Обработка кнопок, EXTI[0]

А что, в АРМах теперь для флагов один бит нельзя? И проверки битов больше нет?

Автор:  AlanDrakes [ Вт ноя 12, 2024 11:26:19 ]
Заголовок сообщения:  Re: Обработка кнопок, EXTI[0]

Кто как, а я опрашиваю кнопки в основном потоке, когда код ничего не делает (внутри 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);
      }
   }
}

Автор:  jcxz [ Вт ноя 12, 2024 11:39:43 ]
Заголовок сообщения:  Re: Обработка кнопок, EXTI[0]

Потом просто хендлер с прерываниями по спаду и по фронту поднимает и опускает флажки при нажатии кнопок...
1. Зачем сброс флагов - тремя операциями вместо одной?
2. Чтение GPIOA->IDR то же самое - зачем 6(!) чтений вместо одного??? :shock:
3. Вместо прерывания EXTI лучше использовать периодическое прерывание.

При таком кривом обработчике прерываний иногда будут создаваться ситуации, когда кнопка оказывается залипшей в нажатом состоянии (или будут пропуски нажатий). Из-за того, что читаете GPIOA->IDR много раз вместо одного.
Подумайте - что будет, если кнопка изменит состояние между вашими чтениями?

PS: Для вставки кода здесь есть соответствующий тэг "Code". (вместо картинок)

Автор:  aleksey chilov [ Вт ноя 12, 2024 11:40:23 ]
Заголовок сообщения:  Re: Обработка кнопок, EXTI[0]

Обработчик у вас интересный. Пожалуй я его возьму к себе в проект. Только у меня контролер не спит но я могу поместить обработчик в хендлер по таймеру там у меня он на 100Гц настроен думаю этого вполне достаточно будет.

Автор:  jcxz [ Вт ноя 12, 2024 11:52:54 ]
Заголовок сообщения:  Re: Обработка кнопок, EXTI[0]

Дальше настроил таймер 3 на 100Гц и в прерывании с частотой 100 ГЦ идёт опрос кнопок
Зачем тогда EXTI, если уже есть периодическое прерывание?
Какой-то бурелом..... :facepalm:

Добавлено after 1 minute 55 seconds:
А что, в АРМах теперь для флагов один бит нельзя? И проверки битов больше нет?
Автор один и тот же порт, содержащий все кнопки, читает 6 раз! А вы про битовые переменные.... 8)
Он в принципе не понимает что такое "биты". Судя по коду. :dont_know:

Автор:  aleksey chilov [ Вт ноя 12, 2024 11:59:40 ]
Заголовок сообщения:  Re: Обработка кнопок, EXTI[0]

Чё вы несёте??? Какие 6 раз???
Там прерывание настроено по фронту и по спаду на каждый пин порта "А" который опрашивается. Порт в нуле флаг поднялся, второе прерывание когда порт в +3,3 когда кнопку бросил флаг сбросился чё не понятно какие 6 раз читайте внимательно что написанно

Автор:  jcxz [ Вт ноя 12, 2024 12:01:54 ]
Заголовок сообщения:  Re: Обработка кнопок, EXTI[0]

Примерно так:
Код:
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.

Автор:  aleksey chilov [ Вт ноя 12, 2024 12:02:08 ]
Заголовок сообщения:  Re: Обработка кнопок, EXTI[0]

EXTI настраивал дамал флагами как-то кнопки отслеживать но можно и без них я пробовал варианты какие лучше

Автор:  jcxz [ Вт ноя 12, 2024 12:03:42 ]
Заголовок сообщения:  Re: Обработка кнопок, EXTI[0]

Чё вы несёте??? Какие 6 раз???
"Несёте" это вы.

чё не понятно какие 6 раз читайте внимательно что написанно
Ясно. Гопник детектед.
Дальше в своём говнокоде бултыхайтесь сами.

Автор:  Martian [ Вт ноя 12, 2024 12:40:54 ]
Заголовок сообщения:  Re: Обработка кнопок, EXTI[0]

EXTI настраивал думал флагами как-то кнопки отслеживать но можно и без них я пробовал варианты какие лучше

Это метод тыка. Даже если получите рабочий вариант, это не даст опыта и знаний.
Надо по науке: изучить язык, изучить контроллер, продумать алгоритм. И вот тогда идти на форум и спрашивать непонятное. Но, скорее всего, с таким вопросом уже не придёте - не будет непонятного, или же быстро разберётесь сами.
jcxz привёл код, так что, больше и говорить нечего.

Автор:  jcxz [ Вт ноя 12, 2024 13:13:19 ]
Заголовок сообщения:  Re: Обработка кнопок, EXTI[0]

jcxz привёл код, так что, больше и говорить нечего.
По уму в той процедуре ещё хорошо бы после:
Код:
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 - разная периферия, а значит - может находиться на разных сегментах шин МК.
Иначе - есть вероятность сбросить событие переключения состояния кнопки до его чтения.

Но это уже - не для ТС. Ему - не читать. Иначе - есть опасность поумнеть. 8)

Автор:  aleksey chilov [ Вт ноя 12, 2024 13:17:30 ]
Заголовок сообщения:  Re: Обработка кнопок, EXTI[0]

За код спасибо!
Меня и интересовали методы реализации опроса кнопок.
Хотел посмотреть кто как делает чтоб не придумывать то что давно придумано.
Ну ничего, разберёмся по маленьку...

Автор:  Adrift [ Вт ноя 12, 2024 13:20:41 ]
Заголовок сообщения:  Re: Обработка кнопок, EXTI[0]

Код:
  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;
}

Тут напрашивается функция которая будет битики переносить:
Код:
uint32_t i = GPIOA->IDR;
buttons = moveBit(i, 7, BUT_1) | moveBit(i, 6, BUT_2) | moveBit(i, 5, BUT_3);

Автор:  jcxz [ Вт ноя 12, 2024 13:22:46 ]
Заголовок сообщения:  Re: Обработка кнопок, EXTI[0]

Тут напрашивается функция которая будет битики переносить:
Код:
uint32_t i = GPIOA->IDR;
buttons = moveBit(i, 7, BUT_1) | moveBit(i, 6, BUT_2) | moveBit(i, 5, BUT_3);
Конечно, так лучше. Но для начинающих может быть уже сложно. Не все они знают - что такое макросы. :wink:

Ещё лучше описать пины кнопок в хидере:
Код:
#define PIN_BUTTON1        A, 7
#define PIN_BUTTON2        A, 6
#define PIN_BUTTON3        A, 5
...
и ссылаться через них, а не через "магические числа".
PS: Это для тех, кто знает - что такое "макрос". :wink:

Автор:  Martian [ Вт ноя 12, 2024 13:35:34 ]
Заголовок сообщения:  Re: Обработка кнопок, EXTI[0]

buttons = GPIOA->IDR & mask; ;)

Автор:  Adrift [ Вт ноя 12, 2024 13:43:24 ]
Заголовок сообщения:  Re: Обработка кнопок, EXTI[0]

Ещё лучше описать пины кнопок в хидере:
Код:
#define PIN_BUTTON1        A, 7
#define PIN_BUTTON2        A, 6
#define PIN_BUTTON3        A, 5
...

Пины в хедере - это уже дикий оверхед, придется читать с порта по разу на каждую кнопку )

Страница 1 из 4 Часовой пояс: UTC + 3 часа
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group
http://www.phpbb.com/