;******************************************************************************
;                                                                             *
;    File Version:  1.02                                                      *
;                                                                             *
;    Author:        Tarasov A.V.                                              *
;                                                                             * 
;******************************************************************************
;    Files required:         P18F2520.INC                                     *
;******************************************************************************
;укажем версию и тип процессора
#DEFINE		VERS	0x0102		;версия программы
#DEFINE		TYPE_PIC	1	;1 => PIC18F2520	

;проверено на версии 4.42
;ЧАСТОТА кварца 32 000 000 Гц
;******************************************************************************
;RA0-AN/IN	вход линия IN8  => №1 X3
;RA1-AN/IN	вход линия IN9  => №3 X3
;RA2-AN/IN	вход линия IN10 => №5 X3
;RA3-AN/IN	вход линия IN11 => №7 X3
;RA4-x
;RA5-AN/IN	вход линия IN12 => №9 X3
;RB0-AN/IN	вход линия IN0  => №1 X2
;RB1-AN/IN	вход линия IN1  => №3 X2
;RB2-AN/IN	вход линия IN2  => №5 X2
;RB3-AN/IN	вход линия IN3  => №7 X2
;RB4-AN/IN	вход линия IN4  => №9 X2
;RB5-IN		вход линия IN5  => №11 X2
;RB6-IN		вход линия IN6  => №13 X2
;RB7-IN		вход линия IN7  => №15 X2
;RC0-IN		вход линия IN13 => №11 X3
;RC1-IN		вход линия IN14 => №13 X3
;RC2-IN		вход линия IN15 => №15 X3
;RC3-I2C		шина I2C
;RC4-I2C		шина I2C
;RC5-x
;RC6-x
;RC7-x  
;******************************************************************************
;Драйвер загружаемый в модули IO1-3/4.75/85 поверх основной прошивки Fractal
;драйвер инициализирует ресурсы в необходимые режимы,
;"сопрягает" ячейки памяти - виртуальные входы и выходы  с реальными ресурсами.
;Таким образом пользователь может работать непосредственно с ячейками RAM  не заботясь
;о том какие реальные порты  и биты в них надо дергать.
;о настройке режима линий аналоговые/цифровые, тоже можно не заботиться

;программно все функции:
;	- аналоговые входы,
;	- цифровые входы,
;	- программные счетчики, 
;	- счетчик на аппаратном таймере
;	- цифровой выход
;работают одновременно - хочешь используй , не хочешь все-равно есть :)

;В ячейках IN_xx дискретное состояние входов после устранения дребезга
;(после устранения дребезга с периодом дискретизации дискретных входов = PR_IN*1мс)

;В ячейках CNT_xx (по 16 бит)производится МЕДЛЕННЫЙ подсчет импульсов с соответствующего входа
;(после устранения дребезга с периодом дискретизации дискретных входов = PR_IN*1мс)

;В ячейках FR_x (по 16 бит)производится БЫСТРЫЙ счет импульсов со входа RC0
;с использованием TMR1 с периодом перезаписи = PER_TMR*1мс

;В ячейках ADC_xx (по 10/12 бит) сохраняется результат измерения напряжения на входах
;обновление 1000 раз/сек
; используется источник опорного напряжения подключенный Vcc равный 5.0В

;В ячейки OUT_xx можно занести данные которые будут передаваться на линии настроенные как выход

;В ячейках DIR_xx задается режим работы линии : "0"-выход "1"-вход

;Значения ячеек OUT_xx, DIR_xx, PER_TMR, PR_IN при старте копируются из EEPROM и могут быть изменены
;###############################################################################
	if	TYPE_PIC==1 
		LIST P=18F2520, F=INHX32	;directive to define processor and file format
		#include <P18F2520.INC>	
		#DEFINE	BEG_USER	0x2000
	endif
	if	TYPE_PIC==7 
		LIST P=18F2523, F=INHX32	;directive to define processor and file format
		#include <P18F2523.INC>	
		#DEFINE	BEG_USER	0x2000
	endif
