; Программа работы FCL-метра.
; Александр Кленин (akl)

; Модификация Serj_K с реализацией автокалибровки по эталону и добавлением частотомера.
; Начальные коэффициенты переносятся в ЕЕПРОМ из прошивки автоматически при первом включени,
; поєтому записывать ЕЕПРОМ не нужно.

; В качестве индикатора ЖКИ-дисплей типа HD44780 20х2 (раскоментировать строку "#define	LCD_20") или 16х2.
; Контроллер AT90S8515 или ATmega16 (раскоментировать/закоментировать соответствующий .INCLUDE).
; Для AT90S8515 и ATmega16 назначение портов совпадает.
; Номинальная частота кварца Fo=8МГц.
; Для ATmega16 следующие FUSE биты должны быть: CKSEL3..0=1111, CKOPT=0. Остальные не меняем.

; Вычисление индуктивности L генераторным методом проводится по выражению
; Lx=Lo*[(nx*No/no*Nx)^2-1], 
; где nx-целое число периодов тактовой частоты контроллера (Fo) за время измерения Nx
; no-целое число периодов Fo за время измерения No
; Nx-целое число периодов частоты генератора с подключенным измеряемым элементом за принятое время измерения
; No-целое число периодов частоты генератора с подключенным эталонным элементом за принятое время измерения
; Вычисление конденсаторов C генераторным методом проводится согласно выражения
; Cx=Co*[nx*No/no*Nx-1],  где
; Co-точно известное значение опорного конденсатора,  при котором производилась калибровка
; nx-целое число периодов Fo,  подсчитанных счетчиком за время измерения Nx периодов колебаний генератора, 
; образованного (Rx+Ro)*Co
; no-целое число периодов Fo,  подсчитанных счетчиком за время измерения Nx периодов колебаний генератора, 
; образованного Ro*Co при калибровке при замкнутых входах "Rx"

; При измерении Lx задействована
; PA3- логич. 1 включает генератор "Lx/Rx"

; При измерении Cx задействована
; PA4- логич. 1 включает генератор "Cx"

; PD4 ">0<" (в режиме LC) или "MODE" (в режиме частотомера)
; PD3 "РЕЖИМ" (в режиме LC) или "P/N" (в режиме частотомера)

; Калибровка

; Кнопкой "РЕЖИМ" установить режим работы Lx
; Закоротить входы "Lx" и нажать кнопку ">0<".
; После измерения и запоминания значения 65536*65536*No/no,  о чем свидетельствует
; появление индикации "0.0",  кнопку "0" отпустить.
; После калибровки 0 на индикатор выводится приглашение калибровки по эталону.
; Для калибровки по эталону необходимо подключить эталонную катушку, индуктивность которой
; была зашита в прошивку, и нажать кнопку ">0<". После отпускания кнопки ">0<" произойдёт пересчёт
; корректирующего коэффициента COEFF_Lo и на индикаторе отображается значение индуктивности эталонной
; катушки.
; Калибровка канала C должна выполняться при разомкнутых входах Cx.
; Для отказа от калибровки по эталону необходимо нажать кнопку "РЕЖИМ", перейдя на измерение другой
; реактивности.
; Значения эталонных элементов, умноженные на 10, заносятся в НЕХ виде в поля C_ETALON и L_ETALON.

; Распредение памяти RAM
; $70...$79 память nx
; $80...$89 память Nx
;
; Для включения режима частотомера необходимо перед включением прибора нажать и удерживать кнопку >0<.
; Режим работы частотомера переключается кнопкой MODE по кругу: Частота-Период-Длительность-Счёт. При удержании
; кнопки переключение происходит автоматически.
; Частота измеряется методом подсчёта входных импульсов за время 1с. Верхний предел измеряемой частоты
; ограничен примерно Fclk/2.5. Низкие частоты с бОльшей точностью можно измерять через измерение периода.
; Минимальная величина измерения периода или длительности импульса примерно 1мкс. Дискретность 0.125мкс.
; Измеряется длительность как положительных, так и отрицательных периодических и одиночных импульсов.
; Полярность импульсов при измерении длительности выбирается кнопкой N/P.
; Импульсы для счёта подаются на вход измерения частоты, а разрешающий импульс нужной полярности на вход
; измерения длительности/прериода. Подярность разрешающего импульса выбирается кнопкой N/P.


	.INCLUDE "8515def.inc"
;	.INCLUDE "m16def.inc"

#define	LCD_20		;длинна строки индикатора 20 символов.
#define	REAL_QUARZ	8008	;реальная частота кварца, кГц
#define	T_1_S		(REAL_QUARZ*1000/256)
#define	T1_CAPT_RF	((1<<ICES1) | (1<<CS10))
#define	T1_CAPT_FF	(1<<CS10)


.equ	GENPORT	=PORTA	;порт управления генераторами
.equ	GEN_DDR	=DDRA
.equ	CX_ON	=4
.equ	LX_ON	=3

.equ	FREQ_PORT	=PORTB	;порт частотомера
.equ	FREQ_DDR	=DDRB
.equ	FREQ_IN	=0			;вход частотомера
.equ	T_IN_POZ=2			;вход измерителя интервалов - прямой вход компаратора
.equ	T_IN_NEG=3			;вход измерителя интервалов - инверсный вход компаратора - подать смещение 2.5В.

.equ	LCDPORT	=PORTC
.equ	LCD_DDR	=DDRC
.equ	LCD_RS	=0
.equ	LCD_EN	=1

.equ	KBDPORT	=PORTD
.equ	KBD_DDR	=DDRD
.equ	KBD_IN	=PIND
.equ	K_MODE	=3
.equ	K_ZERO	=4
.equ	LED		=5
.equ	TEST_OUT=6

	; Арифметические регистры
.def	A	=r16
.def	B	=r17
.def	H	=r18
.def	L	=r19
.def	D	=r20
.def	E	=r21
.def	F	=r22
.def	G	=r23
.def	J	=r24
.def	K	=r25

	
.equ	MINUS			=$6F
.equ	DIAPAZON		=$7F
.equ	RAM_COEFF_Co	=$90
.equ	RAM_CONST_C		=$94
.equ	RAM_COEFF_Lo	=$98
.equ	RAM_CONST_L		=$9C

.equ	T_IND			=$A0

.equ	RAM_C_ETALON	=$D0	;для калибровки по эталону
.equ	RAM_L_ETALON	=$D4	;для калибровки по эталону
.equ	RAM_COEF_x_ETAL =$E0	;промежуточное значение = RAM_COEFF_Xo * RAM_X_ETALON
.equ	MODE			=$F0	;=0-LC-метер
								;=1-частотомер
								;=2-период
								;=3-длительность
								;=4-счётчик импульсов (вход F, разрешение счёта - вход T ) до 16777215
.equ	MAX_MODE=5		;превышение максимального номера режима частотомера

;индикатор
.equ	LINE_1			=$80	;адрес 1-й строки индикатора в DDRAM
.equ	LINE_2			=$c0	;адрес 2-й строки индикатора в DDRAM
.equ	REZULT_LINE		=LINE_1	;для смены строк менять LINE_1 <-> LINE_2
.equ	COMENT_LINE		=LINE_2

	.ESEG		;В EEPROM только коэффициенты и режим
	.ORG	$10
;***************************************************************************
; Предполагается,  что при измерении емкости Ro=1490 Оm Co=4700 pF
;***************************************************************************
COEFF_Co:
	.DB	$00, $00, $BD, $9C		;уже после калибровки. Co*10*K=4700*10*K
E_CONST_C:
	.DB	$04, $D3, $0B, $3B		;65536*65536*No/no
;***************************************************************************
; Предполагается,  что при измерении индуктивности Lo=470 mkH Co=4700 pF
; Используется катушка с сердечником для измерения катушек с сердчником
;***************************************************************************
COEFF_Lo:
	.DB	$00, $00, $10, $8E		;уже после калибровки. Lo*K=461*10*K
E_CONST_L:
	.DB	$03, $75, $76, $50		;65536*65536*No/no
E_END:
;***************************************************************************

	.CSEG
	.ORG	$00
;***************************************************************************
;***************************************************************************
; Прерывания

RESET:
	RJMP	START		; On Reset
	RETI				; On Interrupt 0 - не используется
	RJMP	GO_ISR1		; On Interrupt 1 - прерывание при нажатии кнопки "РЕЖИМ"
#if defined (__ATmega8__) || defined(__ATmega16__)
	RETI				; Timer/Counter2 Compare Match
	RETI				; Timer/Counter2 Overflow
#endif
	IJMP				; Timer 1 capture
	RJMP	T1_COMPA_ISR; Timer 1A compare
	RETI				; Timer 1B compare
	RJMP	T1_OVF_ISR	; Timer 1 overflow
	ADIW	XL, 1		; Timer 0 overflow
	RETI				; Serial transfer complete
	RETI				; UART Rx
	RETI				; UART Data reg empty
	RETI				; UART Tx
	RETI				; Analog Comparator

