;******************************
;* Zespół Szkół Elektrycznych *
;*          Kielce            *
;*     Praca Dyplomowa        *
;* Wykonawca:                 *
;*   Tomasz Cedro             *
;* Promotor:                  *
;*   mgr inż. Andrzej Oko     *
;*                            *
;*   Rok szkolny 2001/2002    *
;******************************


;======================================
;  DEKLARACJA STAŁYCH I ZMIENNYCH

; klawiatura
KEY_X1	EQU	P1.0
KEY_X2	EQU	P1.1
KEY_X3	EQU	P1.2
KEY_X4	EQU	P1.3
KEY_Y1	EQU	P1.4
KEY_Y2	EQU	P1.5
KEY_Y3	EQU	P1.6
KEY_Y4	EQU	P1.7
KEY_NUMBER	EQU	30H
KEY_DELAY	EQU	100

;buzzer piszczyk
BUZZER	EQU	P2.5
CZAS_PIKNIECIA_BLAD	EQU	25

;szeregowa pamiec EEPROM
I2C_MEMORY_SDA	EQU	P2.4
I2C_MEMORY_SCL	EQU	P2.3
I2C_MEMORY_ADDR	EQU	31H
I2C_MEMORY_PAGE	EQU	32H
I2C_READ	EQU	33H
I2C_FAIL	EQU	34H
I2C_FAIL_COUNT	EQU	50
I2C_BYTE_COUNT	EQU	35H
I2C_MEMORY_CHIP_ADDR	EQU	0H
I2C_MEMORY_DATA	EQU	36H
I2C_MEMORY_DATA_ADDR	EQU	37H

;magistrala danych
SECTION_A	EQU	P2.7
SECTION_B	EQU	P2.6
DATA_PORT	EQU	P0

;wyswietlacz
LED_W1	EQU	P3.7
LED_W2	EQU	P3.6
LED_W3	EQU	P3.5
LED_W4	EQU	P3.4
LED_DIGIT1	EQU	38H
LED_DIGIT2	EQU	39H
LED_DIGIT3	EQU	3AH
LED_DIGIT4	EQU	3BH
LED_BLINK_COUNT	EQU	3CH
LED_SECTION_A	EQU	P2.0
LED_SECTION_B	EQU	P2.1

;zmienne sekwencji wyjsciowych
CURRENT_DELAY	EQU	3DH
CURRENT_STEP	EQU	3EH
CURRENT_SECTION	EQU	3FH
CURRENT_DATA_A	EQU	40H
CURRENT_DATA_B	EQU	41H

;timer
TMOD_SET	EQU	00000001B

; KONIEC DEKLARACJI STALYCH I ZMIENNYCH
;======================================



;skaczemy do poczatku programu
	LJMP	START

; wektor przerwania timera 0
	ORG	0BH
	LJMP	WRITE_LED


	ORG	100H
START:
	MOV	LED_BLINK_COUNT,#0	; zerujemy rejstry
	MOV	CURRENT_STEP,#0
	MOV	CURRENT_DELAY,#0
	MOV	CURRENT_SECTION,#0
	MOV	CURRENT_DATA_A,#0
	MOV	CURRENT_DATA_B,#0

	MOV	TMOD,#TMOD_SET		; ustawiamy timery
	MOV	TL0,#0
	MOV	TH0,#0

	SETB	EA			; ogolne zezwolenie na przerwania
	SETB	ET0			; zezwolenie na przerwanie od T0

	LCALL	BEEP_INIT		; gotowy do pracy

MENU:
	LCALL	GET_KEY			; czekamy na nacisniecie guzika
	MOV	A,KEY_NUMBER
	CJNE	A,#0,MENU_BLINK_OFF	; czy jakis zostal nacisniety?
	LCALL	BLINK_LEDS		; nie - migaj diodami
	MOV	R3,#25
	LCALL	CZEKAJ_MS
	LJMP	MENU
MENU_BLINK_OFF:
	MOV	P0,#0FFH
	MOV	KEY_NUMBER,#0
	LCALL	BEEP			; tak - piknij i sprawdz ktory
	MOV	R3,#100
	LCALL	CZEKAJ_MS
MENU_IF1:
	CJNE	A,#1,MENU_IF2		; jesli 1 - wywolaj procedure
	LCALL	PROGRAM_DEVICE		; programowania sekwencji.
	LJMP	MENU			; Pozniej wroc do menu
MENU_IF2:
	CJNE	A,#2,MENU_IF3		; jesli 2 - wywolaj procedure
	LCALL	AUTO_PLAY_SEQUENCE	; odtwarzania sekwencji.
	LJMP	MENU			; Pozniej wroc do menu
MENU_IF3:
	CJNE	A,#3,MENU_IF4		; jesli 3 - wywolaj procedure
	LCALL	MANUAL_PLAY_SEQUENCE	; polautomatycznego odtwarzania.
	LJMP	MENU			; Pozniej wroc do menu
MENU_IF4:
	CJNE	A,#4,MENU		; jesli 4 - wywolaj procedure
	LCALL	ERASE_MEMORY		; kasowania pamieci.
	LJMP	MENU			; Pozniej wroc do menu.








;=============================================
; Procedura programowania sekwencji wyjsciowej

PROGRAM_DEVICE:
	LCALL	I2C_LOAD_SETUP			; Wczytaj ustawienia dla aktualnego kroku.
	LCALL	LED_PRINT_SECTION_DATA		; Wypisz ustawienia dla aktualnej sekcji.
	LCALL	LED_PRINT_STEP_AND_DELAY	; Przygotuj cyfry dla procedury wyswietlajacej.
	SETB	TR0				; Wlacz wyswietlacz LED
PROGRAM_DEVICE_LOOP:
	LCALL	LED_PRINT_STEP_AND_DELAY
	LCALL	GET_KEY				; Sprawdz czy nacisniety jest jakis guzik
	MOV	A,KEY_NUMBER
	CJNE	A,#0,PD_BEEP			; Jesli tak - piknij, jesli nie czekaj na nacisniecie
	LJMP	PROGRAM_DEVICE_LOOP
PD_BEEP:
	MOV	KEY_NUMBER,#0
	LCALL	BEEP				; Piknij
	MOV	R3,#KEY_DELAY
	LCALL	CZEKAJ_MS			; Autorepetycja klawiatury
PD_IF1:
	CJNE	A,#1,PD_IF2			; Czy nacisnieto 1
	CPL	DATA_PORT.0			; tak - zaneguj bit 0 portu danych
	LCALL	LED_PRINT_SECTION_DATA		; port danych wskazuje na sakcje...
	LCALL	LED_PRINT_SECTION_DATA		; wypisz ostateczna zmiane.
	LJMP	PROGRAM_DEVICE_LOOP		; Skocz do poczatku procedury
PD_IF2:
	CJNE	A,#2,PD_IF3			; Nacisnieto 2 - zaneguj 2. bit aktualnej sekcji...
	CPL	DATA_PORT.1
	LCALL	LED_PRINT_SECTION_DATA
	LJMP	PROGRAM_DEVICE_LOOP
PD_IF3:
	CJNE	A,#3,PD_IF4
	CPL	DATA_PORT.2
	LCALL	LED_PRINT_SECTION_DATA
	LJMP	PROGRAM_DEVICE_LOOP
PD_IF4:
	CJNE	A,#4,PD_IF5
	CPL	DATA_PORT.3
	LCALL	LED_PRINT_SECTION_DATA
	LJMP	PROGRAM_DEVICE_LOOP
PD_IF5:
	CJNE	A,#5,PD_IF6
	CPL	DATA_PORT.4
	LCALL	LED_PRINT_SECTION_DATA
	LJMP	PROGRAM_DEVICE_LOOP
PD_IF6:
	CJNE	A,#6,PD_IF7
	CPL	DATA_PORT.5
	LCALL	LED_PRINT_SECTION_DATA
	LJMP	PROGRAM_DEVICE_LOOP
PD_IF7:
	CJNE	A,#7,PD_IF8
	CPL	DATA_PORT.6
	LCALL	LED_PRINT_SECTION_DATA
	LJMP	PROGRAM_DEVICE_LOOP
PD_IF8:
	CJNE	A,#8,PD_IF9
	CPL	DATA_PORT.7
	LCALL	LED_PRINT_SECTION_DATA
	LJMP	PROGRAM_DEVICE_LOOP
PD_IF9:
	CJNE	A,#9,PD_IF10			; Nacisnieto guzik UP
	PUSH	ACC				; Sprawdzamy czy aktualny krok ma wartosc
	MOV	A,CURRENT_STEP			; mnejsza od 99. Jesli tak to ja inkrementujemy.
	LCALL	CHECK_IF_99			; Jesli nie, pikamy blad
	MOV	CURRENT_STEP,A
	POP	ACC
	LCALL	I2C_LOAD_SETUP			; Wczytujemy ustawienia wyjsc dla danego kroku
	LCALL	LED_PRINT_STEP_AND_DELAY	; Aktualizacja danych wyswietlacza.
	LJMP	PROGRAM_DEVICE_LOOP		; Skok do poczatku procedury
PD_IF10:
	CJNE	A,#10,PD_IF11			; Nacisnieto guzik DOWN
	PUSH	ACC				; Sprawdzamy czy aktualny krok ma wartosc
	MOV	A,CURRENT_STEP			; wieksza od 0. Jesli tak to ja dekrementujemy.
	LCALL	CHECK_IF_0			; Jesli nie - pikamy blad
	MOV	CURRENT_STEP,A
	POP	ACC
	LCALL	I2C_LOAD_SETUP			; Wczytujemy ustawienia wyjsc dla danego kroku
	LCALL	LED_PRINT_STEP_AND_DELAY	; Aktualizacja danych wyswietlacza
	LJMP	PROGRAM_DEVICE_LOOP		; Skok do poczatku procedury
PD_IF11:
	CJNE	A,#11,PD_IF12			; Nacisnieto guzik +
	PUSH	ACC				; Akcja taka sama jak dla guzika UP
	MOV	A,CURRENT_DELAY			; tyle ze inkrementujemy aktualne opoznienie
	LCALL	CHECK_IF_99
	MOV	CURRENT_DELAY,A
	POP	ACC
	LJMP	PROGRAM_DEVICE_LOOP
PD_IF12:
	CJNE	A,#12,PD_IF13			; Nacisnieto guzik -
	PUSH	ACC				; Akcja taka sama jak dla guzika DOWN
	MOV	A,CURRENT_DELAY			; tyle ze dekrementujemy aktualne opoznienie
	LCALL	CHECK_IF_0
	MOV	CURRENT_DELAY,A
	POP	ACC
	LJMP	PROGRAM_DEVICE_LOOP
PD_IF13:
	CJNE	A,#13,PD_IF14			; Nacisnieto guzik A/B
	MOV	R0,CURRENT_SECTION		; Bedziemy wybierac sekcje A lub B
	CJNE	R0,#0,PD_IF13_B			; Jesli aktualna jest sekcja A
	MOV	CURRENT_SECTION,#1		; To zamien ja na B
	MOV	CURRENT_DATA_A,DATA_PORT	; I przepisz aktualne dane do A
	LJMP	PD_IF13_END
PD_IF13_B:
	MOV	CURRENT_SECTION,#0		; Jesli aktualna jest sekcja B
	MOV	CURRENT_DATA_B,DATA_PORT	; to zamien na A i przepisz dane do B
PD_IF13_END:
	LCALL	LED_PRINT_SECTION_DATA		; Wypisz aktualne dane sekcji
	LJMP	PROGRAM_DEVICE_LOOP		; Skocz do poczatku procedury

PD_IF14:
	CJNE	A,#14,PD_IF15			; Nacisnieto guzik OK
	LCALL	I2C_SAVE_SETUP			; Zapisz ustawienia aktualnego kroku do pamieci
	INC	CURRENT_STEP			; Inkrementuj aktualny krok
	LCALL	I2C_LOAD_SETUP			; Wczytaj ustawienia aktualnego kroku
	LJMP	PROGRAM_DEVICE_LOOP		; Skocz do pocztku procedury
PD_IF15:
	CJNE	A,#15,PD_GOTO_START		; Naciesnieto guzik MENU
	LJMP	PD_END				; Skocz do konca procedury a wiec wroc do menu
PD_GOTO_START:
	LCALL	BEEP_ERROR			; Nacisnieto zly klawisz - piknij
	LJMP	PROGRAM_DEVICE_LOOP		; Powrot do poczatku procedury
PD_END:
	SETB	LED_SECTION_A			; Wylaczamy diody
	SETB	LED_SECTION_B			;  sygnalizacyjne sekcji A i B
	CLR	TR0				; Wylaczamy
	MOV	P3,#0FFH			; Wyswietlacz LED
	RET

; Koniec procedura programowania sekwencji
;=============================================






;===============================================
; Procedura automatycznego odtwarzania sekwencji

AUTO_PLAY_SEQUENCE:
	PUSH	ACC
	LCALL	I2C_LOAD_SETUP			; Wczytujemy sekwencjie aktualnego kroku
	SETB	TR0				; Wlaczamy wyswietlacz LED
	LCALL	LED_PRINT_STEP_AND_DELAY	; Atualizujemy dane wyswietlacza LED
