Обработка кнопок, EXTI[0]

Кто любит RISC в жизни, заходим, не стесняемся.
jcxz
Мудрый кот
Сообщения: 1717
Зарегистрирован: Вт авг 15, 2017 10:51:13

Re: Обработка кнопок, EXTI[0]

Сообщение jcxz »

[uquote="Adrift",url="/forum/viewtopic.php?p=4648350#p4648350"]ps. Ага, мы битман портов вручную создаем и он будет ассоциирован с нашими пинами? Громоздкий C++ это все автоматически при компиляции делает, мне такое даже с голову сразу не пришло ) Хотя все равно не понятно... Если пина 3, а порт 1, то в битмапе портов будет один порт, но читать все равно нужно не GPIOx->IDR, который volatile, а значение уже прочитанное из него. Нужен рабочий пример )[/uquote]Не думал что такой примитивный вопрос вызовет затруднения..... :facepalm:

Код: Выделить всё

//.h
#define PIN_BUTTON1 A, 7
#define PIN_BUTTON2 A, 6
#define PIN_BUTTON3 A, 5
//.cpp
#define PIOIX_A 0
#define PIOIX_B 1
#define PIOIX_C 2
#define PIOIX_D 3
#define PIOIX_E 4
#define PIOIX_F 5
#define PIOIX_G 6
#define PIOIX_H 7
#define PIOIX_I 8
#define PIOIX_J 9
#define PIOIX_K 10
#define PORT_IX2(port, pin)  PIOIX_##port
#define PORT_IX(port_pin)    PORT_IX2(port_pin)
#define BTN_PORT_MAP (1u << PORT_IX(PIN_BUTTON1) | 1u << PORT_IX(PIN_BUTTON2) | 1u << PORT_IX(PIN_BUTTON3))

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
  ///... повторять по количеству портов в МК                                                       
}
листинг:

Код: Выделить всё

                  _Z1fv: (+1)                                                      
00000000   0x....             LDR.N    R0,??DataTable23_10  ;; 0x40020000          
00000002   0x6900             LDR      R0,[R0, #+16]                               
00000004   0x4770             BX       LR}
Как видно - чтение порта одно-единственное.

Более на примитивные вопросы не отвечаю. Учимся думать самостоятельно.

[uquote="Adrift",url="/forum/viewtopic.php?p=4648350#p4648350"]ps. Ага, мы битман портов вручную создаем и он будет ассоциирован с нашими пинами? Громоздкий C++ это все автоматически при компиляции делает[/uquote]Пример можно чего там наделает си++? Так, чтобы даже на минимальном уровне оптимизации было не более, чем в том листинге, что я привёл?
Пример в студию! 8)

Добавлено after 5 minutes 23 seconds:
[uquote="aleksey chilov",url="/forum/viewtopic.php?p=4648355#p4648355"]Давайте умники![/uquote]На паперти подадут.

Добавлено after 2 minutes 2 seconds:
[uquote="BOB51",url="/forum/viewtopic.php?p=4648357#p4648357"]Не все ли равно, сколько раз читать данные с ЛВК в буфер результата (одной операцией с единого порта или собирать в несколько приемов в общий буфер[/uquote]Не всё равно. Смотрим на тот говнокод, что написал ТС и думаем почему.

PS: Ответ "почему" уж был дан ранее.
Реклама
Martian
Друг Кота
Сообщения: 12867
Зарегистрирован: Сб дек 18, 2021 19:25:32
Контактная информация:

Re: Обработка кнопок, EXTI[0]

Сообщение Martian »

[uquote="aleksey chilov",url="/forum/viewtopic.php?p=4648368#p4648368"]for конечно...[/uquote]так почему Вы здесь пишите:

if(!(GPIOA->IDR & (1 << 5))){ // Кнопка V-
Flag.VOL_minus = true;

}else if((GPIOA->IDR & (1 << 5))){
Flag.VOL_minus = false;
}

Неужели Вы не видите, что это бред? Или в Вашем мк есть третий вариант результата проверки !GPIOA->IDR & (1 << 5) ? Какая религия запрещает написать Flag.VOL_minus = !(GPIOA->IDR & (1 << 5)); (я молчу про #define)
Реклама
jcxz
Мудрый кот
Сообщения: 1717
Зарегистрирован: Вт авг 15, 2017 10:51:13

Re: Обработка кнопок, EXTI[0]

Сообщение jcxz »

[uquote="Martian",url="/forum/viewtopic.php?p=4648382#p4648382"]if(!(GPIOA->IDR & (1 << 5))){ // Кнопка V-
Flag.VOL_minus = true;

}else if((GPIOA->IDR & (1 << 5))){
Flag.VOL_minus = false;
}

Неужели Вы не видите, что это бред?)[/uquote]До человека совершенно не доходит, что между двумя чтениями сигнал может измениться. С "1" на "0" например. :facepalm:
Martian
Друг Кота
Сообщения: 12867
Зарегистрирован: Сб дек 18, 2021 19:25:32
Контактная информация:

Re: Обработка кнопок, EXTI[0]

Сообщение Martian »

Может, наоборот, он именно это учитывает :)
Реклама
Эиком - электронные компоненты и радиодетали
jcxz
Мудрый кот
Сообщения: 1717
Зарегистрирован: Вт авг 15, 2017 10:51:13

