; Генератор мультифазный
; 5 AN2 T, 3 AN3 Duty, 7 GP0 Out1, 6 GP1 Out2, 2 GP5 (резерв под 3 фазу), 4 GP3/MCLR switch (резерв)
; Работа начинаются с лог1, оцифровываются делители 0-5В по AN2 - в зависим от рассчитываются длит периода,
; от периода - длит импульса (лог0) и паузы (лог1), и по AN3 скважность.
list	p=12f675
#include	p12f675.inc

#define Bank0 bcf STATUS,RP0
#define Bank1 bsf STATUS,RP0

 __CONFIG _CPD_OFF & _CP_OFF & _BODEN_OFF & _MCLRE_OFF & _PWRTE_ON & _WDT_OFF & _INTRC_OSC_NOCLKOUT

	cblock 0x20
 a,bH,bL,r3,r2,r1,w_sav,stat_sav,pclath_sav
 Stsflg		; bits (3 Out.lvl, 2 Out.act, 1 1st, 0 cycle)
 Vt		; оцифр значение скважности 3 нога AN3
 th,tl,_th,_tl	; длит импульса, подчерк от пред периода, загружать в таймер
 ph,pl,_ph,_pl	; длит паузы
	endc

; Tmax=FFFF 65,535мс * 2 предделитель	КОНСТАНТЫ==============
TminH	equ	0x8		; 7000RPM (учитывая prescaler)
TminL	equ	0x5C		; 7000RPM (учитывая prescaler)
TdfH	equ	0xF7		; Tdiff=Tmax-Tmin
TdfL	equ	0xA3
; Vmax	equ	0xFF		; Vref=5V
GPPU	EQU	0x7		; Бит подтяжек глобально
Out.lvl	equ	0x3		; текущий уровень на выходах
Out.act	equ	0x2		; активный выход
st1	equ	0x1		; признак начала работы
cycle	equ	0		; признак конца цикла
Out1	equ	0		; 7pin GP0
Out2	equ	0x1		; 6pin GP1

	org	0
	goto	Init
	org	0x4
	movwf   w_sav           ; save context
	swapf   STATUS,w
	movwf   stat_sav
	movf    PCLATH,w        ; only required if using more than first page
	movwf   pclath_sav
	clrf    PCLATH
;	stop TMR
;	if Stsflg:Out.lvl=0 ; call Rise ; start TMR(_p)
;	else call Fall ; call copy_pre ; start TMR1(_t)
	bcf	T1CON,TMR1ON	; — TMR1GE T1CKPS1 T1CKPS0 T1OSCEN T1SYNC TMR1CS TMR1ON
	bcf	PIR1,TMR1IF	; EEIE ADIE - - CMIE - - TMR1E
	btfss	Stsflg,Out.lvl
	goto	TMRp		; таймер паузы, высокого уровня
	call	Fall
	call	Copy_pre	; копирование выч знач для таймеров
	movfw	_th
	movwf	TMR1H		; импульс, низкого уровня
	movfw	_tl
	movwf	TMR1L
	call	start.tmr
	goto	exit.int
TMRp:	call	Rise
	movfw	_ph
	movwf	TMR1H
	movfw	_pl
	movwf	TMR1L
	call	start.tmr
exit.int: movf  pclath_sav,w    ; restore context
	movwf   PCLATH
	swapf   stat_sav,w
	movwf   STATUS
	swapf   w_sav,f
	swapf   w_sav,w
	retfie

