включение и выключение порта одной кнопкой

Обсуждаем контроллеры компании Atmel.
Ответить
Встал на лапы
Аватара пользователя
Сообщения: 113
Зарегистрирован: Пт апр 04, 2014 09:34:08
Откуда: Санкт-Петербург

Сообщение sergo80zxc »

работает исправно прога, организован антидребезг на атмеге8 проверял, длинновата что то, как ужать код?


; одной кнопкой включаем и выключаем светодиод
.include "m8Adef.inc"
ldi r16, high(RAMEND); инициализация стека
out SPH,r16;
ldi r16, low(RAMEND);
out SPL,r16
;**************************************************************
ldi r16, 0b00000000
out DDRD, r16 ;Д на вход

ldi r16, 0b11111111
out PORTD, r16 ;подтягиваем Д к пит через рез

ldi r16, 0b11111111
out DDRC, r16 ;порт С на вых

;**************************************************************
MAIN:
rcall START
ldi r16, 0b00000010
out PORTC, r16 ;зажзигаем лед, 1 ножка порта С
rcall SUKA


rcall START
ldi r16, 0b00000000
out PORTC, r16 ;гасим лед, 1 ножка порта С
rcall SUKA
rjmp MAIN

;**************************************************************

PUKA:
ldi r16,0 ;задержка
ldi r17,10

Loop1: dec r16
brne Loop1
dec r17
brne Loop1
ret
;**************************************************************

START:
sbis PIND, 3 ;читаем порт, пропус. след. команду, если бит =1
rjmp KUKA
rcall PUKA
rjmp START

KUKA:
rcall PUKA
sbis PIND, 3 ;читаем порт, пропус. след. команду, если бит =1
rjmp KUKA1
rcall PUKA
rjmp START
KUKA1:
rcall PUKA
ret
;**************************************************************
SUKA:
rcall PUKA
sbis PIND, 3 ;читаем порт, пропус. след. команду, если бит =1
rjmp SUKA
ret
Вложения
upr1kn3.asm
(1.69 КБ) 174 скачивания
глаза боятся, а руки что то не делают))
Реклама
Вымогатель припоя
Аватара пользователя
Сообщения: 577
Зарегистрирован: Ср июн 19, 2013 08:10:48
Откуда: Москва, СПб, Липецк, Рязань

Сообщение ИС-пытатель »

Ну, для начала закиньте в несколько регистров наиболее часто используемые значения (0, 1, 2, 0x80, 0xFF и т.д.)

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

.def  _0=r0
.def  _FF=r1
.def  temp=r16


.cseg
clr _0 ; можно не писать, т.к. при сбросе там 0, но это считается не приличным
clr _FF ; 
dec _FF
Теперь это будет выглядеть так:

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

ldi temp, high(RAMEND); инициализация стека
out SPH, temp;
out SPL, _FF; SPL всегда равно этому значению во всех моделях, где память больше 255 байт (>=256)
; а если память меньше 256 байт, то можно не инициализировать SPH (его скорее всего и не будет как такового)
;**************************************************************
out DDRD, _0 ;Д на вход. Можно не писать, т.к. после сброса по умолчанию на вход
out PORTD, _FF ;подтягиваем Д к пит через рез
out DDRC, _FF ;порт С на вых

;**************************************************************
MAIN:
rcall START 
ldi temp, 0b10
out PORTC, temp ;зажзигаем лед, 1 ножка порта С    
;Здесь Вы, кстати, меняете весь порт, что также считается не айс. Но здесь это не критично. Правильнее использовать команды чтения-модификации-записи
;В Вашем случае можно эти две команды заменить одной out PORTC, _FF (если на остальных ногах ничего не висит)
rcall SUKA 


rcall START
out PORTC, _0 ;гасим лед, 1 ножка порта С
; аналогично. Чтение-модификация-запись
rcall SUKA
rjmp MAIN
Теперь задержка.

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

PUKA:
ldi r31,10 ;задержка. Инициализацию r30 нулем можно сделать в самом начале,но можно и не делать. В конце цикла он также = 0

