Страница 1 из 2
обработка нажатия кнопок attiny2313 (длительное нажатие)
Добавлено: Чт янв 07, 2010 12:26:22
MTF
Всем привет!!!!! делаю устройство на attiny2313 описание:
внешний кварц 4мгц
кнопки подключены к portD pd1,pd2,pd4,pd5 ,через сопротивление 10ком
к +5в ,замыкаются на минус.
возникла следующая проблема:Для работы мне необходимо отслеживать длинное и короткое нажатие кнопки.
сейчас в основном цикле просто проверяю наличие 0
Код: Выделить всё
.equ K1 = PD1 ;
.equ K2 = PD2 ;
.equ K3 = PD4 ;
.equ K4 = PD5 ;
.def zz0 = r16
.def zz1 = r17
.def zz2 = r18
;основной цикл программы
next:
sbis PIND,K1 ; если 0 то переход
rcall K1
sbis PIND,K2
rcall K2
sbis PIND,K3
rcall K3
sbis PIND,K4
rcall K4
....
....
rjmp next
K1:
ldi zz2 ,$02
ldi zz1 ,$71
ldi zz2 ,$00
rcall delay
...................
ret
delay:
subi zz0 , 1
sbci zz1 , 0
sbci zz2 , 0
brcc delay
ret
сначала сделал без задержки все очень быстро ,вставил задержку ,но даже с задержкой фигня какая то получается ,потом думал сделать цикл на отпускание.
не нравится то что ,приходится использовать задержку в основном цикле
Работаю над тем, как сделать опрос клавы с помощью таймера,
проверять там каким то образом длинное и короткое нажатии и только после этого проверять код нажатой клавиши в основном цикле?????
Может кто знает как это делается!!!!!!!
Добавлено: Чт янв 07, 2010 12:34:08
DrWatson
В прерывании по таймеру сканируешь кнопки, если нажата к.-л. кнопка, считаешь время до её отпускания, допустим: нажата меньше 100мс - дребезг, нажата больше 100мс, но меньше 1000мс - короткое нажатие, нажата дольше 1с - длинное.
Добавлено: Чт янв 07, 2010 14:01:18
Arlleex
помоему sbis - это пропустить. если бит установлен...
sbic - если очищен...
Добавлено: Чт янв 07, 2010 14:50:01
MTF
Вопрос???? как еще можно сканировать порт D
через IN не будет нормально работать ,у меня еще используются выводы порта D
Добавлено: Чт янв 07, 2010 16:52:50
Dexa
через IN не будет нормально работать ,у меня еще используются выводы порта D
не понял.
Я делал так. Кнопка висела на внешнем прерывании, которое изначально настроил на спад (нажатие). Обработчик прерывания начинался с определения действия - нажалась или отжалась кнопка (проверка регистра настройки внешнего прерывания). Если нажалась, меняем настройку внешнего прерывания на нарастание (отжатие), включаем таймер и выходим из обработчика. Далее произошло снова прерывание (кнопка отжалась),снова меняемем настройку внешнего прерывания, соответственно проверяем таймер еще считает или нет, если да то тормозим его (чтоб не попасть в обработчик прерывания по таймеру) и выполняем то действие, которое должно выполнятся при коротком удержании кнопки. Ну а если таймер уже не считает, выходим из обработчика внешнего прерывания и попадаем в обрабочик прерывания по таймеру, где выполняем действие при длительном нажатии на кнопку. Вот эта постоянная настройка прерывания (регистр MCUCR) могла бы отсутствовать, если бы вы юзали другой МК, где есть настройка прерывания на любое изменение фронта. У тини2313 нету.[/quote]
Добавлено: Чт янв 07, 2010 23:03:28
MTF
Не совсем понял у меня же 4 кнопки , или вы имеете ввиду использовать INT0 как общий провод для всех 4 кнопок????
Добавлено: Чт янв 07, 2010 23:35:07
Dexa
MTF писал(а):Не совсем понял у меня же 4 кнопки , или вы имеете ввиду использовать INT0 как общий провод для всех 4 кнопок????
Вообще я сказал как именно можно реализовать 2 действия на 1 кнопке. Вам на всех 4-х кнопках так надо или на одной? Если для всех 4 то надо подумать, ща в 2 ночи и не скажу)) И нет ничего удивительного в том что повесит 4 кнопки на INT. У меня 12 кнопок там весит.
Добавлено: Пт янв 08, 2010 00:01:56
AI_Disable
Я делал так: в основном цикле проверял, нажата ли кнопка, если да, то делаем ++ переменной. Если кнопка не нажата и переменная больше нуля, сравниваем её с неким значением(которое зависит от скорости выполнения основного цикла и подбирается экспериментально). Если переменная меньше - это кратковременно нажатие, если больше - длительное. После, сбрасываем переменную.
На мой взгляд, это самый рациональный и простой способ, т.к. не пожирает драгоценный таймер на такую ерунду и работает без задержек в цикле.
ЗЫ: единственный минус - если основной цикл повторяется очень быстро (тысячи раз в секунду), то тогда переменная начнёт жрать память, неподобающим образом.
Тут уж выбирайте, что вам важнее: таймер или 2-4 байта памяти.
Добавлено: Пт янв 08, 2010 03:00:12
MTF
Возник вопрос?????
допустим
TmKey - счетчик времени нажатия кнопки
.............
inc TmKey
cpi TmKey , 50
brsh Long ; переход если больше или равно 1 секунде
.............
long:
.............
так я могу проверить только длительное нажатие
Кто нибудь знает, можно ли как нибудь при сравнении TmKey использовать выражение (больше 100мс но меньше 1000мс),
как это можно реализовать????
Добавлено: Пт янв 08, 2010 15:52:21
Петро
cpi TmKey, 50
brsh Long; переход если больше или равно 1 секунде
это означает "если больше ровно 1000 мс - переход".
Значит, если нет перехода, т.е. программа выполняется дальше, то проверяем TmKey> 100 мс? если да - переход, если нет - программа выполняет что-то другое. вот і все.
Код:
cpi TmKey, 50
brsh Long ; переход если больше или равно 1 секунде
cpi TmKey, 5
brsh Short ; переход если больше или равно 0.1 секунде - короткое нажатие
rjmp Drebezg ; иначе обрабативаем дребезг
.............
Long:
..........
Short:
..........
Drebezg:
..........
Добавлено: Сб янв 09, 2010 13:52:58
MTF
не могу придумать как обработать нажатие и отпускание кнопки ,вот попробывал набросать!!!!!!!!
Чувствую что что то не так, может кто подскажет что я не так делаю и как надо обрабатывать кнопки????
Код: Выделить всё
T1OVF:
in r16,portd ; считываем порт d
andi r16,0b00110110 ;обнуляем лишние pd
cp r16, keyold ;срав со старым кодом кнопки
mov keyold ,r16 ;записыв в keyold r16
brne A1 ; переход если не совпадает проверяем время кнопки
inc TmKey
????????
????????
????????
????????
A1:
cpi TmKey, 50
brsh Long ; переход если больше или равно 1 секунде
cpi TmKey, 5
brsh Short ; переход если больше или равно 0.1 секунде - короткое нажатие
rjmp Drebezg ; иначе обрабативаем дребезг
.............
Long:
..........
Short:
..........
Drebezg:
..........
Добавлено: Вс янв 10, 2010 00:36:10
Петро
Код: Выделить всё
T1OVF:
in r16,portd ; считываем порт d
andi r16,0b00110110 ;обнуляем лишние pd
cpi r16,0 ;если r16=0, тоесть ни одна кнопка не нажата, то выход из обработчика
brne _next_ ;иначе переход на сравнение со старым кодом кнопки
mov keyold ,r16 ;запись в keyold r16
reti
_next_:
cp r16, keyold ;сравнение со старым кодом кнопки
mov keyold ,r16 ;запись в keyold r16
brne A1 ; переход если не совпадает, проверяем время кнопки
inc TmKey ;если же совпадает и r16 не 0, тоесть r16=1,то считаэм сколько миллисекунд кнопка уже нажата
Ну а если не совпадает, то значит кнопку отпустили
reti
A1:
cpi TmKey, 50
brsh Long ; переход если больше или равно 1 секунде
cpi TmKey, 5
brsh Short ; переход если больше или равно 0.1 секунде - короткое нажатие
rjmp Drebezg ; иначе обрабативаем дребезг
.............
;Обрабатывать всякого рода нажатие нужно по этих метках:
Long:
..........
reti
Short:
..........
reti
Drebezg:
..........
reti
Добавляэм reti, чтобы что-то одно выполнилось из трех,поскольку при переходе на Long после выполнения кода под ним еще и выполнится код под Short i Drebezg.
Добавлено: Вс янв 10, 2010 11:47:12
MTF
Петро Огромное спасибо за помощь в написании кода
один маленький вопрос ???? TmKey надо , где то обнулять или нет ???
Добавлено: Вс янв 10, 2010 12:39:54
Петро
Точно, я же забыл про обнуление TmKey.
Тогда часть кода, где ето нужно сделать, будет такова:
Код: Выделить всё
;Обрабатывать всякого рода нажатие нужно по этих метках:
Long:
..........
rjmp _return_
Short:
..........
rjmp _return_
Drebezg:
..........
rjmp _return_
_return_:
clr TmKey
reti
Ну что, заработало?
Добавлено: Вс янв 10, 2010 22:58:46
MTF
Петро Все OK , заработало

