;---------------------------------------;
;                                       ;
; Подпрограмки, которые я успел наваять ;
;                                       ;
;---------------------------------------;

 LSB (Least Significant Bit) - младший значащий бит,
 MSB (Most Significant Bit) - старший значащий бит.

; байты для вывода 0-9A-F на индикаторы, без точки, общий катод
LEDnd:	.DB	0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71
; байты для вывода 0-9A-F на индикаторы, с точкой
ledwd:	.DB	0xf,0x86,0xdb,0xcf,0xe6,0xed,0xfd,0x87,0xff,0xef,0xf7,0xfc,0xb9,0xde,0xf9,0xf1
"A" - 0x77
"b" - 0x7C
"c" - 0x58, "C" - 0x39
"d" - 0x5E
"E" - 0x79
"F" - 0x71
"r" - 0x50
"h" - 0x56, "H" - 0x76
"i" - 0x04, "I" - 0x06
"J" - 0x1E
"L" - 0x38
"P" - 0x73
"u" - 0x1C, "U" - 0x3E
"Y" - 0x6E

;*******************************************************************
; вывод в компорт байт в HEX-виде
; исходный байт а r17, портим r16
OUTHEX: push	r17
	andi	r17,0b11110000	; старший полубайт
	swap	r17
	rcall	TOASCII
	mov	r16,r17
	rcall	USART_TX	; выводим старший байт
	pop	r17
	andi	r17,0b00001111	; младший полубайт
	mov	r16,r17
	rcall	TOASCII
	mov	r16,r17
	rcall	USART_TX	; выводим младший байт
	ret

;*******************************************************************
; переводит младший полубайт в ASCII-код символа
; исходный и итоговый байт в r16
TOASCII:
	andi	R16,0x0F	; очищаем ненужные биты
	cpi	R16,0x0A
	brsh	ADDA
	subi	R16,-0x30	; ASCII '0'
	ret
ADDA:	subi	R16,-0x37	; + 0x0A = ASCII 'A'
	ret

;*******************************************************************
; вывод байта в уарт (не моё, из мануала :-)
USART_TX:
	sbis	UCSRA,UDRE	; Wait for empty transmit buffer
	rjmp	USART_TX
	out	UDR,r16		; Put data (r16) into buffer, sends the data
	ret

;*******************************************************************
; работа с EEPROM
;в ZH:ZL - адрес EEPROM куда писать
;в temp - записываемый байт
WriteEEP:
	sbic	EECR,EEWE	; ждем очистки бита
	rjmp	WriteEEP	; разрешения записи EEWE
	cli			; запрещаем прерывания
	out	EEARH,ZH	; старший байт адреса
	out	EEARL,ZL	; младший байт адреса
	out	EEDR,temp	; данные
	sbi	EECR,EEMWE	; взводим предохранитель
	sbi	EECR,EEWE	; записываем байт
	sei			; разрешаем прерывания
	ret			; (конец WriteEEP)

; в ZH:ZL - адрес откуда читать
; возврат temp - прочтенный байт
ReadEEP:
	sbic	EECR,EEWE	; ожидание очистки флага записи
	rjmp	ReadEEP
	out	EEARH,ZH	; старший адреса
	out	EEARL,ZL	; младший адреса
	sbi	EECR,EERE	; бит чтения
	in	temp,EEDR	; чтение
	ret			; конец ReadEEP

;*******************************************************************
; sleep
SPIM:	ldi	temp,(1<<SE)	; ко сну
	out	MCUCR,temp
	sleep			; спим. тупой идл
	clr	temp
	out	MCUCR,temp	; со сна
	ret

;*******************************************************************
; маленький, простенький диспетчер :-)
; если delay > 0 -- будем спать, пока обработчик прерываний не доведёт
; счётчик до 0. по флагам можем вызывать разные подпрограммы
; минимальный шаг задержки == периоду таймера
DISPATCHER:
	PUSHF
	sbrc	flags,SADC	; сброшен - простой сон
	rcall	MEASURE
	outi	MCUCR,1<<SE	; простой режим сна
SLL:	sleep			; спим.
	tst	delay		; если сч не 0
	brne	SLL		; спим до сл. прерывания
	outi	MCUCR,0		; со сна
	POPF
	ret
; и в обработчике прерываний от таймера:
	tst	delay		; сч пустой?
	breq	PC+2		; да, не трогаем
	dec	delay		; иначе - уменьшаем