;***************************************************************************
;***************************************************************************
;***************************************************************************
;константы эталонных элементов для калибровки L/C
;***************************************************************************
C_ETALON:
	.DB	$00, $00, $B9, $78		;4748pF *10
;	.DB	$00, $01, $34, $98		;7900pF *10
L_ETALON:
	.DB	$00, $00, $11, $FF		;460.7uH *10
;	.DB	$00, $00, $1A, $90		;680uH *10
;***************************************************************************
;начальные параметры для переноса в еепром при первом запуске
;***************************************************************************
COEFF_Co_FL:
	.DB	$00, $00, $BD, $9C		;Co*10*K=4700*10*K
E_CONST_C_FL:
	.DB	$04, $D3, $0B, $3B		;65536*65536*No/no
COEFF_Lo_FL:
	.DB	$00, $00, $10, $8E		;Lo*K=461*10*K
E_CONST_L_FL:
	.DB	$03, $75, $76, $50		;65536*65536*No/no
	.DB $00, $ff				;индикация, что константы записаны в еепром
E_END_FL:
;************************************************
TTB_IND:
	.DB	'0', '1'
	.DB	'2', '3'
	.DB	'4', '5'
	.DB	'6', '7'
	.DB	'8', '9'
	.DB	' ', '-'
;************************************************
D_LINE:
#ifdef	LCD_20
	.DB		"    Cx= --------"		;16 символов для 20-символьной строки. Начальный текст
#else
	.DB		"  Cx= --------  "		;16 символов для 16-символьной строки. Начальный текст
#endif
INFO:	;>0<, L/C и PWR - напротив соответствующих кнопок,   *-*-X - напротив клемм
#ifdef	LCD_20
	.DB		">0<  *-*-X  C/L  PWR"	;20 символов.
#else
	.DB		"0  *-X  C/L  PWR"		;16 символов.
#endif
CALIBR:
#ifdef	LCD_20
	.DB		">0<-CALIBR, C/L-EXIT"	;20 символов. запрос на калибровку COEFF_Xo по эталону
#else
	.DB		"0-CAL.  C/L-EXIT"		;16 символов. запрос на калибровку COEFF_Xo по эталону
#endif

FREQ:
	.DB		"F, Hz:   ------ "		;16 символов. Начальный текст
PERIOD:
	.DB		"T, us:----------"
PULS:
	.DB		"t ,us:----------"
COUNT:
	.DB		"CNT  :        0 "
FREQ_INFO:
#ifdef	LCD_20
	.DB		"MODE -----  N/P  PWR"	;20 символов.
#else
	.DB		"M -----  N/P PWR"		;16 символов.
#endif
;***************************************************************************
;***************************************************************************
;***************************************************************************
; Обработчики прерываний
;***************************************************************************
GO_ISR1:
	SET
	RET
;************************************************
T1_OVF_ISR:
	ADIW	XL, 1	
	CPI		XH, $10		;время измерения в режиме LC ~32 сек. В режиме частотомера не достигается
	BRCS	IZM
	SET
IZM:
	RETI
;************************************************
CAPT_LC:
	IN		R1, ICR1L
	IN		R0, ICR1H
	LDI		ZL, LOW (CAPT_1); следующее прерывание будет на CAPT_1
	CLR		XH
	CLR		XL		; очистить старшее слово nx_begin
	RETI
;************************************************
CAPT_1:
	IN		R19, ICR1L
	IN		R18, ICR1H	; конечное значение nx
	ADIW	YL, 1		; Nx=Nx+1
	CPI		XL, 40		; время измерения закончилось?
	CPC		XH, ZH
	BRCC	CAPT_3		; да
	RETI				; нет
;************************************************
CAPT_3:
	IN		R16, TIFR
	SBRC	R16, 7		; если есть необработанное требование прерывания OVER_T1
	RETI				; выход для его обработки и ожидания окончания следующего периода

	OUT		TCCR1B, ZH	; STOP T1
	OUT		TIMSK, ZH

	SUB		R19, R1
	SBC		R18, R0
	SBC		XL, ZH
	SBC		XH, ZH		; nx-nx_begin
		
	STS		$76, XH		;сохраняем результат
	STS		$77, XL
	STS		$78, R18
	STS		$79, R19	; nx

	STS		$86, ZH
	STS		$87, ZH
	STS		$88, YH
	STS		$89, YL		; Nx
		
	RJMP	END_IRQ
;************************************************
;************************************************
T1_COMPA_ISR:	;прерывание для измерителя частоты и формирования временных интервалов
	OUT		TCCR0, ZH	;останавливаем счёт Т0
	OUT		TCCR1B, ZH	;останавливаем таймер
	OUT		TIMSK, ZH	;запрещаем прерывания
	CLI
	MOV		R6, ZH		;переносим результат
	MOV		R7, XH
	MOV		R8, XL
	IN		R9, TCNT0
	RJMP	END_IRQ
;************************************************
CAPT_PTM:	;прерывание для измерителя периода и длительности импульсов
	OUT		TCCR1B, R17			;включаем таймер с захватом по нужному фронту
	LDI		ZL, LOW (CAPT1_PTM)	;следующее прерывание будет на CAPT1_PTM
	SBI		KBDPORT, LED
	RETI
;************************************************
CAPT1_PTM:
	OUT		TCCR1B, YH	;STOP T1
	OUT		TIMSK, YH	;запрещаем прерывания
	IN		R9, TCNT1L	;переносим результат
	IN		R8, TCNT1H
	MOV		R7, XL
	MOV		R6, XH
	RJMP	END_IRQ
;************************************************
CAPT_CNT:	;прерывание для счётчика импульсов
	OUT		TCCR0, R19			;разрешаем счёт
	OUT		TCNT0, ZH			;без этого добавлял 1 лишний импульс
	OUT		TCCR1B, R17			;захват по другому фронту
	LDI		ZL, LOW (CAPT1_CNT)	;следующее прерывание будет на CAPT1_CNT
	SBI		KBDPORT, LED
	RETI
;************************************************
CAPT1_CNT:
	OUT		TCCR0, YH	;останавливаем счёт Т0
	OUT		TCCR1B, YH	;STOP T1
	OUT		TIMSK, YH	;запрещаем прерывания
	IN		R19, TCNT0	;переносим результат
	SUBI	R19, 1		;почему-то прибавлялась 1 - вычитаем
	BRCC	CNT_REZ
	SBIW	XL, 1
CNT_REZ:
	MOV		R9, R19
	MOV		R8, XL
	MOV		R7, XH
END_IRQ:
	CBI		KBDPORT, LED
	CLI
	SET
	RETI
;***************************************************************************
;***************************************************************************
START:
	LDI		R16, LOW(RAMEND)
	OUT		SPL, R16
	LDI		R16, HIGH(RAMEND)
	OUT		SPH, R16
	CLR		ZH
	OUT     EEARH, ZH		;данные находятся только в первых 256 байтах
	OUT		TCCR1A, ZH

	LDI		A, (1<<ACD)		;выключить аналоговый компаратор
	OUT		ACSR, A
	RCALL	INIT_PORTS
	CLR		R20				;LC-метр
	SBIC	KBD_IN, K_ZERO	;при включении нажата кнопка >0< ?
	RJMP	LCMETTER		;нет - режим LC-метра
	LDI		R20, 1			;да - частотомер
LCMETTER:
	STS		MODE, R20
	RCALL	INIT_IND		;инициализация индикатора и вывод начального текстта
	LDS		R20, MODE
	CPI		R20, 0			;LC-metter?
	BRNE	F_METTER		;нет
	RCALL	CONST_ROM_RAM
	LDI		ZL, $20
	RCALL	EEREAD
	TST		R0				;коэффициенты в еепром занесены?
	BREQ	SCHIT			;да
	RCALL	COEFF_TO_EEPROM	;нет - переносим
;*************************************************
;  Чтение состояния органов управления,
;  измерение и вывод ни индикатор
;  Основной цикл программы
;************************************************
SCHIT:
	CLI
	CLR		ZH
	STS		MINUS, ZH
	OUT		GIMSK, ZH
	LDI		ZL, $70	
	RCALL	CLEAR_R20
	LDI		ZL, LOW(COEFF_Co)
	LDI		YL, LOW(RAM_COEFF_Co)
_E:
	RCALL	EEREAD			;преносим коэфициенты и номер режима из EEPROM в ОЗУ
	ST		Y, R0
	INC		YL
	INC		ZL
	CPI		ZL, LOW(E_END)
	BRNE	_E

	RCALL	SET_REGIM		;выводим соответствующий символ и включаем соответствующий генератор

	SBIS	KBD_IN, K_ZERO	; обнуление >0< ?
	RJMP	ZER_O			; да

	RCALL	RABOTA			; нет - измерение
	CPI		XH, $10			; время измерения >32 сек?
	BRCS	NO_PEREGR		; нет,  результат в норме
	LDI		R20, '-'		; да - перегрузка
	CLR		XH
