Пятница, 19.04.2024, 00:41
Вы вошли как Гость | Группа "Гости"Приветствую Вас Гость | RSS
Главная | Каталог статей | Мой профиль | Регистрация | Выход | Вход
Обитель RC-инженера
Форма входа
Меню сайта

Категории раздела
Программирование микроконтроллеров AVR [6]
Программирование микроконтроллеров STM32 [1]
Программирование ПЛИС Altera [1]
Разное [1]
Статьи на различную тематику
Самодельные системы управления моделями [0]

Друзья сайта

Статистика

Онлайн всего: 1
Гостей: 1
Пользователей: 0

Главная » Статьи » Программирование микроконтроллеров AVR

Драйвер кнопок устройства
Некоторое время назад я делал проект кодера для радиоуправляемых моделей Vcoder и мне понадобилось использовать кнопки для управления работой прошивки.

тогда я не сильно задумывался о usability своей прошивки, и написал драйвер который организовывал опрос кнопок анализирую время их удержания.

Фактически алгоритм выглядел так

1. Проверяем нажата ли хоть одна кнопка:

-прочитали байт из порта к которому подключены кнопки
-проверим по маске нажата ли хоть одна кнопка
--если не нажата - то счетчик удержания нажатия кнопки =0, и идем на выход из подпрограммы



2. если хоть одна кнопка нажата то:

- запоминаем состояние порта (битовую конфигурацию нажатых и не нажатых кнопок)
- увеличиваем счетчик проверки удержания кнопки.


3. Если счетчик удержания кнопки достиг некоторого порогового значения - то выставляем флаг того что кнопка нажата и сбрасываем счетчик удержания.


В принципе работал этот принцип примерно так же как работает клавиатура на компьютере: при нажатии на кнопку происходит замер длительности нажатия для устранения дребезга, и если кнопка какое то время не отпускалась то генерируется нажатие, далее по истечении еще какого то промежутка времени, если кнопка не отпускалась то нажатие генерируется снова...


удобно? - тогда показалось что вполне !

драйвер кнопок с таким алгоритмом и был реализован в прошивке VCoder

Но прошло некоторое время и это решение показало себя не очень удобным.

Например, нажатие на кнопку @MENU@ приводит к переходу в меню настроек аппаратуры, а в самом меню к переходу по выбранному пункту меню.. и пользователь аппаратуры зачастую чуть передержав кнопку @MENU@ входил не только в меню, но и в первый его пункт (обычно это был пункт RESET MODEL - который сбрасывал все настройки модели !)


Сначала проблему решали полумерами в виде внедрения диалога проверки в пункт RESET MODEL (требовалось ответить YES для сброса), пункт YES конечно же располагался у кнопки @MENU@...

Потом этот пункт переместили на кнопку @EXIT@, а пункт отказа от сброса (NO) разместили у кнопки @MENU@...

но ясности и простоты это не добавило, всегда находился пользователь который перепутал бы нажимаемые кнопки, либо не вчитывался особо в написанное и все таки сбрасывал настроенную модель...

постепенно пользователи привыкли, однако думаю что моя икота иногда вызывается гневом именно пользователей прошивки Vcoder при работе их с кнопкой @MENU@

Через какое то время я начал писать еще одну прошивку (A-Coder) и тогда решил что с этим нужно что то делать - негоже иметь такие ляпы в такой казалось бы простой задачке как опрос кнопок управления.

И придумался мне следующий функционал:
Должны быть кнопки которые при нажатии генерируют автоповтор (после нажатия и удержания кнопки генерируется повторяющееся коды нажатой кнопки), а должны быть те кто не генерируют (то есть при нажатии и удержании кнопки генерируется только одно нажатие, и повторного, сколько бы мы кнопку не удерживали - не будет)

Первый режим (автоповтор при удержании) я назвал push\hold, второй режим, при котором нажатие генерируется только один раз, независимо от времени удержания - push\up