APS_LOOP:
	LCALL	LED_PRINT_SECTION_DATA		; Wypisujemy dane aktualnej sekcji
	LCALL	LED_PRINT_STEP_AND_DELAY	; Atualizujemy dane wyswietlacza LED
	LCALL	GET_KEY				; Sprawdzamy czy jakis klawisz jest acisniety
	MOV	A,KEY_NUMBER
	MOV	KEY_NUMBER,#0
	CJNE	A,#0,APS_BEEP			; Jesli
	LJMP	APS_LOOP			; nie to skocz do poczatku procedury
APS_BEEP:
	LCALL	BEEP				; tak to piknij.
	MOV	R3,#KEY_DELAY			; Autorepetycja
	LCALL	CZEKAJ_MS			;  klawiatury
APS_IF9:
	CJNE	A,#9,APS_IF10			; Nacisnieto klawisz UP
	PUSH	ACC				; jesli aktualny krok rozny od 99
	MOV	A,CURRENT_STEP			; to inkrementuj
	LCALL	CHECK_IF_99
	MOV	CURRENT_STEP,A
	POP	ACC
	LCALL	I2C_LOAD_SETUP			; Wczytaj z pamieci sekwencje danego kroku
	LJMP	APS_LOOP			; Skocz do poczatku procedury
APS_IF10:
	CJNE	A,#10,APS_IF15			; Nacisnieto klawisz DOWN
	PUSH	ACC				; Jesli aktualny krok rozny od 0
	MOV	A,CURRENT_STEP			; to dekrementuj
	LCALL	CHECK_IF_0
	MOV	CURRENT_STEP,A
	POP	ACC
	LCALL	I2C_LOAD_SETUP			; Wczytaj z pamieci sekwencje danego kroku
	LJMP	APS_LOOP			; Skocz do poczatku procedury
APS_IF15:
	CJNE	A,#15,APS_IF14			; Wcisnieto klawisz MENU
	LJMP	APS_END				; koniec procedury - powrot do glownego menu
APS_IF14:
	CJNE	A,#14,APS_ERROR			; Wcisnieto OK
	MOV	R4,#0				; Bedziemy czekac na rozpoczecie odtwarzania
	MOV	LED_BLINK_COUNT,#0		; sekwencji nacisnieciem klawisza LAUNCH

APS_DET_WAIT:
	LCALL	GET_KEY				; Sprawdz czy nacisnieto klawisz
	MOV	A,KEY_NUMBER
	MOV	KEY_NUMBER,#0
	CJNE	A,#0,APS_DW_IF15		; Czy nacisnieto jakis klawisz?
	LCALL	LED_BLINK_DETONATION		; Nie - mrygaj diodami
	LCALL	BEEP_DETONATION			; i wydawaj sygnal dwiekowy
	LJMP	APS_DET_WAIT			; Skocze i sprawdz czy juz nacisnieto klawisz
APS_DW_IF15:
	CJNE	A,#15,APS_DW_IF16		; Nacisnieto MENU - anulujemy wysadzanie
	LJMP	APS_END				; i wracamy do glownego menu
APS_DW_IF16:
	CJNE	A,#16,APS_DET_WAIT		; Nacisnieto LAUNCH - rozpoczynamy wysadzanie

	MOV	R2,CURRENT_STEP			; Przechowaj w rejstrze numer ostatniego kroku
	INC	R2				; Zwieksz o jeden - jego tez bedziemy odtwarzac
	MOV	CURRENT_STEP,#0			; Tymczasem zerujemy licznik krokow

APS_DET_LOOP:					; PETLA ODTWARZANIA SEKWENCJI
	LCALL	I2C_LOAD_SETUP			; Wczytujemy sekwencje wyjsciowa aktualnego kroku
	LCALL	OUTPUT_SEQUENCE			; Wystawiamy sekwencje na zaciski wyjsciowe

	MOV	ACC,CURRENT_DELAY		; Kopiuj do akumlatora aktualne opznienie
	CJNE	A,#0,APS_DET_LOOP2		; Czy opoznienie to rowne jest 0?
	LJMP	APS_DET_LOOP3			; Jesli tak - omijamy odczekanie do nastepnego kroku
APS_DET_LOOP2:
	MOV	CURRENT_DELAY,ACC		; Jesli nie odczekujemy czas opznienie * 100msekund
	LCALL	LED_PRINT_STEP_AND_DELAY	; Aktualizujemy dane wysiweltacza LED
	MOV	R3,#100				; Powtorzenie n-razy czasu 100ms da nam zadane
	LCALL	CZEKAJ_MS			; opoznienie
	DJNZ	ACC,APS_DET_LOOP2		; Czy odczekalismy juz caly czas? Nie - czekamy dalej
APS_DET_LOOP3:
	INC	CURRENT_STEP			; Jesli tak - przechodzimy do nastepnego korku
	MOV	ACC,R2
	CJNE	A,CURRENT_STEP,APS_DET_LOOP	; Czy jest to ostatni krok? Nie - skocz do poczatku petli

	MOV	DATA_PORT,#0			; Jesli tak - wyzeruj wyjscia urzadzenia
	LCALL	STROBE_SECTION_A_CLK
	LCALL	STROBE_SECTION_B_CLK

APS_END:
	CLR	TR0				; Zatrzymaj procedure wyswietlajaca
	MOV	P3,#0FFH			; Wylacz wyswietlacze
	POP	ACC
	RET					; Wracaj

APS_ERROR:					; Tutaj fragment pikajacy w przypadku
	LCALL	BEEP_ERROR			; nacisniecia niewlasciwego guzika
	LJMP	APS_LOOP
	

; Koniec procedury automatycznego odtwarzania
;===============================================




;==================================================
; Procedura polautomatycznego odtwarzania sekwencji

MANUAL_PLAY_SEQUENCE:
	PUSH	ACC
	MOV	CURRENT_STEP,#0			; Zaczynamy od kroku numer 0
	MOV	CURRENT_DELAY,#0		; Opoznienie nie bedzie potrzebne
	SETB	TR0				; Wlaczamy wyswietlacz LED
MPS_LOOP:
	LCALL	LED_PRINT_STEP_AND_DELAY	; Aktualizujemy dane wyswietlacza LED
	LCALL	GET_KEY				; Sprawdzamy czy nacisniety jest jakis klawisz
	MOV	A,KEY_NUMBER
	MOV	KEY_NUMBER,#0
	CJNE	A,#0,MPS_BEEP			; Jesli nie - sprawdzamy jeszcze raz
	LJMP	MPS_LOOP
MPS_BEEP:
	LCALL	BEEP				; Jesli tak - pikamy
	MOV	R3,#KEY_DELAY			; I czekamy jakis czas, tworzac autorepetycje klawiatury
	LCALL	CZEKAJ_MS
MPS_IF1:
	CJNE	A,#1,MPS_IF2			; Nacisnieto 1
	MOV	CURRENT_STEP,#1			; Aktualny krok to 1
	LCALL	I2C_LOAD_SETUP			; Wczytujemy z pamieci sekwencje wyjsciowa
	LCALL	OUTPUT_SEQUENCE			; Wystawiamy sekwencje na zaciski wyjsciowe
	LJMP	MPS_LOOP			; Skaczemy do poczatku procedury
MPS_IF2:
	CJNE	A,#2,MPS_IF3
	MOV	CURRENT_STEP,#2
	LCALL	I2C_LOAD_SETUP
	LCALL	OUTPUT_SEQUENCE
	LJMP	MPS_LOOP
MPS_IF3:
	CJNE	A,#3,MPS_IF4
	MOV	CURRENT_STEP,#3
	LCALL	I2C_LOAD_SETUP
	LCALL	OUTPUT_SEQUENCE
	LJMP	MPS_LOOP
MPS_IF4:
	CJNE	A,#4,MPS_IF5
	MOV	CURRENT_STEP,#4
	LCALL	I2C_LOAD_SETUP
	LCALL	OUTPUT_SEQUENCE
	LJMP	MPS_LOOP
MPS_IF5:
	CJNE	A,#5,MPS_IF6
	MOV	CURRENT_STEP,#5
	LCALL	I2C_LOAD_SETUP
	LCALL	OUTPUT_SEQUENCE
	LJMP	MPS_LOOP
MPS_IF6:
	CJNE	A,#6,MPS_IF7
	MOV	CURRENT_STEP,#6
	LCALL	I2C_LOAD_SETUP
	LCALL	OUTPUT_SEQUENCE
	LJMP	MPS_LOOP
MPS_IF7:
	CJNE	A,#7,MPS_IF8
	MOV	CURRENT_STEP,#7
	LCALL	I2C_LOAD_SETUP
	LCALL	OUTPUT_SEQUENCE
	LJMP	MPS_LOOP
MPS_IF8:
	CJNE	A,#8,MPS_IF9
	MOV	CURRENT_STEP,#8
	LCALL	I2C_LOAD_SETUP
	LCALL	OUTPUT_SEQUENCE
	LJMP	MPS_LOOP
MPS_IF9:
	CJNE	A,#9,MPS_IF10			; Nacisnieto klawisz UP
	MOV	A,CURRENT_STEP			; Czy mozna jeszcze inkrementowac krok?
	LCALL	CHECK_IF_99			; Jesli tak to inkrementuj, jesli nie - piknij blad
	LCALL	I2C_LOAD_SETUP			; Wczytaj ustawienia sekwencji dla aktualnego kroku
	LCALL	OUTPUT_SEQUENCE			; Wystaw sekwencje na zaciski wyjsciowe
	LJMP	MPS_LOOP
MPS_IF10:
	CJNE	A,#10,MPS_IF15			; Nacisnieto klawisz DOWN
	MOV	A,CURRENT_STEP
	LCALL	CHECK_IF_0			; Jesli to mozliwe, to dekrementuj krok
	LCALL	I2C_LOAD_SETUP			; Wczytaj ustawienia sekwencji
	LCALL	OUTPUT_SEQUENCE			; Wystaw sekwencje na zaciski wyjsciowe
	LJMP	MPS_LOOP
MPS_IF15:
	CJNE	A,#15,MPS_ERROR			; Nacisnieto MENU
	LJMP	MPS_END				; Wracamy do glownego menu
MPS_ERROR:
	LCALL	BEEP_ERROR			; Wcisnieto niewlasciwy klawisz
	LJMP	MPS_LOOP			; poknij blad i wroc na poczatek procedury
MPS_END:
	CLR	TR0				; Zatrzymujemy przerwanie wyswietlania
	MOV	P3,#0FFH			; Wylaczamy wyswietlacz
	MOV	DATA_PORT,#0FFH			; Zerujemy
	LCALL	OUTPUT_SEQUENCE			;  zaciski wyjsciowe urzadzenia
	POP	ACC
	RET


; KOniec procedury polautomatycznego odtwarzania
;==================================================







;======================================
; Procedura kasowania pamieci EEPROM

ERASE_MEMORY:
	PUSH	ACC
	MOV	DATA_PORT,#10101010B		; Zaswiec odpowiednie diody sygnalizacyjne
	LCALL	BEEP_MEMORY_ERASE		; Piknij informujac o zamiarze skasowania pamieci
	MOV	CURRENT_STEP,#0			; Kasujemy pamiec od poczatku
	MOV	CURRENT_DELAY,#0		; Opoznienie przyjmie wartosc 0
	LCALL	LED_PRINT_STEP_AND_DELAY	; Aktualizuj dane wyswietlacza LED
	SETB	TR0				; Rozpocznij wyswietlanie LED
ERASE_MEMORY_LOOP:
	LCALL	GET_KEY				; Sprawdz nacisniecie klawisza
	MOV	A,KEY_NUMBER
	MOV	KEY_NUMBER,#0
	CJNE	A,#0,EM_BEEP			; Czy jakis zostal nacisniety?
	LJMP	ERASE_MEMORY_LOOP		; Nie - sprawdz jeszcze razz
EM_BEEP:
	LCALL	BEEP				; Tak - piknij
	MOV	R3,#KEY_DELAY			; Odczekaj do nastepnego nacisniecia
	LCALL	CZEKAJ_MS			; (autorepetycja klawiatury)
EM_IF14:
	CJNE	A,#14,EM_IF15			; Nacisnieto klawisz OK - bedziemy kasowac pamiec
	MOV	I2C_MEMORY_PAGE,#0		; Najpierw strona zawierajaca opznienia krokow
	MOV	I2C_MEMORY_DATA,#0		; Programujemy wartosc 0
	MOV	I2C_MEMORY_DATA_ADDR,CURRENT_STEP ; Rozpoczynamy od aktualnego kroku, czyli od poczatku
	LCALL	I2C_MEMORY_PAGE_WRITE_FIRST	; Rozpoczynamy zapis pierwszego bajtu
EM_LOOP1:
	MOV	I2C_MEMORY_DATA,#0
	MOV	I2C_MEMORY_DATA_ADDR,CURRENT_STEP
	LCALL	I2C_MEMORY_PAGE_WRITE_NEXT	; Zapisujemy kolejny
	LCALL	LED_PRINT_STEP_AND_DELAY	; Aktualizyujemy dane wyswietylacza LED
	INC	CURRENT_STEP			; Zwiekszamy adres kasowanej komorki
	MOV	A,CURRENT_STEP
	CJNE	A,#100,EM_LOOP1			; Petla do poki nie skasuje sie 100 komorek
	LCALL	I2C_MEMORY_PAGE_WRITE_END	; Konczymy zapisywanie do pamieci EEPROM
	MOV	I2C_MEMORY_PAGE,#1		; Teraz bedziemy kasowac strone z sekwencjami wyjsciowymi
	MOV	I2C_MEMORY_DATA_ADDR,CURRENT_DELAY
	MOV	I2C_MEMORY_DATA,#0FFH		; Wypelniamy pamiec sekwencji jedynkami - wowczas wyjscia sa nieaktywne
	LCALL	I2C_MEMORY_PAGE_WRITE_FIRST	; Rozpoczynamy zapis
