;
;	Частотометр, измеритель ёмкости и индуктивности - FCL-meter
;	Автор- Буевский Александр, г. Минск, Беларусь
;	Версия 2x16.1 от 1.01.2004
;
	LIST      P=16F84
	include "P16F84a.inc"		; 4.000 MHz
	__CONFIG _CP_OFF & _WDT_OFF & _PWRTE_ON& _XT_OSC

MSB	EQU	07
LSB	EQU	00

	#define	_DX	Modes,0		; Divider 0- 1, 1- 64
	#define	_LX	Modes,1 	; 0- Lx mode
	#define	_FX	Modes,2		; 0- FCounter, 1- LC measure
	#define	_CX	Modes,3		; 0- Cx mode
	#define	_CAL	PORTA,0		; 0- disable, 1- enable relay
	#define	_BAT	PORTA,1		; 0- low bat
	#define	_RS	PORTA,2
	#define	_E	PORTA,3

	CBLOCK 0x00C

	Modes
	Flags
	Count1
	Count2
	Temp
	TSign
	Temp1
	Temp2
	Temp3
	Temp4
	Sign

	CP
	LP

	T0
	T1

	T2
	T3
	T4
	T5

	LX
	L0
	L1
	L2

	CX
	C0
	C1
	C2

	FX
	F0
	F1
	F2

	AX		; MSB
	A0
	A1
	A2		; LSB

	A3
	A4
	A5

	BX
	B0
	B1
	B2

	CSX
	CS0
	CS1
	CS2

	BCD0
	BCD1
	BCD2
	BCD3
	BCD4

	TimerHH
	TimerH
	TimerM
	TimerL

	FDX
	FD0
	FD1
	FD2

	ENDC

		ORG		0x2100	; Область EEPROM

	;	Данные			; Адрес	
	DE	0x03, 0xE8		; 0x00 =X1= 1000 по умолчанию
	DE	0x03, 0xE8		; 0x02 =X2= 1.000 по умолчанию
	DE	' ','M','H','z',0x00	; 0x04 
	DE	'C','o','n','s','t','a','n','t', ' ','X',0x00	; 0x09
	DE	'C','a','l','i','b','r','a','t','i','o','n',0x00; 0x14
	DE	' ','C','a','p','a','c','i',0x00		; 0x20
	DE	' ','I','n','d','u','c','t','a','n','c','e',' ',0x00; 0x28
	DE	' ','F','r','e','q','u','e','n','c','y',0x00	; 0x35
		ORG		0x0000

		clrf		Flags
		clrf		PORTB
		clrf		PORTA
		bsf		STATUS, RP0
		movlw		b'11110000'
		movwf		TRISB
		movlw		b'00000010'
		movwf		TRISA
		movlw		b'00110111'	; Предделитель 1:256, подключение резисторов
		movwf		OPTION_REG
		bcf		STATUS, RP0
		clrf		INTCON

		bsf		PORTA, 4

;	Инициализация LCD в 4-х битный режим		
InitLCD		call		Delay05sec
		movlw		3
		movwf		Temp
		movwf		PORTB
SetLoop		bsf		_E		; 3 раза
		call		Dly5
		bcf		_E
		decfsz		Temp
		goto		SetLoop
		movlw		2
		movwf		PORTB
		call		Send
		movlw		28		; 4-х битный, 2 строки, 5х7
		call		CmdLCD
		movlw		0C		; Включить дисплей
		call		CmdLCD
		movlw		6
		call		CmdLCD


SetConst	call		ClrDSP		; Очистить дисплей

		btfsc		PORTB, 7
		goto		Main

		movlw		0x09
		call		ReadWString

		call		GetSwitch

		movlw		1
		btfss		_DX		
		movlw		2
		call		NumLCD

		clrw
		btfss		_DX		
		movlw		0x02
		movwf		Temp
		call		EEPROM_To_B
		call		ShowX

ConstLoop	call		GetSwitch

		btfss		Modes, 4
		call		IncB
		btfss		Modes, 5
		call		DecB

		btfss		Flags, 1
		goto		ConstLoop
		movf		B1, W
		movwf		EEDATA
		movf		Temp, W
		call		Save_2_EE				
		incf		EEADR, F
		movf		B2, W
		movwf		EEDATA
		call		Save_2_EE+1	; Пропускаем запись адреса из W
		goto		SetConst


Main		call		ClrDSP		; Очистить дисплей
		call		GetSwitch	; Сканирование переключателей
		call		CursorHome
		btfss		_FX
		goto		FCounter	; Переход в режим частотометра
		btfsc		_LX		; Вход в режим калибровки
		btfss		_CX		; если оба переключателя
		goto		Mode		; отжаты (_LX==1 и _CX==1)
		call		ClrDSP
		goto		Calibration