;###############################################################################
;РАСПРЕДЕЛЕНИЕ ПЕРЕМЕННЫХ В RAM
	CBLOCK	0x000
	IN_X2	;ADR RAM=0x00 ;регистр состояния цифровых входов X2 (RB0-7)
		;Bit 0 =>	IN0 => RB0 => №1 X2
		;Bit 1 =>	IN1 => RB1 => №3 X2
		;Bit 2 =>	IN2 => RB2 => №5 X2
		;Bit 3 =>	IN3 => RB3 => №7 X2
		;Bit 4 =>	IN4 => RB4 => №9 X2
		;Bit 5 =>	IN5 => RB5 => №11 X2
		;Bit 6 =>	IN6 => RB6 => №13 X2
		;Bit 7 =>	IN7 => RB7 => №15 X2
	IN_X3	;ADR RAM=0x01 ;регистр состояния цифровых входов X3 (RA0-3,5;RC0-2)
		;Bit 0 =>	IN8  => RA0 => №1 X3
		;Bit 1 =>	IN9  => RA1 => №3 X3
		;Bit 2 =>	IN10 => RA2 => №5 X3
		;Bit 3 =>	IN11 => RA3 => №7 X3
		;Bit 4 =>	IN12 => RA5 => №9 X3
		;Bit 5 =>	IN13 => RC0 => №11 X3
		;Bit 6 =>	IN14 => RC1 => №13 X3
		;Bit 7 =>	IN15 => RC2 => №15 X3

	OUT_X2	;ADR RAM=0x02 ;регистр состояния цифровых выходов X2 (RB0-7)
	OUT_X3	;ADR RAM=0x03 ;регистр состояния цифровых выходов X3 (RA0-3,5;RC0-2)
	DIR_X2		;ADR RAM=0x04 ;регистр направления линий X2 (RB0-7)
	DIR_X3		;ADR RAM=0x05 ;регистр направления линий X3 (RA0-3,5;RC0-2)

	FR_1L	;ADR RAM=0x06	;младший байт частоты входа(аппаратный счет TMR1) IN13=X3->RC0
	FR_1H	;ADR RAM=0x07	;старший байт частоты входа(аппаратный счет TMR1) IN13=X3->RC0

	PER_TMR	;ADR RAM=0x08 ;ячейка оперативного хранения времени накопления в аппаратных таймерах 
		;пользователь может ее налету менять для изменения времени накопления таймеров
		;после инициализации в нее заносится значение PER_TMR =100 (мс)
		;при этом максимальная входная частота = 655 360 Гц, большая частота переполнит счетчик
		;для работы с большими частотами надо выбирать меньшее время накопления
		;так, например, для PER_TMR =10 (мс) Fmax=6 553 600 Гц
	PER_IN	;ADR RAM=0x09	;ячейка оперативного хранения периода дискретизации логических входов
		;пользователь может ее налету менять для изменения верхней частотной границы 
		;ПРОГРАММНЫХ счетчиков
		;<=> или времени защиты от дребезга дискретных входов
		;после инициализации в нее заносится значение PER_IN =10
		;т.е. время защиты от дребезга = 10мс, верхний предел входной частоты = 50 Гц
	ENDC
	CBLOCK	0x010
	CNT_0L		;младший байт программного счетчика входа IN0 => RB0 => №1 X2
	CNT_0H		;старший байт 
	CNT_1L		;младший байт программного счетчика входа IN1 => RB1 => №3 X2
	CNT_1H		;старший байт 
	CNT_2L		;младший байт программного счетчика входа IN2 => RB2 => №5 X2
	CNT_2H		;старший байт 
	CNT_3L		;младший байт программного счетчика входа IN3 => RB3 => №7 X2
	CNT_3H		;старший байт 
	CNT_4L		;младший байт программного счетчика входа IN4 => RB4 => №9 X2
	CNT_4H		;старший байт 
	CNT_5L		;младший байт программного счетчика входа IN5 => RB5 => №11 X2
	CNT_5H		;старший байт 
	CNT_6L		;младший байт программного счетчика входа IN6 => RB6 => №13 X2
	CNT_6H		;старший байт 
	CNT_7L		;младший байт программного счетчика входа IN7 => RB7 => №15 X2
	CNT_7H		;старший байт 
	CNT_8L		;младший байт программного счетчика входа IN8 => RA0 => №1 X3
	CNT_8H		;старший байт 
	CNT_9L		;младший байт программного счетчика входа IN9 => RA1 => №3 X3
	CNT_9H		;старший байт 
	CNT_10L		;младший байт программного счетчика входа IN10 => RA2 => №5 X3
	CNT_10H		;старший байт
	CNT_11L		;младший байт программного счетчика входа IN11 => RA3 => №7 X3
	CNT_11H		;старший байт 
	CNT_12L		;младший байт программного счетчика входа IN12 => RA5 => №9 X3
	CNT_12H		;старший байт 
	CNT_13L		;младший байт программного счетчика входа IN13 => RC0 => №11 X3
	CNT_13H		;старший байт 
	CNT_14L		;младший байт программного счетчика входа IN14 => RC1 => №13 X3
	CNT_14H		;старший байт 
	CNT_15L		;младший байт программного счетчика входа IN15 => RC2 => №15 X3
	CNT_15H		;старший байт 
	ENDC
	CBLOCK	0x030
	ADC_0L		;младший байт измеренного напряжения IN0 => RB0 => №1 X2
	ADC_0H		;старшие два/четыре бита 
	ADC_1L		;младший байт измеренного напряжения IN1 => RB1 => №3 X2
	ADC_1H		;старший два/четыре бита 
	ADC_2L		;младший байт измеренного напряжения IN2 => RB2 => №5 X2
	ADC_2H		;старшие два/четыре бита  
	ADC_3L		;младший байт измеренного напряжения IN3 => RB3 => №7 X2
	ADC_3H		;старший два/четыре бита 
	ADC_4L		;младший байт измеренного напряжения IN4 => RB4 => №9 X2
	ADC_4H		;старшие два/четыре бита 
	ADC_5L		;младший байт измеренного напряжения IN8 => RA0 => №1 X3
	ADC_5H		;старший два/четыре бита 
	ADC_6L		;младший байт измеренного напряжения IN9 => RA1 => №3 X3
	ADC_6H		;старшие два/четыре бита 
	ADC_7L		;младший байт измеренного напряжения IN10 => RA2 => №5 X3
	ADC_7H		;старший два/четыре бита 
	ADC_8L		;младший байт измеренного напряжения IN11 => RA3 => №7 X3
	ADC_8H		;старшие два/четыре бита 
	ADC_9L		;младший байт измеренного напряжения IN12 => RA5 => №9 X3
	ADC_9H		;старший два/четыре бита 