EM_LOOP2:
	MOV	I2C_MEMORY_DATA,#0FFH
	MOV	I2C_MEMORY_DATA_ADDR,CURRENT_DELAY
	LCALL	I2C_MEMORY_PAGE_WRITE_NEXT	; Zapisujemy kolejny bajt
	LCALL	LED_PRINT_STEP_AND_DELAY	; Aktualizujemy dane wyswietlacza
	INC	CURRENT_DELAY			; Zwiekszamy adres
	MOV	A,CURRENT_DELAY
	CJNE	A,#200,EM_LOOP2			; Czy zapisalismy 200 komorek? Jesli nie to piszemy!
	LCALL	I2C_MEMORY_PAGE_WRITE_END	; Jesli tak, to konczymy
	LJMP	EM_EXIT				; ...i wracamy do glownego menu
EM_IF15:
	CJNE	A,#15,EM_ERROR			; Nacisnieto MENU - wychodzimy
EM_EXIT:
	MOV	CURRENT_STEP,#0
	MOV	CURRENT_DELAY,#0
	CLR	TR0				; Zatrzymujemy wyswietlanie
	MOV	P3,#0FFH			; Wylaczamy wyswietlacze
	POP	ACC				; Przywracamy akumlator
	RET	
EM_ERROR:
	LCALL	BEEP_ERROR			; Nacisnieto niewlasciwy guzik
	LJMP	ERASE_MEMORY_LOOP


; Koniec procedury kasowania pamieci
;======================================








;----------------------------------------
;========================================
;       PROCEDURY UNIWERSALNE
;========================================
;----------------------------------------


; Procedura wystawia na zaciski wyjsciowe
; sekwencje z rejstrow CURRENT_DATA_A
; i CURRENT_DATA_B

OUTPUT_SEQUENCE:
	PUSH	ACC
	MOV	DATA_PORT,CURRENT_DATA_A
	MOV	A,CURRENT_DATA_A
	CPL	A
	MOV	DATA_PORT,A
	LCALL	STROBE_SECTION_A_CLK
	MOV	DATA_PORT,CURRENT_DATA_B
	MOV	A,CURRENT_DATA_B
	CPL	A
	MOV	DATA_PORT,A
	LCALL	STROBE_SECTION_B_CLK
	POP	ACC
	RET

; Procedury zatrzaskuja dane z magistrali
; w zatrzaskach modulu wykonawczego

STROBE_SECTION_A_CLK:
	CLR	SECTION_A
	NOP
	NOP
	NOP
	NOP
	NOP
	SETB	SECTION_A
	RET

STROBE_SECTION_B_CLK:
	CLR	SECTION_B
	NOP
	NOP
	NOP
	NOP
	NOP
	SETB	SECTION_B
	RET


; Procedura sprawdza czy wartosc w akumlatorze
; jest rowna zero, jesli nie, to ja dekrementuje.
; Jesli ACC=0, to pika blad

CHECK_IF_0:
	CJNE	A,#0,CHECK_IF_0_NOT
	LCALL	BEEP_ERROR
	LJMP	CHECK_IF_0_END
CHECK_IF_0_NOT:
	DEC	ACC
CHECK_IF_0_END:
	RET


; Procedura sprawdza czy wartosc w akumlatorze
; jest rowna 99, jesli nie, to ja inkrementuje.
; Jesli ACC=99, to pika blad

CHECK_IF_99:
	CJNE	A,#99,CHECK_IF_99_NOT
	LCALL	BEEP_ERROR
	LJMP	CHECK_IF_99_END
CHECK_IF_99_NOT:
	INC	ACC
CHECK_IF_99_END:
	RET


; Procedura czeka czas R3 * 1MS

CZEKAJ_MS:
	PUSH	ACC
	MOV	ACC,R3
CZEKAJ_MS_LOOP1:
	PUSH	ACC
	MOV	ACC,#2
CZEKAJ_MS_LOOP2:
	PUSH	ACC
	MOV	ACC,#225
	DJNZ	ACC,$
	POP	ACC
	DJNZ	ACC,CZEKAJ_MS_LOOP2
	POP	ACC
	DJNZ	ACC,CZEKAJ_MS_LOOP1
	POP	ACC
	RET



;====================================
;        Obsluga klawiatury


; Procedura sprawdza czy nacisniety jest jakis przycisk.
; Jesli jest nacisniety, to jego numer zwracany jest
; w komorce KEY_NUMBER.
; Jesli zaden klawisz nie jest nacisniety KEY_NUMBER zawiera 0.

GET_KEY:
	PUSH 	ACC
	MOV	A,#1

	MOV	P1,#11111111B

	CLR	KEY_X1
	LCALL	GET_KEY_GET
	SETB	KEY_X1
	CLR	KEY_X2
	LCALL	GET_KEY_GET
	SETB	KEY_X2
	CLR	KEY_X3
	LCALL	GET_KEY_GET
	SETB	KEY_X3
	CLR	KEY_X4
	LCALL	GET_KEY_GET
	SETB	KEY_X4

GET_KEY_CHECK:
	MOV	A,KEY_NUMBER
	CJNE	A,#17,GET_KEY_END
	MOV	KEY_NUMBER,#0
GET_KEY_END:
	POP	ACC
	RET

GET_KEY_GET:
	JNB	KEY_Y1,GET_KEY_GET_END_KEY
	INC	A
	JNB	KEY_Y2,GET_KEY_GET_END_KEY
	INC	A
	JNB	KEY_Y3,GET_KEY_GET_END_KEY
	INC	A
	JNB	KEY_Y4,GET_KEY_GET_END_KEY
	INC	A
	RET
GET_KEY_GET_END_KEY:
	MOV	KEY_NUMBER,ACC
	RET

; Procedura czeka na nacisniecie klawisza
; Jesli klawisz zostanie nacisniety jego numer zwracany jest
; w komorce KEY_NUMBER, dopiero wtedy funkcja wraca z wywolania.

WAIT_FOR_KEY:
	PUSH	ACC
WAIT_FOR_KEY_LOOP:
	LCALL	GET_KEY
	MOV	A,KEY_NUMBER
	CJNE	A,#0,WAIT_FOR_KEY_END
	LJMP	WAIT_FOR_KEY_LOOP
WAIT_FOR_KEY_END:
	POP	ACC
	RET


;    Koniec obslugi klawiatury
;====================================



;======================================
; Obsluga buzzera - generacja dzwiekow

BEEP:
	MOV	R4,#200
	MOV	R5,#150
	LCALL	SOUND
	RET

BEEP_ERROR:
	MOV	R4,#250
	MOV	R5,#250
	LCALL	SOUND
	RET

BEEP_MEMORY_ERASE:
	MOV	R4,#200
	MOV	R5,#75
	LCALL	SOUND
	MOV	R4,#150
	MOV	R5,#75
	LCALL	SOUND
	MOV	R4,#200
	MOV	R5,#75
	LCALL	SOUND
	RET

BEEP_INIT:
	MOV	R4,#100
	MOV	R5,#255
	LCALL	SOUND
	MOV	R4,#150
	MOV	R5,#180
	LCALL	SOUND
	RET

BEEP_DETONATION:
	PUSH	ACC
	MOV	A,R4
	ADD	A,#10
	MOV	R4,A
	MOV	R5,#50
	LCALL	SOUND
	POP	ACC
	RET

BEEP_I2C_ERROR:
	MOV	R4,#250
	MOV	R5,#255
	LCALL	SOUND
	MOV	R4,#150
	MOV	R5,#255
	LCALL	SOUND
	RET



SOUND:
	PUSH	ACC
	MOV	ACC,R5
SOUND_LOOP:
	CPL	BUZZER
	PUSH	ACC
	MOV	ACC,R4
	DJNZ	ACC,$
	POP	ACC
	DJNZ	ACC,SOUND_LOOP
	SETB	BUZZER
	POP	ACC
	RET

; Koniec obslugi buzzera
;======================================



;======================================
; Obsługa szeregowej pamięci EEPROM

; Procedura wczytuje ustawienia sekwencji dla danego kroku i opóźnienie.
; Krok przechowywany jest w komórce CURRENT_STEP, opóźnienie - CURRENT_DELAY
; Wartości ładowane są do komórek CURRENT_DATA_A i CURRENT_DATA_B

I2C_LOAD_SETUP:
	PUSH	ACC
	MOV	I2C_MEMORY_DATA_ADDR,CURRENT_STEP
	MOV	I2C_MEMORY_PAGE,#0
	LCALL	I2C_MEMORY_ADDRESS_READ_BYTE
	MOV	CURRENT_DELAY,I2C_MEMORY_DATA
	MOV	A,CURRENT_STEP
	MOV	B,#2
	MUL	AB
	MOV	I2C_MEMORY_DATA_ADDR,A
	MOV	I2C_MEMORY_PAGE,#1
	LCALL	I2C_MEMORY_ADDRESS_READ_BYTE
	MOV	CURRENT_DATA_A,I2C_MEMORY_DATA
	LCALL	I2C_MEMORY_READ_BYTE
	MOV	CURRENT_DATA_B,I2C_MEMORY_DATA
	LCALL	LED_PRINT_SECTION_DATA
I2C_LOAD_SETUP_END:
	POP	ACC
	RET

; Procedura zapisuje ustawienia sekwencji dla danego kroku i opóźnienie.
; Krok przechowywany jest w komórce CURRENT_STEP, opóźnienie - CURRENT_DELAY
; Wartości zapisywane są z komórek CURRENT_DATA_A i CURRENT_DATA_B

I2C_SAVE_SETUP:
	PUSH	ACC
	MOV	I2C_MEMORY_DATA_ADDR,CURRENT_STEP
	MOV	I2C_MEMORY_DATA,CURRENT_DELAY
	MOV	I2C_MEMORY_PAGE,#0
	LCALL	I2C_MEMORY_WRITE_BYTE
	MOV	A,CURRENT_STEP
	MOV	B,#2
	MUL	AB
	MOV	I2C_MEMORY_DATA_ADDR,A
	MOV	I2C_MEMORY_PAGE,#1
	MOV	I2C_MEMORY_DATA,CURRENT_DATA_A
	LCALL	I2C_MEMORY_PAGE_WRITE_FIRST	
	MOV	I2C_MEMORY_DATA,CURRENT_DATA_B
	LCALL	I2C_MEMORY_PAGE_WRITE_NEXT
	LCALL	I2C_MEMORY_PAGE_WRITE_END
	POP	ACC
	RET

; Procedura odczytuje jeden bajt z pamięci EEPROM, spod aktualnego adresu
; Wartość zwracana jest w komórce I2C_MEMORY_DATA

I2C_MEMORY_READ_BYTE:
	MOV	I2C_READ,#1
	LCALL	I2C_MEMORY_START
	LCALL	I2C_MEMORY_HEADER
	LCALL	WAIT_I2C_MEMORY_ACK
	LCALL	I2C_MEMORY_GET_BYTE
	LCALL	SEND_I2C_MEMORY_NACK
	LCALL	I2C_MEMORY_STOP
	RET

; Procedura odczytuje jeden bajt do komórki I2C_MEMORY_DATA z pamięci EEPROM,
; spod adresu wskazanego w komórce I2C_MEMORY_DATA_ADDR

I2C_MEMORY_ADDRESS_READ_BYTE:
	PUSH	ACC
	MOV	I2C_READ,#0
	LCALL	I2C_MEMORY_START
	LCALL	I2C_MEMORY_HEADER
	LCALL	WAIT_I2C_MEMORY_ACK
	MOV	A,I2C_MEMORY_DATA_ADDR
	LCALL	I2C_MEMORY_SEND_BYTE
	LCALL	WAIT_I2C_MEMORY_ACK
	MOV	I2C_READ,#1
	LCALL	I2C_MEMORY_START
	LCALL	I2C_MEMORY_HEADER
	LCALL	WAIT_I2C_MEMORY_ACK
	LCALL	I2C_MEMORY_GET_BYTE
	LCALL	SEND_I2C_MEMORY_NACK
	LCALL	I2C_MEMORY_STOP
	POP	ACC
	RET

; Procedura zapisuje bajt z komórki I2C_MEMORY_DATA do pamięci EEPRO
; pod adres z komórki I2C_MEMORY_DATA_ADDR,
; w stronę pamięci I2C_MEMORY_PAGE

I2C_MEMORY_WRITE_BYTE:
	PUSH	ACC
	MOV	I2C_READ,#0
	LCALL	I2C_MEMORY_START
	LCALL	I2C_MEMORY_HEADER
	LCALL	WAIT_I2C_MEMORY_ACK
	MOV	A,I2C_MEMORY_DATA_ADDR
	LCALL	I2C_MEMORY_SEND_BYTE
	LCALL	WAIT_I2C_MEMORY_ACK
	MOV	A,I2C_MEMORY_DATA
	LCALL	I2C_MEMORY_SEND_BYTE
	MOV	ACC,25
	DJNZ	ACC,$
	LCALL	WAIT_I2C_MEMORY_ACK
	LCALL	I2C_MEMORY_STOP
	MOV	R3,#5
	LCALL	CZEKAJ_MS
	POP	ACC
	RET



