;******************************************************************
;Кодовая панель на PIC16C84
;Автор: Aleksander I. Gurin         a_gurin@kmv.ru
;Все права на данную разработку принадлежат автору.
;Использование данного устройства в коммерческих целях  
;без разрешения автора запрещено.
;(с) 17.08.99
;******************************************************************

	list p=16c84, r=dec
	errorlevel 0,-305
	include "C:\PROGRA~1\MPLAB\p16c84.inc";здесь стоит указать путь к inc-файлу
;соответствующего процессора

	__config   _cp_off & _wdt_on & _pwrte_off & _xt_osc

	count		equ     h'0010'	;"счетчик" опроса клавиатуры 
	pres		equ     h'0011'	;текущее состояние клавиатуры
	push		equ	h'0012'	;последняя нажатая клавиша
	tout		equ	h'0013'	;счетчик задержки
	ctout		equ	h'0014'	;еще один счетчик задержки
	dummy		equ	h'0015'	;когда - как
;					 (обычно,- счетчик попыток набора кода)
	sum		equ	h'0016'	;регистр проверки правильности ввода кода
	flag		equ	h'0017'	;флаговый регистр
;биты регистра flag
;0 - 	\
;1 - 	 - счетчик 10-ти секундной задержки
;2 - 	/
;3 - 	зарезервирован 
;4 - 	устанавливается, когда набрана очередная цифра кода
;5 -	установлен, когда нажата любая кнопка
;6 -	установлен, когда разрешена запись в EEPROM
;7 -	не используется

;#define	test		;установим режим отладки (после отладки эту строчку нужно закомментировать)

	org	h'00'
	goto	main
	org     h'04'
inter	bcf	intcon,3	;подпрограмма обработки прерываний
	bsf	status,5
	bcf	eecon1,4	;сбросим флаг окончания записи в EEPROM
	bcf	status,5
	bsf	flag,6
	retfie

read	clrf	count		;подпрограмма опроса клавиатуры
	incf	count,1	
	clrf	pres	 
	clrf	push
	bcf	flag,5
seta	comf	count,0		;организуем сканирование клавиатуры "бегущим нулем"
	movwf	porta		;установим порт RA
	call	rest		;задержка на установление сигнала на RA
scanb	movf	portb,0		;прочитаем порт RB
	movwf	pres
	comf	pres,1
	xorlw	0x70
	movwf	pres
	swapf	pres,1
	incf	pres,1
	decfsz	pres,1		;если была нажата любая кнопка -
	goto	key		;посмотрим, что нажали
	bcf	status,c	;если нажатия не было -
	rlf	count,1		;прочитаем следующий ряд кнопок
	btfss	count,4		;если все прочли -
	goto	seta
	goto	eoread		;вернемся в точку вызова.

;Результатом работы следующих семи операторов будет преобразование
;содержимого регистра push к следующему виду (в кавычках - нажатая в 
;данный момент кнопка):
;"1" - 09h 	"2" - 0Ah 	"3" - 0Ch
;"4" - 11h	"5" - 12h	"6" - 14h
;"7" - 21h	"8" - 22h	"9" - 24h
;"*" - 41h	"0" - 42h	"#" - 44h
;В таком же формате код хранится в EEPROM
;Кстати, при прошивке процессора в EEPROM нужно записать какой-нибудь код.
;Я обычно записываю 42h по адресу 20h в EEPROM.
;Код при этом будет "0".

key	movf	count,0
	movwf	push
	rlf	push,1
	rlf	push,1
	rlf	push,1
	movf 	pres,0
	iorwf	push,1
	btfss	flag,5		;если клавиша нажата и мы еще не "пищали" -
	call	beep		;немного "попищим"
	bsf	flag,5		;и установим бит 5 регистра flag,
;				 чтобы больше не "пищать" пока не отпущена
;				 нажатая кнопка
	goto	scanb		;...и посмотрим не отпустили-ли кнопку
eoread	return

beep	movlw   0xff		;подпрограмма включения бипера
	movwf   ctout
	ifndef	test