Re: Обработка кнопок, EXTI[0]

Сообщение jcxz »

[uquote="Martian",url="/forum/viewtopic.php?p=4648384#p4648384"]Может, наоборот, он именно это учитывает :)[/uquote]Если будет переход "1"->"0" то при такой "проверке" событие изменения сост.пина может быть потеряно.
Реклама
Аватара пользователя
BOB51
Друг Кота
Сообщения: 15565
Зарегистрирован: Вт мар 16, 2010 22:02:27
Откуда: ДОНЕЦК

Re: Обработка кнопок, EXTI[0]

Сообщение BOB51 »

jcxz Если кнопки выведены на разные порты то "поштучного" чтения не избежать.
Таковы условия к примеру для тех же адуринко нано/про-мини.
В принципе не столь уж и проблема. Да и схемотехника/топология более удачного размещения компонентов порой свои условия диктует. Это не есть проблема или "некорректность" в данном случае.

aleksey chilov может пока разбирается с примитивом кнопок - каждая только свою фиксированную функцию выполнаяет (минимальный функционал типа настройки параметров -"влево/вправо" и "+/-").
Посему это всего лишь "простейшие кнопы" с минимальным алгоритмом:

по истечении интервала антидребезга (системные часы)

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

ЕСЛИ

совпало
идем к функции исполнения (switch/case согласно текущего кода комбинации ЛВК :sleep: )

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

А дальше по интересам (для менюшки посолиднее и/или "псевдовиндовс" на символьном двустрочнике придется заметно больше поизвращаться).
8)
Реклама
Martian
Друг Кота
Сообщения: 12867
Зарегистрирован: Сб дек 18, 2021 19:25:32
Контактная информация:

Re: Обработка кнопок, EXTI[0]

Сообщение Martian »

... а я бы всё-таки начал с того, что сохранил бы необходимую информацию в обработчике прерывания и сбежал бы из него от греха подальше. Впрочем, у меня с армами небогатый опыт, может, там прощается многое.
Adrift
Вымогатель припоя
Сообщения: 541
Зарегистрирован: Вт окт 01, 2024 15:22:33

Re: Обработка кнопок, EXTI[0]

Сообщение Adrift »

[uquote="jcxz",url="/forum/viewtopic.php?p=4648372#p4648372"]Не думал что такой примитивный вопрос вызовет затруднения..... :facepalm:
Спойлер

Код: Выделить всё

#define PIN_BUTTON1 A, 7
#define PIN_BUTTON2 A, 6
#define PIN_BUTTON3 A, 5
//.cpp
#define PIOIX_A 0
#define PIOIX_B 1
#define PIOIX_C 2
#define PIOIX_D 3
#define PIOIX_E 4
#define PIOIX_F 5
#define PIOIX_G 6
#define PIOIX_H 7
#define PIOIX_I 8
#define PIOIX_J 9
#define PIOIX_K 10
#define PORT_IX2(port, pin)  PIOIX_##port
#define PORT_IX(port_pin)    PORT_IX2(port_pin)
#define BTN_PORT_MAP (1u << PORT_IX(PIN_BUTTON1) | 1u << PORT_IX(PIN_BUTTON2) | 1u << PORT_IX(PIN_BUTTON3))

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
  ///... повторять по количеству портов в МК                                                       
}}
[/uquote]
Не, не, не. Так не честно ) Тут всего 3 пина, но при использовании приходится дублировать чтение IDR из десятка портов и это даже не весь код, а только собственно чтение из порта в переменные ) На C++ будет 2 строки:

Код: Выделить всё

Pins<PA_7, PA_6, PA_5> buttons;