; Trzyczęściowa procedura zapisu całej strony pamięci EEPROM
; I2C_MEMORY_DATA – dana do zapisu
; I2C_MEMORY_DATA_ADDR – adres początkowy danych do zapisu
; I2C_MEMORY_PAGE – strona, w której dana bęzie zapisana
; Zapis rozpoczynamy tą procedurą

I2C_MEMORY_PAGE_WRITE_FIRST:
	PUSH	ACC
	MOV	I2C_READ,#0
	LCALL	I2C_MEMORY_START
	LCALL	I2C_MEMORY_HEADER
	LCALL	WAIT_I2C_MEMORY_ACK
	MOV	A,I2C_MEMORY_DATA_ADDR
	LCALL	I2C_MEMORY_SEND_BYTE
	LCALL	WAIT_I2C_MEMORY_ACK
	MOV	A,I2C_MEMORY_DATA
	LCALL	I2C_MEMORY_SEND_BYTE
	MOV	ACC,25
	DJNZ	ACC,$
	LCALL	WAIT_I2C_MEMORY_ACK
	POP	ACC
	RET

; Następnie dostarczamy w komórce I2C_MEMORY_DATA kolejne dane
; i wywołujemy procedurę

I2C_MEMORY_PAGE_WRITE_NEXT:
	PUSH	ACC
	MOV	A,I2C_MEMORY_DATA
	LCALL	I2C_MEMORY_SEND_BYTE
	MOV	ACC,25
	DJNZ	ACC,$
	LCALL	WAIT_I2C_MEMORY_ACK
	POP	ACC
	RET

I2C_MEMORY_PAGE_WRITE_END:
	LCALL	I2C_MEMORY_STOP
	MOV	R3,#5
	LCALL	CZEKAJ_MS
	RET

; Zapis kończymy procedurą

I2C_MEMORY_HEADER:
	PUSH	ACC
	MOV	A,#10100000B
	ORL	A,I2C_READ
	PUSH	ACC
	MOV	A,I2C_MEMORY_PAGE
	RL	A
	MOV	I2C_MEMORY_PAGE,A
	POP	ACC
	ORL	A,I2C_MEMORY_PAGE
	LCALL	I2C_MEMORY_SEND_BYTE
	POP	ACC
	RET

; Procedura wysyła warunek START na magistrali I2C

I2C_MEMORY_START:
	SETB	I2C_MEMORY_SDA
	SETB	I2C_MEMORY_SCL
	JNB	I2C_MEMORY_SDA,I2C_MEMORY_START_ERROR
	JNB	I2C_MEMORY_SCL,I2C_MEMORY_START_ERROR
	NOP
	CLR	I2C_MEMORY_SDA
	NOP
	NOP
	CLR	I2C_MEMORY_SCL
	NOP
	RET
I2C_MEMORY_START_ERROR:
	LJMP	I2C_ERROR

; Procedura wysyła warunek STOP na magistrali I2C

I2C_MEMORY_STOP:
	CLR	I2C_MEMORY_SDA
	NOP
	NOP
	SETB	I2C_MEMORY_SCL
	NOP
	NOP
	SETB	I2C_MEMORY_SDA
	RET

; Procedura mówi o błędzie transmisji I2C
I2C_ERROR:
	MOV	I2C_FAIL,#15
I2C_ERROR_LOOP:
	LCALL	BEEP_I2C_ERROR
	DJNZ	I2C_FAIL,I2C_ERROR_LOOP
	RET

; Procedura wysyła sygnał zegarowy na magistrali I2C
PULSE_I2C_MEMORY_SCL:
	PUSH	ACC
	MOV	ACC,#5
	DJNZ	ACC,$
	SETB	I2C_MEMORY_SCL
	MOV	ACC,#20
	DJNZ	ACC,$
	CLR	I2C_MEMORY_SCL
	MOV	ACC,#5
	DJNZ	ACC,$
	POP	ACC
	RET

;Procedura czeka na warunek ACK na magistrali I2C
WAIT_I2C_MEMORY_ACK:
	SETB	I2C_MEMORY_SCL
	MOV	I2C_FAIL,#I2C_FAIL_COUNT
WAIT_I2C_MEMORY_ACK_LOOP1:
	JNB	I2C_MEMORY_SDA,WAIT_I2C_MEMORY_ACK_OK
	NOP
	NOP
	DJNZ	I2C_FAIL,WAIT_I2C_MEMORY_ACK_LOOP1
	LJMP	I2C_ERROR
WAIT_I2C_MEMORY_ACK_OK:
	CLR	I2C_MEMORY_SCL
	SETB	I2C_MEMORY_SDA
	RET

; Procedura odczytuje bajt z magistrali I2C
I2C_MEMORY_GET_BYTE:
	PUSH	ACC
	SETB	I2C_MEMORY_SDA
	MOV	I2C_BYTE_COUNT,#8
I2C_MEMORY_GET_BYTE_LOOP2:
	SETB	I2C_MEMORY_SCL
	MOV	R0,#5
	DJNZ	R0,$
	MOV	C,I2C_MEMORY_SDA
	RLC	A
	CLR	I2C_MEMORY_SCL
	MOV	R0,#5
	DJNZ	R0,$
	DJNZ	I2C_BYTE_COUNT,I2C_MEMORY_GET_BYTE_LOOP2
	MOV	I2C_MEMORY_DATA,A
	POP	ACC
	RET

; Procedura wysyła bajt na magistralę I2C
I2C_MEMORY_SEND_BYTE:
	MOV	I2C_BYTE_COUNT,#8
I2C_MEMORY_SEND_BYTE_LOOP1:
	RLC	A
	MOV	I2C_MEMORY_SDA,C
	LCALL	PULSE_I2C_MEMORY_SCL
	DJNZ	I2C_BYTE_COUNT,I2C_MEMORY_SEND_BYTE_LOOP1
	RET

; Procedura wysyła warunek ACK na magistrali I2C
SEND_I2C_MEMORY_ACK:
	CLR	I2C_MEMORY_SDA
	LCALL	PULSE_I2C_MEMORY_SCL
	RET

; Procedura wysy?a warunek NACK na magistrali I2C
SEND_I2C_MEMORY_NACK:
	SETB	I2C_MEMORY_SDA
	LCALL	PULSE_I2C_MEMORY_SCL
	RET

; W przypadku braku odpowiedzi informacja o błędzie
I2C_BRAK_ODPOWIEDZI:
	LCALL	BEEP_I2C_ERROR
	LJMP	I2C_BRAK_ODPOWIEDZI	


; Koniec obsługi szeregowej pamięci
;======================================


;======================================
; Obsługa wyświetlacza LED

; Procedura wyświetla cyfry w przerwaniu
; Poszczególne cyfry do wyświetlenia znajdują się odpowiednio
; w komórkach LED_DIGIT1..LED_DIGIT4
WRITE_LED:
	PUSH	ACC
	CLR	TR0
	MOV	ACC,#11110000B
WRITE_LED_1:
	CJNE	R7,#1,WRITE_LED_2
	ORL	LED_DIGIT1,A
	MOV	P3,LED_DIGIT1
	CLR	LED_W1
	LJMP	WRITE_LED_END
WRITE_LED_2:
	CJNE	R7,#2,WRITE_LED_3
	ORL	LED_DIGIT2,A
	MOV	P3,LED_DIGIT2
	CLR	LED_W2
	LJMP	WRITE_LED_END
WRITE_LED_3:
	CJNE	R7,#3,WRITE_LED_4
	ORL	LED_DIGIT3,A
	MOV	P3,LED_DIGIT3
	CLR	LED_W3
	LJMP	WRITE_LED_END
WRITE_LED_4:
	CJNE	R7,#4,WRITE_LED_SET0
	ORL	LED_DIGIT4,A
	MOV	P3,LED_DIGIT4
	CLR	LED_W4
	LJMP	WRITE_LED_END
WRITE_LED_SET0:
	MOV	R7,#0
WRITE_LED_END:
	INC	R7
	POP	ACC
	MOV	TL0,#100
	MOV	TH0,#225
	SETB	TR0
	RETI


; Procedura jednorazowo przemiata wyświetlacz LED
LED_PRINT:
	PUSH	ACC
	MOV	ACC,#11110000B
	ORL	LED_DIGIT1,A
	ORL	LED_DIGIT2,A
	ORL	LED_DIGIT3,A
	ORL	LED_DIGIT4,A
	POP	ACC
	MOV	P3,LED_DIGIT1
	CLR	LED_W1
	MOV	R3,#1
	LCALL	CZEKAJ_MS
	SETB	LED_W1
	MOV	P3,LED_DIGIT2
	CLR	LED_W2
	MOV	R3,#1
	LCALL	CZEKAJ_MS
	SETB	LED_W2
	MOV	P3,LED_DIGIT3
	CLR	LED_W3
	MOV	R3,#1
	LCALL	CZEKAJ_MS
	SETB	LED_W3
	MOV	P3,LED_DIGIT4
	CLR	LED_W4
	MOV	R3,#1
	LCALL	CZEKAJ_MS
	SETB	LED_W4
	RET

; Procedura animuje diody sygnalizacyjne LED
; Informując o gotowości do pracy / pozycji w głównym menu
BLINK_LEDS:
	PUSH	ACC
	SETB	LED_SECTION_A
	SETB	LED_SECTION_B
	MOV	A,LED_BLINK_COUNT
	CJNE	A,#0,BLINK_LEDS_1
	MOV	P0,#01110111B
	LJMP	BLINK_LEDS_END
BLINK_LEDS_1:
	CJNE	A,#10,BLINK_LEDS_2
	MOV	P0,#10111011B
	LJMP	BLINK_LEDS_END
BLINK_LEDS_2:
	CJNE	A,#20,BLINK_LEDS_3
	MOV	P0,#11011101B
	LJMP	BLINK_LEDS_END
BLINK_LEDS_3:
	CJNE	A,#30,BLINK_LEDS_4
	MOV	P0,#11101110B
	LJMP	BLINK_LEDS_END
BLINK_LEDS_4:
	CJNE	A,#40,BLINK_LEDS_5
	MOV	P0,#11011101B
	LJMP	BLINK_LEDS_END
BLINK_LEDS_5:
	CJNE	A,#50,BLINK_LEDS_END
	MOV	P0,#10111011B
	LJMP	BLINK_LEDS_END
BLINK_LEDS_END:
	INC	A
	CJNE	A,#60,BLINK_LEDS_QUIT
	MOV	A,#0
BLINK_LEDS_QUIT:
	MOV	LED_BLINK_COUNT,A
	POP	ACC
	RET

; Procedura miga diodami sygnalizacyjnymi informując
; o gotowości do odtworzenia sekwencji wyjściowej
LED_BLINK_DETONATION:
	PUSH	ACC
	MOV	A,LED_BLINK_COUNT
	CJNE	A,#0,LED_BLINK_DETONATION_1
	MOV	P0,#11000011B
	CLR	LED_SECTION_A
	SETB	LED_SECTION_B
	LJMP	LED_BLINK_DETONATION_2
LED_BLINK_DETONATION_1:
	CJNE	A,#50,LED_BLINK_DETONATION_2
	MOV	P0,#00111100B
	CLR	LED_SECTION_B
	SETB	LED_SECTION_A
LED_BLINK_DETONATION_2:
	INC	A
	CJNE	A,#100,LED_BLINK_DETONATION_END
	MOV	A,#0
LED_BLINK_DETONATION_END:
	MOV	LED_BLINK_COUNT,A
	POP	ACC
	RET
	
; Procedura włącza odpowiednie diody w SECTION OUTPUT
LED_PRINT_SECTION_DATA:
	PUSH	ACC
	MOV	ACC,CURRENT_SECTION
	CJNE	A,#0,LED_PRINT_SECTION_DATA_B
	MOV	DATA_PORT,CURRENT_DATA_A
	CLR	LED_SECTION_A
	SETB	LED_SECTION_B
	LJMP	LED_PRINT_SECTION_DATA_END
LED_PRINT_SECTION_DATA_B:
	MOV	DATA_PORT,CURRENT_DATA_B
	CLR	LED_SECTION_B
	SETB	LED_SECTION_A
LED_PRINT_SECTION_DATA_END:
	POP	ACC
	RET

; Procedura rozbija liczby CURRENT_STEP i CURRENT_DELAY
; na poszczególne cyfry – dla procedury wyświetlającej w przerwaniu
LED_PRINT_STEP_AND_DELAY:
	PUSH	ACC
	MOV	A,CURRENT_STEP
	MOV	B,#10
	DIV	AB
	MOV	LED_DIGIT4,A
	MOV	LED_DIGIT3,B
	MOV	A,CURRENT_DELAY
	MOV	B,#10
	DIV	AB
	MOV	LED_DIGIT2,A
	MOV	LED_DIGIT1,B
	POP	ACC
	RET