#ifdef	LCD_20
	LDI		XL, (T_IND+8)
#else
	LDI		XL, (T_IND+6)
#endif
	RCALL	PLACE_CHAR_IND
	RJMP	SCHIT			; занести код перегрузки прибора и перейти на индикацию

NO_PEREGR:
	RCALL	CLEAR_R10		; очистить массив R10...R19
	SBIC	KBD_IN, K_MODE	; измерение конденсатора?
	RJMP	RAB_L			; нет
	RCALL	RESULT_Cx		; Cx
	RJMP	RES_GO
RAB_L:
	RCALL	RESULT_Lx		; Lx
RES_GO:
	RCALL	BAND
	RCALL	BIN_BCD
	RCALL	INDEX_DEC_POINT
	RCALL	CODIR
	RJMP	SCHIT
;*************************************************
F_METTER:	;режим частотомера
	SBIS	KBD_IN, K_ZERO	;при включении была нажата кнопка >0<
	RJMP	F_METTER		;ждём отпускания
	RCALL	PAUSE
	RCALL	PAUSE
;ОСНОВНОЙ ЦИКЛ РЕЖИМА ЧАСТОТОМЕРА
F_METTER_LOOP:
	RCALL	CLR_R0_R9		;очистка предыдущего результата измерения
	RCALL	TCNT1_ZERO		;останавливаем и обнуляем таймер1
	LDS		R20, MODE
	CPI		R20, 1
	BREQ	SET_MODE_FRM	;частотомер
	CPI		R20, 2
	BREQ	SET_MODE_PERIOD	;период
	CPI		R20, 3
	BREQ	SET_MODE_PULS	;длительность импульса

SET_MODE_CNT:
	LDI		XL, (T_IND)+4
	SBIC	KBD_IN, K_MODE	;кнопка нажата?
	RJMP	SET_MODE_CNTI_P	;нет
	LDI		R16, 'N'
	ST		X, R16
	LDI		R18, 0			;Старт - Захват по заднему фронту без запуска таймера
	LDI		R17, (1<<ICES1)	;Стоп  - Захват по переднему фронту без запуска таймера
	RJMP	SET_MODE_CNT_START
SET_MODE_CNTI_P:
	LDI		R16, 'P'
	ST		X, R16
	LDI		R18, (1<<ICES1)	;Старт - Захват по переднему фронту без запуска таймера
	LDI		R17, 0			;Стоп  - Захват по заднему фронту без запуска таймера
SET_MODE_CNT_START:
	RCALL	SET_TIMR_CNT	;настраиваем таймеры на счёт импульсов
	OUT		TIMSK, R16		;разрешение OVER_T0+CAPT
	RJMP	WAITF

SET_MODE_FRM:
	RCALL	SET_TIMR_FREQ	;настраиваем таймеры на измерение частоты
WAITF:
	SBIS	KBD_IN, K_ZERO	;нажата кнопка >0< ?
	RJMP	SET_NEW_MODE	;да
	BRTC	WAITF			;ждём конца измрения
	CLT
	RJMP	FREQ_REZ		;выводим результат

SET_MODE_PERIOD:
	LDI		R18, (1<<ICES1)	;Старт - Захват по переднему фронту без запуска таймера
	LDI		R17, T1_CAPT_RF	;разрешение работы Т1, Fclk/1. Стоп - Захват по переднему фронту
	RJMP	SET_MODE_TP

SET_MODE_PULS:
	LDI		XL, (T_IND)+1
	SBIC	KBD_IN, K_MODE	;кнопка нажата?
	RJMP	SET_MODE_T_POZ	;нет
	LDI		R16, 'N'
	ST		X, R16
	LDI		R18, 0			;Старт - Захват по заднему фронту без запуска таймера
	LDI		R17, T1_CAPT_RF	;разрешение работы Т1, Fclk/1. Стоп  - Захват по переднему фронту
	RJMP	SET_MODE_TP
SET_MODE_T_POZ:
	LDI		R16, 'P'
	ST		X, R16
	LDI		R18, (1<<ICES1)	;Старт - Захват по переднему фронту без запуска таймера
	LDI		R17, T1_CAPT_FF	;разрешение работы Т1, Fclk/1. Стоп  - Захват по заднему фронту
SET_MODE_TP:
	RCALL	SET_TIMR_PT		;настраиваем таймеры на измерение периода/длительности
	OUT		TIMSK, R16		;разрешение OVER_T1+CAPT
WAITT:
	SBIS	KBD_IN, K_ZERO	;нажата кнопка >0< ?
	RJMP	SET_NEW_MODE	;да
	BRTC	WAITT			;нет - ждём конца измрения
	CLT
;вычисляем результат измерения периода/длительности
	RCALL	CLEAR_R10				;очистить массив R10...R19
	LDI		R18, HIGH(10000)		;считаем относительно 10МГц(период=0.1мкс)
	LDI		R19, LOW (10000)
	RCALL	MULT
	RCALL	CLEAR_R10				;очистить массив R10...R19
	LDI		R18, HIGH(REAL_QUARZ)	;реально 8МГц(период=0.125мкс)
	LDI		R19, LOW (REAL_QUARZ)
	RCALL	DIV
FREQ_REZ:					;результат измерения в R0...R9
	RCALL	BIN_BCD
	RCALL	REZ_2_LCD		;преобразовать в текст (9 знаков)
	RCALL	IND				;выводим на индикатор результат
	RCALL	PAUSE_02s		;для устранения возможного мерцания
	RJMP	F_METTER_LOOP	;текущий цикл частотомера

SET_NEW_MODE:
;устанавливаем новый режим частотмера и выводим соответствующий текст
	CLI						;запрещаем прерывания
	CLT
	RCALL	TCNT1_ZERO		;останавливаем и обнуляем таймер1
	OUT		TCCR0, ZH
	LDS		R20, MODE
	INC		R20
	CPI		R20, MAX_MODE
	BRLO	SAVE_MODE
	LDI		R20, 1			;да - устанавливаем первый режим частотомера
SAVE_MODE:
	STS		MODE, R20		;сохраняем новый режим
	CPI		R20, 1
	BREQ	LCD_FREQ
	CPI		R20, 2
	BREQ	LCD_PERIOD
	CPI		R20, 3
	BREQ	LCD_PULS

	LDI		ZL, LOW(COUNT*2)
	RJMP	LCD_NEW_MODE
LCD_PULS:
	LDI		ZL, LOW(PULS*2)
	RJMP	LCD_NEW_MODE
LCD_PERIOD:
	LDI		ZL, LOW(PERIOD*2)
	RJMP	LCD_NEW_MODE
LCD_FREQ:
	LDI		ZL, LOW(FREQ*2)
LCD_NEW_MODE:
	RCALL	DATA_L			;заполнить строку вывода
	RCALL	IND				;выводим на индикатор результат
	RCALL	PAUSE_02s
	RCALL	PAUSE_02s
	RCALL	PAUSE_02s
	RJMP	F_METTER_LOOP
;*************************************************
SET_TIMR_FREQ:		;НАСТРОЙКА ТАЙМЕРОВ ДЛЯ ИЗМЕРЕНИЯ ЧАСТОТЫ
	CLT
	OUT		ACSR, ZH		;отключаем компаратор
	LDI		R16, $ff
	OUT		TIFR, R16		;сброс флага
	LDI		R16, (1<<OCIE1A) | (1<<TOIE0)
	OUT		TIMSK, R16		;разрешение OCE1A + OVER_T0
	LDI		R16, HIGH(T_1_S)
	OUT		OCR1AH, R16
	LDI		R16, LOW(T_1_S)
	OUT		OCR1AL, R16		;OCR1A = 31250  -  1с
	LDI		R16, (1<<CS12)	;разрешение работы Т1, Fclk/256.
	LDI		R17, 7			;разрешение работы Т0, счёт с Ext Pin T0 (PB0)
	OUT		TCCR0, R17
	OUT		TCCR1B, R16
	OUT		TCNT0, ZH		;обнуляем счётчик
	SEI						;разрешаем выбранные прерывания
	RET
;*************************************************
SET_TIMR_CNT:
	CLR		XH
;	OUT		TCNT0, XH		;очищаем счётчик
	LDI		R19, 7			;разрешение работы Т0, счёт с Ext Pin T0 (PB0)
	LDI		ZL, LOW (CAPT_CNT)
	LDI		R16, (1<<TOIE0) | (1<<TICIE1)
	RJMP	SET_T