спасибо за помощь

Добавлено: Пн янв 11, 2010 11:12:35
MTF
Извиняюсь за назойливость ,вчера проверил только на короткое нажатие ,начал испытывать длинное нажатие ,выяснилось что (Long) работает как то не так ,если я держу ничего не происходит , только когда отпустишь.
возможно ли как то проверять Long не по отпусканию ?????
Добавлено: Пн янв 11, 2010 15:02:25
ooogo
а что будет если при нажатой кнопке еще и другую кнопку нажмут!? обработчик прерывания остановит счет начнет распознование нажатия на первую кнопку!?
может быть в основной программе проверять нажатие, и по нажатию запускать таймер(с тиканьем ~0.1c), в котором увеличивать переменную при переполнении(не обязательно от нуля) выставлять флаг длительного удержания, а в основной программе, пока нет отпускания этой кнопки(в цикле) проверять флаг длительного нажатия, а как только отпустили кнопку дребезг и короткое нажатие.
Добавлено: Пн янв 11, 2010 16:13:29
MTF
У меня все два таймера работает постоянно T0 СK/256 4Мгц,а второй не всегда поэтому и прилаживаю к T0 ,целую неделю бьюсь c этими кнопками (длительное нажатие), так и ничего не получается

Добавлено: Пн янв 11, 2010 19:53:24
Петро
Чтобы длинное нажатие обрабатывалось во время самого нажатие(действия выполнялись каждие 1 сек соответственно), нужно поместить подпрограму Long сразу после смены TmKey. В обработчику Long заодно и отнимаем 50 от TmKey, чтоб после каждой 1-й секунди нажатия он мог снова дойти до 50 и мог выполниться обработчик.
Может быть еще случай, когда после длинного нажатия кнопку отпустили, а 0<TmKey<50. Поетому чтоб не выполнился лишний обработчик (Drebezg или Short), ми должны проверять в его начале было ли последнее нажатия длинным. Если было - флаг Т=1 (мы же устанавливаем его в 1 если нажатие длинное в обработчику), тогда пропускаем обработчик, переходим на _return_, очищаем флаг, выходим. Если же последнее нажатия не длинное, Т=0, тогда можно спокойно обрабатывать короткое или дребезг.
Код: Выделить всё
;запиши в начале страницы
.def temp=R25 ;или какой там регистр у тебя свободен
;...................
T1OVF:
in r16,portd ; считываем порт d
andi r16,0b00110110 ;обнуляем лишние pd
cpi r16,0 ;если r16=0, тоесть ни одна кнопка не нажата, то выход из обработчика
brne _next_ ;иначе переход на сравнение со старым кодом кнопки
mov keyold ,r16 ;запись в keyold r16
reti
_next_:
cp r16, keyold ;сравнение со старым кодом кнопки
mov keyold ,r16 ;запись в keyold r16
brne A1 ; переход если не совпадает, проверяем время кнопки
inc TmKey ;если же совпадает и r16 не 0, тоесть r16=1,то считаэм сколько миллисекунд кнопка уже нажата
;Ну а если не совпадает, то значит кнопку отпустили
Long:
set
subi TmKey,50
..........
rjmp _return_
reti
A1:
cpi TmKey, 50
brsh Long ; переход если больше или равно 1 секунде
cpi TmKey, 5
brsh Short ; переход если больше или равно 0.1 секунде - короткое нажатие
rjmp Drebezg ; иначе обрабативаем дребезг
.............
;Обрабатывать всякого рода нажатие нужно по этих метках:
Short:
bld temp,0
sbic temp,0
rjmp _return_
..........
rjmp _return_
Drebezg:
bld temp,0
sbic temp,0
rjmp _return_
..........
rjmp _return_
_return_:
clt
clr TmKey
reti
Добавлено: Вт янв 12, 2010 00:03:00
MTF
Петро походу что то не так !!!
а правильно ли мы делаем что считываем 0 (нажатие кнопки) с помощью PORTD ????
Код: Выделить всё
in r16,portd ; считываем порт d
andi r16,0b00110110 ;обнуляем лишние pd
может надо читать из pind ,
а то вообше перестала работать
нажимаешь вообще ничего не происходит
сначала при включении начались проблемы с таймером T0
оказалось ему не нравилось в T1 , выход по reti в начале
Код: Выделить всё
in r16,portd ; считываем порт d
andi r16,0b00110110 ;обнуляем лишние pd
cpi r16,0 ;если r16=0, тоесть ни одна кнопка не нажата, то выход из обработчика
brne _next_ ;иначе переход на сравнение со старым кодом кнопки
mov keyold ,r16 ;запись в keyold r16
rjmp keyend
_next_:
cp r16, keyold ;сравнение со старым кодом кнопки
mov keyold ,r16 ;запись в keyold r16
brne A1 ; переход если не совпадает, проверяем время кнопки
inc TmKey ;если же совпадает и r16 не 0, тоесть r16=1,то считаэм сколько миллисекунд кнопка уже нажата
;Ну а если не совпадает, то значит кнопку отпустили
Long:
set
subi TmKey,50
..........
rjmp _return_
reti
........
..
keyend:
reti
после переделки таймер T1 заработал нормально ,а вот реакции о клавы нет вообще!!!
попробывал в основном цикле такой вариант чтобы просто от нажатия пикало ,то же херь какая то получилась ,после нажатия таймер T1 опять заглючило ,спустя 2-3 сек опять раздался пик и T1 начинает работать нормально ,ума не приложу в чем дело ????
Код: Выделить всё
;основной цикл
next:
; в таком варианте работает
; sbis PIND,plus
; rcall beep
; sbis PIND,minus
; rcall beep
in tmp, pind
andi tmp, 0b00110000 ;
cpi tmp ,0b00010000
rjmp beep
cpi tmp ,0b00100000
rjmp beep
rjmp next
Beep:
sbi OutPort,(0<<OutPin) ; устанавливаем управ имп
ldi Razz2,0x06
ldi Razz1,0x1A
ldi Razz0,0x80
rcall delay ; 0,5 c
cbi OutPort,(0<<OutPin) ; устанавливаем управ имп
ret