;рабочие ячейки
	IN_OLD_X2	;прошлое значение дискретных входов (используется для устанения дребезга)
	IN_OLD_X3	;прошлое значение дискретных входов (используется для устанения дребезга)
	TMR_FR		;таймер для задания частоты дискретизации частотных входов
	TMR_IN		;таймер для задания частоты дискретизации дискретных входов
	N_ADC		;номер преобразуемого канала АЦП PIC
	TMP_1
	TMP_2
	COPYA
	COPYB
	COPYC
	ENDC
;******************************************************************************
;предустановки
adree_PRE	EQU	0x00	;начало области предустановок в EEPROM
	;!последовательность предустановок менять нельзя т.к. призапуске они считываются подряд!
pre_OUT_X2	EQU	0xFF	;состояние выходных линий X2
pre_OUT_X3	EQU	0xFF	;состояние выходных линий X3
pre_DIR_X2	EQU	0xFF	;направление линий("0"=> выход)
pre_DIR_X3	EQU	0xFF	;направление линий("0"=> выход)
pre_PER_TMR	EQU	D'100'	;период дискретизации для частотных входов = 100*1мс=100мс
pre_PER_IN	EQU	D'10'	;период дискретизации дискретных входов = 10*1мс=10мс
;линии ввода/вывода (те, которые не подряд)
#DEFINE		PIN_12	COPYA,5	;линия IN12
#DEFINE		PIN_13	COPYC,0	;линия IN13
#DEFINE		PIN_14	COPYC,1	;линия IN14
#DEFINE		PIN_15	COPYC,2	;линия IN15
	
;******************************************************************************
;###############################################################################
;******************************************************************************
;Таблица пользовательских векторов
;достаточно определить переменную VECT
#DEFINE	VECT	0x00E4
;0x0080	;REG_USER<7>=1 передать управление на адрес BEG_USER + 0x00 после инициализации контроллера
;0x0040	;REG_USER<6>=1 передать управление на адрес BEG_USER + 0x04 перед завершением цикла MAIN
;0x0020	;REG_USER<5>=1 передать управление на адрес BEG_USER + 0x08 после обработки IntHi 10 000 Гц
	;0x0010	;REG_USER<4>=1 передать управление на адрес BEG_USER + 0x0C после обработки IntLo
	;0x0008	;REG_USER<3>=1 передать управление на адрес BEG_USER + 0x10 для дальнейшей обработки команд MODBUS