void f()
{
    buttons.write(~bt::read());
}
Читаем значения наших трех пинов, инвертируем, атомарно записываем обратно не трогая оставшиеся пины. Выхлоп:

Код: Выделить всё

04 4A          ldr r2, [pc, #16]
13 69          ldr r3, [r2, #16] 
DB 43          mvns r3, r3 
03 F0 E0 03    and.w r3, r3, #224
43 F4 60 03    orr.w r3, r3, #14680064
93 61          str r3, [r2, #24] 
70 47          bx lr 
jcxz
Мудрый кот
Сообщения: 1717
Зарегистрирован: Вт авг 15, 2017 10:51:13

Re: Обработка кнопок, EXTI[0]

Сообщение jcxz »

[uquote="Adrift",url="/forum/viewtopic.php?p=4648416#p4648416"]Не, не, не. Так не честно ) Тут всего 3 пина, но при использовании приходится дублировать чтение IDR из десятка портов[/uquote]Вы сами просили для 3-х.

[uquote="Adrift",url="/forum/viewtopic.php?p=4648416#p4648416"]На C++ будет 2 строки:

Код: Выделить всё

Pins<PA_7, PA_6, PA_5> buttons;

void f()
{
    buttons.write(~bt::read());
}
[/uquote]
А где код? Верить на слово?
Очевидно что фраза про "2 строки" - ложь.


[uquote="Adrift",url="/forum/viewtopic.php?p=4648416#p4648416"]Читаем значения наших трех пинов, инвертируем, атомарно записываем обратно не трогая оставшиеся пины. Выхлоп:

Код: Выделить всё

04 4A          ldr r2, [pc, #16]
13 69          ldr r3, [r2, #16] 
DB 43          mvns r3, r3 
03 F0 E0 03    and.w r3, r3, #224
43 F4 60 03    orr.w r3, r3, #14680064
93 61          str r3, [r2, #24] 
70 47          bx lr 
[/uquote]код этот ваш делает следующую операцию:

Код: Выделить всё

u32 *p = ...;
p[6] = ~p[4] & 0xE0 | 0xE00000;
Какое отношение это имеет к теме опроса ног - вообще непонятно.... :dont_know:
Также очевидно, что ноги подключенные к кнопкам, настроены на ввод. Какой смысл в них что-то писать? Что это даст?

Выложили какую-то галиматью......
Мой код имеет точно тот же результат (просто чтение GPIO->IDR), но всего в одну команду. Вместо 5-и у вас. :)))
aleksey chilov
Нашел транзистор. Понюхал.
Сообщения: 167
Зарегистрирован: Вс мар 27, 2022 09:38:17

Re: Обработка кнопок, EXTI[0]

Сообщение aleksey chilov »

Gl.Registr = GPIOA->IDR;
switch(Gl.Registr){
case 0xFF76:
Flag.SET_Ok = true;
break;
case 0xFFB6:
Flag.VOL_plus = true;
break;
case 0xFFD6:
Flag.VOL_minus = true;
break;
case 0xFFF6:
Flag.SET_Ok = false;
Flag.VOL_plus = false;
Flag.VOL_minus = false;
break;
}

Добавлено after 55 seconds:
Сделал вот так.
Может быть опять запинаете но в отладчике работает
Sergi
Мучитель микросхем
Сообщения: 412
Зарегистрирован: Ср янв 04, 2012 11:57:40
Откуда: Алчевск

Re: Обработка кнопок, EXTI[0]

Сообщение Sergi »

Ну как минимум нужно наложить маску на IDR иначе может быть беда.
Аватара пользователя
BOB51
Друг Кота
Сообщения: 15565
Зарегистрирован: Вт мар 16, 2010 22:02:27
Откуда: ДОНЕЦК

Re: Обработка кнопок, EXTI[0]

Сообщение BOB51 »

Работа с флагами - заведомо тупиковая.
Это хорошо для одиночных управляющих кнопок. Для группы кнопок при перспективе обработки комбинации нескольких одновременно нажатых (актуально для небольшого количества кнопок "джойстикового" типа и "оконного меню") такой подход только усложнит программу.
8)
(как нибудь в котуинке положу тестовый "псевдовиндовс" на референсе Си для адуринок под АВР и жирненький "двустрочник").
:sleep:
Martian
Друг Кота
Сообщения: 12867
Зарегистрирован: Сб дек 18, 2021 19:25:32
Контактная информация:

Re: Обработка кнопок, EXTI[0]

Сообщение Martian »

aleksey chilov, уже получше. Но запинаю - в таком виде это всё равно бессмысленно. Зачем лишние флаги, если GPIOA->IDR уже куда-то сохранён? И потом, если флаги Flag.SET_Ok и прочие разместить в том же порядке, в котором биты порта, то весь этот case опять заменяется на
Flags.All = GPIOA->IDR; притом, так отловится и одновременное нажатие.
Вы же в курсе по указатели, структуры, объединения, битовые поля?

...и всё ещё без #define...
Adrift
Вымогатель припоя
Сообщения: 541
Зарегистрирован: Вт окт 01, 2024 15:22:33

Re: Обработка кнопок, EXTI[0]

Сообщение Adrift »

[uquote="jcxz",url="/forum/viewtopic.php?p=4648434#p4648434"]Вы сами просили для 3-х.[/uquote]
Имеется в виду, что даже для всего лишь трех пинов придется написать 30 строк только для чтения IDR в переменные.
jcxz писал(а):А где код? Верить на слово?
Очевидно что фраза про "2 строки" - ложь.
Очевидно, что я посчитал число строк исключая "f() {}", то есть только строки где идет работа с пинами. Код не мой, писал товарищ, могу спросить можно ли его выложить, надо? Впрочем, я его понимаю на 90%, большинство остальных поймут на 10% ) Ваша недооценка возможностей C++ пропорциональна его незнанию, еще и помноженная на скептицизм, в таком случае за подобной сложности код можно даже и не браться.
jcxz писал(а):код этот ваш делает следующую операцию:

Код: Выделить всё

u32 *p = ...;
p[6] = ~p[4] & 0xE0 | 0xE00000;
Какое отношение это имеет к теме опроса ног - вообще непонятно.... :dont_know:
Также очевидно, что ноги подключенные к кнопкам, настроены на ввод. Какой смысл в них что-то писать? Что это даст?
Это же пример, скучно просто читать с порта ) Естественно пины были сконфигурированы на вывод.
В данном случае у нас 3 подряд идущих пина, а может быть 30, с разных портов, в любом порядке, и этот мой код продолжит работать без никаких модификаций. То что результат выглядит как простое чтение из порта с накладыванием маски и записью обратно лишь подтверждает оптимизирующую природу используемого алгоритма, либа научена искать подобные маски которыми можно выделить побольше бит и сдвинуть их за раз в нужные позиции. Даже эти три пина после чтения оказываются в трех младших битах результата, просто write() все сдвинула обратно и оптимизатор сдвиги вообще убрал )
veso74
Поставщик валерьянки для Кота
Сообщения: 1907
Зарегистрирован: Сб май 05, 2012 20:24:52
Откуда: KN34PC, Болгария
Контактная информация:

Re: Обработка кнопок, EXTI[0]

Сообщение veso74 »

Код: Выделить всё

switch(Gl.Registr){
case 0xFF76: ...
case 0xFFB6: ... 
case 0xFFF6: ... 
}
Это серьезно? И через напр. 5 дней будете смотреть на код и удивляться, кто ее написал ... и что он хотел сделать ...
aleksey chilov
Нашел транзистор. Понюхал.
Сообщения: 167
Зарегистрирован: Вс мар 27, 2022 09:38:17

Re: Обработка кнопок, EXTI[0]

Сообщение aleksey chilov »

Добрый день!
Хочу продолжить тему кнопочек.
Я подумал, и что-то придумал.
Наверное опять будете меня закидывать помидорами и оскорблять но всё же,
посмотрите что я сделал и скажите что-то. Ведь если ругают значит есть повод подумать и
устранить ошибки.

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".

Дальше...

void Key_handler(bool *Survey, uint8_t *key_kod){
if(!*Survey)return;

if(*Survey){
if(!(GPIOA->IDR & (1 << 7))){
*key_kod = 1;
}

if(!(GPIOA->IDR & (1 << 6))){
*key_kod = 2;
}

if(!(GPIOA->IDR & (1 << 5))){
*key_kod = 3;
}
*Survey = false; // Сбросить после обработки
}
}
Собственно сама функция, тут в ней обработка кнопок.
Через указатели дотягиваемся до флага и переменной и изменяем их если нужно.

Дальше...

void TIM3_IRQHandler(void){
if(READ_BIT(TIM3->SR,TIM_SR_UIF) == 1)
CLEAR_BIT(TIM3->SR,TIM_SR_UIF);
Key_handler(&Flag.Butoon, &Gl.Key_stat);
Calculation_ADC(&Gl.ADC_res_Battrey, 0);
}