loop1	bcf	portb,2		;проинвертируем биты 1 
	bsf	portb,1		;и 2 порта RB
	call	rest		;... и подождем
	bcf	portb,1		;снова проинвертируем биты 1 
	bsf	portb,2		;и 2 порта RB
	call	rest		;... и снова подождем
	decfsz	ctout,1
	goto	loop1
	bcf	portb,1
	bcf	portb,2
	endif
	return

rest	movlw   0x19		;подпрограмма задержки
	movwf   tout
loop2	nop	
	ifndef	test		;в режиме отладки обойдем эту задержку
	decfsz	tout,1
	goto	loop2
	endif
	return

compare	clrf	sum		;подпрограмма проверки кода
	movlw   0x20
	movwf   fsr
mark02	movf	0x00,0		;просто просуммируем текущие 
	addwf	sum,1		;значения регистров 20h-27h RAM
	incf	fsr,1		;результат оставим  в регистре sum
	movlw	0x28
	xorwf	fsr,0
	btfss	status,z
	goto	mark02
	return

sec	nop			;подпрограмма задержки на 1 сек.
	ifndef	test		;в режиме отладки обойдем эту задержку
	bsf	status,5
	movlw   0x0e		;установим пределитель, чтобы получить  
	movwf	0x81		;задержку примерно в одну секунду
	bcf	status,5
	clrwdt			;сбросим WDT
	sleep			;... и отдохнем
	endif
	return

main	bsf	status,5
	movlw   0x00		;установим порт RA на вывод
        movwf   trisa
	movlw   0x70		;установим RB0-RB3 и RB7 на вывод
	movwf   trisb		;... RB4-RB6 - на ввод
	bcf	0x81,7
	bcf	status,5
	movlw   0x00
	movwf   intcon		;запретим прерывания
	movlw	0x1f
	movwf	porta
	clrf	portb
	movlw	0x03		;число попыток ввода кода
	movwf	dummy
mark00	movlw   0x20		;читаем 8 байт правильного кода
	movwf   fsr		;из EEPROM (20h-27h)
mark01	movf	fsr,0		;в ROM (20h-27h) побайтно
	movwf	eeadr
	bsf	status,5
	bsf	eecon1,rd
	bcf	status,5
	movf	eedata,0
	movwf	0x00
	incf	fsr,1
	movlw	0x28
	xorwf	fsr,0
	btfss	status,z
	goto	mark01
	movlw	0x20
	movwf	fsr
	clrf	flag		;сбросим флаги
	goto	loop0
open	movlw	0x0f		;включим зеленый светодиод
	movwf	porta
	call	sec		;подождем примерно секунду
	call	beep		;"попищим" немного
	bsf	portb,3		;и откроем таки дрерь
	call	sec		;примерно на секунду
mark04	bsf	porta,4		;выключим зеленый светодиод
	clrf	portb
	call	beep		;еще раз "попищим"
	goto	main		;... и все сначала
loop0	clrf	intcon		;запретим все прерывания
	clrwdt			;сбросим WDT
	call	read		;и опросим клавиатуру
mark09	movlw	0x00 
	xorwf	push,0
	btfss	status,z	;если нажата любая кнопка -
	goto	mark05		;пойдем на mark05
	movlw	0x10		;сбросим RA0-RA3
	movwf	porta
loop7	movlw	0x88		;разрешим прерывание по RB
	movwf	intcon
	bsf	status,5	;запустим WDT
	movlw   0x0f
	movwf	0x81	
	bcf	status,5
	clrwdt
	sleep	
	btfsc	intcon,0	;если мы проснулись от нажатия на кнопку -
	goto	loop0		;опросим клавиатуру
	btfss	flag,4
	goto	loop7
	incf	flag,1
	btfsc	flag,2		;если 10 сек. нет нажатий - 
	goto	main		;то стоит навести порядок
	goto 	loop7		;в противном случае - подождем еще...
mark05	movlw	0x41		;... и посмотрим, что нажали.
	xorwf	push,0
	btfss	status,z	;если нажали "*" -
	goto	mark06
	goto	mark10		;пойдем на mark10
mark06	movlw	0x44
	xorwf	push,0
	btfss	status,z	;если нажали "#" -
	goto	mark07
	goto	mark03		;пойдем на mark03
mark07	movf	push,0		;значит набрана очередная цифра кода
	xorwf	0x00		;...запишем ее в EEPROM
	incf	fsr,1
	movlw	0x10		;сбросим счетчик 10-ти секундной задержки
	movwf	flag
	goto	loop0		;... и будем ждать следующей цифры кода