Init:	Bank1
	movlw	b'011100'	; 5 GP2/AN2 T, 3 GP4/AN3 Duty, 7 GP0, 6 GP1, 2 GP5 (резерв под 3 фазу), 4 GP3/MCLR switch
	movwf	TRISIO		; 0x1C
	bsf	OPTION_REG,GPPU	; Выключение подтяжек глобально
	clrf	WPU		; Выключение подтяжек
	clrf	IOC		; Запрещение прерываний на цифр. входах
	movlw	b'1011100'	; Выбор входа/ножки/pin АЦП
	movwf	ANSEL		; 0x58 ; Делитель тактов 16Tosc и выбор AN2-3
	clrf	PIE1		; запрет прерываний от АЦП и проч EEIE ADIE - - CMIE - - TMR1E
	bsf	PIE1,TMR1IE
	Bank0
	movlw	0xff		; Все выходы в 1, импульсы инверсные
	movwf	GPIO
	movlw	b'11000000'	; GIE PEIE T0IE INTE GPIE T0IF INTF GPIF
	movwf	INTCON		; Вкл прерываний TMR1
	movlw	b'111'
	movwf	CMCON		; 0x7 ; Выкл компаратора
	movlw	b'1101'		; ADCON: ADFM VCFG — — CHS1 CHS0 GO/DONE ADON
	movwf	ADCON0		; Выравнивание результата влево, Vref=Vdd и вкл. АЦП (ADON=1)
	clrf	 Stsflg
	bsf	 Stsflg,Out.lvl
	bsf	 Stsflg,st1

ADC:	bsf	ADCON0,CHS0	; выбор AN3 Vt
	BSF	ADCON0,GO       ; Старт АЦП
	BTFSC	ADCON0,GO       ; Ждём конца
	GOTO	$-1
	movfw	ADRESH
	movwf	Vt

	bcf	ADCON0,CHS0	; выбор AN2 VT
	BSF	ADCON0,GO       ; Старт АЦП
	BTFSC	ADCON0,GO       ; Ждём конца
	GOTO	$-1
	movfw	ADRESH
;	movwf	VT

; T=(Tdiff*VT/Vmax)+Tmin  2byte*1byte/1byte(FF)
	movwf	a
	movlw	TdfH
	movwf	bH
	movlw	TdfL
	movwf	bL
	call	mul8x16
; операцию /Vmax исключаем, так как /FF=>>8
; берём старшие два байта r3:r2

; Подпрограмма сложения двухбайтных чисел Первое число bH:bL Второе r3:r2 Результат r3:r2
; результат не должен превышать максимального значения для для двухбайтного числа (65535)
	movlw	TminH
	movwf	bH
	movlw	TminL
;	movwf	bL
;	movf	bL,W		; прибавление числа из регистра bL к числу
	addwf	r2,F		; в регистре r2
	btfss	STATUS,C	; проверка переполнения регистра r2
	goto	s1		; нет переполнения: переход на метку s1
	incf	r3,F		; переполнение: инкремент r3
s1:	movf	bH,W		; прибавление числа из регистра bH к числу
	addwf	r3,F		; в регистре r3
	movfw	r3
	movwf	ph		; предварит значения, используются как TH:TL
	movfw	r2
	movwf	pl		; предварит значения, используются как TH:TL

; t=T*Vt/Vmax длительность импульса
	movfw	Vt
	movwf	a
	movfw	r3
	movwf	bH
	movfw	r2
	movwf	bL
	call	mul8x16
; операцию /Vmax исключаем, так как /FF=>>8
; берём старшие два байта r3:r2

; t=FFFF-t (r3:r2) для загрузки в таймер, тк он считает от нуля
; Подпрограмма вычитания двухбайтных чисел. Уменьшаемое в регистры th:tl
; вычитаемое  в регистр r3:r2. Результат вычитания в регистрах th:tl,
	movlw	0xff
	movwf	th
	movwf	tl
	movf	r2,W
	subwf	tl,F
	btfss	STATUS,C
	decf	th,F
	movf	r3,W		; r3:r2 сохран
	subwf	th,F		; th:tl готовы для загрузки в таймер

