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

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

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

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

; Tmax=FFFF 65,535мс * 2 предделитель	КОНСТАНТЫ==============
TminH	equ	0x8		; минимальный период
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		; текущий уровень на выходах, 0 или 1
Out.act	equ	0x2		; активный выход, для поочерёдного переключения
st1	equ	0x1		; 1 стадия признак начала работы, для первого запуска таймера
cycle	equ	0		; признак начала/конца цикла периода и измерения
Out1	equ	0		; 7pin GP0
Out2	equ	0x1		; 6pin GP1
delayADC equ	0xA		; задержка для восстановления АЦП, кол-во * 2

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

ADC:	BSF	ADCON0,GO	; Старт АЦП AN3 Duty
	BTFSC	ADCON0,GO	; Ждём конца
	GOTO	$-1
	bcf	ADCON0,CHS0	; выбор AN2 VT для след цикла АЦП
	movfw	ADRESH
	movwf	Vt

	movlw	delayADC	; задержка для восстановления АЦП
	movwf	a
	decfsz	a,F		;декремент с условием регистра Sec
	goto	$-1		;регистр Sec не равен нулю: переход на метку p1

	BSF	ADCON0,GO;	Старт АЦП AN2 T
	BTFSC	ADCON0,GO;	Ждём конца
	GOTO	$-1
	bsf	ADCON0,CHS0	; выбор AN3 Vt для след цикла АЦП
	movfw	ADRESH

; T=(Tdiff*VT/Vmax)+Tmin  2byte*1byte/1byte(FF)
; Т - общий период, VT - оцифров значение периода
	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
	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
	movwf	bH		; для след операции
	movfw	r2
	movwf	pl		; предварит значения, используются как TH:TL
	movwf	bL		; для след операции

; t=T*Vt/Vmax длительность отриц импульса, Vt - оцифров значение скважности
	movfw	Vt
	movwf	a
	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: 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
