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

Кто любит RISC в жизни, заходим, не стесняемся.
Ответить
Нашел транзистор. Понюхал.
Сообщения: 167
Зарегистрирован: Вс мар 27, 2022 09:38:17

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

Хочу обратится тут к гуру ARM "jcxz" там спрашивалось типа

( 1. Зачем сброс флагов - тремя операциями вместо одной?
2. Чтение GPIOA->IDR то же самое - зачем 6(!) чтений вместо одного??? )

Там речь вообще шла о флагах прерываний а именно о регистре (EXTI_PR).
Если не сбросить флаг тогда там на всегда и останется всё. Да и что такое макросы я знаю.
Побитовые операции тоже. Ходил в школу рассказывали. Человек на умничал тут настроение испортил
и успокоился. Вот другой человек по нормальному привёл кусок кода, по человечески помог, и спасибо ему!
"AlanDrakes"
Теперь я перенастрою регистры отключу прерывания и сделаю по таймеру, я спросил варианты человек ответил и помог.
И теперь я пропишу макросы для удобства и всё будет работать на ура!
Реклама
Мудрый кот
Сообщения: 1856
Зарегистрирован: Вт авг 15, 2017 10:51:13

Сообщение jcxz »

[uquote="Adrift",url="/forum/viewtopic.php?p=4648283#p4648283"]Затем, что если пины задефайнены как "A, 7", "A, 6" и "A, 5", то, видимо, планируется получить что-то типа "GPIOA, 7"..., тогда для одного чтения придется сравнить все 3 GPIO между собой[/uquote]Не понял - что нужно сравнивать, но вот:

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

#define PORT2(port, pin)    port
#define PIN2(port, pin)     pin
#define PORT(port_pin)      PORT2(port_pin)
#define PIN(port_pin)       PIN2(port_pin)

uint i = concat(GPIO, PORT(PIN_BUTTON1))->IDR;  //операция одного чтения.
и т.д.
[uquote="Adrift",url="/forum/viewtopic.php?p=4648283#p4648283"], а потом еще возможны 3 варианта когда совпадает порт для двух пинов и можно читать всего 2 раза ) А если пинов будет больше? По нормальному это задача со звездочкой для C++ )[/uquote]Если портов много, то - создаём битмап портов:
#define BTN_PORT_MAP (PORT(PIN_BUTTON1) | PORT(PIN_BUTTON2) | ...)
а затем из этого битмапа - набор операций чтения GPIOx->IDR, в набор переменных iA, iB, iC, ....
Тоже - с помощью макросов. Никакие громоздкие си++ тут не нужны.
Но правильнее все кнопки посадить на минимально-возможное кол-во портов. Чтобы уменьшить число необходимых чтений GPIO в ISR и уменьшить время его выполнения.

Добавлено after 12 minutes 32 seconds:
[uquote="Martian",url="/forum/viewtopic.php?p=4648326#p4648326"]Классно. Когда пнули, оказалось, что всё знает, а мы дураки. И оказывается, правильно и неправильно - это теперь вариантами называется :)))[/uquote]
Не, нифига не знает. :)))
Пишет, что знает что такое"побитовые операции", но при этом так и не понял почему обращение к EXPI_PR нужно только одно. Одно высказывание противоречит другому.
И почему плохо читать 6 раз - скорее всего тоже не понял.
Просто тупо скопипастит сейчас чужой код, а потом, когда что-то не станет работать - опять прибежит сюда. :)))
Реклама
Вымогатель припоя
Сообщения: 626
Зарегистрирован: Вт окт 01, 2024 15:22:33

Сообщение Adrift »

[uquote="jcxz",url="/forum/viewtopic.php?p=4648329#p4648329"]Если портов много, то - создаём битмап портов:
#define BTN_PORT_MAP (PORT(PIN_BUTTON1) | PORT(PIN_BUTTON2) | ...)
а затем из этого битмапа - набор операций чтения GPIOx->IDR, в набор переменных iA, iB, iC, ....
Тоже - с помощью макросов. Никакие громоздкие си++ тут не нужны.[/uquote]
В том и дело, что если читать в набор переменных iA, iB, iC из GPIOx->IDR, то будет 3 чтения с порта, даже если он одинаков для всех пинов.
Нашел транзистор. Понюхал.
Сообщения: 167
Зарегистрирован: Вс мар 27, 2022 09:38:17

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

