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

Кто любит RISC в жизни, заходим, не стесняемся.
Ответить
Вымогатель припоя
Сообщения: 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:
Вымогатель припоя
Сообщения: 626
Зарегистрирован: Вт окт 01, 2024 15:22:33

Сообщение 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() все сдвинула обратно и оптимизатор сдвиги вообще убрал )
Поставщик валерьянки для Кота
Сообщения: 1988
Зарегистрирован: Сб май 05, 2012 20:24:52
Откуда: KN34PC, Болгария

Сообщение veso74 »

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

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

Сообщение 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 для стабильной работы.

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

Сообщение 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 раз.
Контактная информация:
Вымогатель припоя
Сообщения: 626
Зарегистрирован: Вт окт 01, 2024 15:22:33

Сообщение Adrift »

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

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