Loop1:
sbiw Z, 1 
brne Loop1
ret
P.S. Маленькое отступление на тему когда можно не инициализировать регистры нулем, т.к. при старте они = 0. Дело в том, что здесь регистры - та же память (к ним можно даже обратиться через команды записи и чтения в память) и они после сброса (и после выключения некоторое время, совсем чуть-чуть) помнят последнее свое состояние. Если Вы в программе пользуете их с нулевым значением и нигде дальше этот 0 не меняете, то можно не парится и не инициализировать их. А если их значение меняется, то после сброса в них окажется последнее значение, которое может отличаться от 0. И далее Ваша программа будет уже работать не правильно. Аналогично - переменные в памяти и их начальная инициализация.
Некоторые регистры периферии сбрасываются в начальное положение при рестарте автоматически
Пример - написанная мной задержка. Если во время ее выполнения вы сбросите контроллер (подачей 0 на ножку reset, например) то в регистре r30 может оказаться не нулевое значение. и первая задержка при следующем цикле работы контроллера будет немного меньше. Но только первая и Вы это вряд ли заметите. Если у Вас дребезг обрабатывается "впритык", можно на единицу увеличить старший регистр (r31=11), чтобы исключить ложные срабатывания.

P.P.S. Зачем было делать вложение, если Вы весь текст из этого вложения привели здесь? Также Вам бы с rjmp-ами разобраться.. Положили сюда больше, чем надо. И скажу по секрету, антидребезг Вы не совсем правильно организовали. Задержку из основного цикла нужно убрать. Оставить только ту, что по факту нажатия. Вообще, лучше для кнопки задействовать внешнее прерывание. Также забыли вектора прерываний обозначить (Хотя здесь можно и сразу код писать, но лучше как-то с ними). Да и так.. Поднакарулесели Вы..
В общем так примерно должно быть:

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

.def MASK_PIN_LED=r20
...
.cseg
...
ldi MASK_PIN_LED, 0b10
...


MAIN:
in temp, PORTD
andi temp, (1<<3)
brne Main
in temp, PORTC
eor temp, MASK_PIN_LED; меняем значение светодиода на противоположное
out PORTC, temp; отправляем значение в порт

ldi r31, 10 ;исключаем дребезг
Loop1:
sbiw Z, 1 
brne Loop1; 
rjmp Main
А остальные пуки, куки и суки можно выкинуть.
Реклама
Встал на лапы
Аватара пользователя
Сообщения: 113
Зарегистрирован: Пт апр 04, 2014 09:34:08
Откуда: Санкт-Петербург

Сообщение sergo80zxc »

ИС-пытатель спасибо большое) много дельного и по делу) не судите строго) с аналоговой техники перебираюсь :)
Про rjmp-пы не совсем понял) много понавтыкал их? :shock:
глаза боятся, а руки что то не делают))
akl
Друг Кота
Сообщения: 4468
Зарегистрирован: Пт мар 07, 2008 06:54:43
Откуда: Ижевск

Сообщение akl »

sergo80zxc Не обольщайтесь. Код, приведенный выше, нерабочий
-кнопки желательно опрашивать через PIND,3, а не PORTD,3. У Вас правильно и проще.
-переключение светика будет происходить каждый раз после выполнения задержки пока нажата кнопка. В каком состоянии будет светик после отпускания кнопки заранее не известно.
Спойлер

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

;*****************************************************
.def temp=r21
.def MASK_PIN_LED=r20

;...
;.cseg
;...
	ldi MASK_PIN_LED, 0b10
;...
TEST_KEY:
	SBIC	PIND,3
	RJMP	TEST_KEY

	IN	R21,PORTC
	EOR	R21,MASK_PIN_LED
	OUT	PORTC,R21
WAIT_UP_KEY:
	RCALL	DELAY
	
	SBIS	PIND,3		; дождаться отпускания кнопки
	RJMP	WAIT_UP_KEY

	RJMP	TEST_KEY
DELAY:
	ldi r31, 10 ;исключаем дребезг
	CLR	R30
Loop1:
	SBIW ZL, 1 ; SBIW ZH:ZL,1
;	sbiw Z, 1
	brne Loop1;
	RET

	




MAIN:
	IN temp, PIND
;	in temp, PORTD
	andi temp, (1<<3)
	brne Main
	in temp, PORTC
	eor temp, MASK_PIN_LED; меняем значение светодиода на противоположное
	out PORTC, temp; отправляем значение в порт

	ldi r31, 10 ;исключаем дребезг
;Loop1:
	sbiw ZL, 1
;	sbiw Z, 1
	brne Loop1;
	rjmp Main
;*****************************************************
Реклама
Эиком - электронные компоненты и радиодетали
Вымогатель припоя
Аватара пользователя
Сообщения: 577
Зарегистрирован: Ср июн 19, 2013 08:10:48
Откуда: Москва, СПб, Липецк, Рязань

