;===============================================
;
;
;		 Матрица светодиодов 4х4
;           X: A0,A1,A2,A3
;			Y: B0,B1,B2,B3
;
;===============================================
list      p=16f876a 
#include <p16f876a.inc>

;==========================
;Биты конфигурации
;==========================
__CONFIG _CP_OFF & _WDT_OFF & _BODEN_OFF & _PWRTE_OFF & _XT_OSC & _WRT_OFF & _LVP_OFF & _DEBUG_OFF & _CPD_OFF

;==========================
; КОНСТАНТЫ
;==========================
;#define L1		diod_mask_1, 7

;==========================
; МАКРОСЫ
;==========================
_BANK_0 macro
	BCF STATUS,RP0
	BCF STATUS,RP1
endm
_BANK_1 macro
	BSF STATUS,RP0
	BCF STATUS,RP1
endm
_BANK_2 macro
	BCF STATUS,RP0
	BSF STATUS,RP1
endm
_BANK_3 macro
	BSF STATUS,RP0
	BSF STATUS,RP1
endm

_MASK macro odin_vosem, devyat_shetnadzat
	;макрос назначить входы RA/RB
	movlw odin_vosem
	movwf mask_1_8
	movlw devyat_shetnadzat
	movwf mask_9_16
	;call wait
endm
;==========================
;   Переменные
;==========================
counter_00_00_XX	EQU 0x20	;
counter_00_XX_00	EQU 0x21	;  3хбайовый счетчик для sleep
counter_XX_00_00	EQU 0x22	;
counter_size		EQU 0x23	;

diod_sdvig_ra		EQU 0x24	;маска подачи питания
diod_sdvig_rb		EQU 0x25	;  на порты RA,RB

sbros_mask_ra		EQU 0x26	;маска сброса только СВЕТОДИОДИОВ
sbros_mask_rb		EQU 0x27	;  для RA,RB

mask_1_8			EQU 0x28	;маска горит/не_горит светодиодов 1-8
mask_9_16			EQU 0x29	;маска горит/не_горит светодиодов 9-16
mask_sdvig			EQU 0x2A	;маска сдвига горит/не_горит
mask_bit			EQU 0x2B	;маска mask_1_8 <> mask_9_16

int_backup_W		EQU 0x2C	;бэкап WREG
int_backup_STATUS	EQU 0x2D	;бэкап регистра STATUS
timer_H				EQU 0x2E	;дополнительный байт для увеличения длительности таймера TMR0
;==========================
;старт программного кода
;==========================
ORG 0x000	
	clrf PCLATH
	call init
goto main

;==========================
;обработчик прерывания
;==========================
ORG 0x004
	;запоминаем значения регистров
	movwf int_backup_W
	movf  STATUS,W
	movwf int_backup_STATUS
	;=====================
	;обработка прерывания
	;  инвертируем подачу питания на светодиод RB
	;=====================
	btfsc PORTB, 4
		goto portb_clear

	bsf PORTB,4
	goto end_portb_clear
	portb_clear
		bcf PORTB, 4

	end_portb_clear
	;восстанавливаем значения регистров
	movf  int_backup_STATUS, W
	movwf STATUS
	movf  int_backup_W, W

	bcf INTCON, TMR0IF	;сброс флага прерывания (у нас прерывание возникает при TMR0)
retfie