Этот хендлер для таймера. Таймер настроен на 100Гц.
Собственно там вызываются 2 функции.
Первая это для кнопок а вторая вычисляет и усредняет данные
от ADC через DMA для стабильной работы.

Всё. Пока что вот так сделал.
Теперь критика ваша, жду...
veso74
Поставщик валерьянки для Кота
Сообщения: 1907
Зарегистрирован: Сб май 05, 2012 20:24:52
Откуда: KN34PC, Болгария
Контактная информация:

Re: Обработка кнопок, EXTI[0]

Сообщение veso74 »

Посмотрите, это форум. Ни у кого нет цели оскорблять. Только направление на размышление даем.
Напр. смотрю на собственный код из прошлом и задаюсь вопросом: так ли я ето написал? Если рядом был человек, то он мог бы дать направление, и путь будет "короче". Если нет человека, то в интернете, или со своим опытом. Но второй способ происходит значительно медленнее. Так что как решите, так и делайте. Цель одна - сокращенный, чистый код, который впоследствии пригодится вам в других проектах. МК не интересует способ составления алгоритма. Для небольших проектов будет ОК. А вот в больших проектах (и ​​при максимальном использовании ресурсов) будет от: медленного режима до невозможности работы. А когда меняешь начина построяния в коде на другой принцип, алгоритм, вдруг все ОК. (частично использую переводчика)
---

Код: Выделить всё

if(*Survey){
if(!(GPIOA->IDR & (1 << 7))){
*key_kod = 1;
}

if(!(GPIOA->IDR & (1 << 6))){
*key_kod = 2;
}

if(!(GPIOA->IDR & (1 << 5))){
*key_kod = 3;
}
прочитали статус порта 3 раза. Если статус изменился во время чтения? (спомните проблем bounce для кнопки).
Как вариант: прочитайте порт раз, присвойте значение переменной, затем отфильтруйте ее значение по кнопок.

Код: Выделить всё

uint32_t x = GPIOA->IDR;
key_0 = !(x & 1 << 7);
key_1 = !(x & 1 << 6);
key_2 = !(x & 1 << 5);
Последний раз редактировалось veso74 Ср ноя 13, 2024 13:45:36, всего редактировалось 1 раз.
Adrift
Вымогатель припоя
Сообщения: 541
Зарегистрирован: Вт окт 01, 2024 15:22:33

Re: Обработка кнопок, EXTI[0]

Сообщение Adrift »

[uquote="veso74",url="/forum/viewtopic.php?p=4648663#p4648663"]прочитали статус порта 3 раза. Если статус изменился во время чтения? (спомните проблем bounce для кнопки).[/uquote]
В текущей реализации ТС из-за дребезга можно прочитать одни единички и пропустить нажатие вообще, даже с одной кнопкой. В нормальном случае, со счетчиком для отдельной кнопки или для всех сразу, без разницы сколько раз читать с портов, три чтения GPIOA->IDR ничем не отличаются от чтения GPIOA->IDR + GPIOB->IDR + GPIOC->IDR, если кнопки будут на разных портах.
veso74
Поставщик валерьянки для Кота
Сообщения: 1907
Зарегистрирован: Сб май 05, 2012 20:24:52
Откуда: KN34PC, Болгария
Контактная информация:

Re: Обработка кнопок, EXTI[0]

Сообщение veso74 »

Да, есть варианты. Но то, что можно читать вместе, лучше/и легче/ читать вместе (например состояние 3 пинов в одном порту).
Martian
Друг Кота
Сообщения: 12867
Зарегистрирован: Сб дек 18, 2021 19:25:32
Контактная информация:

Re: Обработка кнопок, EXTI[0]

Сообщение Martian »

[uquote="aleksey chilov",url="/forum/viewtopic.php?p=4648657#p4648657"]if(!(GPIOA->IDR & (1 << 7))){
*key_kod = 1;
}

if(!(GPIOA->IDR & (1 << 6))){
*key_kod = 2;
}

if(!(GPIOA->IDR & (1 << 5))){
*key_kod = 3;
}
...
Теперь критика ваша, жду...[/uquote]

неужели не видно, что опять можно просто присвоить key_kod`у состояние трёх битов GPIOA->IDR (с маской) за один раз? Более того, они ведь даже подряд идут, если очень хочется, можно даже сделать сдвиг всех трёх и получить 1, 2, 3, если это жизненно важно.
Зачем делать три условия?
печально всё это...
Ответить

Вернуться в «ARM»