; Koniec obsługi wyświetlacza LED
;======================================;******************************
;* Zespół Szkół Elektrycznych *
;*          Kielce            *
;*     Praca Dyplomowa        *
;* Wykonawca:                 *
;*   Tomasz Cedro             *
;* Promotor:                  *
;*   mgr inż. Andrzej Oko     *
;*                            *
;*   Rok szkolny 2001/2002    *
;******************************


;======================================
;  DEKLARACJA STAŁYCH I ZMIENNYCH

; klawiatura
KEY_X1	EQU	P1.0
KEY_X2	EQU	P1.1
KEY_X3	EQU	P1.2
KEY_X4	EQU	P1.3
KEY_Y1	EQU	P1.4
KEY_Y2	EQU	P1.5
KEY_Y3	EQU	P1.6
KEY_Y4	EQU	P1.7
KEY_NUMBER	EQU	30H
KEY_DELAY	EQU	100

;buzzer piszczyk
BUZZER	EQU	P2.5
CZAS_PIKNIECIA_BLAD	EQU	25

;szeregowa pamiec EEPROM
I2C_MEMORY_SDA	EQU	P2.4
I2C_MEMORY_SCL	EQU	P2.3
I2C_MEMORY_ADDR	EQU	31H
I2C_MEMORY_PAGE	EQU	32H
I2C_READ	EQU	33H
I2C_FAIL	EQU	34H
I2C_FAIL_COUNT	EQU	50
I2C_BYTE_COUNT	EQU	35H
I2C_MEMORY_CHIP_ADDR	EQU	0H
I2C_MEMORY_DATA	EQU	36H
I2C_MEMORY_DATA_ADDR	EQU	37H

;magistrala danych
SECTION_A	EQU	P2.7
SECTION_B	EQU	P2.6
DATA_PORT	EQU	P0

;wyswietlacz
LED_W1	EQU	P3.7
LED_W2	EQU	P3.6
LED_W3	EQU	P3.5
LED_W4	EQU	P3.4
LED_DIGIT1	EQU	38H
LED_DIGIT2	EQU	39H
LED_DIGIT3	EQU	3AH
LED_DIGIT4	EQU	3BH
LED_BLINK_COUNT	EQU	3CH
LED_SECTION_A	EQU	P2.0
LED_SECTION_B	EQU	P2.1

;zmienne sekwencji wyjsciowych
CURRENT_DELAY	EQU	3DH
CURRENT_STEP	EQU	3EH
CURRENT_SECTION	EQU	3FH
CURRENT_DATA_A	EQU	40H
CURRENT_DATA_B	EQU	41H

;timer
TMOD_SET	EQU	00000001B

; KONIEC DEKLARACJI STALYCH I ZMIENNYCH
;======================================



;skaczemy do poczatku programu
	LJMP	START

; wektor przerwania timera 0
	ORG	0BH
	LJMP	WRITE_LED


	ORG	100H
START:
	MOV	LED_BLINK_COUNT,#0	; zerujemy rejstry
	MOV	CURRENT_STEP,#0
	MOV	CURRENT_DELAY,#0
	MOV	CURRENT_SECTION,#0
	MOV	CURRENT_DATA_A,#0
	MOV	CURRENT_DATA_B,#0

	MOV	TMOD,#TMOD_SET		; ustawiamy timery
	MOV	TL0,#0
	MOV	TH0,#0

	SETB	EA			; ogolne zezwolenie na przerwania
	SETB	ET0			; zezwolenie na przerwanie od T0

	LCALL	BEEP_INIT		; gotowy do pracy

MENU:
	LCALL	GET_KEY			; czekamy na nacisniecie guzika
	MOV	A,KEY_NUMBER
	CJNE	A,#0,MENU_BLINK_OFF	; czy jakis zostal nacisniety?
	LCALL	BLINK_LEDS		; nie - migaj diodami
	MOV	R3,#25
	LCALL	CZEKAJ_MS
	LJMP	MENU
MENU_BLINK_OFF:
	MOV	P0,#0FFH
	MOV	KEY_NUMBER,#0
	LCALL	BEEP			; tak - piknij i sprawdz ktory
	MOV	R3,#100
	LCALL	CZEKAJ_MS
MENU_IF1:
	CJNE	A,#1,MENU_IF2		; jesli 1 - wywolaj procedure
	LCALL	PROGRAM_DEVICE		; programowania sekwencji.
	LJMP	MENU			; Pozniej wroc do menu
MENU_IF2:
	CJNE	A,#2,MENU_IF3		; jesli 2 - wywolaj procedure
	LCALL	AUTO_PLAY_SEQUENCE	; odtwarzania sekwencji.
	LJMP	MENU			; Pozniej wroc do menu
MENU_IF3:
	CJNE	A,#3,MENU_IF4		; jesli 3 - wywolaj procedure
	LCALL	MANUAL_PLAY_SEQUENCE	; polautomatycznego odtwarzania.
	LJMP	MENU			; Pozniej wroc do menu
MENU_IF4:
	CJNE	A,#4,MENU		; jesli 4 - wywolaj procedure
	LCALL	ERASE_MEMORY		; kasowania pamieci.
	LJMP	MENU			; Pozniej wroc do menu.








;=============================================
; Procedura programowania sekwencji wyjsciowej

PROGRAM_DEVICE:
	LCALL	I2C_LOAD_SETUP			; Wczytaj ustawienia dla aktualnego kroku.
	LCALL	LED_PRINT_SECTION_DATA		; Wypisz ustawienia dla aktualnej sekcji.
	LCALL	LED_PRINT_STEP_AND_DELAY	; Przygotuj cyfry dla procedury wyswietlajacej.
	SETB	TR0				; Wlacz wyswietlacz LED
PROGRAM_DEVICE_LOOP:
	LCALL	LED_PRINT_STEP_AND_DELAY
	LCALL	GET_KEY				; Sprawdz czy nacisniety jest jakis guzik
	MOV	A,KEY_NUMBER
	CJNE	A,#0,PD_BEEP			; Jesli tak - piknij, jesli nie czekaj na nacisniecie
	LJMP	PROGRAM_DEVICE_LOOP
PD_BEEP:
	MOV	KEY_NUMBER,#0
	LCALL	BEEP				; Piknij
	MOV	R3,#KEY_DELAY
	LCALL	CZEKAJ_MS			; Autorepetycja klawiatury
PD_IF1:
	CJNE	A,#1,PD_IF2			; Czy nacisnieto 1
	CPL	DATA_PORT.0			; tak - zaneguj bit 0 portu danych
	LCALL	LED_PRINT_SECTION_DATA		; port danych wskazuje na sakcje...
	LCALL	LED_PRINT_SECTION_DATA		; wypisz ostateczna zmiane.
	LJMP	PROGRAM_DEVICE_LOOP		; Skocz do poczatku procedury
PD_IF2:
	CJNE	A,#2,PD_IF3			; Nacisnieto 2 - zaneguj 2. bit aktualnej sekcji...
	CPL	DATA_PORT.1
	LCALL	LED_PRINT_SECTION_DATA
	LJMP	PROGRAM_DEVICE_LOOP
PD_IF3:
	CJNE	A,#3,PD_IF4
	CPL	DATA_PORT.2
	LCALL	LED_PRINT_SECTION_DATA
	LJMP	PROGRAM_DEVICE_LOOP
PD_IF4:
	CJNE	A,#4,PD_IF5
	CPL	DATA_PORT.3
	LCALL	LED_PRINT_SECTION_DATA
	LJMP	PROGRAM_DEVICE_LOOP
PD_IF5:
	CJNE	A,#5,PD_IF6
	CPL	DATA_PORT.4
	LCALL	LED_PRINT_SECTION_DATA
	LJMP	PROGRAM_DEVICE_LOOP
PD_IF6:
	CJNE	A,#6,PD_IF7
	CPL	DATA_PORT.5
	LCALL	LED_PRINT_SECTION_DATA
	LJMP	PROGRAM_DEVICE_LOOP
PD_IF7:
	CJNE	A,#7,PD_IF8
	CPL	DATA_PORT.6
	LCALL	LED_PRINT_SECTION_DATA
	LJMP	PROGRAM_DEVICE_LOOP
PD_IF8:
	CJNE	A,#8,PD_IF9
	CPL	DATA_PORT.7
	LCALL	LED_PRINT_SECTION_DATA
	LJMP	PROGRAM_DEVICE_LOOP
PD_IF9:
	CJNE	A,#9,PD_IF10			; Nacisnieto guzik UP
	PUSH	ACC				; Sprawdzamy czy aktualny krok ma wartosc
	MOV	A,CURRENT_STEP			; mnejsza od 99. Jesli tak to ja inkrementujemy.
	LCALL	CHECK_IF_99			; Jesli nie, pikamy blad
	MOV	CURRENT_STEP,A
	POP	ACC
	LCALL	I2C_LOAD_SETUP			; Wczytujemy ustawienia wyjsc dla danego kroku
	LCALL	LED_PRINT_STEP_AND_DELAY	; Aktualizacja danych wyswietlacza.
	LJMP	PROGRAM_DEVICE_LOOP		; Skok do poczatku procedury
PD_IF10:
	CJNE	A,#10,PD_IF11			; Nacisnieto guzik DOWN
	PUSH	ACC				; Sprawdzamy czy aktualny krok ma wartosc
	MOV	A,CURRENT_STEP			; wieksza od 0. Jesli tak to ja dekrementujemy.
	LCALL	CHECK_IF_0			; Jesli nie - pikamy blad
	MOV	CURRENT_STEP,A
	POP	ACC
	LCALL	I2C_LOAD_SETUP			; Wczytujemy ustawienia wyjsc dla danego kroku
	LCALL	LED_PRINT_STEP_AND_DELAY	; Aktualizacja danych wyswietlacza
	LJMP	PROGRAM_DEVICE_LOOP		; Skok do poczatku procedury
PD_IF11:
	CJNE	A,#11,PD_IF12			; Nacisnieto guzik +
	PUSH	ACC				; Akcja taka sama jak dla guzika UP
	MOV	A,CURRENT_DELAY			; tyle ze inkrementujemy aktualne opoznienie
	LCALL	CHECK_IF_99
	MOV	CURRENT_DELAY,A
	POP	ACC
	LJMP	PROGRAM_DEVICE_LOOP
PD_IF12:
	CJNE	A,#12,PD_IF13			; Nacisnieto guzik -
	PUSH	ACC				; Akcja taka sama jak dla guzika DOWN
	MOV	A,CURRENT_DELAY			; tyle ze dekrementujemy aktualne opoznienie
	LCALL	CHECK_IF_0
	MOV	CURRENT_DELAY,A
	POP	ACC
	LJMP	PROGRAM_DEVICE_LOOP
PD_IF13:
	CJNE	A,#13,PD_IF14			; Nacisnieto guzik A/B
	MOV	R0,CURRENT_SECTION		; Bedziemy wybierac sekcje A lub B
	CJNE	R0,#0,PD_IF13_B			; Jesli aktualna jest sekcja A
	MOV	CURRENT_SECTION,#1		; To zamien ja na B
	MOV	CURRENT_DATA_A,DATA_PORT	; I przepisz aktualne dane do A
	LJMP	PD_IF13_END
PD_IF13_B:
	MOV	CURRENT_SECTION,#0		; Jesli aktualna jest sekcja B
	MOV	CURRENT_DATA_B,DATA_PORT	; to zamien na A i przepisz dane do B
PD_IF13_END:
	LCALL	LED_PRINT_SECTION_DATA		; Wypisz aktualne dane sekcji
	LJMP	PROGRAM_DEVICE_LOOP		; Skocz do poczatku procedury

PD_IF14:
	CJNE	A,#14,PD_IF15			; Nacisnieto guzik OK
	LCALL	I2C_SAVE_SETUP			; Zapisz ustawienia aktualnego kroku do pamieci
	INC	CURRENT_STEP			; Inkrementuj aktualny krok
	LCALL	I2C_LOAD_SETUP			; Wczytaj ustawienia aktualnego kroku
	LJMP	PROGRAM_DEVICE_LOOP		; Skocz do pocztku procedury
PD_IF15:
	CJNE	A,#15,PD_GOTO_START		; Naciesnieto guzik MENU
	LJMP	PD_END				; Skocz do konca procedury a wiec wroc do menu
PD_GOTO_START:
	LCALL	BEEP_ERROR			; Nacisnieto zly klawisz - piknij
	LJMP	PROGRAM_DEVICE_LOOP		; Powrot do poczatku procedury
PD_END:
	SETB	LED_SECTION_A			; Wylaczamy diody
	SETB	LED_SECTION_B			;  sygnalizacyjne sekcji A i B
	CLR	TR0				; Wylaczamy
	MOV	P3,#0FFH			; Wyswietlacz LED
	RET

; Koniec procedura programowania sekwencji
;=============================================






;===============================================
; Procedura automatycznego odtwarzania sekwencji

AUTO_PLAY_SEQUENCE:
	PUSH	ACC
	LCALL	I2C_LOAD_SETUP			; Wczytujemy sekwencjie aktualnego kroku
	SETB	TR0				; Wlaczamy wyswietlacz LED
	LCALL	LED_PRINT_STEP_AND_DELAY	; Atualizujemy dane wyswietlacza LED