;0x0004	;REG_USER<2>=1 передать управление на адрес BEG_USER + 0x14 после обработки IntHi 1000 Гц
	;0x0002	;REG_USER<1>=1 передать управление на адрес BEG_USER + 0x18 после обработки IntHi 100 Гц
	;0x0001	;REG_USER<0>=1 передать управление на адрес BEG_USER + 0x1C выполнить один раз  
	;0x8000	;REG_USER2<7>=1 передать управление на адрес BEG_USER + 0x20 до обработки HiInt
	;0x4000	;REG_USER2<6>=1 передать управление на адрес BEG_USER + 0x24 до обработки LoInt
	;0x2000	;REG_USER2<5>=1 передать управление на адрес BEG_USER + 0x28 до обработки I2C_slave_RD
	;0x1000	;REG_USER2<4>=1 передать управление на адрес BEG_USER + 0x2C до обработки I2C_slave_WR
	;0x0100	;REG_USER2<0>=1 заблокировать возможность сброса векторов и т.д. после 10 сбросов в первую минуту

			ORG	BEG_USER + 0x00	;точка входа после инициализации (REG_USER<7>=1)
			if	low VECT & B'10000000'
			goto 	Init
			else
				return
			endif
			ORG	BEG_USER + 0x04	;точка входа Main (REG_USER<6>=1)
			if	low VECT & B'01000000'
			goto 	Main
			else
				return
			endif
			ORG	BEG_USER + 0x08	;точка входа 10 000гц или после Hi_Int (REG_USER<5>=1)
			if	low VECT & B'00100000'
			goto 	HiInt
			else
				return
			endif
			ORG	BEG_USER + 0x0C	;точка входа после Lo_Int (REG_USER<4>=1)
			if	low VECT & B'00010000'
			goto 	LoInt
			else
				return
			endif
			ORG	BEG_USER + 0x10	;точка входа после Modbus (REG_USER<3>=1)
			if	low VECT & B'00001000'
			goto 	Modbus
			else
				return
			endif
			ORG	BEG_USER + 0x14	;точка входа 1 000гц (REG_USER<2>=1)
			if	low VECT & B'00000100'
			goto 	T1000Hz
			else
				return
			endif
			ORG	BEG_USER + 0x18	;точка входа 100гц (REG_USER<1>=1)
			if	low VECT & B'00000010'
			goto 	T100Hz
			else
				return
			endif
			ORG	BEG_USER + 0x1C	;точка входа выполнить один раз (REG_USER<0>=1)
			if	low VECT & B'00000001'
			goto 	One
			else
				return
			endif
			ORG	BEG_USER + 0x20	;точка входа перед обработкой Hi_Int (REG_USER2<7>=1)
			if	high VECT & B'10000000'
			goto 	PreHi
			else
				return
			endif
			ORG	BEG_USER + 0x24	;точка входа перед обработкой Lo_Int (REG_USER2<6>=1)
			if	high VECT & B'01000000'
			goto 	PreLo
			else
				return
			endif
			ORG	BEG_USER + 0x28	;точка входа перед обработкой I2C_salave_RD (REG_USER2<5>=1)
			if	high VECT & B'00100000'
			goto 	I2C_salave_RD
			else
				return
			endif
			ORG	BEG_USER + 0x2C	;точка входа перед обработкой I2C_salave_WR (REG_USER2<4>=1)
			if	high VECT & B'00010000'
			goto 	I2C_salave_WR
			else
				return
			endif
;***************************************************************************
	ORG	BEG_USER + 0x40	
;Инициализация
Init	;зададим конфигурацию контроллера
;PORTA
	setf   TRISA  	;все входы
;PORTB
	setf   TRISB  	;все входы
;PORTC
ошибка
	movlw	B'11111000'	;RC0-2 -входы
	andwf	TRISC,f

;ADC
	movlw	B'00001111'	;AN0-AN12 -> дискретные, опора от питания
	movwf   ADCON1
	movlw	B'10010010'	;правое выравнивание,пред-пауза=4*Tad,Tad=Fosc/32(общее время=16мкс) 
	movwf   ADCON2
	movlw	B'00000001'	;АЦП включен  
	movwf   ADCON0

;TMR1	;будет считать импульсы с №11 X3 ->RC0
	movlw	B'10000011'	;16бит,-,1:1,,генератор выкл,синхронизировать,внешний вход,включить
	movwf	T1CON
	clrf	TMR1H	;почистим таймер
	clrf	TMR1L

