; ATtiny13 project
; VOLTMETER

.INCLUDE "tn13def.inc"

.DEF	TMP1 	= R17
.DEF	TMP2  	= R18
.DEF	SYM		= R19
.DEF	VOLT	= R20

; OUTP port, value
.MACRO OUTP
	LDI R16,@1 			
	OUT @0,R16 	
.ENDM

.CSEG
.ORG 0x0000

RJMP init

sym_table:
	; 7 segment display symbol table
	; for ATtiny13 xBoard v2 board
	
	; Q0 = C, Q1 = D, Q2 = dot, Q3 = E,
	; Q4 = F, Q5 = A, Q6 = B,   Q7 = G

	; 0 = segment ON, 1 = sement OFF

	;     qqqqqqqq
	;     01234567

	.DB 0b00100001, 0b01111101
	.DB 0b10101000, 0b00111000
	.DB 0b01110100, 0b00110010
	.DB 0b00100010, 0b01111001
	.DB 0b00100000, 0b00110000
	.DB 0b01100000, 0b00100110
	.DB 0b10100011, 0b00101100
	.DB 0b10100010, 0b11100010
	.DB 0b11111111, 0b00000000

; setdisplay draws the specified 
; symbol on the 7-segment display
; NB! specify SYM prior to call
setdisplay:
	
	; Set control signals
	OUTP DDRB, (1<<PB3) | (1<<PB4)
	
	; Load symbol table address
	LDI ZL, LOW (2*sym_table)
	LDI ZH, HIGH(2*sym_table)

	; Find required symbol
	ADD ZL, SYM

	; Load symbol data to R0
	LPM
	
	; Start iteration
	LDI TMP1, 8
	
	back1:
	
		SBRC R0, 0
		RJMP bitset
			; Set segment to 0 (ON)
			OUTP PORTB,(0<<PB3)|(0<<PB4)
			OUTP PORTB,(1<<PB3)|(0<<PB4)
		RJMP bitunset
		bitset:
			; Set segment to 1 (OFF)
			OUTP PORTB,(0<<PB3)|(1<<PB4)
			OUTP PORTB,(1<<PB3)|(1<<PB4)
		bitunset:
		
		LSR R0
		DEC TMP1

	BRNE back1	

	; Return to caller
	RET

;Initialization
init:

	; Set button as input, LED as output
	OUTP DDRB, (1<<PB0) | (0<<PB1) | (0<<PB2)
	
	; Initialize ADC1 on PB2
	; Use +5V reference voltage, left adjust, use PB2
	OUTP ADMUX, (0<<REFS0) | (1<<ADLAR) | (0<<MUX1) | (1<<MUX0)

	; Put 0 to SYM and display it
	LDI SYM, 0
	RCALL setdisplay

	; Start ADC
	OUTP ADCSRA, (1<<ADEN) | (1<<ADSC)

main:

	; Get left adjusted value
	IN VOLT, ADCH
	
	; Calculate the threshold by decrementing 25 values
	LDI TMP1, 0
	LDI TMP2, 25

	; Begin iteration

back:
	
	; Increment voltage value*2
	INC TMP1

	SBC VOLT, TMP2
	BRCS next

	RJMP back

next:

	; Divide voltage value by 2
	; to get the real value (+/- 0.5V)	
	LSR TMP1
	
	; Compare current value and the one before
	; and do not change display if they are equal
	CP SYM, TMP1
	BREQ equal

	; Otherwise set voltage value
	MOV SYM, TMP1
	RCALL setdisplay

equal:
	
	; If A/D conversion is over, restart it
	SBIS ADCSRA, 6
	OUTP ADCSRA, (1<<ADSC) | (1 << ADEN)

RJMP main
	

