;filename = main.asm
; Программа будет выводить значение записаное в регистре с помощью 3х семисигметных индикаторов с общим анодом.

; регистры проекта:
; R16 и R17 регистры для временного хранения данных.

; Регистры, которые содержать значения выводимые на семисегментые индикаторы.
.DEF REG0_SEG = R14 ; Первые 4 бит это нулевой индикатор, вторые 4 бит это первый индикатор.
.EQU REG0_SEG0_M = 0b00001111 ; маска которая отвечает какие разряды занимает число выводимое на индикатор SEG0 ; менять их надо с опаской. Код подрузомевает что они менно такие, но это можно обощить.
.EQU REG0_SEG1_M = 0b11110000
.DEF REG1_SEG = R15 ; Первые 4 бит это второй индикатор, вторые 4 бит это резерв(можно подключить еще один идикатор)
.EQU REG1_SEG2_M = 0b00001111

;Порт  8 выводов котрого отданы индикаторам
.EQU DDR_SEG = DDRA
.EQU PORT_SEG = PORTA
.EQU PIN_SEG = PINA

; Порт и 3 вывода которые отданы для питания общего анода индикаторов. А также маски-константы для этих 3х выводов
.EQU DDR_SEG_VCC = DDRC
.EQU PORT_SEG_VCC = PORTC
.EQU PIN_SEG_VCC = PINC
.EQU SEG0 = 0 ; Это номер вывода к которому подключено питание 0 индикатора 
.EQU SEG1 = 1
.EQU SEG2 = 2
;В соответсвии со схемой индикатора(лежит в файле проекта) называем вывода так же как обозначены светодиоды за которые они отвечают
.EQU A = PA0
.EQU B = PA1
.EQU C = PA2
.EQU D = PA3
.EQU E = PA4
.EQU F = PA5
.EQU G = PA6
.EQU DP = PA7


.CSEG
.ORG $0000
; адреса для прерываний 
rjmp RESET ; RESET
reti ; INT0
reti ; INT1
reti ; TIMER2_COMP
reti ; TIMER2_OVF
reti ; TIMER1_CAPT
reti ; TIMER1_COMPA
reti ; TIMER1_COMPB
reti ; TIMER1_OVF
reti ; TIMER0_OVF
reti ; SPI_STC
reti ; UART_RXC
reti ; UART_UDRE
reti ; UART_TXC
reti ; ADC
reti ; EE_RDY
reti ; ANA_COMP
reti ; TWI
reti ; INT2
rjmp TIMER0_COMP; TIMER0_COMP
reti ; SPM_RDY