Mode		movlw		'C'		; Для калибровки необходимо отжать "C"
		btfss		_LX
		movlw		'L'		; или "L"
		call		CharLCD
		call		TestBat		; Проверка источника питания
		goto		Main+1		; Пропустить очистку дисплея


;	Сканирование переключателей
GetSwitch	bsf		STATUS, RP0
		movlw		0xFF		; Все порты В на вход
		movwf		TRISB
		bcf		STATUS, RP0	
		call		Dly5
		movf		PORTB, W	; Чтение портов
		movwf		Modes		; в регистр-аккумулятор
		bsf		STATUS, RP0
		movlw		b'11110000'
		movwf		TRISB
		bcf		STATUS, RP0	

		bcf		Flags, 1
		movf		Modes, W	; Установка флага если положение
		xorwf		Flags, W	; переключателя _DX (F1/F2)
		andlw		1		; было изменёно.
		btfss		STATUS, Z	; Включает двойную калибровку
		bsf		Flags, 1

		bcf		Flags, 0	; Сохранение последнего
		btfsc		Modes, 0	; положения переключателя
		bsf		Flags, 0
		return

;	Определение и индикация разряда батареи
TestBat		movlw		0xC0		; Курсор на вторую строку
		call		CmdLCD
		movlw		' '		; Пробел, если норма
		btfss		PORTA,1
		movlw		0x21		; '!', если понижено
		goto		CharLCD		; Индикация и выход

;	Вход в режим частотометра
FCounter	bcf		Flags, 6	; Сброс флага двойной калибровки
		call		ClrDSP		; Очистка всего дисплея

		movlw		0x35		; Вывод названия режима
		call		ReadWString	; "Frequancy"

;	Главный цикл частотометра
FLoop		call		Measure		; Измерение частоты

		call		SecLine

		btfsc		_DX		; В режиме F2 необходимо умножение
		call		Mpy64
		call		BCD


		btfss		_DX
		goto		$+3
		movf		BCD4, W		; Сотни МГц
		call		NumLCD

		movlw		BCD3		; Десятки МГц
		call		DispBCD

		movlw		BCD3		; Единицы МГц
		call		DispBCD

		movlw		','
		call		CharLCD

		movlw		BCD2		; Сотни кГц
		call		DispBCD

		movlw		BCD2		; Десятки кГц
		call		DispBCD

		call		Digit1		; Единицы кГц

		call		DispDot
		call		Digit2		; Сотни Гц
		call		Digit3		; Десятки Гц
		btfss		_DX
		call		Digit4		; Единицы Гц

		movlw		0x04
		call		ReadWString

		call		TestBat		; в 16-м знакоместе

		call		GetSwitch
		btfss		_FX		; Если режим не изменён, то продолжить
		goto		FLoop
		call		ClrDSP		; иначе очистка  и выход
		btfss		Flags, 7	; режим ожидания калибровки
		goto		Main		; или главный цикл, если
		goto		Meter		; калибровка уже была

;	Пересчёт частоты с учётом внешнего делителя
Mpy64		movlw		6		; Множитель 2^6=64
		movwf		Count1
MLoop		bcf		STATUS, C
		rlf		A2, F		; Умножение на 2
		rlf		A1, F
		rlf		A0, F
		rlf		AX, F
		decfsz		Count1, F
		goto		MLoop
		return

;	Инкрементирование полублока А
IncB		incf		B2, F
		btfsc		STATUS, Z
		incf		B1, F
		goto		ShowX


;	Декрементирование полублока А
DecB		movf		B2, F
		btfsc		STATUS, Z
		decf		B1, F
		decf		B2, F

ShowX		movlw		BX
		call		Copy_To_A
		call		BCD
		movlw		0x8B
		call		SecLine
		call		Digit1
		btfss		_DX		
		call		DispDot
		call		Digit2
		call		Digit3
		call		Digit4
		call		DispSP
		call		Delay05sec
		return


;	Копирование "по назначению" блока (4 байта) данных
;	Temp1 - адрес получателя
;	Temp2 = адрес источника
CEQUA		movlw		CX		; C=A
Copy_From_A	movwf		Temp1		; Xw=A
		movlw		AX
		movwf		Temp2
		goto		Copy

BEQUA		movlw		AX		; B=A
Copy_To_B	movwf		Temp2		; B=Xw
		movlw		BX
		goto		Copy_B

AEQUF		movlw		FX		; A=F
Copy_To_A	movwf		Temp2		; A=Xw
		movlw		AX

Copy_B		movwf		Temp1
Copy		movlw		4		; Объём блока
		movwf		Count1