main
	movlw d'55'
	call wait

	;сброс питания по маске
	movf sbros_mask_ra, W
	andwf PORTA, F
	movf sbros_mask_rb, W
	andwf PORTB, F
	;===========================================
	movlw 0x01						;выбираем текущую маску (mask_1_8 или mask_9_16) в зависимости от mask_bit
	andwf mask_bit, W
	btfsc STATUS, Z
		goto set_mask_1

	movf mask_9_16, W
	goto start_test

	set_mask_1
		movf mask_1_8, W

	start_test						;проверка, должен ли гореть светодиод
	andwf mask_sdvig, W
	btfsc STATUS, Z
		goto raschet_sdviga
	;===========================================
	movf diod_sdvig_ra,W
	iorwf PORTA, F
	movwf PORTA
	movf diod_sdvig_rb,W
	iorwf PORTB, F
	movwf PORTB

	raschet_sdviga
	;расчет сдвига маски
	movlw 0x01
	xorwf mask_sdvig, W				;перешли от 1000 0000 => 0000 0001
	btfsc STATUS, Z
		goto mask_sdvig_sbros		;если да, то сбрасываем бит на 1000 0000
	rrf mask_sdvig					;если нет, то сдвигаем на 1 бит вправо
	goto raschet_XY

	mask_sdvig_sbros
		movlw b'10000000'			
		movwf mask_sdvig
		;инвертируем бит обращения к mask_1_8 <> mask_9_16
		comf mask_bit
	raschet_XY
	;расчет сдвига позиции XY
		movlw 0x01
		xorwf diod_sdvig_ra, W
		btfsc STATUS, Z
			goto RA_SBROS
	
		rrf diod_sdvig_ra
		goto main
	
		RA_SBROS
			movlw b'00001000'
			movwf diod_sdvig_ra
			;sbros/decrement RB
			movlw 0x01
			xorwf diod_sdvig_rb, W
			btfsc STATUS, Z
				goto RB_SBROS

			rrf diod_sdvig_rb
			bcf PORTC, 6
			goto main	
	
			RB_SBROS
				movlw b'00001000'
				movwf diod_sdvig_rb
goto main

init
	_BANK_0	
	bcf INTCON, GIE		;глобальное отключение прерываний	
	clrf PORTA
	clrf PORTB
	clrf PORTC
	_BANK_1
	movlw b'00000110'		;все выходы RA - цифровые
	movwf ADCON1

	movlw b'11110000'		;RA0,RA1,RA2,RA3 - цифровые выходы, остальные - цифровые входы
	movwf TRISA

	movlw b'00000111'	;TMR0, внутренний тактовый сигнал, коэффициент предделителя 1:256
	movwf OPTION_REG		

	;В0,В1,В2,В3 - цифровые выходы
	movlw b'11100000'
	movwf TRISB

	movlw b'00011111'
	movwf TRISC

	_BANK_0
	clrf INTCON
	;bsf INTCON, TMR0IE	;разрешить прерывание при переполнении таймера TMR0

	;сброс первые 4 бита (RA и RB параллельны: RA0-RA3, RB0-RB3)
	movlw b'11110000'
	andwf sbros_mask_ra,F
	andwf sbros_mask_rb,F
	
	;начальные параметры подачи питания на PORTA,PORTB
	movlw b'00001000'	
	movwf diod_sdvig_ra
	movwf diod_sdvig_rb

	;начальная маска - ничто не горит (вечно)
	movlw b'11111111'
	movwf mask_1_8
	movlw b'11111111'
	movwf mask_9_16
	
	;начальный бит обращения mask_1_8(0) <> mask_9_16(1)
	movlw 0x00
	movwf mask_bit

	;начальный бит опроса маски
	movlw b'10000000'
	movwf mask_sdvig
	;тест светодиодов
	movlw 0xFF
	movwf PORTA
	movwf PORTB
	movlw b'11100000'
	movwf PORTC
	movlw d'60'
	call wait
	;sleep parametr

	movlw 0x00
	movwf PORTA
	movwf PORTB
	movwf PORTC

	movlw 0x01
	movwf TMR0
	bsf INTCON, GIE		;включение прерываний
return

wait
	movwf counter_XX_00_00
 	loop_counter_XX_00_00
		movwf counter_00_XX_00

		loop_counter_00_XX_00
			movwf counter_00_00_XX

		 	loop_counter_00_00_XX
			 	decfsz counter_00_00_XX, F
			goto loop_counter_00_00_XX

			decfsz counter_00_XX_00, F
	 	goto loop_counter_00_XX_00

	 	decfsz counter_XX_00_00, F
 	goto loop_counter_XX_00_00
return 

END