;*************************************************
SET_TIMR_PT:		;НАСТРОЙКА ТАЙМЕРОВ ДЛЯ ИЗМЕРЕНИЯ ПЕРИОДА И ДЛИТЕЛЬНОСТИ ИМПУЛЬСОВ
	LDI		ZL, LOW (CAPT_PTM)
	LDI		R16, (1<<TOIE1) | (1<<TICIE1)
SET_T:
	CLT
	CLR		XL
	LDI		R20, (1<<ACIC)
	OUT		ACSR, R20		;включаем компаратор
	LDI		R20, $ff
	OUT		TIFR, R20		;сброс флагов
	OUT		TCCR1B, R18		;устанавливаем захват по нужному фронту
	SEI						;разрешаем выбранные прерывания
	RET
;*************************************************
PAUSE_02s:
	RCALL	TCNT1_ZERO
	LDI		R16, $ff
	OUT		TIFR, R16		;сброс флага
	LDI		R16, (1<<OCIE1A) | (1<<TOIE0)
	OUT		TIMSK, R16		;разрешение OCE1A + OVER_T0
	LDI		R16, HIGH(6250)
	OUT		OCR1AH, R16
	LDI		R16, LOW(6250)
	OUT		OCR1AL, R16		;OCR1A = 31250  -  1с
	LDI		R16, (1<<CS12)	;разрешение работы Т1, Fclk/256
	OUT		TCCR1B, R16
	RCALL	WAIT_T
	RET
;*************************************************
CLR_R0_R9:
	CLR		R0				; очистка результата измерения
	CLR		R1
	CLR		R2
	CLR		R3
	CLR		R4
	CLR		R5
	CLR		R6
	CLR		R7
	CLR		R8
	CLR		R9
	RET
;*************************************************
INIT_PORTS:
	OUT		GENPORT, ZH		;заблокировать генераторы
	LDI		R20, ((1<<LX_ON) | (1<<CX_ON))
	OUT		GEN_DDR, R20
	LDI		R20, (1<<T_IN_POZ)
	OUT		FREQ_PORT, R20	;подтяжка
	LDI		R20, ~((1<<FREQ_IN) | (1<<T_IN_POZ) | (1<<T_IN_NEG))
	OUT		FREQ_DDR, R20
	LDI		R20, 0xff
	OUT		LCD_DDR, R20
	OUT		LCDPORT, ZH
	LDI		R20, ((1<<K_ZERO) | (1<<K_MODE))
	OUT		KBDPORT, R20	;подтягивающие резисторы
	LDI		R20, ~((1<<K_ZERO) | (1<<K_MODE))
	OUT		KBD_DDR, R20	;кнопки на входы
	RET
;*************************************************
SET_REGIM:
	SBIC	KBD_IN, K_MODE	; кнопка "РЕЖИМ" нажата? 
	RJMP	REGIM_Lx		; нет - измеряем Lx
	LDI		R16, (1<<CX_ON)	; да - Cx
	OUT		GENPORT, R16	; включить соотв. генератор
	LDI		R16, 'C'
	RJMP	PRINT_REGIM
REGIM_Lx:
	LDI		R16, (1<<LX_ON)	; Lx
	OUT		GENPORT, R16	; включить соотв. генератор
	LDI		R16, 'L'
PRINT_REGIM:	
#ifdef	LCD_20
	STS		T_IND+4, R16
#else
	STS		T_IND+2, R16
#endif
	RCALL	IND				; вывод текущей информации из буфера в строку результата
	RET
;*************************************************
INDEX_DEC_POINT:
	RCALL	CLEAR_RAM_IND	; очистить массив индикатора
	LDS		R20, MINUS
	TST		R20
	BRPL	PLUS
	LDI		R21, '-'		; зажигание '-' при минусовом результате
#ifdef	LCD_20
	STS		T_IND+7, R21
#else
	STS		T_IND+5, R21
#endif
PLUS:
	LDS		R24, DIAPAZON
	LDI		R21, '.'
DIAPAZON1:
	CPI		R24, 1
	BRNE	DIAPAZON2
#ifdef	LCD_20
	STS		T_IND+11, R21	; установить децимальную точку ххх.х
#else
	STS		T_IND+9, R21
#endif
	RJMP	DIAPAZON_OUT
DIAPAZON2:
	CPI		R24, 2
	BRNE	DIAPAZON3
#ifdef	LCD_20
	STS		T_IND+9, R21	; установить децимальную точку х.ххх
#else
	STS		T_IND+7, R21
#endif
	RJMP	DIAPAZON_OUT
DIAPAZON3:
	CPI		R24, 3
	BRNE	DIAPAZON4
#ifdef	LCD_20
	STS		T_IND+10, R21	; установить децимальную точку хх.хх
#else
	STS		T_IND+8, R21
#endif
	RJMP	DIAPAZON_OUT
DIAPAZON4:
	CPI		R24, 4
	BRNE	DIAPAZON5
#ifdef	LCD_20
	STS		T_IND+11, R21	; установить децимальную точку ххх.х
#else
	STS		T_IND+9, R21
#endif
	RJMP	DIAPAZON_OUT
DIAPAZON5:
	CPI	R24, 5
	BRNE	DIAPAZON6
#ifdef	LCD_20
	STS		T_IND+9, R21	; установить децимальную точку х.ххх
#else
	STS		T_IND+7, R21
#endif
	RJMP	DIAPAZON_OUT
DIAPAZON6:
	CPI		R24, 6
	BRNE	DIAPAZON7
#ifdef	LCD_20
	STS		T_IND+10, R21	; установить децимальную точку хх.хх
#else
	STS		T_IND+8, R21
#endif
	OR		R16, R21
	RJMP	DIAPAZON_OUT
DIAPAZON7:
	CPI		R24, 7
	BRNE	DIAPAZON_OUT
#ifdef	LCD_20
	STS		T_IND+11, R21	; установить децимальную точку ххх.х
#else
	STS		T_IND+9, R21
#endif
;*************************************************
DIAPAZON_OUT:
	SBIC	KBD_IN, K_MODE	; кнопка "РЕЖИМ" нажата? 
	RJMP	INDEX_L			; нет
INDEX_C:					; индекс Cx
	LDI		R21, ' '
	LDI		R23, 'F'		; указатель F
	CPI		R24, 1			; pF?
	BRNE	INDEX_C_nF		; нет не pF
INDEX_pF:
	LDI		R22, 'p'		; указатель p
	RJMP	INDEX_C_OUT
INDEX_C_nF:	
	CPI		R24, 5
	BRCC	INDEX_C_uF
	LDI		R22, 'n'		; указатель n
	RJMP	INDEX_C_OUT
INDEX_C_uF:
	LDI		R22, 'u'		; указатель u
INDEX_C_OUT:
	RJMP	INDEX_GND
;*************************************************
INDEX_L:				; индекс Lx
	LDI		R21, ' '
	LDI		R23, 'H'	; указатель H
	CPI		R24, 4		; uH?
	BREQ	INDEX_L_uH	; uH
	LDI		R22, 'm'	; указатель м
	RJMP	INDEX_GND
INDEX_L_uH:
	LDI		R22, 'u'	; указатель uH
INDEX_GND:
#ifdef	LCD_20
	STS		T_IND+13, R21
	STS		T_IND+14, R22
	STS		T_IND+15, R23
#else
	STS		T_IND+11, R21
	STS		T_IND+12, R22
	STS		T_IND+13, R23
#endif
	RET
;*************************************************
LD_R16_R19_Z:
	LD		R16, Z+
	LD		R17, Z+
	LD		R18, Z+
	LD		R19, Z
	RET
;*************************************************
NOX_NX:
	RCALL	LD_R16_R19_Z	; загрузить 65536*65536*No/no из RAM
	RCALL	RES_nox			; загрузить nx
	RCALL 	MULT			; результат (65536*65536*No/no)*nx
	RCALL	RES_Nx			; загрузить Nx
	RCALL	DIV				; результат [(65536*65536*No/no)*nx]/Nx
	RET
;*************************************************
MOV_R4_R9_to_R14_R19:
	MOV		R14, R4
	MOV		R15, R5
	MOV		R16, R6
	MOV		R17, R7
	MOV		R18, R8
	MOV		R19, R9
	RET
;***************************************************************************
MOV_R0_R5_to_R4_R9:
	MOV		R9, R5
	MOV		R8, R4
	MOV		R7, R3
	MOV		R6, R2
	MOV		R5, R1
	MOV		R4, R0
	CLR		R3
	CLR		R2
	CLR		R1
	CLR		R0
	RET