Опять тоже самое!
Хотел бы использовать готовые решения использовал бы библиотеку HAL+ CubeMX и готовую библиотеку.


На и успокойся!!!

void EXTI9_5_IRQHandler(void){
EXTI->PR = (EXTI_PR_PR5|EXTI_PR_PR6|EXTI_PR_PR7); // Сбросить флаг прерывания!
//EXTI->PR = EXTI_PR_PR6; // Сбросить флаг прерывания!
//EXTI->PR = EXTI_PR_PR7; // Сбросить флаг прерывания!
// asm("nop");
// asm("nop");

if((GPIOA->IDR & (1 << 7)) == 0){ // Кнопка ОК
Flag.SET_Ok = true;

}else if((GPIOA->IDR & (1 << 7)) != 0){
Flag.SET_Ok = false;
}

if((GPIOA->IDR & (1 << 6)) == 0){ // Кнопка V+
Flag.VOL_plus = true;

}else if((GPIOA->IDR & (1 << 6)) != 0){
Flag.VOL_plus = false;
}

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

}else if((GPIOA->IDR & (1 << 5)) != 0){
Flag.VOL_minus = false;
}
}
Реклама
Эиком - электронные компоненты и радиодетали
Мудрый кот
Сообщения: 1856
Зарегистрирован: Вт авг 15, 2017 10:51:13

Сообщение jcxz »

[uquote="Adrift",url="/forum/viewtopic.php?p=4648336#p4648336"]В том и дело, что если читать в набор переменных iA, iB, iC из GPIOx->IDR, то будет 3 чтения с порта, даже если он одинаков для всех пинов.[/uquote]Такое может быть если кодонаписатель совсем безголовый. 8)
У вменяемого будет одно чтение. Подумайте - как. Там всё просто.

Добавлено after 2 minutes 53 seconds:
[uquote="Martian",url="/forum/viewtopic.php?p=4648326#p4648326"]оказалось, что всё знает, а мы дураки.[/uquote]
Вот видите какую галиматью пишет:
[uquote="aleksey chilov",url="/forum/viewtopic.php?p=4648339#p4648339"]if((GPIOA->IDR & (1 << 7)) == 0){ // Кнопка ОК
Flag.SET_Ok = true;

}else if((GPIOA->IDR & (1 << 7)) != 0){
Flag.SET_Ok = false;
}[/uquote]
"Не в коня корм"..... :)))
Реклама
Вымогатель припоя
Сообщения: 626
Зарегистрирован: Вт окт 01, 2024 15:22:33

Сообщение Adrift »

[uquote="jcxz",url="/forum/viewtopic.php?p=4648344#p4648344"]Такое может быть если кодонаписатель совсем безголовый. 8)
У вменяемого будет одно чтение. Подумайте - как. Там всё просто.[/uquote]
На всякий случай уточню, а то вдруг действительно безголовый ) Один и тот же код из примитивных макросов будет читать один раз из GPIOx->IDR если все пины с одного порта, но будет читать 3 раза, если порты все разные, в остальных случаях будет 2 чтения? Как он это будет делать не сравнивая порты друг с другом, раз уж ты не понимаешь что нужно сравнивать? )

ps. Ага, мы битман портов вручную создаем и он будет ассоциирован с нашими пинами? Громоздкий C++ это все автоматически при компиляции делает, мне такое даже с голову сразу не пришло ) Хотя все равно не понятно... Если пина 3, а порт 1, то в битмапе портов будет один порт, но читать все равно нужно не GPIOx->IDR, который volatile, а значение уже прочитанное из него. Нужен рабочий пример )
Реклама
Нашел транзистор. Понюхал.
Сообщения: 167
Зарегистрирован: Вс мар 27, 2022 09:38:17

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

Давайте умники!
3 кнопки.
притянуты к +.
Обработчик один на 4 пина.
Нужно поднять флаг по спаду и сбросить по нарастанию.
Давайте, покажите как вы это видите...
В отладчике всё работает. Или отладчик тоже "Не в коня корм?"
По одному из портов происходит прерывание, там проверяется по какому, дальше флаг.
Вы чё там??? Пьяные???
Вы крутые программисты покажите тогда как это должно быть или не алё?