Сообщение ИС-пытатель »

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

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

...
brne Loop1;

Loop2:
in temp, PORTD;  опять читаем
andi temp, (1<<3)
breq Loop2 ; Ждем отпускания.

ldi r31, 10 ;исключаем дребезг
Loop3:
sbiw Z, 1 
brne Loop3;

rjmp Main
Вот и всего-то. В этом случае антидребезг можно вынести в отдельную функцию и вызывать по rcall
-кнопки желательно опрашивать через PIND,3, а не PORTD,3. У Вас правильно и проще.
Это не принципиально (по крайней мере здесь). Потому что в момент чтения в порт сохраняется как раз текущее значение ножек. По поводу проще.. я бы так не горячился...

Можно этот же код еще и по другому организовать, через "память кнопки":

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

.def MASK_PIN_LED=r20
.def OLD_BUTTON=r21 ; предыдущее положение кнопки
...
.cseg
...
ldi MASK_PIN_LED, 0b10

in OLD_BUTTON, PIND ; Здесь нам придется инициализировать переменную стартовым значением
andi OLD_BUTTON, (1<<3)
...


MAIN:
in temp, PIND           ; а вот здесь уже sbis и sbic не прокатят, потому что нам каждый раз нужно разное состояние бита .
andi temp, (1<<3)
cp OLD_BUTTON, temp ; сравниваем текущее состояние кнопки с прошлым.
breq Main ; если состояние кнопки не поменялось - возврат обратно и ждем смены состояния

; если состояние поменялось
mov OLD_BUTTON, temp ; сохраняем сменившееся состояние кнопки

sbrc temp, 3       ; пропуск следующей команды, если бит в регистре сброшен
rjmp antidrebezg ; это для того, чтобы диод менял состояние только при нажатии на кнопку. Если убрать - то будет меняться и по отпускании.

in temp, PINC
eor temp, MASK_PIN_LED; меняем значение светодиода на противоположное
out PORTC, temp; отправляем значение в порт

antidrebezg:
ldi r31, 10 ;исключаем дребезг
Loop1:
sbiw Z, 1 
brne Loop1; 
rjmp Main
В этом случае мы используем один и тот же код для опроса обоих состояний кнопки. А диоды зажигаем в зависимости от состояния
akl, спорим, круче уже не сделаете? 8) Хотя, если сильно извернетесь.. :))

И у Вас, akl, кстати тоже код не правильный. Вы поленились написать второй раз rcall delay и вот результат: У Вас при ожидании поднятия кнопки будет постоянно влазить задержка (которая там не нужна, в принципе), а по факту отпускания задержки нет. В результате Вы можете поймать дребезг и у Вас также будет фиг знает что по отпусканию. А проверять нажатие можно и через sbis, я написал иначе в силу привычки писать так на СИ.
Реклама
Вымогатель припоя
Аватара пользователя
Сообщения: 577
Зарегистрирован: Ср июн 19, 2013 08:10:48
Откуда: Москва, СПб, Липецк, Рязань

Сообщение ИС-пытатель »

sergo80zxc! Хочу Вас предупредить, что ввел всех в блуд! Я сейчас перечитал даташит, освежил память. чтобы получить значение ножки, необходимо читать регистр PINx. akl был прав. При чтении регистра PORTx Вы прочтете последнее значение, которое туда когда-то записывали (или не записывали).
Реклама
Встал на лапы
Аватара пользователя
Сообщения: 113
Зарегистрирован: Пт апр 04, 2014 09:34:08
Откуда: Санкт-Петербург

Сообщение sergo80zxc »

ИС-пытатель, aki спасибо :) ИС-пытатель так и не понял про rjmp - пы?
глаза боятся, а руки что то не делают))
Вымогатель припоя
Аватара пользователя
Сообщения: 577
Зарегистрирован: Ср июн 19, 2013 08:10:48
Откуда: Москва, СПб, Липецк, Рязань

Сообщение ИС-пытатель »

Да вы там просто их много воткнули. как видите, можно меньшим количеством обойтись. когда программа туда-сюда скачет - тоже плохой тон. легко запутаться в коде и наделать ошибок.
Встал на лапы
Аватара пользователя
Сообщения: 113
Зарегистрирован: Пт апр 04, 2014 09:34:08
Откуда: Санкт-Петербург

Сообщение sergo80zxc »

а, понял) спс, я уже думал , если их слишком много, то код может не работать :)
глаза боятся, а руки что то не делают))
Ответить

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