Copy_Loop	movf		Temp2, W
		movwf		FSR
		movf		INDF, W
		movwf		Temp3
		movf		Temp1, W
		movwf		FSR
		movf		Temp3, W
		movwf		INDF
		incf		Temp1, F
		incf		Temp2, F
		decfsz		Count1, F
		goto		Copy_Loop
		return

;	Чтение данных из EEPROM в полублок B
EEPROM_To_B	bcf		STATUS, RP0
		movwf		EEADR		; Адрес первого байта

		call		ClrB
	        call		ReadEEPROM
		movwf		B1
		incf		EEADR, F
	        call		ReadEEPROM
		movwf		B2
		return

;	Чтение строки из EEPROM пока не встретится 0x00  и вывод на дисплей
ReadWString	movwf		EEADR
ReadFString	movf		EEADR, W
		call		ReadEEPROM
		andlw		0xFF
		btfsc		STATUS, Z
		return
		call		CharLCD
		incf		EEADR, F
		goto		ReadFString


;	Чтение EEPROM
ReadEEPROM	bsf		STATUS, RP0
	        bsf		EECON1, RD	; Запрос на чтение EEPROM
        	bcf		STATUS, RP0
		movf		EEDATA, W
		return

;	Сохранение данных в EEPROM
Save_2_EE	movwf		EEADR
		bsf		STATUS, RP0
		bsf		EECON1, WREN
		movlw		0x55
		movwf		EECON2
		movlw		0xAA
		movwf		EECON2
		bsf		EECON1, WR
		bcf		EECON1, WREN
		btfsc		EECON1, WR
		goto		$-1

		bcf		STATUS, RP0
		return

;	Очистка регистров ОЗУ с 0x0F по 0x50
ClrRegs		movlw		0x0F
		movwf		FSR
		movlw		.65
		goto		ClrLoop-1

ClrB		movlw		BX		; Очистка блока В
		goto		ClrA+1

ClrA		movlw		AX		; Очистка блока А
		movwf		FSR
		movlw		4
		movwf		Count1

ClrLoop		clrf		INDF		; Цикл очистки
		incf		FSR, F
		decfsz		Count1, F
		goto		ClrLoop
		return


;	Вход в режим двойной калибровки (для больших индуктивностей)
DoubleCheck	btfsc		Flags, 5	; Выход, если индуктивность
		goto		Meter		; отсоединили от клемм

		bsf		Flags, 6	; Установка флага двойной калибровки

		call		Measure
		goto		Double

DoubleLX	movlw		CSX		; Сохраниение в CS суммарной ёмкости
		call		Copy_From_A	; катушки, С1 и монтажа

		call		AEQUF

CalcDouble	movlw		CSX
		call		Copy_To_B	; B=Cs


		call		LCalc		; Расчёт индуктивности [L1+Lx]

		movlw		LX
		call		Copy_To_B
		call		Sub		; Lx=[L1+Lx]-L1
		call		DispLX		; Вывод на дисплей


		movlw		CX		; Извлечение ёмкости С1 и монтажа
		call		Copy_To_B	; в блок B,
		movlw		CSX		; а суммарной C1+катушки+монтаж
		call		Copy_To_A	; в блок А.
		call		Sub		; Ёмкоскь катушки = А-В

		movlw		0xC9		; Курсор на 3-е знакоместо
		call		CMDLCD
		bsf		_LX		; Включить индикацию ёмкости
		goto		DispVal+1	; и вывести её

		goto		Meter