;*************************************************
RESULT_Lx:
	LDI		ZL, LOW(RAM_CONST_L)

	RCALL	NOX_NX

	MOV		R10, R0			; повторить как множимое для получения квадрата числа
	MOV		R11, R1			; nx*No*65536/no*Nx
	MOV		R12, R2
	MOV		R13, R3
	RCALL	MOV_R4_R9_to_R14_R19

	RCALL 	MULT			; результат {[(65536*65536*No/no)*nx]/Nx}^2

	LDI		R20, 1
	SUB		R1, R20
	SBC		R0, ZH			; результат {[(No/no)*(nx/Nx)]^2-1}*65536^4
	TST		R0
	BRPL	RES_Lx01

	LDI		R20, $80
	STS		MINUS, R20
	
	RCALL	CONV
RES_Lx01:
	RCALL	MOV_R0_R5_to_R4_R9
	RCALL	CLEAR_R10		; очистить массив R10...R19
	
	LDI		ZL, LOW(RAM_COEFF_Lo)

	RJMP	RES_GND			; результат Lo*10*{[(No/no)*(nx/Nx)]^2-1}
;*************************************************
RESULT_Cx:
	LDI		ZL, LOW(RAM_CONST_C)

	RCALL	NOX_NX

	LDI		R20, 1

	SUB		R5, R20
	SBC		R4, ZH
	SBC		R3, ZH
	SBC		R2, ZH
	SBC		R1, ZH
	SBC		R0, ZH		; [(65536*65536*No/no)*(nx/Nx)]-1 0000 0000
	TST		R0
	BRPL	RES_Cx01

	LDI		R20, $80
	STS		MINUS, R20

	RCALL	CONV	
RES_Cx01:
	RCALL	CLEAR_R10	;  очистить начальное значение результата

	LDI		ZL, LOW(RAM_COEFF_Co)
RES_GND:
	RCALL	LD_R16_R19_Z
	RCALL	MULT
	RCALL	MOV_R0_R5_to_R4_R9
; окончательный результат измерения генераторным методом
	RET
;***************************************************************************
ZER_O:
; начало рассчета и автозанесения коэффициентов
	RCALL	RABOTA
	RCALL	CLEAR_R0_R19	; очистить массив R0...R19
	
	LDS		R2, $86
	LDS		R3, $87
	LDS		R4, $88
	LDS		R5, $89			; загрузить N*65536^2
	
	LDS		R16, $76
	LDS		R17, $77
	LDS		R18, $78
	LDS		R19, $79		; nx

	RCALL	DIV

	SBIS	KBD_IN, K_MODE	; измерение конденсатора?
	RJMP	ZERO_C			; да
;***************************************************************************
ZERO_L:
; полученные значения N и n принимаются за No и no
;65536*65536*No/no
;***************************************************************************
	STS		RAM_CONST_L+0, R6
	STS		RAM_CONST_L+1, R7
	STS		RAM_CONST_L+2, R8
	STS		RAM_CONST_L+3, R9

	RCALL	SAVE			; осуществить запись полученных значений 0 в EEPROM

	SBIS	KBD_IN, K_ZERO	; кнопка >0< нажата?
	RJMP	NO_PEREGR		; да - цикл калибровки 0
; запуск калибровки по эталону
	LDI		ZL, LOW (CALIBR*2)
	RCALL	COMMENT			; вывод приглашния на калибровку по эталону
WAIT_L_CALIBR:
	SBIS	KBD_IN, K_ZERO	; кнопка >0< нажата?
	RJMP	CALC_L_COEF		; да - вычисление коэффициента
	SBIC	KBD_IN, K_MODE	; кнопка L/C нажата?
	RJMP	WAIT_L_CALIBR	; нет - анализ выбора
	RJMP	MAIN_COMMENT	; да - выход
;***************************************************************************
ZERO_C:
;65536*65536*No/no
	STS		RAM_CONST_C+0, R6
	STS		RAM_CONST_C+1, R7
	STS		RAM_CONST_C+2, R8
	STS		RAM_CONST_C+3, R9

	RCALL	SAVE			; осуществить запись полученных значений 0 в EEPROM

	SBIS	KBD_IN, K_ZERO	; кнопка >0< нажата?
	RJMP	NO_PEREGR		; да
; запуск калибровки по эталону
	LDI		ZL, LOW (CALIBR*2)
	RCALL	COMMENT			; вывод приглашния на калибровку по эталону
WAIT_C_CALIBR:
	SBIS	KBD_IN, K_ZERO	; кнопка >0< нажата?
	RJMP	CALC_C_COEF		; да - вычисление коэффициента
	SBIS	KBD_IN, K_MODE	; кнопка L/C отжата?
	RJMP	WAIT_C_CALIBR	; нет - анализ выбора
MAIN_COMMENT:
	LDI		ZL, LOW (INFO*2)
	RCALL	COMMENT
	RJMP	NO_PEREGR		; да - выход
;***************************************************************************
CALC_L_COEF:				;COEFF_Lo_NEW=COEFF_Lo*L_ETALON/Lx
	RCALL	WAIT_0_OFF		; ждём отпускания кнопки
	LDI		ZL, LOW(RAM_COEFF_Lo)
	RCALL	LD_R16_R19_Z
	LDI		ZL, LOW(RAM_L_ETALON)
	RCALL	MULT_ETALON
	RCALL	RESULT_Lx		; получаем результат измерения эталона
	RCALL	CALC_COEF		; вычисляем новое значение коэффициента
	LDI		ZL, LOW(RAM_COEFF_Lo)
	RJMP	SAVE_NEW_COEFF
;***************************************************************************
CALC_C_COEF:				;COEFF_Co_NEW=COEFF_Co*C_ETALON/Cx
	RCALL	WAIT_0_OFF
	LDI		ZL, LOW(RAM_COEFF_Co)
	RCALL	LD_R16_R19_Z	; заносим коэффициент для умножения
	LDI		ZL, LOW(RAM_C_ETALON)
	RCALL	MULT_ETALON
	RCALL	RESULT_Cx		; получаем результат измерения эталона
	RCALL	CALC_COEF
	LDI		ZL, LOW(RAM_COEFF_Co)
SAVE_NEW_COEFF:
	RCALL	NEW_COEFF		; перенести пересчитанный коэффициент в ОЗУ
	RCALL	SAVE			; сохранить в ЕЕПРОМ
	RJMP	MAIN_COMMENT
;***************************************************************************
MULT_ETALON:				; множим эталон на текущий коэффициент и запускаем измерение
	LD		R6, Z+			; заносим значение эталона для умножения
	LD		R7, Z+
	LD		R8, Z+
	LD		R9, Z
	RCALL	MULT			; множим
	RCALL	SAVE_COEF_x_ETAL; сохраняем результат
	RCALL	RABOTA			; начинаем измерение эталона
	RJMP	CL_R019
;***************************************************************************
WAIT_0_OFF:
	SBIS	KBD_IN, K_ZERO	; кнопка >0< нажата?
	RJMP	WAIT_0_OFF		; да - ждем отпускания
	RCALL	PAUSE_YL		; антидребезг
	SBIS	KBD_IN, K_ZERO	; кнопка >0< нажата?
	RJMP	WAIT_0_OFF		; да - ждем отпускания
CL_R019:
	RCALL	CLEAR_R0_R19	; очистить массив R19...R0
	RET
;***************************************************************************
SAVE_COEF_x_ETAL:
	LDI		ZL, LOW(RAM_COEF_x_ETAL)
	ST		Z+, R0
	ST		Z+, R1
	ST		Z+, R2
	ST		Z+, R3
	ST		Z+, R4
	ST		Z+, R5
NEW_COEFF:
	ST		Z+, R6
	ST		Z+, R7
	ST		Z+, R8
	ST		Z,  R9
	RET
;***************************************************************************
CALC_COEF:
	RCALL	MOV_R4_R9_to_R14_R19	;переносим результат в делитель
	LDI		ZL, LOW(RAM_COEF_x_ETAL);загружаем делимое
	LD		R0, Z+
	LD		R1, Z+
	LD		R2, Z+
	LD		R3, Z+
	LD		R4, Z+
	LD		R5, Z+
	LD		R6, Z+
	LD		R7, Z+
	LD		R8, Z+
	LD		R9, Z+
	RCALL	DIV						;получаем новый коэффициент
	RET
;***************************************************************************
TCNT1_ZERO:
	CLR		XH
	CLR		XL				; счетчик переполнений Т1=0 
	CLR		YH
	CLR		YL				; счетчик Nx=0
	CLR		ZH
	OUT		TCCR1B, ZH
	OUT		TCNT1H, ZH
	OUT		TCNT1L, ZH		; начинать с 0
	RET
;***************************************************************************
T1_OVF_CAPT_INIT:
	LDI		R16, (1<<TOIE1) | (1<<TICIE1)
	OUT		TIMSK, R16		; разрешение OVER_T1+CAPT
	LDI		R16, $ff
	OUT		TIFR, R16		; сброс флагов
	CLR		XH
	CLR		XL				; очистить старшее слово nx_begin
	RET
