ps. Ага, мы битман портов вручную создаем и он будет ассоциирован с нашими пинами? Громоздкий C++ это все автоматически при компиляции делает, мне такое даже с голову сразу не пришло ) Хотя все равно не понятно... Если пина 3, а порт 1, то в битмапе портов будет один порт, но читать все равно нужно не GPIOx->IDR, который volatile, а значение уже прочитанное из него. Нужен рабочий пример )
Не думал что такой примитивный вопрос вызовет затруднения.....
ps. Ага, мы битман портов вручную создаем и он будет ассоциирован с нашими пинами? Громоздкий C++ это все автоматически при компиляции делает
Пример можно чего там наделает си++? Так, чтобы даже на минимальном уровне оптимизации было не более, чем в том листинге, что я привёл? Пример в студию!
Неужели Вы не видите, что это бред? Или в Вашем мк есть третий вариант результата проверки !GPIOA->IDR & (1 << 5) ? Какая религия запрещает написать Flag.VOL_minus = !(GPIOA->IDR & (1 << 5)); (я молчу про #define)
jcxz Если кнопки выведены на разные порты то "поштучного" чтения не избежать. Таковы условия к примеру для тех же адуринко нано/про-мини. В принципе не столь уж и проблема. Да и схемотехника/топология более удачного размещения компонентов порой свои условия диктует. Это не есть проблема или "некорректность" в данном случае.
aleksey chilov может пока разбирается с примитивом кнопок - каждая только свою фиксированную функцию выполнаяет (минимальный функционал типа настройки параметров -"влево/вправо" и "+/-"). Посему это всего лишь "простейшие кнопы" с минимальным алгоритмом:
по истечении интервала антидребезга (системные часы)
считал ЛВК привел данные к единообразию (собрал в байт) сверил с прошлым значением (буфер прошлого значения)
ЕСЛИ
совпало идем к функции исполнения (switch/case согласно текущего кода комбинации ЛВК )
не совпало заносим текущие данные в буфер прошлого значения и выход по фальстарту
А дальше по интересам (для менюшки посолиднее и/или "псевдовиндовс" на символьном двустрочнике придется заметно больше поизвращаться).
... а я бы всё-таки начал с того, что сохранил бы необходимую информацию в обработчике прерывания и сбежал бы из него от греха подальше. Впрочем, у меня с армами небогатый опыт, может, там прощается многое.
void f() { #if BTN_PORT_MAP & 1 << 0 uint iA = GPIOA->IDR; #endif #if BTN_PORT_MAP & 1 << 1 uint iB = GPIOB->IDR; #endif #if BTN_PORT_MAP & 1 << 2 uint iC = GPIOC->IDR; #endif ///... повторять по количеству портов в МК }}
Не, не, не. Так не честно ) Тут всего 3 пина, но при использовании приходится дублировать чтение IDR из десятка портов и это даже не весь код, а только собственно чтение из порта в переменные ) На C++ будет 2 строки:
Код:
Pins<PA_7, PA_6, PA_5> buttons;
void f() { buttons.write(~bt::read()); }
Читаем значения наших трех пинов, инвертируем, атомарно записываем обратно не трогая оставшиеся пины. Выхлоп:
Какое отношение это имеет к теме опроса ног - вообще непонятно.... Также очевидно, что ноги подключенные к кнопкам, настроены на ввод. Какой смысл в них что-то писать? Что это даст?
Выложили какую-то галиматью...... Мой код имеет точно тот же результат (просто чтение GPIO->IDR), но всего в одну команду. Вместо 5-и у вас.
Работа с флагами - заведомо тупиковая. Это хорошо для одиночных управляющих кнопок. Для группы кнопок при перспективе обработки комбинации нескольких одновременно нажатых (актуально для небольшого количества кнопок "джойстикового" типа и "оконного меню") такой подход только усложнит программу. (как нибудь в котуинке положу тестовый "псевдовиндовс" на референсе Си для адуринок под АВР и жирненький "двустрочник").
aleksey chilov, уже получше. Но запинаю - в таком виде это всё равно бессмысленно. Зачем лишние флаги, если GPIOA->IDR уже куда-то сохранён? И потом, если флаги Flag.SET_Ok и прочие разместить в том же порядке, в котором биты порта, то весь этот case опять заменяется на Flags.All = GPIOA->IDR; притом, так отловится и одновременное нажатие. Вы же в курсе по указатели, структуры, объединения, битовые поля?
Имеется в виду, что даже для всего лишь трех пинов придется написать 30 строк только для чтения IDR в переменные.
jcxz писал(а):
А где код? Верить на слово? Очевидно что фраза про "2 строки" - ложь.
Очевидно, что я посчитал число строк исключая "f() {}", то есть только строки где идет работа с пинами. Код не мой, писал товарищ, могу спросить можно ли его выложить, надо? Впрочем, я его понимаю на 90%, большинство остальных поймут на 10% ) Ваша недооценка возможностей C++ пропорциональна его незнанию, еще и помноженная на скептицизм, в таком случае за подобной сложности код можно даже и не браться.
jcxz писал(а):
код этот ваш делает следующую операцию:
Код:
u32 *p = ...; p[6] = ~p[4] & 0xE0 | 0xE00000;
Какое отношение это имеет к теме опроса ног - вообще непонятно.... Также очевидно, что ноги подключенные к кнопкам, настроены на ввод. Какой смысл в них что-то писать? Что это даст?
Это же пример, скучно просто читать с порта ) Естественно пины были сконфигурированы на вывод. В данном случае у нас 3 подряд идущих пина, а может быть 30, с разных портов, в любом порядке, и этот мой код продолжит работать без никаких модификаций. То что результат выглядит как простое чтение из порта с накладыванием маски и записью обратно лишь подтверждает оптимизирующую природу используемого алгоритма, либа научена искать подобные маски которыми можно выделить побольше бит и сдвинуть их за раз в нужные позиции. Даже эти три пина после чтения оказываются в трех младших битах результата, просто write() все сдвинула обратно и оптимизатор сдвиги вообще убрал )
Зарегистрирован: Вс мар 27, 2022 09:38:17 Сообщений: 167
Рейтинг сообщения:0
Добрый день! Хочу продолжить тему кнопочек. Я подумал, и что-то придумал. Наверное опять будете меня закидывать помидорами и оскорблять но всё же, посмотрите что я сделал и скажите что-то. Ведь если ругают значит есть повод подумать и устранить ошибки.
void EXTI9_5_IRQHandler(void){ EXTI->PR = (EXTI_PR_PR5|EXTI_PR_PR6|EXTI_PR_PR7); // Сбросить флаг прерывания! asm("nop"); // Пропуск для установки флага asm("nop"); // Пропуск для установки флага Flag.Butoon = true; // Нажата одна из кнопок }
Вот тут в этом хендлере флагу "Flag.Butoon" присваивается true. Этот флаг будет использоваться в функции которая будет обрабатывать кнопки. Если флаг будет false то когда в обработчике дойдёт очередь до этой функции, в неё зайдёт и сразу выедет тем самым сократится количество манипуляций. Если true тогда обработает и присвоит код кнопки переменной которая была нажата 1,2,3 и в конце сбросит флаг "Flag.Butoon".
if(!(GPIOA->IDR & (1 << 5))){ *key_kod = 3; } *Survey = false; // Сбросить после обработки } } Собственно сама функция, тут в ней обработка кнопок. Через указатели дотягиваемся до флага и переменной и изменяем их если нужно.
Этот хендлер для таймера. Таймер настроен на 100Гц. Собственно там вызываются 2 функции. Первая это для кнопок а вторая вычисляет и усредняет данные от ADC через DMA для стабильной работы.
Всё. Пока что вот так сделал. Теперь критика ваша, жду...
Посмотрите, это форум. Ни у кого нет цели оскорблять. Только направление на размышление даем. Напр. смотрю на собственный код из прошлом и задаюсь вопросом: так ли я ето написал? Если рядом был человек, то он мог бы дать направление, и путь будет "короче". Если нет человека, то в интернете, или со своим опытом. Но второй способ происходит значительно медленнее. Так что как решите, так и делайте. Цель одна - сокращенный, чистый код, который впоследствии пригодится вам в других проектах. МК не интересует способ составления алгоритма. Для небольших проектов будет ОК. А вот в больших проектах (и при максимальном использовании ресурсов) будет от: медленного режима до невозможности работы. А когда меняешь начина построяния в коде на другой принцип, алгоритм, вдруг все ОК. (частично использую переводчика) ---
прочитали статус порта 3 раза. Если статус изменился во время чтения? (спомните проблем bounce для кнопки). Как вариант: прочитайте порт раз, присвойте значение переменной, затем отфильтруйте ее значение по кнопок.
прочитали статус порта 3 раза. Если статус изменился во время чтения? (спомните проблем bounce для кнопки).
В текущей реализации ТС из-за дребезга можно прочитать одни единички и пропустить нажатие вообще, даже с одной кнопкой. В нормальном случае, со счетчиком для отдельной кнопки или для всех сразу, без разницы сколько раз читать с портов, три чтения GPIOA->IDR ничем не отличаются от чтения GPIOA->IDR + GPIOB->IDR + GPIOC->IDR, если кнопки будут на разных портах.
неужели не видно, что опять можно просто присвоить key_kod`у состояние трёх битов GPIOA->IDR (с маской) за один раз? Более того, они ведь даже подряд идут, если очень хочется, можно даже сделать сдвиг всех трёх и получить 1, 2, 3, если это жизненно важно. Зачем делать три условия? печально всё это...
Вы не можете начинать темы Вы не можете отвечать на сообщения Вы не можете редактировать свои сообщения Вы не можете удалять свои сообщения Вы не можете добавлять вложения