Добавлено after 1 minute 16 seconds:
STM32F103C6T6 на всякий случай
Друг Кота
Аватара пользователя
Сообщения: 15813
Зарегистрирован: Вт мар 16, 2010 22:02:27
Откуда: ДОНЕЦК

Сообщение BOB51 »

Собственно опять "кнопы преткновения"?
:))
Да еще и под СИ, где особой разницы между МК не наблюдается...
Одна часть прожки - обработчик линий возврата кнопок, вторая - обработчик полученных данных.
Сколько раз уже вылизывалось во всевозможных вариантах...
8)
Не все ли равно, сколько раз читать данные с ЛВК в буфер результата (одной операцией с единого порта или собирать в несколько приемов в общий буфер -накопитель) - для механических кнопок те интервалы совершенно мизерные по сравнению с интервалом антидребезга. Вылизать более оптимальный вариант под конкретный МК и схему - это уже задача вопрошающего.
Может дальше смотреть надо - работа по фиксации данных, антидребезгу, обработка системы подмены функционала нажатой комбинации, длительность удержания, контроль покоя, контроль интервала без обращений к клавиатуре (автоотключение сканирования), контроль интервала "залипания" (повреждение клавиатуры).
Следующий шаг - подменные функции для конкретных комбинаций в разных программах (соответственно разделам менюшки устройства).
:wink:
Последний раз редактировалось BOB51 Вт ноя 12, 2024 18:12:07, всего редактировалось 1 раз.
Нашел транзистор. Понюхал.
Сообщения: 167
Зарегистрирован: Вс мар 27, 2022 09:38:17

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

Я могу написать вот так:

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

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

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

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

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

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


Всё работает и так.
В чём проблема???

Добавлено after 1 minute 8 seconds:
В прерывании проверяется пин. Что там не так?


Изображение
Последний раз редактировалось aleksey chilov Вт ноя 12, 2024 18:14:27, всего редактировалось 1 раз.
Друг Кота
Аватара пользователя
Сообщения: 15813
Зарегистрирован: Вт мар 16, 2010 22:02:27
Откуда: ДОНЕЦК

Сообщение BOB51 »

Так ежли проблем нету - зачем все вышесказанное в обсуждении?
:wink:
Нюансы системы "кнопы + менюшки" позже повылазят (ежли их в самом начале не удалось узреть).
Боно будет, да поздно (код переделывать ой как влом обычно).
:tea: 8)
Нашел транзистор. Понюхал.
Сообщения: 167
Зарегистрирован: Вс мар 27, 2022 09:38:17

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

Я понял о чём вы.
Там действительно отладчик показал что при нажатии любой из кнопок
он пробегает по всем условиям и пере сбрасывает флаги...
Извиняюсь за свои психи.
Я почему то об этом как-то даже и не думал...
Сделаю по другому.
Тут нужно подумать...
Последний раз редактировалось aleksey chilov Вт ноя 12, 2024 20:16:48, всего редактировалось 2 раза.
Мудрый кот
Сообщения: 1856
Зарегистрирован: Вт авг 15, 2017 10:51:13

Сообщение 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: Ответ "почему" уж был дан ранее.
Мудрый кот
Сообщения: 1856
Зарегистрирован: Вт авг 15, 2017 10:51:13

Сообщение 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:
Мудрый кот
Сообщения: 1856
Зарегистрирован: Вт авг 15, 2017 10:51:13

Сообщение jcxz »

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

Сообщение BOB51 »

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

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

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

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

ЕСЛИ

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

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

А дальше по интересам (для менюшки посолиднее и/или "псевдовиндовс" на символьном двустрочнике придется заметно больше поизвращаться).
8)
Вымогатель припоя
Сообщения: 626
Зарегистрирован: Вт окт 01, 2024 15:22:33

Сообщение 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 
Мудрый кот
Сообщения: 1856
Зарегистрирован: Вт авг 15, 2017 10:51:13

Сообщение 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-и у вас. :)))
Нашел транзистор. Понюхал.
Сообщения: 167
Зарегистрирован: Вс мар 27, 2022 09:38:17

Сообщение 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:
Сделал вот так.
Может быть опять запинаете но в отладчике работает
Мучитель микросхем
Сообщения: 413
Зарегистрирован: Ср янв 04, 2012 11:57:40
Откуда: Алчевск

Сообщение Sergi »

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

Сообщение BOB51 »

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

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