APS_LOOP:
	LCALL	LED_PRINT_SECTION_DATA		; Wypisujemy dane aktualnej sekcji
	LCALL	LED_PRINT_STEP_AND_DELAY	; Atualizujemy dane wyswietlacza LED
	LCALL	GET_KEY				; Sprawdzamy czy jakis klawisz jest acisniety
	MOV	A,KEY_NUMBER
	MOV	KEY_NUMBER,#0
	CJNE	A,#0,APS_BEEP			; Jesli
	LJMP	APS_LOOP			; nie to skocz do poczatku procedury
APS_BEEP:
	LCALL	BEEP				; tak to piknij.
	MOV	R3,#KEY_DELAY			; Autorepetycja
	LCALL	CZEKAJ_MS			;  klawiatury
APS_IF9:
	CJNE	A,#9,APS_IF10			; Nacisnieto klawisz UP
	PUSH	ACC				; jesli aktualny krok rozny od 99
	MOV	A,CURRENT_STEP			; to inkrementuj
	LCALL	CHECK_IF_99
	MOV	CURRENT_STEP,A
	POP	ACC
	LCALL	I2C_LOAD_SETUP			; Wczytaj z pamieci sekwencje danego kroku
	LJMP	APS_LOOP			; Skocz do poczatku procedury
APS_IF10:
	CJNE	A,#10,APS_IF15			; Nacisnieto klawisz DOWN
	PUSH	ACC				; Jesli aktualny krok rozny od 0
	MOV	A,CURRENT_STEP			; to dekrementuj
	LCALL	CHECK_IF_0
	MOV	CURRENT_STEP,A
	POP	ACC
	LCALL	I2C_LOAD_SETUP			; Wczytaj z pamieci sekwencje danego kroku
	LJMP	APS_LOOP			; Skocz do poczatku procedury
APS_IF15:
	CJNE	A,#15,APS_IF14			; Wcisnieto klawisz MENU
	LJMP	APS_END				; koniec procedury - powrot do glownego menu
APS_IF14:
	CJNE	A,#14,APS_ERROR			; Wcisnieto OK
	MOV	R4,#0				; Bedziemy czekac na rozpoczecie odtwarzania
	MOV	LED_BLINK_COUNT,#0		; sekwencji nacisnieciem klawisza LAUNCH

APS_DET_WAIT:
	LCALL	GET_KEY				; Sprawdz czy nacisnieto klawisz
	MOV	A,KEY_NUMBER
	MOV	KEY_NUMBER,#0
	CJNE	A,#0,APS_DW_IF15		; Czy nacisnieto jakis klawisz?
	LCALL	LED_BLINK_DETONATION		; Nie - mrygaj diodami
	LCALL	BEEP_DETONATION			; i wydawaj sygnal dwiekowy
	LJMP	APS_DET_WAIT			; Skocze i sprawdz czy juz nacisnieto klawisz
APS_DW_IF15:
	CJNE	A,#15,APS_DW_IF16		; Nacisnieto MENU - anulujemy wysadzanie
	LJMP	APS_END				; i wracamy do glownego menu
APS_DW_IF16:
	CJNE	A,#16,APS_DET_WAIT		; Nacisnieto LAUNCH - rozpoczynamy wysadzanie

	MOV	R2,CURRENT_STEP			; Przechowaj w rejstrze numer ostatniego kroku
	INC	R2				; Zwieksz o jeden - jego tez bedziemy odtwarzac
	MOV	CURRENT_STEP,#0			; Tymczasem zerujemy licznik krokow

APS_DET_LOOP:					; PETLA ODTWARZANIA SEKWENCJI
	LCALL	I2C_LOAD_SETUP			; Wczytujemy sekwencje wyjsciowa aktualnego kroku
	LCALL	OUTPUT_SEQUENCE			; Wystawiamy sekwencje na zaciski wyjsciowe

	MOV	ACC,CURRENT_DELAY		; Kopiuj do akumlatora aktualne opznienie
	CJNE	A,#0,APS_DET_LOOP2		; Czy opoznienie to rowne jest 0?
	LJMP	APS_DET_LOOP3			; Jesli tak - omijamy odczekanie do nastepnego kroku
APS_DET_LOOP2:
	MOV	CURRENT_DELAY,ACC		; Jesli nie odczekujemy czas opznienie * 100msekund
	LCALL	LED_PRINT_STEP_AND_DELAY	; Aktualizujemy dane wysiweltacza LED
	MOV	R3,#100				; Powtorzenie n-razy czasu 100ms da nam zadane
	LCALL	CZEKAJ_MS			; opoznienie
	DJNZ	ACC,APS_DET_LOOP2		; Czy odczekalismy juz caly czas? Nie - czekamy dalej
APS_DET_LOOP3:
	INC	CURRENT_STEP			; Jesli tak - przechodzimy do nastepnego korku
	MOV	ACC,R2
	CJNE	A,CURRENT_STEP,APS_DET_LOOP	; Czy jest to ostatni krok? Nie - skocz do poczatku petli

	MOV	DATA_PORT,#0			; Jesli tak - wyzeruj wyjscia urzadzenia
	LCALL	STROBE_SECTION_A_CLK
	LCALL	STROBE_SECTION_B_CLK

APS_END:
	CLR	TR0				; Zatrzymaj procedure wyswietlajaca
	MOV	P3,#0FFH			; Wylacz wyswietlacze
	POP	ACC
	RET					; Wracaj

APS_ERROR:					; Tutaj fragment pikajacy w przypadku
	LCALL	BEEP_ERROR			; nacisniecia niewlasciwego guzika
	LJMP	APS_LOOP
	

; Koniec procedury automatycznego odtwarzania
;===============================================




;==================================================
; Procedura polautomatycznego odtwarzania sekwencji

MANUAL_PLAY_SEQUENCE:
	PUSH	ACC
	MOV	CURRENT_STEP,#0			; Zaczynamy od kroku numer 0
	MOV	CURRENT_DELAY,#0		; Opoznienie nie bedzie potrzebne
	SETB	TR0				; Wlaczamy wyswietlacz LED
MPS_LOOP:
	LCALL	LED_PRINT_STEP_AND_DELAY	; Aktualizujemy dane wyswietlacza LED
	LCALL	GET_KEY				; Sprawdzamy czy nacisniety jest jakis klawisz
	MOV	A,KEY_NUMBER
	MOV	KEY_NUMBER,#0
	CJNE	A,#0,MPS_BEEP			; Jesli nie - sprawdzamy jeszcze raz
	LJMP	MPS_LOOP
MPS_BEEP:
	LCALL	BEEP				; Jesli tak - pikamy
	MOV	R3,#KEY_DELAY			; I czekamy jakis czas, tworzac autorepetycje klawiatury
	LCALL	CZEKAJ_MS
MPS_IF1:
	CJNE	A,#1,MPS_IF2			; Nacisnieto 1
	MOV	CURRENT_STEP,#1			; Aktualny krok to 1
	LCALL	I2C_LOAD_SETUP			; Wczytujemy z pamieci sekwencje wyjsciowa
	LCALL	OUTPUT_SEQUENCE			; Wystawiamy sekwencje na zaciski wyjsciowe
	LJMP	MPS_LOOP			; Skaczemy do poczatku procedury
MPS_IF2:
	CJNE	A,#2,MPS_IF3
	MOV	CURRENT_STEP,#2
	LCALL	I2C_LOAD_SETUP
	LCALL	OUTPUT_SEQUENCE
	LJMP	MPS_LOOP
MPS_IF3:
	CJNE	A,#3,MPS_IF4
	MOV	CURRENT_STEP,#3
	LCALL	I2C_LOAD_SETUP
	LCALL	OUTPUT_SEQUENCE
	LJMP	MPS_LOOP
MPS_IF4:
	CJNE	A,#4,MPS_IF5
	MOV	CURRENT_STEP,#4
	LCALL	I2C_LOAD_SETUP
	LCALL	OUTPUT_SEQUENCE
	LJMP	MPS_LOOP
MPS_IF5:
	CJNE	A,#5,MPS_IF6
	MOV	CURRENT_STEP,#5
	LCALL	I2C_LOAD_SETUP
	LCALL	OUTPUT_SEQUENCE
	LJMP	MPS_LOOP
MPS_IF6:
	CJNE	A,#6,MPS_IF7
	MOV	CURRENT_STEP,#6
	LCALL	I2C_LOAD_SETUP
	LCALL	OUTPUT_SEQUENCE
	LJMP	MPS_LOOP
MPS_IF7:
	CJNE	A,#7,MPS_IF8
	MOV	CURRENT_STEP,#7
	LCALL	I2C_LOAD_SETUP
	LCALL	OUTPUT_SEQUENCE
	LJMP	MPS_LOOP
MPS_IF8:
	CJNE	A,#8,MPS_IF9
	MOV	CURRENT_STEP,#8
	LCALL	I2C_LOAD_SETUP
	LCALL	OUTPUT_SEQUENCE
	LJMP	MPS_LOOP
MPS_IF9:
	CJNE	A,#9,MPS_IF10			; Nacisnieto klawisz UP
	MOV	A,CURRENT_STEP			; Czy mozna jeszcze inkrementowac krok?
	LCALL	CHECK_IF_99			; Jesli tak to inkrementuj, jesli nie - piknij blad
	LCALL	I2C_LOAD_SETUP			; Wczytaj ustawienia sekwencji dla aktualnego kroku
	LCALL	OUTPUT_SEQUENCE			; Wystaw sekwencje na zaciski wyjsciowe
	LJMP	MPS_LOOP
MPS_IF10:
	CJNE	A,#10,MPS_IF15			; Nacisnieto klawisz DOWN
	MOV	A,CURRENT_STEP
	LCALL	CHECK_IF_0			; Jesli to mozliwe, to dekrementuj krok
	LCALL	I2C_LOAD_SETUP			; Wczytaj ustawienia sekwencji
	LCALL	OUTPUT_SEQUENCE			; Wystaw sekwencje na zaciski wyjsciowe
	LJMP	MPS_LOOP
MPS_IF15:
	CJNE	A,#15,MPS_ERROR			; Nacisnieto MENU
	LJMP	MPS_END				; Wracamy do glownego menu
MPS_ERROR:
	LCALL	BEEP_ERROR			; Wcisnieto niewlasciwy klawisz
	LJMP	MPS_LOOP			; poknij blad i wroc na poczatek procedury
MPS_END:
	CLR	TR0				; Zatrzymujemy przerwanie wyswietlania
	MOV	P3,#0FFH			; Wylaczamy wyswietlacz
	MOV	DATA_PORT,#0FFH			; Zerujemy
	LCALL	OUTPUT_SEQUENCE			;  zaciski wyjsciowe urzadzenia
	POP	ACC
	RET


; KOniec procedury polautomatycznego odtwarzania
;==================================================







;======================================
; Procedura kasowania pamieci EEPROM

ERASE_MEMORY:
	PUSH	ACC
	MOV	DATA_PORT,#10101010B		; Zaswiec odpowiednie diody sygnalizacyjne
	LCALL	BEEP_MEMORY_ERASE		; Piknij informujac o zamiarze skasowania pamieci
	MOV	CURRENT_STEP,#0			; Kasujemy pamiec od poczatku
	MOV	CURRENT_DELAY,#0		; Opoznienie przyjmie wartosc 0
	LCALL	LED_PRINT_STEP_AND_DELAY	; Aktualizuj dane wyswietlacza LED
	SETB	TR0				; Rozpocznij wyswietlanie LED
ERASE_MEMORY_LOOP:
	LCALL	GET_KEY				; Sprawdz nacisniecie klawisza
	MOV	A,KEY_NUMBER
	MOV	KEY_NUMBER,#0
	CJNE	A,#0,EM_BEEP			; Czy jakis zostal nacisniety?
	LJMP	ERASE_MEMORY_LOOP		; Nie - sprawdz jeszcze razz
EM_BEEP:
	LCALL	BEEP				; Tak - piknij
	MOV	R3,#KEY_DELAY			; Odczekaj do nastepnego nacisniecia
	LCALL	CZEKAJ_MS			; (autorepetycja klawiatury)
EM_IF14:
	CJNE	A,#14,EM_IF15			; Nacisnieto klawisz OK - bedziemy kasowac pamiec
	MOV	I2C_MEMORY_PAGE,#0		; Najpierw strona zawierajaca opznienia krokow
	MOV	I2C_MEMORY_DATA,#0		; Programujemy wartosc 0
	MOV	I2C_MEMORY_DATA_ADDR,CURRENT_STEP ; Rozpoczynamy od aktualnego kroku, czyli od poczatku
	LCALL	I2C_MEMORY_PAGE_WRITE_FIRST	; Rozpoczynamy zapis pierwszego bajtu
EM_LOOP1:
	MOV	I2C_MEMORY_DATA,#0
	MOV	I2C_MEMORY_DATA_ADDR,CURRENT_STEP
	LCALL	I2C_MEMORY_PAGE_WRITE_NEXT	; Zapisujemy kolejny
	LCALL	LED_PRINT_STEP_AND_DELAY	; Aktualizyujemy dane wyswietylacza LED
	INC	CURRENT_STEP			; Zwiekszamy adres kasowanej komorki
	MOV	A,CURRENT_STEP
	CJNE	A,#100,EM_LOOP1			; Petla do poki nie skasuje sie 100 komorek
	LCALL	I2C_MEMORY_PAGE_WRITE_END	; Konczymy zapisywanie do pamieci EEPROM
	MOV	I2C_MEMORY_PAGE,#1		; Teraz bedziemy kasowac strone z sekwencjami wyjsciowymi
	MOV	I2C_MEMORY_DATA_ADDR,CURRENT_DELAY
	MOV	I2C_MEMORY_DATA,#0FFH		; Wypelniamy pamiec sekwencji jedynkami - wowczas wyjscia sa nieaktywne
	LCALL	I2C_MEMORY_PAGE_WRITE_FIRST	; Rozpoczynamy zapis