;почистим RAM c 0x000 по 0x04F	
	lfsr	FSR0,0x000
Init_1	clrf	POSTINC0
	btfss	FSR0L,6	
	bra	Init_1
	btfss	FSR0L,4	
	bra	Init_1

;константы из EEPROM
		bcf	EECON1,EEPGD
		bcf	EECON1,CFGS	
	movlw	adree_PRE	;укажем начало расположения предустановок
	movwf	EEADR
	bsf	EECON1,RD
	movff	EEDATA,OUT_X2
	incf	EEADR,f
	bsf	EECON1,RD
	movff	EEDATA,OUT_X3	
	incf	EEADR,f
	bsf	EECON1,RD
	movff	EEDATA,DIR_X2	
	incf	EEADR,f
	bsf	EECON1,RD
	movff	EEDATA,DIR_X3	
	incf	EEADR,f
	bsf	EECON1,RD
	movff	EEDATA,PER_TMR	
	incf	EEADR,f
	bsf	EECON1,RD
	movff	EEDATA,PER_IN	

	setf	IN_OLD_X2	;для исключения паразитного счета первого импульса
	setf	IN_OLD_X3
	setf	COPYA
	setf	COPYB
	setf	COPYC
	return
;***************************************************************************
;Время 
HiInt	;попадаем сюда каждые 100мкс
	movlw	B'00001111'	;вернем все линии в дискретный режим
	movwf	ADCON1
	;проверим -какой из каналов обрабатываем в этот раз
	movlw	0x00	;линия IN0 ?
	cpfseq	N_ADC
	bra	Hi_1	;нет
	movlw	B'00110011'	;слово для запуска преобразования канала IN0=AN12(№1 X2)
	lfsr	FSR0,ADC_9L	;установим указатель на прошлый результат
	bra	Hi_end

Hi_1	movlw	0x01	;линия IN1 ?
	cpfseq	N_ADC
	bra	Hi_2	;нет
	movlw	B'00101011'	;слово для запуска преобразования канала IN1=AN10(№3 X2)
	lfsr	FSR0,ADC_0L	;установим указатель на прошлый результат
	bra	Hi_end

Hi_2	movlw	0x02	;линия IN2 ?
	cpfseq	N_ADC
	bra	Hi_3	;нет
	movlw	B'00100011'	;слово для запуска преобразования канала IN2=AN8(№5 X2)
	lfsr	FSR0,ADC_1L	;установим указатель на прошлый результат
	bra	Hi_end

Hi_3	movlw	0x03	;линия IN3 ?
	cpfseq	N_ADC
	bra	Hi_4	;нет
	movlw	B'00100111'	;слово для запуска преобразования канала IN3=AN9(№7 X2)
	lfsr	FSR0,ADC_2L	;установим указатель на прошлый результат
	bra	Hi_end

Hi_4	movlw	0x04	;линия IN4 ?
	cpfseq	N_ADC
	bra	Hi_5	;нет
	movlw	B'00101111'	;слово для запуска преобразования канала IN4=AN11(№9 X2)
	lfsr	FSR0,ADC_3L	;установим указатель на прошлый результат
	bra	Hi_end

Hi_5	movlw	0x05	;линия IN8 ?
	cpfseq	N_ADC
	bra	Hi_6	;нет
	movlw	B'00000011'	;слово для запуска преобразования канала IN8=AN0(№1 X3)
	lfsr	FSR0,ADC_4L	;установим указатель на прошлый результат
	bra	Hi_end

Hi_6	movlw	0x06	;линия IN9 ?
	cpfseq	N_ADC
	bra	Hi_7	;нет
	movlw	B'00000111'	;слово для запуска преобразования канала IN9=AN1(№3 X3)
	lfsr	FSR0,ADC_5L	;установим указатель на прошлый результат
	bra	Hi_end

Hi_7	movlw	0x07	;линия IN10 ?
	cpfseq	N_ADC
	bra	Hi_8	;нет
	movlw	B'00001011'	;слово для запуска преобразования канала IN10=AN2(№5 X3)
	lfsr	FSR0,ADC_6L	;установим указатель на прошлый результат
	bra	Hi_end

Hi_8	movlw	0x08	;линия IN11 ?
	cpfseq	N_ADC
	bra	Hi_9	;нет
	movlw	B'00001111'	;слово для запуска преобразования канала IN11=AN3(№7 X3)
	lfsr	FSR0,ADC_7L	;установим указатель на прошлый результат
	bra	Hi_end