;	Просто расчёт по формуле F^2=1/4*Pi*L*C
LCalc		call		Mpy		; A=F^2*C
		call		BEQUA		; B=F^2*C

		movlw		0xB2		; A=1013211836423377,7
		movwf		AX		; (H'B2.66 60 B1)
		movlw		0x66
		movwf		A0
		movlw		0x60
		movwf		A1
		movlw		0xB1
		movwf		A2

		call		Div		; A=1.013212E15/(F1^2*Cs)=L
		movlw		0x02
		call		X_To_B		

		call		ClrB		; B=1000pf (H'8A.7A 00 00)
		movlw		0x8A
		movwf		BX
		movlw		0x7A
		movwf		B0

		call		Div
		return


X_To_B 		call		EEPROM_To_B	; Загрузка коэффициента X
		call		ASwapB
		call		Float
		call		Mpy
		return


ASwapB		movlw		T2
		call		Copy_From_A
		movlw		BX
		call		Copy_To_A
		movlw		T2
		call		Copy_To_B
		return


; Самокалибровка - определение C1 и L1 и сохраниение их значений
; C1=F2^2 * C2/(F1^2-F2^2)
; L1=1/(4*pi^2*[F1/5]^2*C1) = 1.013212E15/F1^2/C1

Calibration	call		ClrDSP

		movlw		0x14
		call		ReadWString

		call		Measure		; Подготовка предделителя к работе
		clrf		Temp
		movlw		0x13
		call		DelayXsec
		call		ClrRegs

		call		Measure

		movlw		FDX
		call		Copy_From_A	; F=F1^2

Double		movlw		FX
		call		Copy_From_A	; F=F1^2

		bsf		_CAL		; Подключение С2 к контуру

		call		Delay05sec
		call		TestBat

		movlw		0x09
		call		DelayXsec	; Установление стабильной генерации

		call		Measure

		movlw		CSX
		call		Copy_From_A	; CS=F2^2 временно

		call		BEQUA		; B=F2^2

		bcf		_CAL		; Отключение С2

		call		AEQUF		; A=F1^2
		call		Sub		; A=F1^2 - F2^2
		call		BEQUA		; B=F1^2 - F2^2


		movlw		CSX		; A=F2^2
		call		Copy_To_A

		call		Div		; A=F2^2/(F1^2 - F2^2)

		clrw				; Адрес в EEPROM 0x2100
		call		X_To_B		; Загрузка коэффициента X1 (C2)
						; A=F2^2*1000pf/(F1^2-F2^2)=C

		btfsc		Flags, 6	; Переход  при двойной калибровке
		goto		DoubleLX

		call		CEQUA		; C=A
		call		BEQUA		; B=C
		call		AEQUF		; A=F1^2
	
		call		LCalc

		movlw		LX		; L=A
		call		Copy_From_A

		call		ClrDSP
		movlw		'O'		; 'OK'
		call		CharLCD		; Калибровка завершена
		movlw		'K'
		call		CharLCD
		call		TestBat
		bsf		Flags, 7	; Флаг прохождения калибровки

;	Главный цикл измерения
Meter		call		GetSwitch
		btfss		_FX
		goto		FCounter	; Режим частотометра
		btfsc		_LX
		btfss		_CX
		goto		Label_2		; Режим LC-метра
		btfsc		Temp, 07	; Задержка между режимами
		goto		Calibration
		incf		Temp, F

		movlw		0xFF
		call		Delay

		goto		Meter

Label_2		call		CursorHome

		movlw		0x77
		movwf		Temp

		btfsc		Flags, 1	; Вход в режим двойной калибровки
		goto		DoubleCheck	; переключатель F1/F2 был переключен

		call		Measure		; A=F2^2

		btfsc		_LX		; Если в середине режима Cx,
		goto		Label_6		; то простой переход

		btfss		Flags, 5	; Если же выходим из режима
		goto		Label_7		; двойной калибровки,
		btfsc		Flags, 6	; то нужно 
		call		ClrDSP		; очистить дисплей
		bcf		Flags, 6	; и сбросить флаг


Label_7		btfsc		Flags, 6	; Если флаг установлен, то
		goto		CalcDouble	; продолжается режим двойной калибровки

Label_6		btfsc		Flags, 6	; Если из дв. калибр. сразу перешли 
		call		ClrDSP		; к измерению ёмкости, то надо один раз
		bcf		Flags, 6	; очистить дисплей и сбросить флаг

;	Общая часть расчёта для ёмкости и индуктивности
		call		BEQUA		; B=F2^2
		movlw		FDX		; Частота генератора с
		call		Copy_To_A	; контуром только из L1 и C1


		call		Div		; A=F1^2/F2^2

		call		ClrB		; Загрузка в В единицы
		movlw		0x81		; (вид с плавающей точкой)
		movwf		BX		; B=1

		call		Sub		; A=F1^2/F2^2-1
		movf		AX, W
		btfss		STATUS, Z	; Если результат положительный,
		goto		NoNeg		; то далее

		call		ClrA		; иначе обнулить А

NoNeg		btfsc		_LX		; Разветвление расчёта
		goto		Cx_Meas		; для ёмкости или индуктивности

		movlw		LX		; Извлечение индуктивности L1
		call		Copy_To_B	; из соостветствующего банка

		call		Mpy		; A=(F1^2/F2^2-1)*L1


DispLX		movlw		0x28
		call		ReadWString

		btfss		Flags, 5
		goto		CheckOK

		call		ClrA

CheckOK		goto		DispVal		; Вывод результата

Cx_meas		movlw		CX		; Дорасчёт для ёмкости
		call		Copy_To_B

		call		Mpy		; A=(F1^2/F2^2-1)*C1

		movlw		0x20
		call		ReadWString
		movlw		0x2E
		call		ReadWString

; Индикация результата
DispVal		call		TestBat
		clrf		TSign		; TSign = 0
NoOne		movf		AX, W		; Если A>=1
		sublw		0x80
		btfsc		STATUS, C	
		goto		IsOne		; А<1, Результат=А*10^TSign

		call		ClrB
		movlw		0x84		; A=A/10
		movwf		BX
		movlw		0x20
		movwf		B0

		call		Div
		incf		TSign, F	; TSign=TSign+1

		goto		NoOne

IsOne		movlw		0x8E		; В=10000
		movwf		BX		; Приведём А к целому числу
		movlw		0x1C
		movwf		B0
		movlw		0x40
		movwf		B1
		clrf		B2

		call		Mpy		; A=INT(A*10000)
		call		Int		; В формат с фикс. точкой
		call		BCD		; В ASCII  формат
		movf		TSign, W	; Множитель сохраним в AX
		movwf		AX		; AX = TSign
		movlw		'u'		; "u"
		movwf		LP		; Префикс для индуктивности
		movlw		'p'		; "p"
		movwf		CP		; Префикс для ёмкости

AX0		movf		AX, W		; Если AX=0
		btfss		STATUS, Z
		goto		AX1   		; иначе далее
		call		Disp0		; Вывод 0.12 для ёмкости
		call		DispDot
		call		Digit1
		call		Digit2

		btfsc		_LX
		goto		SP
		call		Digit3		; или 0.123 для индуктивности
		goto		Units

AX1		decfsz		AX, F		; Если А=1
		goto		AX2   		; иначе далее

AX1Disp		call		Digit1		; Вывод 1.23 для ёмкости
		call		DispDot
		call		Digit2        
		call		Digit3

		btfsc		_LX
		goto		SP
		call		Digit4		;  или 1.234 для индуктивности
		goto		Units

AX2		decfsz		AX, F		; Если А=2
		goto		AX3   

AX2Disp		call		Digit1		; Вывод 12.34
		call		Digit2
		call		DispDot
		call		Digit3
		call		Digit4
		goto		Units		; AND ENG UNITS

AX3		decfsz		AX, F		; Если А=3
		goto		AX4   

AX3Disp		call		Digit1		; Вывод 123.4
		call		Digit2
		call		Digit3
		call		DispDot
		call		Digit4
		goto		Units

AX4		movlw		'm'
		movwf		LP		; Префикс "m" - милли
		movlw		'n'
		movwf		CP		; или  "n" - нано

		decfsz		AX, F		; Если А=4
		goto		AX5

AX4Disp		call		Digit1		; Вывод 1.234
		call		DispDot
		call		Digit2
		call		Digit3
		call		Digit4
		goto		Units

AX5		movlw		0xE4        
		decfsz		AX, F		; А=5
		goto		AX6
		goto		AX2Disp		; 12.34

AX6		decfsz		AX, F		; A=6
		goto		AX7
		goto		AX3Disp		; 123.4

AX7		movlw		" "
		movwf		LP		; Нет префикса
		decfsz		AX, F		; А=7
		goto		AX2Disp		; 12.34 H
		goto		AX1Disp		; 1.234 H

SP		call		DispSP
Units		btfsc		_LX
		goto		DispCap
		movf		LP, W
		call		CharLCD		; Вывод префикса u, m или пусто
		movlw		'H'
		call		CharLCD

		call		DispSP

		btfsc		Flags, 6	; В режиме дв. калибровки 
		return				; выход здесь,

		goto		Meter		; а в обычном здесь

DispCap		movf		CP, W		;  Префикс для ёмкости
		call		CharLCD

		movlw		'F'
		call		CharLCD
		call		DispSP

		goto		Meter

;	Вывод разряда и подготовка к выводу следующего
DispBCD		movwf		FSR
NextNibble	swapf		INDF,F
		movf		INDF,W
		call		NumLCD
		return

Digit1		movlw		BCD1		; Разряд 1
		goto		DispBCD
Digit2		EQU		Digit1		; Разряд 2

Digit3		movlw		BCD0		; Разряд 3
		goto		DispBCD
Digit4		EQU		Digit3		; Разряд 4	


;	Подпрограммы пауз
DLY5		movlw		7		; 5 миллисекунд
		goto		Delay
DLY200		movlw		0x3F		; 200 микросекунд
		movwf		T1		; 9+(3T1+2)T2 min step 5
		movlw		1
		goto		Delay2
Delay		clrf		T1
Delay2		movwf		T0
DelayL		decfsz		T1, F
		goto		DelayL
		decfsz		T0, F
		goto		DelayL
		return

;	0,5 секунд
Delay05sec	movlw		0x02
DelayXsec	movwf		T2
TD1		movlw		0xFF
		call		Delay
		decfsz		T2, F
		goto		TD1
		return

;	 Перевод указателя  на второй символ второй строки
SecLine		movlw		0xC1


;	Загрузка команды
CmdLCD		movwf		Temp4
		bcf		_RS
		goto		SendLCD
;	Перекодировка в ASCII и вывод
NumLCD		andlw		0x0F		; маска
		iorlw		0x30		; ASCII
;	Вывод ASCII символа
CharLCD		movwf		Temp4
		bsf		_RS
SendLCD		swapf		Temp4, W
		andlw		0x0F
		movwf		PORTB
		bsf		_E
		bcf		_E
		movf		Temp4, W
		andlw		0x0F
		movwf		PORTB
Send		bsf		_E
		bcf		_E
		clrf		PORTB
		call		DLY200
		return

CursorHome	movlw		0x02		; Дисплей в исходное состояние
		goto		LongSend
ClrDSP		movlw		1		; Очистка дисплея
LongSend	call		CmdLCD
		goto		DLY5

DispDot		movlw		"."
		goto		CharLCD

Disp0		movlw		"0"
		goto		CharLCD

DispSP		movlw		" "
		goto		CharLCD


;	Измерение частоты со входа RA4 с периодом измерения в 0,2 и 1 секунду
Measure		clrf		TimerH
		clrf		TimerHH
		clrf		INTCON
		clrf		TMR0



		movlw		.41		; Пауза для 0,2 сек
		btfss		_FX
	        movlw	  	.206		; Пауза для 1 сек
	        movwf		Count2        

		bsf		STATUS, RP0	; Начало измерения
		movlw		b'00010010'
		movwf		TRISA
		bcf		STATUS, RP0

Pause2		movlw		.22
		movwf		Count1
Pause1		call		Provtmr		; Проверка счетчика на переполнение
		call		DLY200
		decfsz		Count1, F
	        goto		Pause1
		nop
		decfsz		Count2, F
		goto		Pause2

		movlw		.60		; 0.2 сек
		btfss		_FX
		movlw		.170		; 1 сек
		movwf		Count1

Pause3		call		Provtmr		; Проверка счетчика на переполнение
		goto		$+1
		call		Provtmr
		decfsz		Count1, F
		goto		Pause3

		bsf		STATUS, RP0
		movlw		b'00000010'	; RA4-вход
		movwf		TRISA        
		bcf		STATUS, RP0

		call		Provtmr		; Последняя проверка счетчика на переполнение

;	Анализ содержимого предварительного делителя
		movf		TMR0, W		; Пересылка данных
		movwf		TimerM		; счетчика в TimerM
		clrf		TimerL

Cont		bsf		STATUS, RP0
		bsf		OPTION_REG, T0SE	; Досчёт	
		nop
		bcf		OPTION_REG, T0SE
		bcf		STATUS, RP0
		decf		TimerL, F
		movf		TMR0, W
		xorwf		TimerM, W
		btfsc		STATUS, Z
		goto		Cont

		movlw		TimerHH		; Копирование измеренного 
		call		Copy_To_A	; значения в блок А

		bcf		Flags, 5	; Установка флага
		movlw		0xF0		; если измеренное значение
		andwf		TimerL, W	; менее 80 Гц, т.е. индуктивность
		iorwf		TimerM, W	; не подключена
		iorwf		TimerH,	W
		btfsc		STATUS,	Z
		bsf		Flags, 5

		btfss		_FX		; Выход здесь в 
		return				; режиме частотометра

		call		Float		; Плавающая точка
		call		BEQUA		; B=A
		call		Mpy		; A=A*A возведение в квадрат
		return

;	Проверка TMR0 на переполнение
Provtmr		btfss		INTCON, T0IF	; Проверка переполнения
	        goto		Paus		; нет, идем на паузу.
		movlw		0xFF		; Проверка не равен ли
		bcf		STATUS, Z	; TimerH=0xFF
		subwf		TimerH, W
		btfss		STATUS, Z
	       	goto		No
		incf		TimerHH, F	; если равен, то увеличиваем
		clrf		TimerH		; TimerHH на единицу и
		bcf		INTCON, T0IF	; обнуляем TimerH
		goto		Ret
No		incf		TimerH, F
		bcf		INTCON, T0IF
		nop
		goto		Ret
Paus		nop
		goto		$+1		; Просто выравнивание длительности
		goto		$+1		; выполнения подпрограммы 
		goto		$+1		; для различных вариантов
		goto		$+1		; хода событий
Ret		return


;	Перекодировка значения из двоичного в десятичный формат
BCD		movlw		0x20
		movwf		T1
		clrf		BCD0
		clrf		BCD1
		clrf		BCD2
		clrf		BCD3
		clrf		BCD4

BcdLoop		rlf		A2, F
		rlf		A1, F
		rlf		A0, F
		rlf		AX, F

		rlf		BCD0, F
		rlf		BCD1, F
		rlf		BCD2, F
		rlf		BCD3, F
		rlf		BCD4, F
		decfsz		T1, F
		goto		Adjust
		return

Adjust		movlw		.5
		movwf		count2

		movlw		BCD0
		movwf		FSR
		goto		ADloop+1

ADloop		incf		FSR, F
		call		Adjbcd
		decfsz		count2, F
		goto		ADloop
		goto		BcdLoop

Adjbcd		movlw		0x03
		addwf		INDF, W
		movwf		T0		
		btfsc		T0, 3		
		movwf		INDF
		movlw		0x30
		addwf		INDF, W
		movwf		T0
		btfsc		T0, 7
		movwf		INDF
		return

;	32-х битная библитека с плавающей точкой
EXPBIAS	equ	H'80'		; База представления числа

;	Конвертирование 24-х битного числа из блока А в формат с пл. точкой 32 бита в блок А
Float		movlw		0x18+EXPBIAS
		movwf		AX
		clrf		Sign

;	Нормализация
NRM32		clrf		T0
		movf		A0, W
		BTFSS		STATUS, Z
		goto		NORM32
		movf		A1, W
		movwf		A0
		movf		A2, W
		movwf		A1
		clrf		A2
		bsf		T0, 3

		movf		A0, W
		btfss		STATUS, Z
		goto		NORM32
		movf		A1, W
		movwf		A0
		clrf		A1
		bcf		T0, 3
		bsf		T0, 4
	
		movf		A0, W
		btfsc		STATUS, Z
		goto		RES032

NORM32		movf		T0, W
		subwf		AX, F
		bcf		STATUS, C

NORM32A		btfsc		A0, MSB
		goto		FIXSIGN32
		rlf		A2, F
		rlf		A1, F
		rlf		A0, F
		decf		AX, F
		goto		NORM32A


FIXSIGN32	btfss		SIGN, MSB
		bcf		A0, MSB
		retlw		0

;	Результат:	A  <--  INT( A )
Int		bsf		A0, MSB

		movlw		EXPBIAS
		subwf		AX, F
		btfss		AX, MSB
		btfsc		STATUS, Z
		goto		RES032
		movf		AX, W
		sublw		0x18
		movwf		AX

SHIFT32		bcf		STATUS, C
		rrf		A0, F
		rrf		A1, F
		rrf		A2, F
		decfsz  	AX, F
		goto		SHIFT32
		retlw		0
                
RES032		call		ClrA
						; clear AX for other routines
INT32OK		retlw		0


;	Результат:	A  <--  A * B
Mpy		movf		AX, W
		btfss		STATUS, Z
		movf		BX, W
		btfsc		STATUS, Z
		goto		RES032

M32BNE0		movf		A0, W
		xorwf		B0, W
		movwf		Sign

		movf		BX, W
		addwf		AX, F
		movlw		EXPBIAS
		btfss		STATUS, C
		goto		MTUN32
		addwf		AX, F
		goto		MOK32
MTUN32		addwf		AX, F
MOK32		bsf		A0, MSB
		bsf		B0, MSB
		bcf		STATUS, C
		clrf		A3
		clrf		A4
		clrf		A5
		movlw		0x18
		movwf		T0

MLOOP32		btfss		A2, LSB
		goto		MNOADD32

MADD32		movf		B2, W
		addwf		A5, F
		movf		B1, W
		btfsc		STATUS, C
		incfsz		B1, W
		addwf		A4, F

		movf		B0, W
		btfsc		STATUS, C
		incfsz		B0, W
		addwf		A3, F

MNOADD32	rrf		A3, F
		rrf		A4, F
		rrf		A5, F
		rrf		A0, F
		rrf		A1, F
		rrf		A2, F
		bcf		STATUS, C
		decfsz		T0, F
		goto		MLOOP32

		btfsc		A3, MSB
		goto		MUL32OK
		rlf		A0, F
		rlf		A5, F
		rlf		A4, F
		rlf		A3, F
		decf		AX, F

MUL32OK		btfss		Sign, MSB
		bcf		A3, MSB

		movf		A3, W
		movwf		A0
		movf		A4, W
		movwf		A1
		movf		A5, W
		movwf		A2
		retlw		0  


;	Результат:	A  <--  A / B
Div		movf		A0, W
		xorwf		B0, W
		movwf		Sign
		bsf		A0, MSB
		bsf		B0, MSB

TALIGN32	clrf		T0
		movf		A0, W
		movwf		A3
		movf		A1, W
		movwf		A4
		movf		A2, W
		movwf		A5

		movf		B2, W
		subwf		A5, F
		movf		B1, W
		btfss		STATUS, C
		incfsz		B1, W

TS1ALIGN32	subwf		A4, F
		movf		B0, W
		btfss		STATUS, C
		incfsz		B0, W

TS2ALIGN32	subwf		A3, F

		clrf		A3
		clrf		A4
		clrf		A5

		btfss		STATUS, C
		goto		DALIGN32OK

		bcf		STATUS, C
		rrf		A0, F
		rrf		A1, F
		rrf		A2, F
		rrf		A3, F
		movlw		0x01
		movwf		T0

DALIGN32OK	movf		BX, W
		subwf		AX, F
		btfss		STATUS, C
		goto		ALTB32
	
AGEB32		movlw		EXPBIAS
		addwf		T0, W
		addwf		AX, F
		goto		DARGOK32

ALTB32		movlw		EXPBIAS
		addwf		T0, W
		addwf		AX, F

DARGOK32	movlw		.24
		movwf		T1

DLOOP32		rlf		A5, F
		rlf		A4, F
		rlf		A3, F
		rlf		A2, F
		rlf		A1, F
		rlf		A0, F
		rlf		T0, F

		movf		B2, W
		subwf		A2, F
		movf		B1, W
		btfss		STATUS, C
		incfsz		B1, W
DS132		subwf		A1, F

		movf		B0, W
		btfss		STATUS, C
		incfsz		B0, W
DS232		subwf		A0, F

		rlf		B0, W
		iorwf		T0, F
		
		btfss		T0, LSB
		goto		DREST32

		bsf		A5, LSB
		goto		DOK32

DREST32		movf		B2, W
		addwf		A2, F
		movf		B1, W
		btfsc		STATUS, C
		incfsz		B1, W
DAREST32	addwf		A1, F

		movf		B0, W
		btfsc		STATUS, C
		incf		B0, W
		addwf		A0, F

		bcf		A5, LSB

DOK32		decfsz		T1, F
		goto		DLOOP32

DDIV32OK	btfss		SIGN, MSB
		bcf		A3, MSB

		movf		A3, W
		movwf		A0
		movf		A4, W
		movwf		A1
		movf		A5, W
		movwf		A2

		retlw		0


;	Результат:	A  <--  A - B
Sub		movf		BX, W
		btfss		STATUS, Z
		goto		SUB1
		movf		B0, W
		btfsc		STATUS, Z
		retlw		0
SUB1		movlw		0x80
		xorwf		B0, F


;	Result:	A  <--  A - B
Add		movf		A0, W
		xorwf		B0, W
		movwf		T0

		movf		AX, W
		subwf		BX, W
		btfss		STATUS, C
		goto		USEA32

		call		ASwapB

USEA32		movf		A0, W
		movwf		Sign
		bsf		A0, MSB
		bsf		B0, MSB

		movf		B0, W
		movwf		A3
		movf		B1, W
		movwf		A4
		movf		B2, W
		movwf		A5

		movf		BX, W
		subwf		AX, W
		movwf		BX
		btfsc		STATUS, Z
		goto		ALIGNED32

		movlw		8
		subwf		BX, W
		btfss		STATUS, C
		goto		ALIGNB32
		movwf		BX
		rlf		A5, F
		movf		A4, W
		movwf		A5
		movf		A3, W
		movwf		A4
		clrf		A3

		movlw		8
		subwf		BX, W
		btfss		STATUS, C
		goto		ALIGNB32
		movwf		BX
		rlf		A5, F
		movf		A4, W
		movwf		A5
		clrf		A4


ALIGNB32	movf		BX, W
		btfsc		STATUS, Z
		goto		ALIGNED32

ALOOPB32	bcf		STATUS, C
		rrf		A3, F
		rrf		A4, F
		rrf		A5, F
		decfsz		BX, F
		goto		ALOOPB32

ALIGNED32	btfss		T0, MSB
		goto		AOK32

		comf		A3, F
		comf		A4, F
		comf		A5, F
		incf		A5, F
		btfsc		STATUS, Z
		incf		A4, F
		btfsc		STATUS, Z
		incf		A3, F

AOK32		movf		A5, W
		addwf		A2, F
		movf		A4, W
		btfsc		STATUS, C
		incfsz		A4, W
		addwf		A1, F

		movf		A3, W
		btfsc		STATUS, C
		incfsz		A3, W
		addwf		A0, F

		btfsc		T0, MSB
		goto		ACOMP32
		btfss		STATUS, C
		goto		FIXSIGN32

		rrf		A0, F
		rrf		A1, F
		rrf		A2, F
		incf	        AX, F
		goto		FIXSIGN32

ACOMP32		btfsc		STATUS, C
		goto		NRM32

		comf		A0, F
		comf		A1, F
		comf		A2, F
		incf		A2, F
		btfsc		STATUS, Z
		incf		A1, F
		btfsc		STATUS, Z
		incf		A0, F

		movlw		0x80
		xorwf		Sign, F
		goto		NRM32
                END