EM_LOOP2:
	MOV	I2C_MEMORY_DATA,#0FFH
	MOV	I2C_MEMORY_DATA_ADDR,CURRENT_DELAY
	LCALL	I2C_MEMORY_PAGE_WRITE_NEXT	; Zapisujemy kolejny bajt
	LCALL	LED_PRINT_STEP_AND_DELAY	; Aktualizujemy dane wyswietlacza
	INC	CURRENT_DELAY			; Zwiekszamy adres
	MOV	A,CURRENT_DELAY
	CJNE	A,#200,EM_LOOP2			; Czy zapisalismy 200 komorek? Jesli nie to piszemy!
	LCALL	I2C_MEMORY_PAGE_WRITE_END	; Jesli tak, to konczymy
	LJMP	EM_EXIT				; ...i wracamy do glownego menu
EM_IF15:
	CJNE	A,#15,EM_ERROR			; Nacisnieto MENU - wychodzimy
EM_EXIT:
	MOV	CURRENT_STEP,#0
	MOV	CURRENT_DELAY,#0
	CLR	TR0				; Zatrzymujemy wyswietlanie
	MOV	P3,#0FFH			; Wylaczamy wyswietlacze
	POP	ACC				; Przywracamy akumlator
	RET	
EM_ERROR:
	LCALL	BEEP_ERROR			; Nacisnieto niewlasciwy guzik
	LJMP	ERASE_MEMORY_LOOP


; Koniec procedury kasowania pamieci
;======================================








;----------------------------------------
;========================================
;       PROCEDURY UNIWERSALNE
;========================================
;----------------------------------------


; Procedura wystawia na zaciski wyjsciowe
; sekwencje z rejstrow CURRENT_DATA_A
; i CURRENT_DATA_B

OUTPUT_SEQUENCE:
	PUSH	ACC
	MOV	DATA_PORT,CURRENT_DATA_A
	MOV	A,CURRENT_DATA_A
	CPL	A
	MOV	DATA_PORT,A
	LCALL	STROBE_SECTION_A_CLK
	MOV	DATA_PORT,CURRENT_DATA_B
	MOV	A,CURRENT_DATA_B
	CPL	A
	MOV	DATA_PORT,A
	LCALL	STROBE_SECTION_B_CLK
	POP	ACC
	RET

; Procedury zatrzaskuja dane z magistrali
; w zatrzaskach modulu wykonawczego

STROBE_SECTION_A_CLK:
	CLR	SECTION_A
	NOP
	NOP
	NOP
	NOP
	NOP
	SETB	SECTION_A
	RET

STROBE_SECTION_B_CLK:
	CLR	SECTION_B
	NOP
	NOP
	NOP
	NOP
	NOP
	SETB	SECTION_B
	RET


; Procedura sprawdza czy wartosc w akumlatorze
; jest rowna zero, jesli nie, to ja dekrementuje.
; Jesli ACC=0, to pika blad

CHECK_IF_0:
	CJNE	A,#0,CHECK_IF_0_NOT
	LCALL	BEEP_ERROR
	LJMP	CHECK_IF_0_END
CHECK_IF_0_NOT:
	DEC	ACC
CHECK_IF_0_END:
	RET


; Procedura sprawdza czy wartosc w akumlatorze
; jest rowna 99, jesli nie, to ja inkrementuje.
; Jesli ACC=99, to pika blad

CHECK_IF_99:
	CJNE	A,#99,CHECK_IF_99_NOT
	LCALL	BEEP_ERROR
	LJMP	CHECK_IF_99_END
CHECK_IF_99_NOT:
	INC	ACC
CHECK_IF_99_END:
	RET


; Procedura czeka czas R3 * 1MS

CZEKAJ_MS:
	PUSH	ACC
	MOV	ACC,R3
CZEKAJ_MS_LOOP1:
	PUSH	ACC
	MOV	ACC,#2
CZEKAJ_MS_LOOP2:
	PUSH	ACC
	MOV	ACC,#225
	DJNZ	ACC,$
	POP	ACC
	DJNZ	ACC,CZEKAJ_MS_LOOP2
	POP	ACC
	DJNZ	ACC,CZEKAJ_MS_LOOP1
	POP	ACC
	RET



;====================================
;        Obsluga klawiatury


; Procedura sprawdza czy nacisniety jest jakis przycisk.
; Jesli jest nacisniety, to jego numer zwracany jest
; w komorce KEY_NUMBER.
; Jesli zaden klawisz nie jest nacisniety KEY_NUMBER zawiera 0.

GET_KEY:
	PUSH 	ACC
	MOV	A,#1

	MOV	P1,#11111111B

	CLR	KEY_X1
	LCALL	GET_KEY_GET
	SETB	KEY_X1
	CLR	KEY_X2
	LCALL	GET_KEY_GET
	SETB	KEY_X2
	CLR	KEY_X3
	LCALL	GET_KEY_GET
	SETB	KEY_X3
	CLR	KEY_X4
	LCALL	GET_KEY_GET
	SETB	KEY_X4

GET_KEY_CHECK:
	MOV	A,KEY_NUMBER
	CJNE	A,#17,GET_KEY_END
	MOV	KEY_NUMBER,#0
GET_KEY_END:
	POP	ACC
	RET

GET_KEY_GET:
	JNB	KEY_Y1,GET_KEY_GET_END_KEY
	INC	A
	JNB	KEY_Y2,GET_KEY_GET_END_KEY
	INC	A
	JNB	KEY_Y3,GET_KEY_GET_END_KEY
	INC	A
	JNB	KEY_Y4,GET_KEY_GET_END_KEY
	INC	A
	RET
GET_KEY_GET_END_KEY:
	MOV	KEY_NUMBER,ACC
	RET

; Procedura czeka na nacisniecie klawisza
; Jesli klawisz zostanie nacisniety jego numer zwracany jest
; w komorce KEY_NUMBER, dopiero wtedy funkcja wraca z wywolania.

WAIT_FOR_KEY:
	PUSH	ACC
WAIT_FOR_KEY_LOOP:
	LCALL	GET_KEY
	MOV	A,KEY_NUMBER
	CJNE	A,#0,WAIT_FOR_KEY_END
	LJMP	WAIT_FOR_KEY_LOOP
WAIT_FOR_KEY_END:
	POP	ACC
	RET


;    Koniec obslugi klawiatury
;====================================



;======================================
; Obsluga buzzera - generacja dzwiekow

BEEP:
	MOV	R4,#200
	MOV	R5,#150
	LCALL	SOUND
	RET

BEEP_ERROR:
	MOV	R4,#250
	MOV	R5,#250
	LCALL	SOUND
	RET

BEEP_MEMORY_ERASE:
	MOV	R4,#200
	MOV	R5,#75
	LCALL	SOUND
	MOV	R4,#150
	MOV	R5,#75
	LCALL	SOUND
	MOV	R4,#200
	MOV	R5,#75
	LCALL	SOUND
	RET

BEEP_INIT:
	MOV	R4,#100
	MOV	R5,#255
	LCALL	SOUND
	MOV	R4,#150
	MOV	R5,#180
	LCALL	SOUND
	RET

BEEP_DETONATION:
	PUSH	ACC
	MOV	A,R4
	ADD	A,#10
	MOV	R4,A
	MOV	R5,#50
	LCALL	SOUND
	POP	ACC
	RET

BEEP_I2C_ERROR:
	MOV	R4,#250
	MOV	R5,#255
	LCALL	SOUND
	MOV	R4,#150
	MOV	R5,#255
	LCALL	SOUND
	RET



SOUND:
	PUSH	ACC
	MOV	ACC,R5
SOUND_LOOP:
	CPL	BUZZER
	PUSH	ACC
	MOV	ACC,R4
	DJNZ	ACC,$
	POP	ACC
	DJNZ	ACC,SOUND_LOOP
	SETB	BUZZER
	POP	ACC
	RET

; Koniec obslugi buzzera
;======================================



;======================================
; Obsługa szeregowej pamięci EEPROM

; Procedura wczytuje ustawienia sekwencji dla danego kroku i opóźnienie.
; Krok przechowywany jest w komórce CURRENT_STEP, opóźnienie - CURRENT_DELAY
; Wartości ładowane są do komórek CURRENT_DATA_A i CURRENT_DATA_B

I2C_LOAD_SETUP:
	PUSH	ACC
	MOV	I2C_MEMORY_DATA_ADDR,CURRENT_STEP
	MOV	I2C_MEMORY_PAGE,#0
	LCALL	I2C_MEMORY_ADDRESS_READ_BYTE
	MOV	CURRENT_DELAY,I2C_MEMORY_DATA
	MOV	A,CURRENT_STEP
	MOV	B,#2
	MUL	AB
	MOV	I2C_MEMORY_DATA_ADDR,A
	MOV	I2C_MEMORY_PAGE,#1
	LCALL	I2C_MEMORY_ADDRESS_READ_BYTE
	MOV	CURRENT_DATA_A,I2C_MEMORY_DATA
	LCALL	I2C_MEMORY_READ_BYTE
	MOV	CURRENT_DATA_B,I2C_MEMORY_DATA
	LCALL	LED_PRINT_SECTION_DATA
I2C_LOAD_SETUP_END:
	POP	ACC
	RET

; Procedura zapisuje ustawienia sekwencji dla danego kroku i opóźnienie.
; Krok przechowywany jest w komórce CURRENT_STEP, opóźnienie - CURRENT_DELAY
; Wartości zapisywane są z komórek CURRENT_DATA_A i CURRENT_DATA_B

I2C_SAVE_SETUP:
	PUSH	ACC
	MOV	I2C_MEMORY_DATA_ADDR,CURRENT_STEP
	MOV	I2C_MEMORY_DATA,CURRENT_DELAY
	MOV	I2C_MEMORY_PAGE,#0
	LCALL	I2C_MEMORY_WRITE_BYTE
	MOV	A,CURRENT_STEP
	MOV	B,#2
	MUL	AB
	MOV	I2C_MEMORY_DATA_ADDR,A
	MOV	I2C_MEMORY_PAGE,#1
	MOV	I2C_MEMORY_DATA,CURRENT_DATA_A
	LCALL	I2C_MEMORY_PAGE_WRITE_FIRST	
	MOV	I2C_MEMORY_DATA,CURRENT_DATA_B
	LCALL	I2C_MEMORY_PAGE_WRITE_NEXT
	LCALL	I2C_MEMORY_PAGE_WRITE_END
	POP	ACC
	RET

; Procedura odczytuje jeden bajt z pamięci EEPROM, spod aktualnego adresu
; Wartość zwracana jest w komórce I2C_MEMORY_DATA

I2C_MEMORY_READ_BYTE:
	MOV	I2C_READ,#1
	LCALL	I2C_MEMORY_START
	LCALL	I2C_MEMORY_HEADER
	LCALL	WAIT_I2C_MEMORY_ACK
	LCALL	I2C_MEMORY_GET_BYTE
	LCALL	SEND_I2C_MEMORY_NACK
	LCALL	I2C_MEMORY_STOP
	RET

; Procedura odczytuje jeden bajt do komórki I2C_MEMORY_DATA z pamięci EEPROM,
; spod adresu wskazanego w komórce I2C_MEMORY_DATA_ADDR

I2C_MEMORY_ADDRESS_READ_BYTE:
	PUSH	ACC
	MOV	I2C_READ,#0
	LCALL	I2C_MEMORY_START
	LCALL	I2C_MEMORY_HEADER
	LCALL	WAIT_I2C_MEMORY_ACK
	MOV	A,I2C_MEMORY_DATA_ADDR
	LCALL	I2C_MEMORY_SEND_BYTE
	LCALL	WAIT_I2C_MEMORY_ACK
	MOV	I2C_READ,#1
	LCALL	I2C_MEMORY_START
	LCALL	I2C_MEMORY_HEADER
	LCALL	WAIT_I2C_MEMORY_ACK
	LCALL	I2C_MEMORY_GET_BYTE
	LCALL	SEND_I2C_MEMORY_NACK
	LCALL	I2C_MEMORY_STOP
	POP	ACC
	RET

; Procedura zapisuje bajt z komórki I2C_MEMORY_DATA do pamięci EEPRO
; pod adres z komórki I2C_MEMORY_DATA_ADDR,
; w stronę pamięci I2C_MEMORY_PAGE

I2C_MEMORY_WRITE_BYTE:
	PUSH	ACC
	MOV	I2C_READ,#0
	LCALL	I2C_MEMORY_START
	LCALL	I2C_MEMORY_HEADER
	LCALL	WAIT_I2C_MEMORY_ACK
	MOV	A,I2C_MEMORY_DATA_ADDR
	LCALL	I2C_MEMORY_SEND_BYTE
	LCALL	WAIT_I2C_MEMORY_ACK
	MOV	A,I2C_MEMORY_DATA
	LCALL	I2C_MEMORY_SEND_BYTE
	MOV	ACC,25
	DJNZ	ACC,$
	LCALL	WAIT_I2C_MEMORY_ACK
	LCALL	I2C_MEMORY_STOP
	MOV	R3,#5
	LCALL	CZEKAJ_MS
	POP	ACC
	RET