;***************************************************************************
WAIT_T:
	CLT
	SEI						;разрешаем выбранные прерывания
WAIT:
	BRTC	WAIT			;ждём конца измрения
;	CLI
	CLT
	RET
;***************************************************************************
RABOTA:
	RCALL	TCNT1_ZERO
	LDI		ZL, LOW (CAPT_LC)
	STS		MINUS, ZH		;убрать знак числа
;прерывание по переднему фронту INT1 (отпускание "РЕЖИМ" - переход на измерение Lx)
	LDI		A, ((1<<ISC11)|(1<<ISC10))
	SBIC	KBD_IN, K_MODE	; кнопка "РЕЖИМ" нажата? 
;прерывание по заднему фронту INT1 (нажатие "РЕЖИМ" - переход на измерение Сx)
	LDI		A, (1<<ISC11)	; нет
	OUT		MCUCR, A		; разрешить прерывание по изменению состояния кнопки "РЕЖИМ"
	LDI		A, (1<<INT1)
	OUT		GIMSK, A
	OUT		GIFR, A			; сброс флага вектора прерывания
	RCALL	T1_OVF_CAPT_INIT
	LDI		R16, (1<<CS10)	; разрешение работы Т1, Fclk/1
	OUT		TCCR1B, R16
	RCALL	WAIT_T			;ждём конца измрения
	RET
;*************************************************
; $70...$79-память nx
; $80...$89-память Nx
;*************************************************
CONV:
	COM		R9
	COM		R8
	COM		R7
	COM		R6
	COM		R5
	COM		R4
	COM		R3
	COM		R2
	COM		R1
	COM		R0

	LDI		R20, 1
	ADD		R9, R20
	ADC		R8, ZH
	ADC		R7, ZH
	ADC		R6, ZH
	ADC		R5, ZH
	ADC		R4, ZH
	ADC		R3, ZH
	ADC		R2, ZH
	ADC		R1, ZH
	ADC		R0, ZH

	RET
;*************************************************
RES_Nx:
	LDI		ZL, $80
	LDI		YL, $0A
	RJMP	GND_SET
;*************************************************
RES_nox:
	LDI		ZL, $70
	LDI		YL, $00
GND_SET:
	LDI		YH, $00
	LDI		R20, 10
SET_RAM:
	LD		R21, Z+
	ST		Y+, R21
	DEC		R20
	BRNE	SET_RAM
	RET
;************************************************
SAVE:
	PUSH	R0
	PUSH	A
	LDI		ZL, LOW(COEFF_Co)		;адрес в ЕЕПРОМ
	CLR		YH
	LDI		YL, LOW(RAM_COEFF_Co)	;адрес в ОЗУ
E_RAM:
	RCALL	EEREAD
	LD		A, Y
	CPSE	A, R0					;байт в ОЗУ и ЕЕПРОМ равны?
	RCALL	R0_A					;нет - записать новое значение в ЕЕПРОМ
	INC		YL
	INC		ZL
	CPI		ZL, LOW(E_END)			;последний байт прочитан?
	BRNE	E_RAM					;нет - прочитать следуюющий байт
#ifdef	LCD_20
	LDI		YL, LOW(T_IND + 6)
	LDI		ZL, LOW(D_LINE*2 + 6)
#else
	LDI		YL, LOW(T_IND + 4)
	LDI		ZL, LOW(D_LINE*2 + 4)
#endif
	LPM
	LD		A, Y
	CPSE	A, R0
	RCALL	R0_A
	POP		A
	POP		R0
	RET
;*************************************************
; Запись в EEPROM
; ZH, ZL -адрес
; R0- данные
;************************************************
R0_A:
	MOV		R0, A
EEWRITE:
	SBIC	EECR, EEWE
	RJMP	EEWRITE
	OUT     EEARL, ZL
	OUT     EEDR, R0
	SBI     EECR, EEMWE
	SBI     EECR, EEWE
EEWWAIT:
	SBIC    EECR, EEWE
	RJMP    EEWWAIT
	RET
;************************************************
; Чтение из EEPROM
; ZH, ZL-адрес
; R0-данные
;************************************************
EEREAD:
	OUT     EEARL, ZL
	SBI     EECR, EERE
	IN      R0, EEDR
	RET
;************************************************
;вход - R5..R9
REZ_2_LCD:	;вывод 9-значного числа
	CLR		XH
	LDI		XL, T_IND+6
	LDI		R21, 9		;счётчик
	LDI		R22, 0
REZ_2_LCD_LOOP:
	mov		R20, R5
	andi	r20, $0f	;выделяем выводимое число
	TST		R20			;=0?
	BRNE	PLACE_DIG	;нет - выводим	
	TST		R22			;да - гашение 0?
	BRNE	PLACE_DIG	;нет	
	LDI		R20, ' '	;да
	RJMP	PLACE_SP

PLACE_DIG:
	LDI		R22, 1		;0 не гасим
	ori		r20, '0'	;преобразуем в символ
PLACE_SP:
	ST		X+, R20		;заносим в буфер вывода
	
	LDI		R24, 4		;сдвигаем для вывода следующего числа
SD_1:
	LSL		R9
	ROL		R8
	ROL		R7
	ROL		R6
	ROL		R5
	DEC		R24
	BRNE	SD_1

	CPI		R21, 2		;предпоследний символ?
	BREQ	TST_TM		;да
NO_T:
	DEC		R21
	BRNE	REZ_2_LCD_LOOP
	RET

TST_TM:
	LDS		R22, MODE
	CPI		R22, 1		;измерение частоты?
	BREQ	NO_T		;да
	CPI		R22, 4		;счёт импульсов?
	BREQ	NO_T		;да
	LDI		R20, '.'	;измерение длительности/периода
	ST		X+, R20		;заносим в буфер вывода
	RJMP	NO_T
;************************************************
CODIR:
#ifdef	LCD_20
	LDI		XL, T_IND+8	;начало вывода в буфере индикатора
#else
	LDI		XL, T_IND+6
#endif
	CLR		R21
	LDI		R22, 10
	LDI		R25, 5
	LDI		R23, 1
	LDS		R24, DIAPAZON
	CPI		R24, 8
	BRCC	T8
	RCALL	SDVIG_4
	LDI		R25, 4
T8:
	RCALL	SDVIG_4
COD:	
	LDI		ZL, LOW (TTB_IND*2)
	RCALL	SDVIG_4
	TST		R23
	BRMI	COD_ZERO
	TST		R21
	BRNE	COD_ZERO
	TST		R6
	BREQ	COD_ZERO1
	INC		R21		; признак окончания гашения незначащих нулей
	RJMP	COD_ZERO
COD_ZERO1:
	MOV		R6, R22
COD_ZERO:
	ADD		ZL, R6	;получить смещение в таблице
	LPM
	ST		X+, R0
	
	LDI		R16, $2E
	LD		R17, X
	CPSE	R16, R17
	RJMP	NO_DEC_POINT
	ADIW	XL, 1		; перепрыгнуть через десятичную точку
NO_DEC_POINT:
	DEC		R23
	DEC		R25
	BRNE	COD
	
	RET
;************************************************
SDVIG_4:
	CLR		R6
	LDI		R24, 4
SD1:
	LSL		R9
	ROL		R8
	ROL		R7
	ROL		R6
	
	DEC		R24
	BRNE	SD1
	
	RET
;************************************************
CLR_R20_R29:
	CLR		R20
	CLR		R21
	CLR		R22
	CLR		R23
	CLR		R24
	CLR		R25
	CLR		R26
	CLR		R27
	CLR		R28
	CLR		R29			; начальное значение результата
	RET
;************************************************
ROL_R9_R0:
	LSL		R9
	ROL		R8
	ROL		R7
	ROL		R6
	ROL		R5
	ROL		R4
	ROL		R3
	ROL		R2
	ROL		R1
	ROL		R0
	RET
;************************************************
; Программа умножения 80 разрядного числа на 80 разрядное число
; Для получения корректного результата сумма разрядов множимого и множителя должна быть меньше 80 
; R0...R9-MNOGIMOE, R10...R19-MNOGITEL, R20...R29-RAB
; R0...R9-RESULT
; R20...R29-RESULT
; R0, R10, R20 - старший байт числа
; R9, R19, R29 - младший байт числа
; ZL(R30)-TEMP
;************************************************
MULT:
	CLT		; сбос флага ошибки,  если это не было сделано при входе в программу
	
	LDI		ZL, 80		; установить счетчик сдвигов
		
	RCALL	CLR_R20_R29
OBRAT:
	LSR		R10
	ROR		R11
	ROR		R12
	ROR		R13
	ROR		R14
	ROR		R15
	ROR		R16
	ROR		R17
	ROR		R18
	ROR		R19			; показать значение младшего разряда множителя в С, 
	BRCC	NO_SUMMIR	; С=0 пропустить суммирование