; p=T-t длительность паузы     2byte
; Подпрограмма вычитания двухбайтных чисел. Уменьшаемое в регистры ph:pl
; вычитаемое  в регистр r3:r2. Результат вычитания в регистрах ph:pl,
	movf	r2,W		; вычитаем число лежащее в регистре r2 из числа
	subwf	pl,F		; в регистре pl
	btfss	STATUS,C	; проверка на факт заема
	decf	ph,F		; возник факт заема: декремент регистра ph
	movf	r3,W		; нет заема: вычитаем r3 из ph
	subwf	ph,F		; ph:pl длительность паузы готовы

; p=FFFF-p (ph:pl) для загрузки в таймер, тк он считает от нуля
; Подпрограмма вычитания двухбайтных чисел. Уменьшаемое в регистры r3:r2
; вычитаемое  в ph:pl. Результат в ph:pl
	movlw	0xff
	movwf	r3
	movwf	r2
	movf	pl,W
	subwf	r2,F
	btfss	STATUS,C
	decf	r3,F
	movf	ph,W
	subwf	r3,F
	movfw	r3
	movwf	ph
	movfw	r2
	movwf	pl		; ph:pl готовы для загрузки в таймер

; if Stsflg:1st clr Stsflg:1st ; call Fall ; call copy_pre ; start TMR1(t) ; goto ADC
	btfss	Stsflg,st1	; для первоначального запуска
	goto	Wait
	bcf	Stsflg,st1
	call	Fall
	call	Copy_pre
	movfw	_th
	movwf	TMR1H
	movfw	_tl
	movwf	TMR1L
	call	start.tmr
	goto	ADC

; clr Stsflg:cycle, scan Stsflg:cycle, goto ADC
Wait:	bcf	Stsflg,cycle
	btfss	Stsflg,cycle	; цикл, пока прерывание не сбросит флаг
	goto	$-1		; измерение один раз за цикл по таймеру импульса, Fall ↓
	goto	ADC

; Копирование выч знач в этом цикле для запуска таймера в следующем
Copy_pre: movfw	th
	movwf	_th
	movfw	tl
	movwf	_tl
	movfw	ph
	movwf	_ph
	movfw	pl
	movwf	_pl
	return

; старт таймера, регистры уже
start.tmr: clrf	T1CON
	bsf	T1CON,T1CKPS0	; prescaler 1:2
	bsf	T1CON,TMR1ON	; — TMR1GE T1CKPS1 T1CKPS0 T1OSCEN T1SYNC TMR1CS TMR1ON
	return

;	set Out1=1 Out2=1
;	set Stsflg:Out.lvl=1
;	invert Stsflg:Out.act
Rise:	movlw	0xff		; Все выходы в 1
	movwf	GPIO
	bsf	Stsflg,Out.lvl	; отражение фо флаге
	movlw	0x4		; вес Out.act
	xorwf	Stsflg		; инверсия смена активного выхода для след цикла
	return

;	set Stsflg:Out.lvl=0
;	if Stsflg:Out.act=0 set Out1=0
;	else set Out2=0
;	set Stsflg:cycle
Fall:	bcf	Stsflg,Out.lvl	; вкл одного выхода, отличного от активного в пред цикле
	btfss	Stsflg,Out.act
	bcf	GPIO,Out1
	btfsc	Stsflg,Out.act
	bcf	GPIO,Out2
	bsf	Stsflg,cycle	; начало цикла периода и измерений
	return

;  a * bH:bL -> r3:r2:r1 (a is modified)
; 18 cycles, 84-124, 104 average
mul8x16: CLRF	r3
	CLRF	r2
	CLRF	r1
	BSF	r1,7
m1:	RRF	a,F
	SKPC
	GOTO	m2
	MOVFW	bL
	ADDWF	r2,F
	MOVFW	bH
	SKPNC
	INCFSZ	bH,W
	ADDWF	r3,F
m2:	RRF	r3,F
	RRF	r2,F
	RRF	r1,F
	SKPC
	GOTO	m1
	return

;	fill (goto Init),__CODE_END-$
	end