;*******************************************************************
; ADC Noise Reduction Mode
ADCNR:	ldi	temp,1<<SE|1<<SM0
	out	MCUCR,temp
	sleep			; пока проц спит, АЦП меряет сигнал
	clr	temp
	out	MCUCR,temp	; со сна
	ret

;*******************************************************************
;запись через SPI. посылаемый байт в data_out
; этот конкрентный случай - для регистров 595
RW_SPI:	ldi	temp,8		; счетчик бит
SPIL:	cbi	PORTB,SCK	; выдали строб
	lsl	data_out	; старший бит в перенос
	brcc	PUT_0		; если в переносе 0 — перейти
	sbi	PORTB,MOSI	; выдали 1
	rjmp	SPIE
PUT_0:	cbi	PORTB,MOSI
	nop			; задержка на один такт
SPIE:	sbi	PORTB,sck	; защёлкнули строб
	dec	temp
	brne	SPIL
	ret
; пример использования:
	cbi	PORTB,LCH
	ldi	data_out,0x3f
	rcall	RW_SPI
	ldi	data_out,0x06
	rcall	RW_SPI
	sbi	PORTB,LCH	; регистры - на экран!

;***************************************************************************
;* "bin2BCD24" - 24-bit Binary to 8xBCD conversion
;*
;* This subroutine converts a 24-bit number (fbinH:fbinL) to a 8-digit
;* packed BCD number represented by 4 bytes (tBCD3:tBCD2:tBCD1:tBCD0).
;* MSD of the 8-digit number is placed in the lowermost nibble of tBCD3.
;*
;* Low registers used	:4 (tBCD0,tBCD1,tBCD2,tBCD3)
;* High registers used  :4 (fbinL,fbinM,fbinH,tmp1,temp)
;* Pointers used	:Z
;* портим: temp, tmp1
;***************************************************************************
.equ	AtBCD0	= 0
.equ	AtBCD3	= 3
.def	tBCD0	= r0	;BCD value digits 0 and 1
.def	tBCD1	= r1	;BCD value digits 2 and 3
.def	tBCD2	= r2	;BCD value digits 4 and 5
.def	tBCD3	= r3	;BCD value digits 6 and 7
.def	fbinH	= r10	;binary value High byte
.def	fbinH	= r11	;binary value Middle byte
.def	fbinL	= r12	;binary value Low byte
; ZL, ZH
bin2BCD24:
	ldi	tmp1,24		; Init loop counter
	clr	tBCD3		; clear result (4 bytes)
	clr	tBCD2
	clr	tBCD1
	clr	tBCD0
	clr	ZH		; clear ZH (not needed for AT90Sxx0x)
bBCDx_1:lsl	fbinL		; shift input value
	rol	fbinM		;
	rol	fbinH		; through all bytes
	rol	tBCD0
	rol	tBCD1
	rol	tBCD2
	rol	tBCD3
	dec	tmp1		; decrement loop counter
	brne	bBCDx_2		; if counter not zero
	ret			; return
bBCDx_2:ldi	r30,AtBCD3+1	; Z points to result MSB + 1
bBCDx_3:
	ld	temp,-Z		; get (Z) with pre-decrement
	subi	temp,-$03	; add 0x03
	sbrc	temp,3		; if bit 3 not clear
	st	Z,temp		; store back
	ld	temp,Z		; get (Z)
	subi	temp,-$30	; add 0x30
	sbrc	temp,7		; if bit 7 not clear
	st	Z,temp		; store back
	cpi	ZL,AtBCD0	; done all three?
	brne	bBCDx_3		; loop again if not
	rjmp	bBCDx_1

;***************************************************************************
; Исправленная процедура из 204-го аппнота
; родная нормально преобразовывает только числа от 0 до 99
; входное число в R16, выход: R17(сотни) и R16(десятки и единицы)
; в R17 копятся десятки, в R18 сотни, в R16 - остаток, единицы.
; потом R17 складывается с R16, а R18 переносится в R17
bin2bcd8:
	push	R18
	clr	R18
	clr	R17		;clear result MSD
bBCD8_1:subi	R16,10		;input = input - 10
	brcs	bBCD8_2		;abort if carry set
	subi	R17,-$10 	;tBCDH = tBCDH + 10
	cpi	R17,0xA0
	brlo	bBCD8_1
	inc	R18
	subi	R17,0xA0
	rjmp	bBCD8_1		;loop again
bBCD8_2:subi	R16,-10		;compensate extra subtraction
	add	R16,R17
	mov	R17,R18
	pop	R18
	ret
