;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;   Schemat podłączeń programowanego układu
;
;                 +----v----+
;           MCLR [| 1     40|] 
;                [| 2     39|] 
;                [| 3     38|] 
;                [| 4     37|] 
;                [| 5     36|] 
;                [| 6     35|] 
;                [| 7     34|] 
;                [| 8     33|] RB0/INT <- S1
;                [| 9     32|] VDD
;                [|10     31|] VSS
;            VDD [|11     30|] 
;            VSS [|12     29|] 
;(20 MHz) / OSC1 [|13     28|]
;         \ OSC2 [|14     27|]
;                [|15     26|] 
;                [|16     25|] 
;                [|17     24|]
;                [|18     23|] 
;      D1 <- RD0 [|19     22|] 
;      D2 <- RD1 [|20     21|] 
;                 +---------+
;                 PIC16F877A
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
#include	<p16f877A.inc>	

;ustawienia bitów konfiguracyjnych	
__CONFIG _CP_OFF&_WDT_OFF&_BODEN_OFF&_PWRTE_OFF&_HS_OSC&_WRT_OFF&_LVP_OFF&_CPD_OFF

;**********************************************************************
;zmienne dla podprogramu obsługi przerwań
w_temp		EQU	0x7D	
status_temp	EQU	0x7E	
pclath_temp	EQU	0x7F
;**********************************************************************
;zmienne programu
licznik_D1	EQU 0x24
licznik_D2	EQU 0x25
			
;**********************************************************************
;początek programu
	ORG     0x000
  	goto	main			;skok do etykiety programu głównego

;**********************************************************************
;podprogram obsługi przerwań
	ORG		0x004			;adres wektora przerwań
;zapamiętanie wartości rejestrów
	movwf	w_temp			;W -> w_temp
	movf	STATUS, w		;STATUS -> W
	movwf	status_temp		;W -> status_temp
	movf	PCLATH, w		;PCLATH -> W
	movwf	pclath_temp		;W -> pclath_temp
;kod obsługi przerwań
	btfss	PIR1, TMR1IF	;przerwanie przepełnienia TMR1
	goto	czy_to_RB0_INT	;jeśli bit TMR1IF nie jest ustawiony, to sprawdź przerwanie RB0/INT
		;obsłuż diodę D1
		incf	licznik_D1, f	;inkrementuj licznik_D1
		;if(licznik_D1>24)
		movf	licznik_D1, w	;licznik -> W
		sublw	d'24'			;W = 24 - W
		btfsc	STATUS, C		;pomiń skok, gdy C == 0
		goto	licznik_D1_mn24	;skocz do etykiety, jeśli licznik_D1 <= 24
			;jeśli licznik_D1 > 24
			movlw	1			;W <- 1
			xorwf	PORTD, f	;przełącz stan diody D1
			clrf	licznik_D1	;wyzeruj licznik
licznik_D1_mn24:				;tu zostanie wykonany skok, jeśli licznik_D1 <= 24
		;obsłuż diodę D2
		;if(licznik_D2 > 0) zastąpimy warunkiem if(licznik_D2 != 0)
		movf	licznik_D2, f	;licznik_D2 -> licznik_D2
		btfsc	STATUS, Z		;pomiń skok, gdy Z == 0
		goto	licznik_D2_0	;skocz do etykiety, jeśli licznik_D2 == 0
			;jeśli licznik_D2 != 0
			bsf		PORTD, 1	;zaświeć diodę D2
			decf	licznik_D2,f;dekrementuj licznik
			goto	ustaw_TMR1	;skocz do etykiety
licznik_D2_0:					;tu zostanie wykonany skok, jeśli licznik_D2 == 0
			bcf		PORTD, 1	;zgaś diodę D2
		;obsłuż moduł Timer1
ustaw_TMR1:
		movlw	0x9E			;W <- 0x9E
		movwf	TMR1H			;W -> TMR1H
		movlw	0x58			;W <- 0x58
		movwf	TMR1L			;W -> TMR1L
		bcf		PIR1, TMR1IF	;wyczyść flagę przerwania
		goto	koniec_isr		;skocz do etykiety
czy_to_RB0_INT:
	btfss	INTCON, INTF	;przerwanie RB0/INT
	goto	koniec_isr		;jeśli bit INTF nie jest ustawiony, to wyjdź
		movlw	d'200'		;W <- 200
		movwf	licznik_D2	;W -> licznik
		bcf		INTCON, INTF;wyczyść flagę przerwania
koniec_isr:
;przywrócenie wartości rejestrów
	movf	pclath_temp, w	;pclath_temp -> W
	movwf	PCLATH			;W -> PCLATH
	movf    status_temp, w	;status_temp -> W
	movwf	STATUS			;W -> STATUS
	swapf	w_temp, f		;zamiast movf w_temp, w są 2 instrukcje swapf,
	swapf	w_temp, w		;by nie ustawiać rejestru STATUS (w_temp -> W)
	retfie					;powrót z przerwania

;**********************************************************************
;program główny
main:
	banksel (TRISD)			;ustaw bank dla TRISD (bank 1)
	bcf		TRISD, 0		;linia RD0 z diodą D1 wyjściowa
	bcf		TRISD, 1		;linia RD1 z diodą D2 wyjściowa
	banksel (PORTD)			;ustaw bank dla PORTD (bank 0)
	bcf		PORTD, 0		;dioda D1 nie świeci
	bcf 	PORTD, 1		;dioda D2 nie świeci

	;konfiguracja przerwania RB0/INT
	banksel (OPTION_REG)		;ustaw bank dla OPTION_REG
	bcf		OPTION_REG, INTEDG	;reakcja na zbocze opadające
	banksel (INTCON)			;ustaw bank dla INTCON
	bsf		INTCON, INTE		;włącz przerwanie RB0/INT

	;konfiguracja przerwania modułu Timer1
	movlw	0x9E				;W <- 0x9E
	movwf	TMR1H				;W -> TMR1H
	movlw	0x58				;W <- 0x58
	movwf	TMR1L				;W -> TMR1L
	banksel (PIE1)				;ustaw bank dla PIE1
	bsf		PIE1, TMR1IE		;włącz przerwanie Timer1
	banksel (T1CON)				;ustaw bank dla T1CON	
	bsf		T1CON, TMR1ON		;włącz moduł Timer1

	clrf	licznik_D1			;wyzerowanie licznika diody D1
	clrf	licznik_D2			;wyzerowanie licznika diody D2

	bsf		INTCON, PEIE		;włączenie przerwań urządzeń peryferyjnych
	bsf		INTCON, GIE			;globalne włączenie przerwań

;nieskończona pętla
petla:
	goto petla


	END