SUMMIR:
						; С=1 суммировать значение множимого с частичным результатом
	ADD		R29, R9
	ADC		R28, R8
	ADC		R27, R7
	ADC		R26, R6
	ADC		R25, R5
	ADC		R24, R4
	ADC		R23, R3
	ADC		R22, R2
	ADC		R21, R1
	ADC		R20, R0
	BRLT	GDIV_ERROR	; S-флаг установлен
	BRCS	GDIV_ERROR
NO_SUMMIR:
	RCALL	ROL_R9_R0	; множимое*2

	DEC		ZL
	BRNE	OBRAT

	MOV		R0, R20
	MOV		R1, R21
	MOV		R2, R22
	MOV		R3, R23
	MOV		R4, R24
	MOV		R5, R25
	MOV		R6, R26
	MOV		R7, R27
	MOV		R8, R28
	MOV		R9, R29
		
	RET
;**********************************************************************
; Программа деления 78 разрядного числа на 78 разрядное число
; R0...R9-ДЕЛИМОЕ,   R10...R19-ДЕЛИТЕЛЬ!!!!R0...R9-РЕЗУЛЬТАТ
; R20...R29-РЕЗУЛЬТАТ, ZL-TEMP,  ZH-ZERO
;**********************************************************************
DIV:
	CLT		; сбос флага ошибки,  если это небыло сделано при входе в программу
	CLR		ZH	; ZERO-регистр

	RCALL	CLR_R20_R29
;**********************************************************************
; проверка области допустимых значений делимого и делителя
	TST		R0
	BRMI	GDIV_ERROR	; делимое отрицательное,  ERROR
		
	CP		R19, R29
	CPC		R18, R28
	CPC		R17, R27
	CPC		R16, R26
	CPC		R15, R25
	CPC		R14, R24
	CPC		R13, R23
	CPC		R12, R22
	CPC		R11, R21
	CPC		R10, R20
	BREQ	GDIV_ERROR	; YES, DELITEL=0,  ERROR

	CP		R29, R9
	CPC		R28, R8
	CPC		R27, R7
	CPC		R26, R6
	CPC		R25, R5
	CPC		R24, R4
	CPC		R23, R3
	CPC		R22, R2
	CPC		R21, R1
	CPC		R20, R0
	BREQ	GDIV_OUT2	; YES, DELIMOE=0,  REZULTAT=0

	RCALL	CPC_R0_R9_R10_R19
	BRPL	DIV_GO1		; NO,  DELITEL<DELIMOGO
	RJMP	DIV_OUT1
DIV_GO1:
	BRNE	DIV_GO
	RJMP	DIV_EQU		; делитель=делимому,  результат=1

GDIV_ERROR:
	SET
GDIV_OUT2:
	RET
;***************************************************************************
CPC_R0_R9_R10_R19:
	CP		R9, R19
	CPC		R8, R18
	CPC		R7, R17
	CPC		R6, R16
	CPC		R5, R15
	CPC		R4, R14
	CPC		R3, R13
	CPC		R2, R12
	CPC		R1, R11
	CPC		R0, R10
	RET
CPC_R10_R19_R0_R9:
	CP		R19, R9
	CPC		R18, R8
	CPC		R17, R7
	CPC		R16, R6
	CPC		R15, R5
	CPC		R14, R4
	CPC		R13, R3
	CPC		R12, R2
	CPC		R11, R1
	CPC		R10, R0
	RET
;***************************************************************************
; выравнивание порядков делителя с делимым
;***************************************************************************
DIV_GO:
	CLR		ZL			; очистить счетчик сдвигов
DIV1:
	RCALL	CPC_R10_R19_R0_R9

	BRCC	DIV2		; YES, DELITEL>DELIMOGO
      		
	LSL		R19
	ROL		R18
	ROL		R17
	ROL		R16
	ROL		R15
	ROL		R14
	ROL		R13
	ROL		R12
	ROL		R11
	ROL		R10			; DELITEL*2
		
	INC		ZL
	CPI		ZL, 80
	BRNE	DIV1
;***************************************************************************
; порядкок делителя найден с превышением
;***************************************************************************
DIV2:
T_DIV0:
	CLT
	
	RCALL	ROL_R9_R0			; делимое или остаток*2
	RCALL	CPC_R10_R19_R0_R9	; делитель больше делимого ?

	BRCS	T_DIV20		; да, оставляем в 0 сооответствующий разряд результата
		
	SET			; нет,  взвести в 1 сооответствующий разряд результата
T_DIV20:
	ROL	R29
	ROL	R28
	ROL	R27
	ROL	R26
	ROL	R25
	ROL	R24
	ROL	R23
	ROL	R22
	ROL	R21
	ROL	R20
	BRTS	T_DIV40

	SUB	R9, R19
	SBC	R8, R18
	SBC	R7, R17
	SBC	R6, R16
	SBC	R5, R15
	SBC	R4, R14
	SBC	R3, R13
	SBC	R2, R12
	SBC	R1, R11
	SBC	R0, R10
T_DIV40:
	DEC		ZL
	BRNE	T_DIV0
;***************************************************************************
; проверка остатка для округления результата
DIV_OUT:
	RCALL	ROL_R9_R0	; остаток*2 или 0.ххх*2
	RCALL	CPC_R0_R9_R10_R19	; делитель больше остатка или остаток >0.5 ?
	BRCS	DIV_OUT1	; нет,  остаток <0.5
				; да остаток > 0.5,  добавить 1
;***************************************************************************
DIV_EQU:		
	SEC
		
	ADC	R29, ZH		
	ADC	R28, ZH		
	ADC	R27, ZH		
	ADC	R26, ZH		
	ADC	R25, ZH		
	ADC	R24, ZH		
	ADC	R23, ZH		
	ADC	R22, ZH		
	ADC	R21, ZH		
	ADC	R20, ZH		
DIV_OUT1:		
	MOV	R0, R20
	MOV	R1, R21
	MOV	R2, R22
	MOV	R3, R23
	MOV	R4, R24
	MOV	R5, R25
	MOV	R6, R26
	MOV	R7, R27
	MOV	R8, R28
	MOV	R9, R29

	CLT
	RET
;**********************************************************************
; Переделанная под себя программа преобразования от UMUP
; http://electronix.ru/forum/index.php?s=&showtopic=10934&view=findpost&p=324208
;**********************************************************************
BIN_BCD:
	CLR	R25		; BCD OUT 1'000'000'000, 100'000'000
	CLR	R26		; BCD OUT 10'000'000, 1'000'000
	CLR	R27		; BCD OUT 100'000, 10'000
	CLR	R28		; BCD OUT 1'000, 100
	CLR	R29		; BCD OUT 10, 1

	LDI	R24, 32
bin32bcd10:
	subi r29, -0x33	;add 0x33
	sbrs r29,  3	;if carry to bit 3
	subi r29,  3	;subtract 3
	sbrs r29,  7	;if carry to bit 7
	subi r29,  0x30	;subtract 0x30

	subi r28, -0x33      ; ; /*add 0x33*/
	sbrs r28,  3         ; ; /*if carry to bit 3, */
	subi r28,  3         ; ; /*subtract 3*/
	sbrs r28,  7         ; ; /*if carry to bit 7, */
	subi r28,  0x30      ; ; /*subtract 0x30*/

	subi r27, -0x33       ;; /*add 0x33*/
	sbrs r27,  3          ;; /*if carry to bit 3, */
	subi r27,  3          ;; /*subtract 3*/
	sbrs r27,  7          ;; /*if carry to bit 7, */
	subi r27,  0x30       ;; /*subtract 0x30*/

	subi r26, -0x33       ;; /*add 0x33*/
	sbrs r26,  3          ;; /*if carry to bit 3, */
	subi r26,  3          ;; /*subtract 3*/
	sbrs r26,  7          ;; /*if carry to bit 7, */
	subi r26,  0x30       ;; /*subtract 0x30*/

	subi r25, -0x33       ;; /*add 0x33*/
	sbrs r25,  3          ;; /*if carry to bit 3, */
	subi r25,  3          ;; /*subtract 3*/
	sbrs r25,  7          ;; /*if carry to bit 7, */
	subi r25,  0x30       ;; /*subtract 0x30*/

	lsl r29
	rol r28
	rol r27
	rol r26		; /*shift out buffer*/
	rol r25
   
	sbrc R6,  7	;skip if msbit of input =0*/
	ori  R29,  1        ;set lsb of output*/

	lsl R9
	rol R8
	rol R7		;shift input*/
	rol R6
   
	dec R24		;;
	brne bin32bcd10	;repeat for all bits*/

	MOV	R5, R25
	MOV	R6, R26
	MOV	R7, R27
	MOV	R8, R28
	MOV	R9, R29

	RET
