Зарегистрирован: Вс мар 27, 2022 09:38:17 Сообщений: 160
Рейтинг сообщения: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 ..
Компания MEAN WELL пополнила ассортимент своей широкой линейки светодиодных драйверов новым семейством XLC для внутреннего освещения. Главное отличие – поддержка широкого спектра проводных и беспроводных технологий диммирования. Новинки представлены в MEANWELL.market моделями с мощностями 25 Вт, 40 Вт и 60 Вт. В линейке есть модели, работающие как в режиме стабилизации тока (СС), так и в режиме стабилизации напряжения (CV) значением 12, 24 и 48 В.
Кто как, а я опрашиваю кнопки в основном потоке, когда код ничего не делает (внутри 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; }
Таким образом счётчик фильтра кнопки будет считать с нуля (у меня каждую милисекунду просыпается контроллер, ибо 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); } } }
Потом просто хендлер с прерываниями по спаду и по фронту поднимает и опускает флажки при нажатии кнопок...
1. Зачем сброс флагов - тремя операциями вместо одной? 2. Чтение GPIOA->IDR то же самое - зачем 6(!) чтений вместо одного??? 3. Вместо прерывания EXTI лучше использовать периодическое прерывание.
При таком кривом обработчике прерываний иногда будут создаваться ситуации, когда кнопка оказывается залипшей в нажатом состоянии (или будут пропуски нажатий). Из-за того, что читаете GPIOA->IDR много раз вместо одного. Подумайте - что будет, если кнопка изменит состояние между вашими чтениями?
PS: Для вставки кода здесь есть соответствующий тэг "Code". (вместо картинок)
Последний раз редактировалось jcxz Вт ноя 12, 2024 11:43:16, всего редактировалось 2 раз(а).
Зарегистрирован: Вс мар 27, 2022 09:38:17 Сообщений: 160
Рейтинг сообщения:0
Обработчик у вас интересный. Пожалуй я его возьму к себе в проект. Только у меня контролер не спит но я могу поместить обработчик в хендлер по таймеру там у меня он на 100Гц настроен думаю этого вполне достаточно будет.
А что, в АРМах теперь для флагов один бит нельзя? И проверки битов больше нет?
Автор один и тот же порт, содержащий все кнопки, читает 6 раз! А вы про битовые переменные.... Он в принципе не понимает что такое "биты". Судя по коду.
Зарегистрирован: Вс мар 27, 2022 09:38:17 Сообщений: 160
Рейтинг сообщения:0
Чё вы несёте??? Какие 6 раз??? Там прерывание настроено по фронту и по спаду на каждый пин порта "А" который опрашивается. Порт в нуле флаг поднялся, второе прерывание когда порт в +3,3 когда кнопку бросил флаг сбросился чё не понятно какие 6 раз читайте внимательно что написанно
EXTI настраивал думал флагами как-то кнопки отслеживать но можно и без них я пробовал варианты какие лучше
Это метод тыка. Даже если получите рабочий вариант, это не даст опыта и знаний. Надо по науке: изучить язык, изучить контроллер, продумать алгоритм. И вот тогда идти на форум и спрашивать непонятное. Но, скорее всего, с таким вопросом уже не придёте - не будет непонятного, или же быстро разберётесь сами. jcxz привёл код, так что, больше и говорить нечего.
добавить какую-то синхронизацию перед чтением 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 - разная периферия, а значит - может находиться на разных сегментах шин МК. Иначе - есть вероятность сбросить событие переключения состояния кнопки до его чтения.
Но это уже - не для ТС. Ему - не читать. Иначе - есть опасность поумнеть.
Зарегистрирован: Вс мар 27, 2022 09:38:17 Сообщений: 160
Рейтинг сообщения:0
За код спасибо! Меня и интересовали методы реализации опроса кнопок. Хотел посмотреть кто как делает чтоб не придумывать то что давно придумано. Ну ничего, разберёмся по маленьку...
Последний раз редактировалось aleksey chilov Вт ноя 12, 2024 13:23:59, всего редактировалось 1 раз.
Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 18
Вы не можете начинать темы Вы не можете отвечать на сообщения Вы не можете редактировать свои сообщения Вы не можете удалять свои сообщения Вы не можете добавлять вложения