RESET:
	;выставляем начальное положение вершины стека на конец памяти RAM
	ldi r16, $02
	out SPH, r16
	ldi r16, $5F
	out SPL, r16

	; Даем общее разрешение прерываний
	sei

	; настраиваем все необходимые выводы портов DDR_SEG and DDR_SEG_VCC
	ser r16
	out DDR_SEG, r16
	clr r16
	ori r16, (1 <<SEG0 | 1 <<SEG1 | 1<<SEG2 )
	out DDR_SEG_VCC, r16
	clr r16
	ori r16, (1 <<SEG0 | 0 <<SEG1 | 0<<SEG2 )
	out PORT_SEG_VCC, r16

	; Запишим в регистры со значением, выводимом на семисегментые индикаторы калибровочное число. 987
	ldi r16, 0b00001001
	mov REG1_SEG, r16
	ldi r16, 0b10000111
	mov REG0_SEG, r16

	; настраиваем таймер 0 для последовательного включения индикаторов.
	in r16, TCCR0
	ori r16, (1 << WGM01 | 1 << CS02 | 1 << CS01 | 1 << CS00) ; !!!!  устанавлием режим СТС и деление частоты на 1024(тестово)
	out TCCR0, r16
	in r16, TIMSK
	ori r16, (1 << OCIE0)
	out TIMSK, r16
	ser r16
	out OCR0, r16


	rjmp main 

	TIMER0_COMP:
		push r16
		push r17

		; определяем какой индикатор сейчас включен
		in r16, PORT_SEG_VCC;
		andi r16, (1 <<SEG0 | 1 <<SEG1 | 1<<SEG2 ) ; В ходе этой операции в r17 осталось еденица только на выводе SEG на котором сейчас логическая еденица.
		; проверяем какой из выводов сейчас был включен
		cpi r16, (0 <<SEG0 | 1 <<SEG1 | 1<<SEG2 ) ; если по итогу получиться 0, то был включен SEG0
		breq HANDLE_SEG0
		cpi r16, (1 <<SEG0 | 0<<SEG1 | 1<<SEG2 ) 
		breq HANDLE_SEG1
		cpi r16, (1 <<SEG0 | 1 <<SEG1 | 0<<SEG2 )
		breq HANDLE_SEG2
		; По итогу этих выборов изменился подвод питания к нужному индикатору, а также в регистре r17 теперь находиться число которое нужно вывести на новый индикатор
		DONE:
		cpi r17, $00
		breq PRINT_0
		cpi r17, $01
		breq PRINT_1
		cpi r17, $02
		breq PRINT_2
		cpi r17, $03
		breq PRINT_3
		cpi r17, $04
		breq PRINT_4
		cpi r17, $05
		breq PRINT_5
		cpi r17, $06
		breq PRINT_6
		cpi r17, $07
		breq PRINT_7
		cpi r17, $08
		breq PRINT_8
		cpi r17, $09
		breq PRINT_9

		EXIT:
		pop r17
		pop r16
		reti
		;подподпрограммы 
		HANDLE_SEG0:
			;меняем подачу питания к другому индикатору
			cbi PORT_SEG_VCC, SEG0
			sbi PORT_SEG_VCC, SEG1
	
			mov r17, REG0_SEG;
			andi r17, REG0_SEG0_M  ; Теперь в r17 4 старших бита нулевые, а 4 младших наше число
			rjmp DONE


		HANDLE_SEG1:
			cbi PORT_SEG_VCC, SEG1
			sbi PORT_SEG_VCC, SEG2

			mov r17, REG0_SEG;
			andi r17, REG0_SEG1_M 
			swap r17 ; дальше этот регистр r17 обрабатывается одинаково во всех случах поэтому он должен имет одинаковый вид во всех случаях  0b0000xxxx
			rjmp DONE

		HANDLE_SEG2:
			cbi PORT_SEG_VCC, SEG2
			sbi PORT_SEG_VCC, SEG0

			mov r17, REG1_SEG;
			andi r17, REG1_SEG2_M 
			rjmp DONE

		PRINT_0:
		in r16, PORT_SEG
		ori r16, (0 << A | 0 <<B | 0<< C| 0 << D| 0 << E| 0 << F | 1 <<G)
		out PORT_SEG, r16
		rjmp EXIT

		PRINT_1:
		in r16, PORT_SEG
		ori r16, ( 1 <<A | 0 << B| 0 << C | 1 <<D | 1 <<E| 1 <<F| 1 <<G)
		out PORT_SEG, r16
		rjmp EXIT

		PRINT_2:
		in r16, PORT_SEG
		ori r16, (0 << A | 0 <<B | 1<< C| 0 << D| 0 << E| 1 << F | 0 <<G)
		out PORT_SEG, r16
		rjmp EXIT

		PRINT_3:
		in r16, PORT_SEG
		ori r16, (0 << A | 0 <<B | 0<< C| 0 << D| 1 << E| 1 << F | 0 <<G)
		out PORT_SEG, r16
		rjmp EXIT

		PRINT_4:
		in r16, PORT_SEG
		ori r16, (1 << A | 0 <<B | 0<< C| 1 << D| 1<< E| 0 << F | 0 <<G)
		out PORT_SEG, r16
		rjmp EXIT

		PRINT_5:
		in r16, PORT_SEG
		ori r16, (0 << A | 1 <<B | 0<< C| 0 << D| 1 << E| 0 << F | 0 <<G)
		out PORT_SEG, r16
		rjmp EXIT

		PRINT_6:
		in r16, PORT_SEG
		ori r16, (0 << A | 1 <<B | 0<< C| 0 << D| 0 << E| 0 << F | 0 <<G)
		out PORT_SEG, r16
		rjmp EXIT

		PRINT_7:
		in r16, PORT_SEG
		ori r16, (0 << A | 0 <<B | 0<< C| 1 << D| 1 << E| 1 << F | 1 <<G)
		out PORT_SEG, r16
		rjmp EXIT

		PRINT_8:
		in r16, PORT_SEG
		ori r16, (0 << A | 0 <<B | 0<< C| 0 << D| 0 << E| 0 << F | 0 <<G)
		out PORT_SEG, r16
		rjmp EXIT

		PRINT_9:
		in r16, PORT_SEG
		ori r16, (0 << A | 0 <<B | 0<< C| 0 << D| 1 << E| 0 << F | 0 <<G)
		out PORT_SEG, r16
		rjmp EXIT
main:
	
	rjmp main