Этот функционал реализовывался несколько раз и алгоритм каждый раз мне нравился все больше и больше :)
предлагаю вам текст этой подпрограммы для использования в ваших проектах

константы:

конфигурация подключения кнопок:

  • PIN_MN_KEY - порт PINx к которому
    подключены кнопки, все кнопки управления должны быть подключены к одному
    порту, но не обязательно к пинам порта идущим подряд


  • MN_KEY_MASK - битовая маска кнопок порта (соответствующие биты кнопок установлены в "1")


  • MN_KEY_UP, MN_KEY_DN, MN_KEY_LF, MN_KEY_RG - номера бит к которым подключены кнопки, внимание в константах именно номера бит!!

внешние переменные (размещаются в DSEG, изменяются другой подпрограммой)

  • COUNTER - переменная в DSEG: счетчик
    интервалов, от 20 до 100 гц (в принципе любой частоты, изменяется в
    пределах 0..255 циклически)

переменные драйвера (размещаются в DSEG):
  • KR1_KEY_MASK - входной параметр: маска кнопок которые опрашиваются в режиме push\hold
  • KR1_KEY_READ - выходной параметр: зарегистрированный код нажатой кнопки (выходная переменная модуля !)
  • KR1_OLD_KEY - временно хранимый код нажатой кнопки
  • KR1_PH_ONTIME - количество циклов вызова для регистрации кнопки в режиме push\hold
  • KR1_PU_ONTIME - количество циклов вызова для регистрации кнопки в режиме push\up
  • KR1_PU_WAIT - вспомогательная переменная, флаг того что кнопка в режиме push\hold еще не отпускалась


; key_reader.asm - модуль чтения нажатых кнопок меню

.equ            COUNTER = T1_COUNTER        ; имя переменной-счетчика в DSEG
KEY_READER:            ; прочитаем состояние кнопок
                    IN        R16        , PIN_MN_KEY
                    ANDI    R16        , MN_KEY_MASK   ; маска кнопок меню

                    ; проверим нажата ли хоть одна кнопка
                    CPI        R16        , (1<<MN_KEY_UP)|(1<<MN_KEY_DN)|(1<<MN_KEY_LF)|(1<<MN_KEY_RG)
                    BREQ    KR1_EXIT                ; ни одна из кнопок не нажата, идем на выход
                   
                    ; зарегистрировано нажатие какой-то кнопки
                    LDS        R17        , KR1_OLD_KEY    ; нажатые кнопки в прошлый период
                    CP        R16        , R17            ; сравним текущие и старые нажатые кнопки
                    BREQ    KR1_TIMER_LIST            ; кнопки удерживаются - проверим время

                    ; нажатые кнопки сейчас и нажатые ранее кнопки - отличаются
                    STS        KR1_OLD_KEY    , R16        ; сохраним нажатые кнопки
                    LDS        R16        , COUNTER
                    STS        KR1_KEY_COUNTER    , R16    ; сохраним момент нажатия
                    RJMP    KR1_END                    ; идем на выход

KR1_TIMER_LIST:        ; кнопка нажата и удерживается, проверим достаточное ли времени прошло для
                    ; регистрации нажатия в обоих режимах сканирования клавиатуры

KR1_TIMER_PH_LIST:    ; режим push\hold
                    ; проверка достаточности нажатия в режиме push\hold
                    MOV        R15        , R16            ; сохраним нажатые кнопки меню

                    LDS        R17        , KR1_KEY_MASK    ; прочитаем маску чтения push\hold
                    AND        R16        , R17            ; наложим маску
                    CP        R16        , R17            ; есть кнопки нажатые для этого режима?
                    BREQ    KR1_TIMER_PU_LIST        ; перейдем к проверке нажатых кнопок в режиме
                                                    ; push\up
                    ; у нас нажаты кнопки в режиме push\hold
                    LDS        R16        , COUNTER        ; загрузим текущий счетчик
                    LDS        R17        , KR1_KEY_COUNTER    ; загрузим счетчик когда было зарегистрировано
                                                        ; нажатие кнопок
                    SUB        R16        , R17            ; определим время нажатия
                    LDS        R17        , KR1_PH_ONTIME    ; берем необходимую длительность нажатия
                    CP        R16        , R17
                    BRLO    KR1_TIMER_PH_LIST_NO    ; кнопка удерживается недостаточное время, выходим
                   