Hi_9	;последнюю проверку можно не делать, и так понятно что это IN12
	movlw	B'00010011'	;слово для запуска преобразования канала IN12=AN4(№7 X3)
	lfsr	FSR0,ADC_8L	;установим указатель на прошлый результат

Hi_end
	movff	ADRESL,POSTINC0	;запоминаем результат по заранее установленному указателю
	movff	ADRESH,INDF0
	movff	PORTA,COPYA	;сделаем копии цифровых входов для дальнейшего разбора
	movff	PORTB,COPYB
	movff	PORTC,COPYC
	clrf	ADCON1	;все входные линии аналоговые, опора от питания

	movwf   ADCON0		;запустим преобразование нужного канала
	
	incf	N_ADC,f		;следующий канал
	movlw	0x0A
	cpfslt	N_ADC
	clrf	N_ADC

	return

;***************************************************************************
;Время 
T1000Hz	;попадаем сюда каждую 1мс
;займемся временем все- равно ждем
	tstfsz	TMR_FR	;если таймер еще не обнулен - будем вычитать каждую 1мс
	decf	TMR_FR,f
	tstfsz	TMR_IN	;если таймер еще не обнулен - будем вычитать каждую 1мс
	decf	TMR_IN,f

	return
	;PS
	;если бы мы здесь воспользовались например вектором 10 мс
	;то время бы шло в 10 раз медленее
;***************************************************************************
Main	tstfsz	TMR_FR	;проверим пришло ли время обработать частотные входы
	bra	Mn_1

	movff	PER_TMR,TMR_FR	;да, перевзведем таймер
	;таймер работает в 16-битном режиме, поэтому нагло копируем его, соблюдая последовательность H<->L	
	bcf	INTCON,GIEH	;запретим ненадолго прерывания по интерфейсам,чтобы не считали ложные данные
		movff	TMR1L,FR_1L	;скопируем накопленное значение в RAM
		movff	TMR1H,FR_1H
	bsf	INTCON,GIEH	;вернем прерывание
		clrf	TMR1H		;очистим
		clrf	TMR1L

Mn_1	tstfsz	TMR_IN	;проверим пришло ли время обработать дискретные входы
	bra	Mn_2

	movff	PER_IN,TMR_IN	;да, перевзведем таймер

;разъем X3	;перенесем информацию с входных линий в ячейки RAM
	movff	COPYA,IN_X3	;перенесем мдадшие 4 бита RA
	movlw	B'00001111'	;обрежем лишнее
	andwf	IN_X3,f		
	btfsc	PIN_12		;соберем оставшиеся биты X3
	bsf	IN_X3,4
	btfsc	PIN_13		;соберем оставшиеся биты X3
	bsf	IN_X3,5
	btfsc	PIN_14		;соберем оставшиеся биты X3
	bsf	IN_X3,6
	btfsc	PIN_15		;соберем оставшиеся биты X3
	bsf	IN_X3,7
	;теперь посмотрим что изменилось
	movf	IN_X3,w
	xorwf	IN_OLD_X3,w
	andwf	IN_X3,w		;посмотрим какие из них были фронты
	;обработаем счетчики
	lfsr	FSR1,CNT_0L	;установим указатель на начало области счетчиков
	rcall	COUNT_INC
	movff	IN_X3,IN_OLD_X3	;занесем текущее значение входов для обработки на следующем шаге

;разъем X2
	movff	COPYB,IN_X2	;перенесем RB
	;теперь посмотрим что изменилось
	movf	IN_X2,w
	xorwf	IN_OLD_X2,w
	andwf	IN_X2,w		;посмотрим какие из них были фронты
	;обработаем счетчики
	rcall	COUNT_INC
	movff	IN_X2,IN_OLD_X2	;занесем текущее значение входов для обработки на следующем шаге
	