;*************************************************
PAUSE:		;~500mks
	LDI		YH, $04
	LDI		YL, $FF
	RJMP	DEL
PAUSE_YL:
	LDI		YH, $00
	LDI		YL, $00
DEL:
	SBIW	YL, 1
	BRNE	DEL
	RET
;*************************************************
CLEAR_R0_R19:
	LDI		R21, 20
	CLR		ZL
	RJMP	CLEAR0

CLEAR_R20:
	LDI		R21, ' '
	RJMP	CLEAR0

CLEAR_R10:
	LDI		ZL, $0A
	LDI		R21, 10
CLEAR0:
	CLR		R22
	ST		Z+, R22
	DEC		R21
	BRNE	CLEAR0
	RET
;*************************************************
BAND:
	LDI		R20, $01		; начальный диапазон канала C
	SBIS	KBD_IN, K_MODE	; измерение конденсатора?
	RJMP	BAND_GO			; да
	LDI		R20, $04		; начальный диапазон канала L, R
BAND_GO:
	STS		DIAPAZON, R20
POISK_BAND:
	RCALL	CLEAR_R10		; очистить массив R10...R19
	
	LDI		R18, $27		; старший байт
	LDI		R19, $10		; порог сравнения 10'000
	
	RCALL	CPC_R0_R9_R10_R19
	BRCS	BAND_OUT
	
	RCALL	CLEAR_R10	; очистить массив R10...R19
	LDI		R19, 10		; делитель 10
	RCALL	DIV

	LDS		R20, DIAPAZON	
	INC		R20
	STS		DIAPAZON, R20
	CPI		R20, 8
	BRCS	POISK_BAND
BAND_OUT:
	RET
;************************************************
CONST_ROM_RAM:	;пересылает константы образцовых элементов из флэш в ОЗУ
	CLR		XH
	LDI		XL, (RAM_C_ETALON)
	LDI		ZL, LOW (C_ETALON*2)
	LDI		R21, 8			;8 байт
MOVE_CONST:
	LPM
	ST		X+, R0
	INC		ZL
	DEC		R21
	BRNE	MOVE_CONST
	RET
;************************************************
COEFF_TO_EEPROM:
	CLR		XH
	LDI		XL, LOW(COEFF_Co)		;адрес в ЕЕПРОМ - приёмник
	LDI		YL, LOW(COEFF_Co_FL*2)	;источник
	LDI		R21, 17					;16 байт данных + индикатор записи
MOVE_COEFF:
	MOV		ZL, YL
	LPM
	MOV		ZL, XL
	RCALL	EEWRITE
	INC		XL
	INC		YL
	DEC		R21
	BRNE	MOVE_COEFF
	RET
;**************************************************
;**************     ИНДИКАТОР     *****************
;**************************************************
IND:
	CLR		XH
	CLR		YH
	LDI		XL, (T_IND)
	LDI		D, REZULT_LINE	; Начало строки результата в DDRAM
	RCALL	OUT_LCI			; установить позицию вывода символа
		
	LDI		R21, ((INFO)-(D_LINE))*2	;длинна строки вывода
IND_GO:
	LD		D, X+
	RCALL	OUT_LCD
	DEC		R21
	BRNE	IND_GO
	RET
;************************************************
OUT_LCD:
	SBI		LCDPORT, LCD_RS	; REGISTR DATA DR (RS=1)
	RJMP	OUT_LCI+1
;************************************************
OUT_LCI:
	CBI		LCDPORT, LCD_RS	; REGISTR COMAND IR (RS=0)
	RCALL	LOOP
	SBI		LCDPORT, LCD_EN	; SET ENABLE (E)
	RCALL	LOOP

	MOV		R0, D
	RCALL	OUT_4			; вывод старшей тетрады
		
	RCALL	LOOP
	CBI		LCDPORT, LCD_EN	; CLOSE ENABLE (E)
	RCALL	LOOP
	MOV		D, R0
	SWAP	D
OUT_LCI1:
	SBI		LCDPORT, LCD_EN	; SET ENABLE (E)
	RCALL	LOOP

	RCALL	OUT_4			; вывод младшей тетрады

	RCALL	LOOP
	CBI		LCDPORT, LCD_EN	; CLOSE ENABLE (E)

	RCALL	PAUSE
	CBI		LCDPORT, LCD_RS	; REGISTR COMAND IR (RS=0)
LOOP:
	RET
;************************************************
OUT_4:
	IN		A, LCDPORT
	ANDI	A, $0F
	ANDI	D, $F0
	OR		A, D
	OUT		LCDPORT, A
	RET
;************************************************
CLEAR_RAM_IND:
	LDI		R20, ' '
	CLR		XH
#ifdef	LCD_20
	LDI		XL, (T_IND+7)
#else
	LDI		XL, (T_IND+5)
#endif
PLACE_CHAR_IND:
	ST		X+, R20			;заносим символ
	CPI		XL, (T_IND+16)
	BRCS	PLACE_CHAR_IND
	RET
;***********************************************
INIT_IND:	;начинаем в 8-битном режиме
	RCALL	PAUSE_02s
	LDI		D, $30		;LCD_BUS8 - 8-битный режим
	RCALL	OUT_LCI1
	RCALL	PAUSE_YL
	RCALL	OUT_LCI1	;LCD_BUS8
	RCALL	PAUSE		;~500mks (8MHz)
	RCALL	OUT_LCI1	;LCD_BUS8
	RCALL	PAUSE
	LDI		D, $20		;LCD_BUS4
	RCALL	OUT_LCI1	;перейти в 4-битный режим
	RCALL	PAUSE
	RCALL	OUT_LCI		;подтверждение 4-битного режима в 4-битном
	RCALL	PAUSE
	LDI		D, $28		;LCD_FUN4
	RCALL	OUT_LCI
	RCALL	PAUSE
	LDI		D, $0C		;LCD_ON
	RCALL	OUT_LCI
	RCALL	PAUSE
	LDI		D, $01		;LCD_CLR
	RCALL	OUT_LCI
	RCALL	PAUSE_YL
	LDI		D, $06		;LCD_EMS
	RCALL	OUT_LCI
	RCALL	PAUSE

	LDS		R21, MODE	;читаем текущий режим
	CPI		R21, 0		;LC-metter?
	BREQ	LCM			;да

; вывод на индикатор начального текстта
FM:
	LDI		ZL, LOW(FREQ_INFO*2)	;адрес выводимой строки
	RCALL	COMMENT
	LDI		ZL, LOW(FREQ*2)			;адрес выводимой строки
	RJMP	DATA_L

LCM:
	LDI		ZL, LOW(INFO*2)			;адрес выводимой строки
	RCALL	COMMENT
	LDI		ZL, LOW(D_LINE*2)		;адрес выводимой строки
DATA_L:
	LDI		R21,((INFO)-(D_LINE))*2	;длинна строки вывода
	LDI		XL, (T_IND)				;адрес буфера вывода строки
SET_RAM_IND1:
	LPM
	ST		X+, R0
	ADIW	ZL, 1
	DEC		R21
	BRNE	SET_RAM_IND1
	RET
;***************************************************************************
COMMENT:	
	LDI		R21, ((CALIBR)-(INFO))*2	;длинна строки вывода
	LDI		D, COMENT_LINE	; Начало строки коментария в DDRAM индикатора
	RCALL	OUT_LCI
ASC2:
	LPM						;считываем символ из строки вывода
	MOV		D, R0
	RCALL	OUT_LCD
	ADIW	ZL, 1
	DEC		R21
	BRNE	ASC2
	RET

;      		END

; для справки
;		R10  R11  R12  R13  R14  R15  R16  R17  R18  R19
;.DB	$00, $00, $00, $00, $00, $00, $2E, $00, $00, $00	; xxxxx.xxx P4 децимальная точка
;.DB	$00, $00, $00, $00, $00, $2E, $00, $00, $00, $00	; xxxx.xxxx P5 децимальная точка
;.DB	$00, $00, $00, $00, $2E, $00, $00, $00, $00, $00	; xxx.xxxxx P6 децимальная точка

;.DB	$00, $00, $00, $00, $00, $00, $00, $00, $70, $46	; указатель pF
;.DB	$00, $00, $00, $00, $00, $00, $00, $00, $6E, $46	; указатель nF
;.DB	$00, $00, $00, $00, $00, $00, $00, $00, $75, $46	; указатель uF

;.DB	$00, $00, $00, $00, $00, $00, $00, $00, $75, $48	; указатель uH
;.DB	$00, $00, $00, $00, $00, $00, $00, $00, $6D, $48	; указатель mH

;.DB	$00, $00, $00, $00, $00, $00, $00, $00, $4F, $00	; указатель Ом
;.DB	$00, $00, $00, $00, $00, $00, $00, $BA, $4F, $BC	; указатель кОм