mark03	bcf	status,c	;был набран код + "#"
	call	compare		;проверим правильность набора кода
	incf	sum,1
	decfsz	sum,1		;если код правильный -
	goto	mark08
	goto	open		;откроем дверь
mark08	decfsz	dummy		;"ошибочка" - вычтем одну попытку и проверим,- не была ли она последней
	goto	mark00		;попробуем еще раз...
;				 три раза неправильно введен код! 
;				 любые действия пользователя игнорируются!
	movlw	0x40		
	movwf	dummy
	clrf	porta
loop4	clrf	portb
	call	beep		;"пищим" примерно минуту
	call	sec
	bsf	porta,4
	decfsz	dummy,1
	goto	loop4
	goto	main		;... и все сначала
mark10	bcf	status,c	;был набран код + "*" - попытка смены кода
	call	compare		;проверим правильность набора кода
	incf	sum,1
	decfsz	sum,1		;если  "старый_код" правильный -
	goto	main
	movlw	0x20
	movwf	fsr
	bcf	porta,4		;включим зеленый светодиод
	call	beep		;радостно "пискнем"
	bsf	porta,4		;и выключим зеленый светодиод
loop6	clrwdt
	call	read		;опросим клавиатуру
	movlw	0x00
	xorwf	push,0
	btfss	status,z	;если что-то нажато -
	goto	mark11		
	goto	loop6
mark11	movlw	0x41		;... проверим, не нажали-ли "*"
	xorwf	push,0
	btfss	status,z	;если "*" -
	goto	mark12
	goto	main		;пользователь передумал, пора навести порядок
mark12	movlw	0x44		;... проверим, не нажали-ли "#"
	xorwf	push,0
	btfss	status,z	;если "#" -
	goto	mark13
	goto	save		;... значит завершен набор "нового_кода" и его стоит сохранить в EEPROM
mark13	movf	push,0		;если мы сюда "дошли" - значит набрана очередная цифра "нового_кода"
	movwf	0x00		;запишем ее в RAM
	incf	fsr,1
	movlw	0x29
	xorwf	fsr,0
	btfss	status,z	;если была попытка ввести 9-ю цифру
	goto	loop6
	call	sec		;два раза "пискнем" и не будем сохранять "новый_код"
	call	beep
	call	sec
	call	beep
	goto	main
save	call	sec		;перепишем новый код в ееprom
	bcf	porta,4
	call	beep
	bsf	porta,4
	clrwdt
	movlw	0x20
	movwf	fsr
loop5	bsf	status,5	;разрешим запись (стандартная процедура записи в EEPROM)
	movlw	0x04
	movwf	eecon1
	bcf	status,5
	bcf	flag,6
	movf	fsr,0
	movwf	eeadr
	movf	0x00,0
	movwf	eedata
	movlw	0xc0
	movwf	intcon
	bsf	status,5
	movlw	0x09
	movwf	0x81
	movlw	0x55
	movwf	eecon2
	movlw	0xaa
	movwf	eecon2
	bsf	eecon1,wr
loop8	bcf	status,5
	btfss	flag,6		;пока запись не завершена
	goto	loop8		;наматываем круги 
	clrf	intcon
	clrwdt
	bcf	flag,6
	incf	fsr,1		;... и так пока не перепишем байты 20h-27h из ROM в EEPROM
	movlw	0x28	
	xorwf	fsr,0
	btfss	status,z
	goto	loop5
	bsf	status,5
	clrf	eecon1
	clrf	eecon2
	movlw	0x0e
	movwf	0x81
	bcf	status,5
	clrwdt			;запись завершена
stop	bcf	porta,4		;включим зеленый светодиод
	call	beep		;радостно "пискнем"
	bsf	porta,4		;и выключим зеленый светодиод
	call	sec		;подождем секунду
	bcf	porta,4		;включим зеленый светодиод
	call	beep		;радостно "пискнем"
	bsf	porta,4		;и выключим зеленый светодиод
	goto	main		;... и все сначала
end	end	


--------------------------------------------------------------------------------

Автор: Aleksander I. Gurin. a_gurin@kmv.ru 