KR1_REG_KEY_PRESS:    ; кнопка удерживается достаточное время, зарегистрируем нажатие
                    STS        KR1_KEY_READ    , R15    ; сохраним нажатые кнопки
                    LDI        R16        , (1<<MN_KEY_UP)|(1<<MN_KEY_DN)|(1<<MN_KEY_LF)|(1<<MN_KEY_RG)
                    STS        KR1_OLD_KEY    , R16        ; сбросим временный код нажатых кнопок
                    RJMP    KR1_END                    ; идем на выход   

KR1_TIMER_PU_LIST:    ; режим push\up                   
                    LDS        R16        , KR1_PU_WAIT    ; проверим не ожидаем ли мы отпускания кнопок
                    CPI        R16        , 1                ; меню после регистрации нажатия
                    BREQ    KR1_PROC_WAIT            ; выходим ожидая отпускания кнопок
                                       
                    ; проверим нужное время ли удерживается кнопка
                    LDS        R16        , COUNTER        ; загрузим текущий счетчик
                    LDS        R17        , KR1_KEY_COUNTER    ; загрузим счетчик когда было зарегистрировано
                                                        ; нажатие кнопок
                    SUB        R16        , R17            ; определим время нажатия
                    LDS        R17        , KR1_PU_ONTIME    ; берем необходимую длительность нажатия
                    CP          R16        , R17
                    BRLO      KR1_TIMER_PH_LIST_NO    ; кнопка удерживается недостаточное время, выходим
                   
                    ; кнопка удерживается достаточное время установим флаг ожидания отпускания
                    LDI        R16        , 1
                    STS        KR1_PU_WAIT    , R16
                    RJMP      KR1_REG_KEY_PRESS        ; и зарегистрируем нажатие кнопки

KR1_EXIT:            ; выход, по отпусканию кнопок
                    STS       KR1_OLD_KEY    , R16    ; сбросим временные нажатые кнопки
                    LDI        R16        , 0
                    STS       KR1_PU_WAIT    , R16        ; сбросим флаг ожидания отпускания (уже отпустили)
                                                    ; для режима push\up

KR1_END:            ; выход
KR1_TIMER_PH_LIST_NO: ; выходим по недостаточному времени удержания кнопок
KR1_PROC_WAIT:        ; ожидаем отпускание нажатых кнопок в режиме push\up

                    RET


И следом идет процедура которая считывает код кнопок нажатие которых было зарегистрировано

GET_KEY:            ; функция чтения считанной кнопки
                    PUSH      R17
                    LDS        R16        , KR1_KEY_READ
                    LDI         R17        , (1<<MN_KEY_UP)|(1<<MN_KEY_DN)|(1<<MN_KEY_LF)|(1<<MN_KEY_RG)
                    STS        KR1_KEY_READ    , R17
                    POP        R17
                    RET

Файл драйвера на языке ассемблера можно скачать здесь -> http://vg.ucoz.ru/load/iskhodnye_teksty_programm_na_assemblere_avr/drajver_knopok_ustrojstva/4-1-0-8
Категория: Программирование микроконтроллеров AVR | Добавил: ВитГо (15.08.2012)
Просмотров: 4469 | Комментарии: 1 | Теги: avr, кнопки | Рейтинг: 5.0/1
Всего комментариев: 1
1 mirash_24  
0

Добавлять комментарии могут только зарегистрированные пользователи.
[ Регистрация | Вход ]

Copyright MyCorp © 2024
Сделать бесплатный сайт с uCoz