Mn_2	
;займемся выходами
	;разъем X2 - с ним все просто
	movff	OUT_X2,LATB
	movff	DIR_X2,TRISB
	;разъем X3 - здесь все дольше, действуем побитно, чтобы ничего лишнего не дрогнуло
	;делаем это постоянно в основном цикле т.к. пользователь может все динамически изменять
	;сначала состояние
	btfss	OUT_X3,0
	bra	$+6
	bsf	LATA,0	
	bra	$+4
	bcf	LATA,0	
	
	btfss	OUT_X3,1
	bra	$+6
	bsf	LATA,1	
	bra	$+4
	bcf	LATA,1	
	
	btfss	OUT_X3,2
	bra	$+6
	bsf	LATA,2	
	bra	$+4
	bcf	LATA,2	
	
	btfss	OUT_X3,3
	bra	$+6
	bsf	LATA,3	
	bra	$+4
	bcf	LATA,3	
	
	btfss	OUT_X3,4
	bra	$+6
	bsf	LATA,5	
	bra	$+4
	bcf	LATA,5	
	
	btfss	OUT_X3,5
	bra	$+6
	bsf	LATC,0	
	bra	$+4
	bcf	LATC,0	
	
	btfss	OUT_X3,6
	bra	$+6
	bsf	LATC,1	
	bra	$+4
	bcf	LATC,1	
	
	btfss	OUT_X3,7
	bra	$+6
	bsf	LATC,2	
	bra	$+4
	bcf	LATC,2	
	;теперь направление
	btfss	DIR_X3,0
	bra	$+6
	bsf	TRISA,0	
	bra	$+4
	bcf	TRISA,0	
	
	btfss	DIR_X3,1
	bra	$+6
	bsf	TRISA,1	
	bra	$+4
	bcf	TRISA,1	
	
	btfss	DIR_X3,2
	bra	$+6
	bsf	TRISA,2	
	bra	$+4
	bcf	TRISA,2	
	
	btfss	DIR_X3,3
	bra	$+6
	bsf	TRISA,3	
	bra	$+4
	bcf	TRISA,3	
	
	btfss	DIR_X3,4
	bra	$+6
	bsf	TRISA,5	
	bra	$+4
	bcf	TRISA,5	
	
	btfss	DIR_X3,5
	bra	$+6
	bsf	TRISC,0	
	bra	$+4
	bcf	TRISC,0	
	
	btfss	DIR_X3,6
	bra	$+6
	bsf	TRISC,1	
	bra	$+4
	bcf	TRISC,1	
	
	btfss	DIR_X3,7
	bra	$+6
	bsf	TRISC,2	
	bra	$+4
	bcf	TRISC,2	
	
	return
;***************************************************************************
;***************************************************************************
;подпрограмма обработки программных 8-ми 16-битных счетчиков
COUNT_INC	movwf	TMP_1	;сохраним информацию по фронтам
	movlw	B'00000001'	;загрузим маску
	movwf	TMP_2
	
C_2	movf	TMP_1,w
	andwf	TMP_2,w
	
	bz	C_1	;если фронта не было, то идем на следующий бит
  bcf	INTCON,GIEH	;для обеспечения целостности данных на время обработки запретим прерывания
	infsnz	POSTINC1,f	;здесь только-что был фронт, нарастим счетчик
	incf	INDF1,f		;перенос
  bsf	INTCON,GIEH
	decf	FSR1L,f		;вернем указатель
C_1	incf	FSR1L,f		;укажем на следующую регистровую пару
	incf	FSR1L,f
	bcf	STATUS,C	;сбросим на всякий перенос чтобы не мешался
	rlcf	TMP_2		;крутанем маску
	bnc	C_2	;проверим завершение
	return	
;***************************************************************************
;;*************************************************************************;
;Служебная область EEPROM:
;(0xF0)<= младший байт версии драйвера
;(0xF1)<= старший байт версии драйвера
;(0xFA)<= младший вектор пользователя (для данной программы => 0xA0)
;(0xFB)<= старший вектор пользователя ==>0x00
;(0xFC)<= младший байт скорости UART1 (для 115200: для PIC18F6520 =>0x10; для PIC18F6621 =>0x43);для PIC18F6527 =>0x44)
;(0xFD)<= старший байт скорости UART1 (для 115200  ==>0x00)
;(0xFE)<= адрес I2C
;(0xFF)<= адрес UART1
	ORG     0xF00000 + adree_PRE	;начало области предустановок
        DE	pre_OUT_X2, pre_OUT_X3
        DE	pre_DIR_X2, pre_DIR_X3
        DE	pre_PER_TMR, pre_PER_IN
	ORG     0xF000F0
        DE	low VERS, high VERS
	ORG     0xF000FA
	DE	low VECT, high VECT
	ORG     0xF000FE
	DE	0x10, 0x02	;сменим адрес I2C(сохранив адрес MODBUS)
;*************************************************************************;
;End of program
		END