; Trzyczęściowa procedura zapisu całej strony pamięci EEPROM
; I2C_MEMORY_DATA – dana do zapisu
; I2C_MEMORY_DATA_ADDR – adres początkowy danych do zapisu
; I2C_MEMORY_PAGE – strona, w której dana bęzie zapisana
; Zapis rozpoczynamy tą procedurą

I2C_MEMORY_PAGE_WRITE_FIRST:
	PUSH	ACC
	MOV	I2C_READ,#0
	LCALL	I2C_MEMORY_START
	LCALL	I2C_MEMORY_HEADER
	LCALL	WAIT_I2C_MEMORY_ACK
	MOV	A,I2C_MEMORY_DATA_ADDR
	LCALL	I2C_MEMORY_SEND_BYTE
	LCALL	WAIT_I2C_MEMORY_ACK
	MOV	A,I2C_MEMORY_DATA
	LCALL	I2C_MEMORY_SEND_BYTE
	MOV	ACC,25
	DJNZ	ACC,$
	LCALL	WAIT_I2C_MEMORY_ACK
	POP	ACC
	RET

; Następnie dostarczamy w komórce I2C_MEMORY_DATA kolejne dane
; i wywołujemy procedurę

I2C_MEMORY_PAGE_WRITE_NEXT:
	PUSH	ACC
	MOV	A,I2C_MEMORY_DATA
	LCALL	I2C_MEMORY_SEND_BYTE
	MOV	ACC,25
	DJNZ	ACC,$
	LCALL	WAIT_I2C_MEMORY_ACK
	POP	ACC
	RET

I2C_MEMORY_PAGE_WRITE_END:
	LCALL	I2C_MEMORY_STOP
	MOV	R3,#5
	LCALL	CZEKAJ_MS
	RET

; Zapis kończymy procedurą

I2C_MEMORY_HEADER:
	PUSH	ACC
	MOV	A,#10100000B
	ORL	A,I2C_READ
	PUSH	ACC
	MOV	A,I2C_MEMORY_PAGE
	RL	A
	MOV	I2C_MEMORY_PAGE,A
	POP	ACC
	ORL	A,I2C_MEMORY_PAGE
	LCALL	I2C_MEMORY_SEND_BYTE
	POP	ACC
	RET

; Procedura wysyła warunek START na magistrali I2C

I2C_MEMORY_START:
	SETB	I2C_MEMORY_SDA
	SETB	I2C_MEMORY_SCL
	JNB	I2C_MEMORY_SDA,I2C_MEMORY_START_ERROR
	JNB	I2C_MEMORY_SCL,I2C_MEMORY_START_ERROR
	NOP
	CLR	I2C_MEMORY_SDA
	NOP
	NOP
	CLR	I2C_MEMORY_SCL
	NOP
	RET
I2C_MEMORY_START_ERROR:
	LJMP	I2C_ERROR

; Procedura wysyła warunek STOP na magistrali I2C

I2C_MEMORY_STOP:
	CLR	I2C_MEMORY_SDA
	NOP
	NOP
	SETB	I2C_MEMORY_SCL
	NOP
	NOP
	SETB	I2C_MEMORY_SDA
	RET

; Procedura mówi o błędzie transmisji I2C
I2C_ERROR:
	MOV	I2C_FAIL,#15
I2C_ERROR_LOOP:
	LCALL	BEEP_I2C_ERROR
	DJNZ	I2C_FAIL,I2C_ERROR_LOOP
	RET

; Procedura wysyła sygnał zegarowy na magistrali I2C
PULSE_I2C_MEMORY_SCL:
	PUSH	ACC
	MOV	ACC,#5
	DJNZ	ACC,$
	SETB	I2C_MEMORY_SCL
	MOV	ACC,#20
	DJNZ	ACC,$
	CLR	I2C_MEMORY_SCL
	MOV	ACC,#5
	DJNZ	ACC,$
	POP	ACC
	RET

;Procedura czeka na warunek ACK na magistrali I2C
WAIT_I2C_MEMORY_ACK:
	SETB	I2C_MEMORY_SCL
	MOV	I2C_FAIL,#I2C_FAIL_COUNT
WAIT_I2C_MEMORY_ACK_LOOP1:
	JNB	I2C_MEMORY_SDA,WAIT_I2C_MEMORY_ACK_OK
	NOP
	NOP
	DJNZ	I2C_FAIL,WAIT_I2C_MEMORY_ACK_LOOP1
	LJMP	I2C_ERROR
WAIT_I2C_MEMORY_ACK_OK:
	CLR	I2C_MEMORY_SCL
	SETB	I2C_MEMORY_SDA
	RET

; Procedura odczytuje bajt z magistrali I2C
I2C_MEMORY_GET_BYTE:
	PUSH	ACC
	SETB	I2C_MEMORY_SDA
	MOV	I2C_BYTE_COUNT,#8
I2C_MEMORY_GET_BYTE_LOOP2:
	SETB	I2C_MEMORY_SCL
	MOV	R0,#5
	DJNZ	R0,$
	MOV	C,I2C_MEMORY_SDA
	RLC	A
	CLR	I2C_MEMORY_SCL
	MOV	R0,#5
	DJNZ	R0,$
	DJNZ	I2C_BYTE_COUNT,I2C_MEMORY_GET_BYTE_LOOP2
	MOV	I2C_MEMORY_DATA,A
	POP	ACC
	RET

; Procedura wysyła bajt na magistralę I2C
I2C_MEMORY_SEND_BYTE:
	MOV	I2C_BYTE_COUNT,#8
I2C_MEMORY_SEND_BYTE_LOOP1:
	RLC	A
	MOV	I2C_MEMORY_SDA,C
	LCALL	PULSE_I2C_MEMORY_SCL
	DJNZ	I2C_BYTE_COUNT,I2C_MEMORY_SEND_BYTE_LOOP1
	RET

; Procedura wysyła warunek ACK na magistrali I2C
SEND_I2C_MEMORY_ACK:
	CLR	I2C_MEMORY_SDA
	LCALL	PULSE_I2C_MEMORY_SCL
	RET

; Procedura wysy?a warunek NACK na magistrali I2C
SEND_I2C_MEMORY_NACK:
	SETB	I2C_MEMORY_SDA
	LCALL	PULSE_I2C_MEMORY_SCL
	RET

; W przypadku braku odpowiedzi informacja o błędzie
I2C_BRAK_ODPOWIEDZI:
	LCALL	BEEP_I2C_ERROR
	LJMP	I2C_BRAK_ODPOWIEDZI	


; Koniec obsługi szeregowej pamięci
;======================================


;======================================
; Obsługa wyświetlacza LED

; Procedura wyświetla cyfry w przerwaniu
; Poszczególne cyfry do wyświetlenia znajdują się odpowiednio
; w komórkach LED_DIGIT1..LED_DIGIT4
WRITE_LED:
	PUSH	ACC
	CLR	TR0
	MOV	ACC,#11110000B
WRITE_LED_1:
	CJNE	R7,#1,WRITE_LED_2
	ORL	LED_DIGIT1,A
	MOV	P3,LED_DIGIT1
	CLR	LED_W1
	LJMP	WRITE_LED_END
WRITE_LED_2:
	CJNE	R7,#2,WRITE_LED_3
	ORL	LED_DIGIT2,A
	MOV	P3,LED_DIGIT2
	CLR	LED_W2
	LJMP	WRITE_LED_END
WRITE_LED_3:
	CJNE	R7,#3,WRITE_LED_4
	ORL	LED_DIGIT3,A
	MOV	P3,LED_DIGIT3
	CLR	LED_W3
	LJMP	WRITE_LED_END
WRITE_LED_4:
	CJNE	R7,#4,WRITE_LED_SET0
	ORL	LED_DIGIT4,A
	MOV	P3,LED_DIGIT4
	CLR	LED_W4
	LJMP	WRITE_LED_END
WRITE_LED_SET0:
	MOV	R7,#0
WRITE_LED_END:
	INC	R7
	POP	ACC
	MOV	TL0,#100
	MOV	TH0,#225
	SETB	TR0
	RETI


; Procedura jednorazowo przemiata wyświetlacz LED
LED_PRINT:
	PUSH	ACC
	MOV	ACC,#11110000B
	ORL	LED_DIGIT1,A
	ORL	LED_DIGIT2,A
	ORL	LED_DIGIT3,A
	ORL	LED_DIGIT4,A
	POP	ACC
	MOV	P3,LED_DIGIT1
	CLR	LED_W1
	MOV	R3,#1
	LCALL	CZEKAJ_MS
	SETB	LED_W1
	MOV	P3,LED_DIGIT2
	CLR	LED_W2
	MOV	R3,#1
	LCALL	CZEKAJ_MS
	SETB	LED_W2
	MOV	P3,LED_DIGIT3
	CLR	LED_W3
	MOV	R3,#1
	LCALL	CZEKAJ_MS
	SETB	LED_W3
	MOV	P3,LED_DIGIT4
	CLR	LED_W4
	MOV	R3,#1
	LCALL	CZEKAJ_MS
	SETB	LED_W4
	RET

; Procedura animuje diody sygnalizacyjne LED
; Informując o gotowości do pracy / pozycji w głównym menu
BLINK_LEDS:
	PUSH	ACC
	SETB	LED_SECTION_A
	SETB	LED_SECTION_B
	MOV	A,LED_BLINK_COUNT
	CJNE	A,#0,BLINK_LEDS_1
	MOV	P0,#01110111B
	LJMP	BLINK_LEDS_END
BLINK_LEDS_1:
	CJNE	A,#10,BLINK_LEDS_2
	MOV	P0,#10111011B
	LJMP	BLINK_LEDS_END
BLINK_LEDS_2:
	CJNE	A,#20,BLINK_LEDS_3
	MOV	P0,#11011101B
	LJMP	BLINK_LEDS_END
BLINK_LEDS_3:
	CJNE	A,#30,BLINK_LEDS_4
	MOV	P0,#11101110B
	LJMP	BLINK_LEDS_END
BLINK_LEDS_4:
	CJNE	A,#40,BLINK_LEDS_5
	MOV	P0,#11011101B
	LJMP	BLINK_LEDS_END
BLINK_LEDS_5:
	CJNE	A,#50,BLINK_LEDS_END
	MOV	P0,#10111011B
	LJMP	BLINK_LEDS_END
BLINK_LEDS_END:
	INC	A
	CJNE	A,#60,BLINK_LEDS_QUIT
	MOV	A,#0
BLINK_LEDS_QUIT:
	MOV	LED_BLINK_COUNT,A
	POP	ACC
	RET

; Procedura miga diodami sygnalizacyjnymi informując
; o gotowości do odtworzenia sekwencji wyjściowej
LED_BLINK_DETONATION:
	PUSH	ACC
	MOV	A,LED_BLINK_COUNT
	CJNE	A,#0,LED_BLINK_DETONATION_1
	MOV	P0,#11000011B
	CLR	LED_SECTION_A
	SETB	LED_SECTION_B
	LJMP	LED_BLINK_DETONATION_2
LED_BLINK_DETONATION_1:
	CJNE	A,#50,LED_BLINK_DETONATION_2
	MOV	P0,#00111100B
	CLR	LED_SECTION_B
	SETB	LED_SECTION_A
LED_BLINK_DETONATION_2:
	INC	A
	CJNE	A,#100,LED_BLINK_DETONATION_END
	MOV	A,#0
LED_BLINK_DETONATION_END:
	MOV	LED_BLINK_COUNT,A
	POP	ACC
	RET
	
; Procedura włącza odpowiednie diody w SECTION OUTPUT
LED_PRINT_SECTION_DATA:
	PUSH	ACC
	MOV	ACC,CURRENT_SECTION
	CJNE	A,#0,LED_PRINT_SECTION_DATA_B
	MOV	DATA_PORT,CURRENT_DATA_A
	CLR	LED_SECTION_A
	SETB	LED_SECTION_B
	LJMP	LED_PRINT_SECTION_DATA_END
LED_PRINT_SECTION_DATA_B:
	MOV	DATA_PORT,CURRENT_DATA_B
	CLR	LED_SECTION_B
	SETB	LED_SECTION_A
LED_PRINT_SECTION_DATA_END:
	POP	ACC
	RET

; Procedura rozbija liczby CURRENT_STEP i CURRENT_DELAY
; na poszczególne cyfry – dla procedury wyświetlającej w przerwaniu
LED_PRINT_STEP_AND_DELAY:
	PUSH	ACC
	MOV	A,CURRENT_STEP
	MOV	B,#10
	DIV	AB
	MOV	LED_DIGIT4,A
	MOV	LED_DIGIT3,B
	MOV	A,CURRENT_DELAY
	MOV	B,#10
	DIV	AB
	MOV	LED_DIGIT2,A
	MOV	LED_DIGIT1,B
	POP	ACC
	RET

; Koniec obsługi wyświetlacza LED
;======================================