Материал из EPIRB Wiki
Перейти к: навигация, поиск

Контроллер маяка на PIC16F630

Контроллер маяка на PIC16F630
Контроллер маяка на PIC16F630 в корпусе
Переключатель для управления маяком
Схема контроллера

Версия прошивки 3.0, циклы 30с/30с; 60с/60с; 1м/4м


;-Передает в режиме лисы код Морзе (MO, MOE, MOI, MOS, MOH, MO5, MOT, T). Вариант кода задается переключателем.
;-Может работать непрерывно или циклом: 30с/30с; 60с/60с; 1м/4м.
;-Есть выход 1000 Гц для модуляции маяка на 144 МГц.
;-Автоотключение через 8 часов.
;-Потребление в выключенном состоянии 0.08 ма, во время работы, при передаче позывного, 0.5 ма.
;-Уход часов определяется кварцем.
;-Код с переключателя считывается один раз после сброса.
;-Режим отложенного старта (ОС), задержка 120 минут
;-Ускорение передачи позывного за 10 сек до конца цикла (только для 5 мин цикла)
;-Питание от 3 до 5 вольт 
;
; PIC16F630
; WDT off, intLC, MCLR on, BOR on, PWRTE on
;
	list	P=16F630
	radix	HEX

;====================================================================
; именование пользовательских регистров
;	
 	CBLOCK	0X20	; начальный адрес пользовательских регистров
        TMPW		; временный регистр для хранения W во время прерывания
	TMPS		; временный регистр для хранения STATUS                                                    
	SEC_CNT		; счетчик пар секунд
	MIN_CNT 	; счетчик минут (пятиминуток, автовыключение)
	FLAG		; регистр флагов:
			; FLAG,0 разрешает передачу позывного в свое время
			; FLAG,2 флаг задержки включения (1-можно работать)
                        ; FLAG,3 флаг взводится через 5 мин после начала работы
			; и отменяет задержку включения при сбросе
			; FLAG,4 флаг устанавливается за 10 сек до конца цикла


	DELAY		; счетчик пятиминуток, задержка включения
	TX_ALL_CNT	; счетчик пар секунд в цикле
	TX_OFF		; с какой секунды пауза
	TX_ALL		; сколько пар секунд в цикле

	SWITCH		; состояние переключателя
	CHAR_INDEX	; номер передаваемого символа

	CW_SPEED	; скорость передачи

; процедура SEND_TONE
	NBR_DIT		; NBR_DIT кол-во пропускаемых точек
	CTR_NBR		; счетчик пропускаемых точек
	TONE		; счетчик частоты
	SET_TONE	; установка тона передаваемого сигнала
; процедура SEND_SPACE
	NBR_SPACE	; колво пропускаемых точек
	CTR_DIT		; счетчик пропускаемых точек
; процедура SEND_ONE_CHAR
	CW_CHAR		; передаваемый символ
	ENDC


;
; Именование регистров микроконтроллера
;
CMCON		EQU	0X19	; регистр контроля компаратора
TMR0		EQU	0X01	; timer0
TMR1L		EQU	0X0E	; timer1 младший байт
TMR1H		EQU	0X0F	; timer1 старший байт     
T1CON		EQU	0X10	; timer1 control register
PCL		EQU	0X02	; программный счетчик
STATUS		EQU	0X03	; регистр status
FSR		EQU	0X04	; указатель адреса в памяти данных
PORTA		EQU	0X05	; порт A
PORTC		EQU	0X07	; порт C
PCLATH		EQU	0X0A	; верхние 5 бит программного счетчика
INTCON		EQU	0X0B	; регистр контроля прерываний
TRISA		EQU	0X85	; управляющий регистр порта A
TRISC		EQU	0X87	; управляющий регистр порта C 
OPTION_REG	EQU	0X81	; регистр option
EEADR		EQU	0X9B	; адресный регистр EEPROM
EECON1		EQU	0X9C	; содержит бит RD
EEDAT		EQU	0X9A	; прочитанные из EEPROM данные
PCON		EQU	0X8E	; регистр power control
PIE1		EQU	0X8C	; регистр контроля периферийных прерываний
PIR1		EQU	0X0C	; регистр флагов прерываний от 
				; периферийных модулей

;
; присвоение значений символьным константам
;
RP0		EQU	0X05	; бит-указатель страницы данных в STATUS
W		EQU	0X00	; file register designator = W
F		EQU	0X01	; file register designator = F 
Z		EQU	0X02	; бит нуля в STATUS 
C		EQU	0X00	; бит преноса в STATUS
RD		EQU	0X00	; инициализация чтения EEPROM
POR		EQU	0X01	; бит POR регистра PCON обнуляется, если был
				; сброс по включению питания
BOR		EQU	0X00	; сброс по снижению питания
TMR1IF		EQU	0X00	; бит переполнения TMR1 in register PIR1
TMR1ON		EQU	0X00	;
GIE		EQU	0X07	;
TMR1IE		EQU	0X00	; бит разрешения прерываний от TMR1
PON		EQU	0X00	; POWER ON IN FLAG
;
;=================================================================
; vector table
;
	ORG 0X000		; стартовый адрес	
	GOTO START		; 

;==================================================================
; TIMER1 INTERRUPT 
;
	ORG 0X004		; адрес	прерывания
	MOVWF TMPW		; сохраняем W
	SWAPF STATUS,W
	MOVWF TMPS		; сохраняем STATUS
	
	BTFSC PIR1,0		; прерывание от TMR1?
	GOTO T1_INT		; да
        NOP			; обработчик левого прерывания
	GOTO END_ISR		; 

T1_INT
	MOVF TX_ALL_CNT,W	; вычитание
	SUBWF TX_OFF,W		; TX_OFF-TX_ALL_CNT
	
	BCF FLAG,0		;
	SKPC			; пропустить, если результат >=0
	BSF FLAG,0		;


	MOVF TX_ALL_CNT,W	; ускоряемся за 10 сек до конца цикла
	SUBLW D'125'		; ставим флаг, по которому во время передачи
	SKPNZ			; меняем скорость
	BSF FLAG,4		; только при 5 мин цикле

				; использовать либо верхнее, либо нижнее

	;SUBLW D'250'		; а это костыль для ускорения за 10 сек
	;SKPNZ			; до конца любого цикла, даже если
	;BSF FLAG,4		; работаем непрерывно

	DECFSZ TX_ALL_CNT,F	; TX_ALL_CNT-1, пропустить, если 0
	GOTO POP_TX
	MOVF TX_ALL,W		; восстанавливаем
	MOVWF TX_ALL_CNT	;

	BCF FLAG,4		; в конце цикла сбросить флаг ускорения
POP_TX

       	DECFSZ SEC_CNT, F	; SEC_CNT-1
	GOTO POP		; 
	MOVLW D'150'		; 300 секунд = 5 мин
	MOVWF SEC_CNT
	
	BTFSS FLAG,2		; если задержка активирована, то
	BSF FLAG,3		; через 5 мин после запуска поднимаем флаг
				; отмены задержки включения

	DECF MIN_CNT,F		; MIN_CNT-1
	DECFSZ DELAY,F		; DELAY-1, пропустить след, если 0
	GOTO POP
	BSF FLAG,2		; устанавливаем флаг разрешения работы	

POP	
	BCF PIR1,0		; сброс флага переполнения

END_ISR
	SWAPF TMPS,W		; восстанавливаем регистры W and SATUS
	MOVWF STATUS		;
	SWAPF TMPW,F		;
	SWAPF TMPW,W		;
	RETFIE			; возврат из прерывания

;==================================================================
;  Начало основной программы 
;==================================================================
START	
	MOVLW B'10001110'       ;
	BSF STATUS, RP0		; bank 1
	MOVWF OPTION_REG	; инициализация регистра option
	BCF STATUS, RP0		; bank 0	
			
	CLRF PORTA		; очистка порта A 
	CLRF PORTC		; очистка порта C

	MOVLW B'00000111'	; 
	MOVWF CMCON		; запрещаем работу компаратора

	BSF STATUS, RP0		; bank 1
	MOVLW B'00000000'	; 
	MOVWF TRISA		; порт A - все выходы
	MOVLW B'11111111'	; 
	MOVWF TRISC		; порт C - все входы
	BCF STATUS, RP0		; bank 0	

	CLRF TMR0		; на всякий случай. Говорят, надо...
	CLRWDT			; сбрасываем WDT

	BSF PORTA,2		; на 11 ноге висят подтягивающие резисторы,
				; подключенные к переключателю
				; после считывания напряжение с переключателя
				; снимается для экономии энергии

;==================================================================
; инициализация TMR1
;
	CLRF T1CON		; очистить TIMER1 control register
	CLRF TMR1H		; очистить верхний байт TMR1
	CLRF TMR1L		; очистить нижний байт TMR1
	CLRF INTCON		; запретить прерывания
	BSF STATUS,RP0		; bank 1
	CLRF PIE1		; очистить рег контроля периферийных прерываний
	BCF STATUS, RP0		; bank 0	
	CLRF PIR1		; очистить рег флагов периферийных прерываний
	MOVLW B'00001110'	; инициализация TIMER1 control register
	MOVWF T1CON		; с этого момента генератор 32.768 включен


;==================================================================

	MOVLW D'150'		; инициализация счетчика пар секунд
	MOVWF SEC_CNT		; 150 пар = 300 сек = 5 мин
        DECF SEC_CNT,F		; имитируем прерывание

	;MOVLW D'2'		; сколько пятиминуток будем работать	
	MOVLW D'96'		; сколько пятиминуток будем работать
	MOVWF MIN_CNT		; 96х5=8 час

;	MOVLW D'2'		; сколько пятиминуток задержка включения
	MOVLW D'24'		; сколько пятиминуток задержка включения
	MOVWF DELAY		; 24х5=120 мин

	MOVLW D'178'		; тон звука, 178 ~ 1000 Гц
	MOVWF SET_TONE		; чем больше, тем ниже частота

	BSF FLAG,0		; поднимаем флаг

	BCF FLAG,4


;==================================================================
; если это включение питания, то выполняется задержка для
; гарантированного запуска генератора 32768 и его инициализация
; если другой сброс, то инициализация и задержка пропускаются
;
	BSF STATUS, RP0		; bank 1
	MOVF PCON,W		; PCON -> W
	BCF STATUS, RP0		; bank 0

	MOVWF TMPW		; W -> TMPW
	BTFSS TMPW,POR		; проверяем состояние POR, если 0, то был сброс
	GOTO DELAY_START	; по включению - задержка однозначно нужна
	BTFSC TMPW,BOR          ; а это был сброс по снижению напр питания
        GOTO SKIP_DELAY         ; или не был...
	
DELAY_START

	BCF FLAG,3		; при первом включении очистить FLAG,3

	; задержка 
	MOVLW D'255'		; скорость передачи 
	MOVWF CW_SPEED		; чем больше, тем медленней
	 
 	MOVLW 0X80	
	MOVWF CW_CHAR		; 
        CALL SEND_ONE_CHAR	; в качестве задержки предаем 7 точек

	BSF STATUS, RP0		; bank 1
	BSF PCON,POR		; устанавливаем POR=1
	BSF PCON,BOR		; устанавливаем BOR=1
	BCF STATUS, RP0		; bank 0

	SLEEP			; ожидаем запуск

SKIP_DELAY


;==================================================================
; читаем переключатель
;
        MOVF PORTC,W		; читаем порт C
	ANDLW B'00011100'	; маска 
	MOVWF SWITCH		; сохраняем состояние переключателя

        MOVF PORTC,W		; читаем порт C
	ANDLW B'00000011'	; маска двух младших бит

	BCF FLAG,2		; обнуляем флаг задержки
	BTFSC PORTC,5		; если перекл. on (на землю, 0) пропуск. след.
	BSF FLAG,2		; устанавливаем флаг, можно работать

	BCF PORTA,2		; отключаем подтягивающие резисторы

	ADDWF PCL,F		; таблица
	GOTO SW00
	GOTO SW01
	GOTO SW10
	GOTO SW11
SW00			; непрерывно
	MOVLW D'0'		; молчим последние 0 с
	MOVWF TX_OFF		;
	MOVLW D'30'		; цикл 60 сек
	GOTO END_SW
SW01			; цикл 30сек/30сек
	MOVLW D'15'		; молчим последние 30 с
	MOVWF TX_OFF		;
	MOVLW D'30'		; цикл 60 сек
	GOTO END_SW
SW10			; цикл 1 мин/1 мин
	MOVLW D'30'		; молчим последние 60 с
	MOVWF TX_OFF		;
	MOVLW D'60'		; цикл 120 сек
	GOTO END_SW
SW11			; цикл 1 мин/4 мин
	MOVLW D'120'		; молчим последние 4 m
	MOVWF TX_OFF		;
	MOVLW D'150'		; цикл 5 m

END_SW
	MOVWF TX_ALL		;
	MOVWF TX_ALL_CNT	; инициализация	
        DECF TX_ALL_CNT,F	; считаем, что 1 прерывание уже случилось

;==================================================================
; Окончание инициализации TIMER1
;

	MOVLW B'11000000'	; разрешить прерывания от периферийных модулей
	MOVWF INTCON

	BSF STATUS,RP0		; bank 1
	BSF PIE1,TMR1IE		; разрешить прерывания от TMR1
	BCF STATUS, RP0		; bank 0	
	BSF T1CON,TMR1ON        ; TMR1 ON


;==================================================================
; Если с момента запуска прошло 5 мин, то при сбросе задержку 
; включения игнорируем

	BTFSC FLAG,3		; FLAG,3 поднимается через 5 м после начала
				; работы
	BSF FLAG,2		; задержка включения не нужна

;==================================================================
; MAIN
; передача последовательности символов
; можно предавать любое количество, 0XFF означает конец последовательности,
; после чего формируется пауза и передача циклически повторяется
;
SEND_MSG
                                ; если автоотключение не нужно, то три 
				; нижеследующих строчки надо закомментировать
	MOVF MIN_CNT,F		; проверяем, не обнулился ли 
	SKPNZ			; счетчик пятиминуток
	GOTO POWER_OFF		; если да, то выключаемся

	BTFSS FLAG,2		; пропустить след, если задержка включения
				; кончилась (1-разрешение работы)
	GOTO FLASH		; мигнуть и sleep

        BTFSS FLAG,0		; если флаг сброшен, то идем спать
	GOTO TO_SLEEP
	
	MOVF SWITCH,W
	MOVWF CHAR_INDEX	; SWITCH -> CHAR_INDEX

GET_MSG
	MOVF CHAR_INDEX,W		
	BCF INTCON,GIE		; запрещаем прерывания
	BSF STATUS, RP0		; bank 1
	MOVWF EEADR		; значение CHAR_INDEX = адресу кода в EEPROM
	BSF EECON1,RD		; разрешаем чтение EEPROM
	MOVF EEDAT,W		; значение ячейки -> регистр W
	BCF STATUS, RP0		; bank 0	 
	BSF INTCON,GIE		; разрешаем прерывания
	;MOVLW 0x06
	MOVWF CW_CHAR		; W -> CW_CHAR	

	MOVLW 0XFF		; конец сообщения?
	SUBWF CW_CHAR,W		;
	SKPNZ
	GOTO END_MSG		; да, перейти к END_MSG

	MOVLW D'60'		; скорость передачи быстро
	BTFSS FLAG,4		; устанавливается за 10 с до конца цикла
	MOVLW D'160'		; скорость передачи медленно
	MOVWF CW_SPEED		; чем больше, тем медленней

	CALL SEND_CHAR		; передаем букву и паузу в 3 точки
                                ; или паузу 6 точек, если SPACE
	INCF CHAR_INDEX		; CHAR_INDEX+1	
	GOTO GET_MSG

END_MSG
	CALL WORD_SPACE         ; пауза 6 точек 
	GOTO SEND_MSG		;	

				; время работы закончилось
POWER_OFF			; отсюда выход только через RESET
	CLRF T1CON		; очистить TIMER1 control register, выключаем
				; генератор 32768
	;BCF T1CON,TMR1ON       ; TMR1 OFF
	CLRF INTCON		; запретить прерывания

				; после сброса считаем, что это сброс по питанию
	BSF STATUS, RP0		; bank 1
	BCF PCON,POR		; устанавливаем POR=0
	BCF PCON,BOR		; устанавливаем BOR=0
	BCF STATUS, RP0		; bank 0

TO_SLEEP			;
	CLRF PORTA
	SLEEP
	NOP
	GOTO SEND_MSG
;========================================================================
; индикатор включенной задержки
; мигаем порт A.1
FLASH
	MOVLW D'60'		; скорость передачи 
	MOVWF CW_SPEED		; чем больше, тем медленней
	BSF PORTA,1
	MOVLW 0X01		;
	MOVWF NBR_SPACE		; пауза в 1 точку
	CALL SEND_SPACE		;
	BCF PORTA,1
	GOTO TO_SLEEP
;========================================================================
; SEND_CHAR
; Подпрограмма получает код символа в регистре CW_CHAR, побитно перебирает 
; его, и, в зависимости от состояния бита, передает: тире, если бит = 1;
; точку, если бит = 0.
; Знак передается, пока в слове есть хоть одна единица. Последняя единица
; "съедается", она означает конец слова. 
;
SEND_CHAR
	MOVLW 0X00		; пауза?
	SUBWF CW_CHAR,W		;
	SKPNZ			; 
	GOTO WORD_SPACE

SEND_ONE_CHAR 
        BTFSS FLAG,0		; обрываем передачу, если флаг сброшен
	RETURN

	CLRC			; очистить бит переноса
	RRF CW_CHAR, F		; сдвиг вправо через перенос
				; 
	MOVF CW_CHAR, F         ; проверяем содержимое CW_CHAR, если все "0"
	SKPNZ                   ; то Z=1, выполняем RETURN, иначе пропускаем
	GOTO PAUSE2		; конец буквы
	SKPC			; проверить бит переноса, пропустить, если=1
	GOTO SEND_A_DIT		; перейти к SEND_A_DIT

SEND_A_DAH			; передаем тире 
	MOVLW 0X03		; 1 тире = 3 точки
	MOVWF NBR_DIT
	MOVLW 0X01		;
	MOVWF NBR_SPACE		; после тире - пауза в 1 точку
	BSF PORTA,0		; включаем PORT A.2
	CALL SEND_TONE		; генериуем звук, оно же - пауза
	BCF PORTA,0		; выключаем PORT A.2
	CALL SEND_SPACE
	GOTO SEND_ONE_CHAR

SEND_A_DIT 
	MOVLW 0X01		; передаем точку
	MOVWF NBR_DIT
	MOVWF NBR_SPACE		; после точки - пауза в 1 точку
	BSF PORTA,0		; включаем PORT A.2
	CALL SEND_TONE          ; генерируем звук, оно же - пауза
	BCF PORTA,0		; выключаем PORT A.2
	CALL SEND_SPACE
	GOTO SEND_ONE_CHAR

PAUSE2
	MOVLW D'2'		; пауза в 2 точки после буквы	
	MOVWF NBR_SPACE		; 
	CALL SEND_SPACE         ;
	RETURN

WORD_SPACE
	MOVLW D'6'		; пауза в 6 точек между словами	
	MOVWF NBR_SPACE		; 
	CALL SEND_SPACE         ;
	RETURN

;==================================================================
; SEND_TONE
; Подпрограмма осуществляет задержку и одновременно формирует сигнал
; звуковой частоты (порт A.1)
;

SEND_TONE
 
	MOVF NBR_DIT, W		; NBR_DIT кол-во пропускаемых точек 
	MOVWF CTR_NBR		; 

DIT_LENGTH 
	MOVF CW_SPEED, W	; CW_SPEED скорость передачи
	MOVWF CTR_DIT		;

START_CYCLE 
	BSF PORTA,1		; A.1=1 в начале цикла
	MOVF SET_TONE,W		; 
	MOVWF TONE		; заносим значение в счетчик цикла задержки

HIGH_HALF 
	DECFSZ TONE, F		; считаем до нуля
	GOTO HIGH_HALF
	BCF PORTA,1		; A.1=0 в конце цикла

	MOVF SET_TONE,W		;
	MOVWF TONE

LOW_HALF 
	DECFSZ TONE, F		; 
	GOTO LOW_HALF
	DECFSZ CTR_DIT, F	;
	GOTO START_CYCLE
	DECFSZ CTR_NBR, F
	GOTO DIT_LENGTH		; 
	RETURN			; 

;================================================================
; SEND_SPACE
; Делает тоже самое, что и SEND_TONE, только вместо команд управления
; портами стоит команда NOP
;

SEND_SPACE
 
	MOVF NBR_SPACE, W	; 
	MOVWF CTR_NBR

DIT_LENGTH_SP 
	MOVF CW_SPEED, W	; 
	MOVWF CTR_DIT

START_CYCLE_SP
	NOP
	MOVF SET_TONE,W
	MOVWF TONE		; 

HIGH_HALF_SP 
	DECFSZ TONE, F		; 
	GOTO HIGH_HALF_SP
	NOP
	MOVF SET_TONE,W
	MOVWF TONE

LOW_HALF_SP 
	DECFSZ TONE, F		; 
	GOTO LOW_HALF_SP
	DECFSZ CTR_DIT, F	;
	GOTO START_CYCLE_SP
	DECFSZ CTR_NBR, F
	GOTO DIT_LENGTH_SP	; 
	RETURN			; 

;==================================================================
;==================================================================
; Идентификатор
	ORG  0x2000	; стартовый адрес

        DATA 0x0000
        DATA 0x0000
        DATA 0x0000
        DATA 0x0000

;==================================================================
; Слово конфигурации
	ORG  0x2007	; стартовый адрес

	DATA 0x31E4

;==================================================================
; Запись в EEPROM при программировании
; Переключателем адресуется номер ячейки, кратный 4. Соответственно, маяк
; может передавать последовательно три символа Морзе, четвертым обязательно
; должен быть EOM
; В последнюю адресуемую ячейку можно записать большее количество символов

	ORG  0X2100	; стартовый адрес

	DATA 0x07	; M --    00000111
	DATA 0x0F	; O ---   00001111
        DATA 0xFF	; EOM     11111111
        DATA 0xFF	; EOM     11111111

	DATA 0x07	; M --    00000111
	DATA 0x0F	; O ---   00001111
        DATA 0x02	; E .     00000010  	
        DATA 0xFF	; EOM     11111111

	DATA 0x07	; M --    00000111
	DATA 0x0F	; O ---   00001111
	DATA 0x04	; I ..    00000100
        DATA 0xFF	; EOM     11111111

	DATA 0x07	; M --    00000111
	DATA 0x0F	; O ---   00001111
	DATA 0x08	; S ...   00001000
        DATA 0xFF	; EOM     11111111

	DATA 0x07	; M --    00000111
	DATA 0x0F	; O ---   00001111
	DATA 0x10	; H ....  00010000
        DATA 0xFF	; EOM     11111111

	DATA 0x07	; M --    00000111
	DATA 0x0F	; O ---   00001111
	DATA 0x20	; 5 ..... 00100000
        DATA 0xFF	; EOM     11111111

	DATA 0x07	; M --    00000111
	DATA 0x0F	; O ---   00001111
	DATA 0x03	; T -     00000011
        DATA 0xFF	; EOM     11111111

	DATA 0x03	; T -     00000011
        DATA 0xFF	; EOM     11111111
        DATA 0xFF	; EOM     11111111
        DATA 0xFF	; EOM     11111111

	END

Версия прошивки 3.1, циклы 30с/120с; 60с/60с; 1м/4м

;-Передает в режиме лисы код Морзе (MO, MOE, MOI, MOS, MOH, MO5, MOT, T). Вариант кода задается переключателем.
;-Может работать непрерывно или циклом: 30с/120с; 60с/60с; 1м/4м.
;-Есть выход 1000 Гц для модуляции маяка на 144 МГц.
;-Автоотключение через 8 часов.
;-Потребление в выключенном состоянии 0.08 ма, во время работы, при передаче позывного, 0.5 ма.
;-Уход часов определяется кварцем.
;-Код с переключателя считывается один раз после сброса.
;-Режим отложенного старта (ОС), задержка 60 минут
;-Ускорение передачи позывного за 10 сек до конца цикла (только для 5 мин цикла)
;-Питание от 3 до 5 вольт 
;
; PIC16F630
; WDT off, intLC, MCLR on, BOR on, PWRTE on
;
	list	P=16F630
	radix	HEX

;====================================================================
; именование пользовательских регистров
;	
 	CBLOCK	0X20	; начальный адрес пользовательских регистров
        TMPW		; временный регистр для хранения W во время прерывания
	TMPS		; временный регистр для хранения STATUS                                                    
	SEC_CNT		; счетчик пар секунд
	MIN_CNT 	; счетчик минут (пятиминуток, автовыключение)
	FLAG		; регистр флагов:
			; FLAG,0 разрешает передачу позывного в свое время
			; FLAG,2 флаг задержки включения (1-можно работать)
                        ; FLAG,3 флаг взводится через 5 мин после начала работы
			; и отменяет задержку включения при сбросе
			; FLAG,4 флаг устанавливается за 10 сек до конца цикла


	DELAY		; счетчик пятиминуток, задержка включения
	TX_ALL_CNT	; счетчик пар секунд в цикле
	TX_OFF		; с какой секунды пауза
	TX_ALL		; сколько пар секунд в цикле

	SWITCH		; состояние переключателя
	CHAR_INDEX	; номер передаваемого символа

	CW_SPEED	; скорость передачи

; процедура SEND_TONE
	NBR_DIT		; NBR_DIT кол-во пропускаемых точек
	CTR_NBR		; счетчик пропускаемых точек
	TONE		; счетчик частоты
	SET_TONE	; установка тона передаваемого сигнала
; процедура SEND_SPACE
	NBR_SPACE	; колво пропускаемых точек
	CTR_DIT		; счетчик пропускаемых точек
; процедура SEND_ONE_CHAR
	CW_CHAR		; передаваемый символ
	ENDC


;
; Именование регистров микроконтроллера
;
CMCON		EQU	0X19	; регистр контроля компаратора
TMR0		EQU	0X01	; timer0
TMR1L		EQU	0X0E	; timer1 младший байт
TMR1H		EQU	0X0F	; timer1 старший байт     
T1CON		EQU	0X10	; timer1 control register
PCL		EQU	0X02	; программный счетчик
STATUS		EQU	0X03	; регистр status
FSR		EQU	0X04	; указатель адреса в памяти данных
PORTA		EQU	0X05	; порт A
PORTC		EQU	0X07	; порт C
PCLATH		EQU	0X0A	; верхние 5 бит программного счетчика
INTCON		EQU	0X0B	; регистр контроля прерываний
TRISA		EQU	0X85	; управляющий регистр порта A
TRISC		EQU	0X87	; управляющий регистр порта C 
OPTION_REG	EQU	0X81	; регистр option
EEADR		EQU	0X9B	; адресный регистр EEPROM
EECON1		EQU	0X9C	; содержит бит RD
EEDAT		EQU	0X9A	; прочитанные из EEPROM данные
PCON		EQU	0X8E	; регистр power control
PIE1		EQU	0X8C	; регистр контроля периферийных прерываний
PIR1		EQU	0X0C	; регистр флагов прерываний от 
				; периферийных модулей

;
; присвоение значений символьным константам
;
RP0		EQU	0X05	; бит-указатель страницы данных в STATUS
W		EQU	0X00	; file register designator = W
F		EQU	0X01	; file register designator = F 
Z		EQU	0X02	; бит нуля в STATUS 
C		EQU	0X00	; бит преноса в STATUS
RD		EQU	0X00	; инициализация чтения EEPROM
POR		EQU	0X01	; бит POR регистра PCON обнуляется, если был
				; сброс по включению питания
BOR		EQU	0X00	; сброс по снижению питания
TMR1IF		EQU	0X00	; бит переполнения TMR1 in register PIR1
TMR1ON		EQU	0X00	;
GIE		EQU	0X07	;
TMR1IE		EQU	0X00	; бит разрешения прерываний от TMR1
PON		EQU	0X00	; POWER ON IN FLAG
;
;=================================================================
; vector table
;
	ORG 0X000		; стартовый адрес	
	GOTO START		; 

;==================================================================
; TIMER1 INTERRUPT 
;
	ORG 0X004		; адрес	прерывания
	MOVWF TMPW		; сохраняем W
	SWAPF STATUS,W
	MOVWF TMPS		; сохраняем STATUS
	
	BTFSC PIR1,0		; прерывание от TMR1?
	GOTO T1_INT		; да
        NOP			; обработчик левого прерывания
	GOTO END_ISR		; 

T1_INT
	MOVF TX_ALL_CNT,W	; вычитание
	SUBWF TX_OFF,W		; TX_OFF-TX_ALL_CNT
	
	BCF FLAG,0		;
	SKPC			; пропустить, если результат >=0
	BSF FLAG,0		;


	MOVF TX_ALL_CNT,W	; ускоряемся за 10 сек до конца цикла
	SUBLW D'125'		; ставим флаг, по которому во время передачи
	SKPNZ			; меняем скорость
	BSF FLAG,4		; только при 5 мин цикле

				; использовать либо верхнее, либо нижнее

	;SUBLW D'250'		; а это костыль для ускорения за 10 сек
	;SKPNZ			; до конца любого цикла, даже если
	;BSF FLAG,4		; работаем непрерывно

	DECFSZ TX_ALL_CNT,F	; TX_ALL_CNT-1, пропустить, если 0
	GOTO POP_TX
	MOVF TX_ALL,W		; восстанавливаем
	MOVWF TX_ALL_CNT	;

	BCF FLAG,4		; в конце цикла сбросить флаг ускорения
POP_TX

       	DECFSZ SEC_CNT, F	; SEC_CNT-1
	GOTO POP		; 
	MOVLW D'150'		; 300 секунд = 5 мин
	MOVWF SEC_CNT
	
	BTFSS FLAG,2		; если задержка активирована, то
	BSF FLAG,3		; через 5 мин после запуска поднимаем флаг
				; отмены задержки включения

	DECF MIN_CNT,F		; MIN_CNT-1
	DECFSZ DELAY,F		; DELAY-1, пропустить след, если 0
	GOTO POP
	BSF FLAG,2		; устанавливаем флаг разрешения работы	

POP	
	BCF PIR1,0		; сброс флага переполнения

END_ISR
	SWAPF TMPS,W		; восстанавливаем регистры W and SATUS
	MOVWF STATUS		;
	SWAPF TMPW,F		;
	SWAPF TMPW,W		;
	RETFIE			; возврат из прерывания

;==================================================================
;  Начало основной программы 
;==================================================================
START	
	MOVLW B'10001110'       ;
	BSF STATUS, RP0		; bank 1
	MOVWF OPTION_REG	; инициализация регистра option
	BCF STATUS, RP0		; bank 0	
			
	CLRF PORTA		; очистка порта A 
	CLRF PORTC		; очистка порта C

	MOVLW B'00000111'	; 
	MOVWF CMCON		; запрещаем работу компаратора

	BSF STATUS, RP0		; bank 1
	MOVLW B'00000000'	; 
	MOVWF TRISA		; порт A - все выходы
	MOVLW B'11111111'	; 
	MOVWF TRISC		; порт C - все входы
	BCF STATUS, RP0		; bank 0	

	CLRF TMR0		; на всякий случай. Говорят, надо...
	CLRWDT			; сбрасываем WDT

	BSF PORTA,2		; на 11 ноге висят подтягивающие резисторы,
				; подключенные к переключателю
				; после считывания напряжение с переключателя
				; снимается для экономии энергии

;==================================================================
; инициализация TMR1
;
	CLRF T1CON		; очистить TIMER1 control register
	CLRF TMR1H		; очистить верхний байт TMR1
	CLRF TMR1L		; очистить нижний байт TMR1
	CLRF INTCON		; запретить прерывания
	BSF STATUS,RP0		; bank 1
	CLRF PIE1		; очистить рег контроля периферийных прерываний
	BCF STATUS, RP0		; bank 0	
	CLRF PIR1		; очистить рег флагов периферийных прерываний
	MOVLW B'00001110'	; инициализация TIMER1 control register
	MOVWF T1CON		; с этого момента генератор 32.768 включен


;==================================================================

	MOVLW D'150'		; инициализация счетчика пар секунд
	MOVWF SEC_CNT		; 150 пар = 300 сек = 5 мин
        DECF SEC_CNT,F		; имитируем прерывание

	;MOVLW D'2'		; сколько пятиминуток будем работать	
	MOVLW D'96'		; сколько пятиминуток будем работать
	MOVWF MIN_CNT		; 96х5=8 час

;	MOVLW D'2'		; сколько пятиминуток задержка включения
	MOVLW D'12'		; сколько пятиминуток задержка включения
	MOVWF DELAY		; 12х5=60 мин

	MOVLW D'178'		; тон звука, 178 ~ 1000 Гц
	MOVWF SET_TONE		; чем больше, тем ниже частота

	BSF FLAG,0		; поднимаем флаг

	BCF FLAG,4


;==================================================================
; если это включение питания, то выполняется задержка для
; гарантированного запуска генератора 32768 и его инициализация
; если другой сброс, то инициализация и задержка пропускаются
;
	BSF STATUS, RP0		; bank 1
	MOVF PCON,W		; PCON -> W
	BCF STATUS, RP0		; bank 0

	MOVWF TMPW		; W -> TMPW
	BTFSS TMPW,POR		; проверяем состояние POR, если 0, то был сброс
	GOTO DELAY_START	; по включению - задержка однозначно нужна
	BTFSC TMPW,BOR          ; а это был сброс по снижению напр питания
        GOTO SKIP_DELAY         ; или не был...
	
DELAY_START

	BCF FLAG,3		; при первом включении очистить FLAG,3

	; задержка 
	MOVLW D'255'		; скорость передачи 
	MOVWF CW_SPEED		; чем больше, тем медленней
	 
 	MOVLW 0X80	
	MOVWF CW_CHAR		; 
        CALL SEND_ONE_CHAR	; в качестве задержки предаем 7 точек

	BSF STATUS, RP0		; bank 1
	BSF PCON,POR		; устанавливаем POR=1
	BSF PCON,BOR		; устанавливаем BOR=1
	BCF STATUS, RP0		; bank 0

	SLEEP			; ожидаем запуск

SKIP_DELAY


;==================================================================
; читаем переключатель
;
        MOVF PORTC,W		; читаем порт C
	ANDLW B'00011100'	; маска 
	MOVWF SWITCH		; сохраняем состояние переключателя

        MOVF PORTC,W		; читаем порт C
	ANDLW B'00000011'	; маска двух младших бит

	BCF FLAG,2		; обнуляем флаг задержки
	BTFSC PORTC,5		; если перекл. on (на землю, 0) пропуск. след.
	BSF FLAG,2		; устанавливаем флаг, можно работать

	BCF PORTA,2		; отключаем подтягивающие резисторы

	ADDWF PCL,F		; таблица
	GOTO SW00
	GOTO SW01
	GOTO SW10
	GOTO SW11
SW00			; непрерывно
	MOVLW D'0'		; молчим последние 0 с
	MOVWF TX_OFF		;
	MOVLW D'30'		; цикл 60 сек
	GOTO END_SW
SW01			; цикл 30сек/120сек
	MOVLW D'60'		; молчим последние 120 с
	MOVWF TX_OFF		;
	MOVLW D'75'		; цикл 150 сек
	GOTO END_SW
SW10			; цикл 1 мин/1 мин
	MOVLW D'30'		; молчим последние 60 с
	MOVWF TX_OFF		;
	MOVLW D'60'		; цикл 120 сек
	GOTO END_SW
SW11			; цикл 1 мин/4 мин
	MOVLW D'120'		; молчим последние 4 m
	MOVWF TX_OFF		;
	MOVLW D'150'		; цикл 5 m

END_SW
	MOVWF TX_ALL		;
	MOVWF TX_ALL_CNT	; инициализация	
        DECF TX_ALL_CNT,F	; считаем, что 1 прерывание уже случилось

;==================================================================
; Окончание инициализации TIMER1
;

	MOVLW B'11000000'	; разрешить прерывания от периферийных модулей
	MOVWF INTCON

	BSF STATUS,RP0		; bank 1
	BSF PIE1,TMR1IE		; разрешить прерывания от TMR1
	BCF STATUS, RP0		; bank 0	
	BSF T1CON,TMR1ON        ; TMR1 ON


;==================================================================
; Если с момента запуска прошло 5 мин, то при сбросе задержку 
; включения игнорируем

	BTFSC FLAG,3		; FLAG,3 поднимается через 5 м после начала
				; работы
	BSF FLAG,2		; задержка включения не нужна

;==================================================================
; MAIN
; передача последовательности символов
; можно предавать любое количество, 0XFF означает конец последовательности,
; после чего формируется пауза и передача циклически повторяется
;
SEND_MSG
                                ; если автоотключение не нужно, то три 
				; нижеследующих строчки надо закомментировать
	MOVF MIN_CNT,F		; проверяем, не обнулился ли 
	SKPNZ			; счетчик пятиминуток
	GOTO POWER_OFF		; если да, то выключаемся

	BTFSS FLAG,2		; пропустить след, если задержка включения
				; кончилась (1-разрешение работы)
	GOTO FLASH		; мигнуть и sleep

        BTFSS FLAG,0		; если флаг сброшен, то идем спать
	GOTO TO_SLEEP
	
	MOVF SWITCH,W
	MOVWF CHAR_INDEX	; SWITCH -> CHAR_INDEX

GET_MSG
	MOVF CHAR_INDEX,W		
	BCF INTCON,GIE		; запрещаем прерывания
	BSF STATUS, RP0		; bank 1
	MOVWF EEADR		; значение CHAR_INDEX = адресу кода в EEPROM
	BSF EECON1,RD		; разрешаем чтение EEPROM
	MOVF EEDAT,W		; значение ячейки -> регистр W
	BCF STATUS, RP0		; bank 0	 
	BSF INTCON,GIE		; разрешаем прерывания
	;MOVLW 0x06
	MOVWF CW_CHAR		; W -> CW_CHAR	

	MOVLW 0XFF		; конец сообщения?
	SUBWF CW_CHAR,W		;
	SKPNZ
	GOTO END_MSG		; да, перейти к END_MSG

	MOVLW D'60'		; скорость передачи быстро
	BTFSS FLAG,4		; устанавливается за 10 с до конца цикла
	MOVLW D'160'		; скорость передачи медленно
	MOVWF CW_SPEED		; чем больше, тем медленней

	CALL SEND_CHAR		; передаем букву и паузу в 3 точки
                                ; или паузу 6 точек, если SPACE
	INCF CHAR_INDEX		; CHAR_INDEX+1	
	GOTO GET_MSG

END_MSG
	CALL WORD_SPACE         ; пауза 6 точек 
	GOTO SEND_MSG		;	

				; время работы закончилось
POWER_OFF			; отсюда выход только через RESET
	CLRF T1CON		; очистить TIMER1 control register, выключаем
				; генератор 32768
	;BCF T1CON,TMR1ON       ; TMR1 OFF
	CLRF INTCON		; запретить прерывания

				; после сброса считаем, что это сброс по питанию
	BSF STATUS, RP0		; bank 1
	BCF PCON,POR		; устанавливаем POR=0
	BCF PCON,BOR		; устанавливаем BOR=0
	BCF STATUS, RP0		; bank 0

TO_SLEEP			;
	CLRF PORTA
	SLEEP
	NOP
	GOTO SEND_MSG
;========================================================================
; индикатор включенной задержки
; мигаем порт A.1
FLASH
	MOVLW D'60'		; скорость передачи 
	MOVWF CW_SPEED		; чем больше, тем медленней
	BSF PORTA,1
	MOVLW 0X01		;
	MOVWF NBR_SPACE		; пауза в 1 точку
	CALL SEND_SPACE		;
	BCF PORTA,1
	GOTO TO_SLEEP
;========================================================================
; SEND_CHAR
; Подпрограмма получает код символа в регистре CW_CHAR, побитно перебирает 
; его, и, в зависимости от состояния бита, передает: тире, если бит = 1;
; точку, если бит = 0.
; Знак передается, пока в слове есть хоть одна единица. Последняя единица
; "съедается", она означает конец слова. 
;
SEND_CHAR
	MOVLW 0X00		; пауза?
	SUBWF CW_CHAR,W		;
	SKPNZ			; 
	GOTO WORD_SPACE

SEND_ONE_CHAR 
        BTFSS FLAG,0		; обрываем передачу, если флаг сброшен
	RETURN

	CLRC			; очистить бит переноса
	RRF CW_CHAR, F		; сдвиг вправо через перенос
				; 
	MOVF CW_CHAR, F         ; проверяем содержимое CW_CHAR, если все "0"
	SKPNZ                   ; то Z=1, выполняем RETURN, иначе пропускаем
	GOTO PAUSE2		; конец буквы
	SKPC			; проверить бит переноса, пропустить, если=1
	GOTO SEND_A_DIT		; перейти к SEND_A_DIT

SEND_A_DAH			; передаем тире 
	MOVLW 0X03		; 1 тире = 3 точки
	MOVWF NBR_DIT
	MOVLW 0X01		;
	MOVWF NBR_SPACE		; после тире - пауза в 1 точку
	BSF PORTA,0		; включаем PORT A.2
	CALL SEND_TONE		; генериуем звук, оно же - пауза
	BCF PORTA,0		; выключаем PORT A.2
	CALL SEND_SPACE
	GOTO SEND_ONE_CHAR

SEND_A_DIT 
	MOVLW 0X01		; передаем точку
	MOVWF NBR_DIT
	MOVWF NBR_SPACE		; после точки - пауза в 1 точку
	BSF PORTA,0		; включаем PORT A.2
	CALL SEND_TONE          ; генерируем звук, оно же - пауза
	BCF PORTA,0		; выключаем PORT A.2
	CALL SEND_SPACE
	GOTO SEND_ONE_CHAR

PAUSE2
	MOVLW D'2'		; пауза в 2 точки после буквы	
	MOVWF NBR_SPACE		; 
	CALL SEND_SPACE         ;
	RETURN

WORD_SPACE
	MOVLW D'6'		; пауза в 6 точек между словами	
	MOVWF NBR_SPACE		; 
	CALL SEND_SPACE         ;
	RETURN

;==================================================================
; SEND_TONE
; Подпрограмма осуществляет задержку и одновременно формирует сигнал
; звуковой частоты (порт A.1)
;

SEND_TONE
 
	MOVF NBR_DIT, W		; NBR_DIT кол-во пропускаемых точек 
	MOVWF CTR_NBR		; 

DIT_LENGTH 
	MOVF CW_SPEED, W	; CW_SPEED скорость передачи
	MOVWF CTR_DIT		;

START_CYCLE 
	BSF PORTA,1		; A.1=1 в начале цикла
	MOVF SET_TONE,W		; 
	MOVWF TONE		; заносим значение в счетчик цикла задержки

HIGH_HALF 
	DECFSZ TONE, F		; считаем до нуля
	GOTO HIGH_HALF
	BCF PORTA,1		; A.1=0 в конце цикла

	MOVF SET_TONE,W		;
	MOVWF TONE

LOW_HALF 
	DECFSZ TONE, F		; 
	GOTO LOW_HALF
	DECFSZ CTR_DIT, F	;
	GOTO START_CYCLE
	DECFSZ CTR_NBR, F
	GOTO DIT_LENGTH		; 
	RETURN			; 

;================================================================
; SEND_SPACE
; Делает тоже самое, что и SEND_TONE, только вместо команд управления
; портами стоит команда NOP
;

SEND_SPACE
 
	MOVF NBR_SPACE, W	; 
	MOVWF CTR_NBR

DIT_LENGTH_SP 
	MOVF CW_SPEED, W	; 
	MOVWF CTR_DIT

START_CYCLE_SP
	NOP
	MOVF SET_TONE,W
	MOVWF TONE		; 

HIGH_HALF_SP 
	DECFSZ TONE, F		; 
	GOTO HIGH_HALF_SP
	NOP
	MOVF SET_TONE,W
	MOVWF TONE

LOW_HALF_SP 
	DECFSZ TONE, F		; 
	GOTO LOW_HALF_SP
	DECFSZ CTR_DIT, F	;
	GOTO START_CYCLE_SP
	DECFSZ CTR_NBR, F
	GOTO DIT_LENGTH_SP	; 
	RETURN			; 

;==================================================================
;==================================================================
; Идентификатор
	ORG  0x2000	; стартовый адрес

        DATA 0x0000
        DATA 0x0000
        DATA 0x0000
        DATA 0x0000

;==================================================================
; Слово конфигурации
	ORG  0x2007	; стартовый адрес

	DATA 0x31E4

;==================================================================
; Запись в EEPROM при программировании
; Переключателем адресуется номер ячейки, кратный 4. Соответственно, маяк
; может передавать последовательно три символа Морзе, четвертым обязательно
; должен быть EOM
; В последнюю адресуемую ячейку можно записать большее количество символов

	ORG  0X2100	; стартовый адрес

	DATA 0x07	; M --    00000111
	DATA 0x0F	; O ---   00001111
        DATA 0xFF	; EOM     11111111
        DATA 0xFF	; EOM     11111111

	DATA 0x07	; M --    00000111
	DATA 0x0F	; O ---   00001111
        DATA 0x02	; E .     00000010  	
        DATA 0xFF	; EOM     11111111

	DATA 0x07	; M --    00000111
	DATA 0x0F	; O ---   00001111
	DATA 0x04	; I ..    00000100
        DATA 0xFF	; EOM     11111111

	DATA 0x07	; M --    00000111
	DATA 0x0F	; O ---   00001111
	DATA 0x08	; S ...   00001000
        DATA 0xFF	; EOM     11111111

	DATA 0x07	; M --    00000111
	DATA 0x0F	; O ---   00001111
	DATA 0x10	; H ....  00010000
        DATA 0xFF	; EOM     11111111

	DATA 0x07	; M --    00000111
	DATA 0x0F	; O ---   00001111
	DATA 0x20	; 5 ..... 00100000
        DATA 0xFF	; EOM     11111111

	DATA 0x07	; M --    00000111
	DATA 0x0F	; O ---   00001111
	DATA 0x03	; T -     00000011
        DATA 0xFF	; EOM     11111111

	DATA 0x03	; T -     00000011
        DATA 0xFF	; EOM     11111111
        DATA 0xFF	; EOM     11111111
        DATA 0xFF	; EOM     11111111

	END

Версия прошивки 3.2, циклы 30с/120с; 60с/60с; 1м/4м


;-Передает в режиме лисы код Морзе (MO, MOE, MOI, MOS, MOH, MO5, RA1AMO). Вариант кода задается переключателем.
;-Может работать непрерывно или циклом: 30с/120с; 60с/60с; 1м/4м.
;-Есть выход 1000 Гц для модуляции маяка на 144 МГц.
;-Автоотключение через 8 часов, без учета ОС.
;-Потребление в выключенном состоянии менее 0.08 ма, во время работы, при передаче позывного, 0.5 ма.
;-Уход часов определяется кварцем.
;-Код с переключателя считывается один раз после сброса.
;-Режим отложенного старта (ОС), задержка 120 минут
;-Питание от 3 до 5 вольт 
;
; PIC16F630
; WDT off, intLC, MCLR on, BOR on, PWRTE on
;
	list	P=16F630
	radix	HEX

;====================================================================
; именование пользовательских регистров
;	
 	CBLOCK	0X20	; начальный адрес пользовательских регистров
        TMPW		; временный регистр для хранения W во время прерывания
	TMPS		; временный регистр для хранения STATUS                                                    
	SEC_CNT		; счетчик пар секунд
	MIN_CNT 	; счетчик минут (пятиминуток, автовыключение)
	FLAG		; регистр флагов:
			; FLAG,0 разрешает передачу позывного в свое время
			; FLAG,2 флаг задержки включения (1-можно работать)
                        ; FLAG,3 флаг взводится через 5 мин после начала работы
			; и отменяет задержку включения при сбросе
			; FLAG,4 флаг устанавливается за 10 сек до конца цикла


	DELAY		; счетчик пятиминуток, задержка включения
	TX_ALL_CNT	; счетчик пар секунд в цикле
	TX_OFF		; с какой секунды пауза
	TX_ALL		; сколько пар секунд в цикле

	SWITCH		; состояние переключателя
	CHAR_INDEX	; номер передаваемого символа

	CW_SPEED	; скорость передачи

; процедура SEND_TONE
	NBR_DIT		; NBR_DIT кол-во пропускаемых точек
	CTR_NBR		; счетчик пропускаемых точек
	TONE		; счетчик частоты
	SET_TONE	; установка тона передаваемого сигнала
; процедура SEND_SPACE
	NBR_SPACE	; колво пропускаемых точек
	CTR_DIT		; счетчик пропускаемых точек
; процедура SEND_ONE_CHAR
	CW_CHAR		; передаваемый символ
	ENDC


;
; Именование регистров микроконтроллера
;
CMCON		EQU	0X19	; регистр контроля компаратора
TMR0		EQU	0X01	; timer0
TMR1L		EQU	0X0E	; timer1 младший байт
TMR1H		EQU	0X0F	; timer1 старший байт     
T1CON		EQU	0X10	; timer1 control register
PCL		EQU	0X02	; программный счетчик
STATUS		EQU	0X03	; регистр status
FSR		EQU	0X04	; указатель адреса в памяти данных
PORTA		EQU	0X05	; порт A
PORTC		EQU	0X07	; порт C
PCLATH		EQU	0X0A	; верхние 5 бит программного счетчика
INTCON		EQU	0X0B	; регистр контроля прерываний
TRISA		EQU	0X85	; управляющий регистр порта A
TRISC		EQU	0X87	; управляющий регистр порта C 
OPTION_REG	EQU	0X81	; регистр option
EEADR		EQU	0X9B	; адресный регистр EEPROM
EECON1		EQU	0X9C	; содержит бит RD
EEDAT		EQU	0X9A	; прочитанные из EEPROM данные
PCON		EQU	0X8E	; регистр power control
PIE1		EQU	0X8C	; регистр контроля периферийных прерываний
PIR1		EQU	0X0C	; регистр флагов прерываний от 
				; периферийных модулей

;
; присвоение значений символьным константам
;
RP0		EQU	0X05	; бит-указатель страницы данных в STATUS
W		EQU	0X00	; file register designator = W
F		EQU	0X01	; file register designator = F 
Z		EQU	0X02	; бит нуля в STATUS 
C		EQU	0X00	; бит преноса в STATUS
RD		EQU	0X00	; инициализация чтения EEPROM
POR		EQU	0X01	; бит POR регистра PCON обнуляется, если был
				; сброс по включению питания
BOR		EQU	0X00	; сброс по снижению питания
TMR1IF		EQU	0X00	; бит переполнения TMR1 in register PIR1
TMR1ON		EQU	0X00	;
GIE		EQU	0X07	;
TMR1IE		EQU	0X00	; бит разрешения прерываний от TMR1
PON		EQU	0X00	; POWER ON IN FLAG
;
;=================================================================
; vector table
;
	ORG 0X000		; стартовый адрес	
	GOTO START		; 

;==================================================================
; TIMER1 INTERRUPT 
;
	ORG 0X004		; адрес	прерывания
	MOVWF TMPW		; сохраняем W
	SWAPF STATUS,W
	MOVWF TMPS		; сохраняем STATUS
	
	BTFSC PIR1,0		; прерывание от TMR1?
	GOTO T1_INT		; да
        NOP			; обработчик левого прерывания
	GOTO END_ISR		; 

T1_INT
	MOVF TX_ALL_CNT,W	; вычитание
	SUBWF TX_OFF,W		; TX_OFF-TX_ALL_CNT
	
	BCF FLAG,0		;
	SKPC			; пропустить, если результат >=0
	BSF FLAG,0		;


;	MOVF TX_ALL_CNT,W	; ускоряемся за 10 сек до конца цикла
;	SUBLW D'125'		; ставим флаг, по которому во время передачи
;	SKPNZ			; меняем скорость
;	BSF FLAG,4		; только при 5 мин цикле

				; использовать либо верхнее, либо нижнее

	;SUBLW D'250'		; а это костыль для ускорения за 10 сек
	;SKPNZ			; до конца любого цикла, даже если
	;BSF FLAG,4		; работаем непрерывно

	DECFSZ TX_ALL_CNT,F	; TX_ALL_CNT-1, пропустить, если 0
	GOTO POP_TX
	MOVF TX_ALL,W		; восстанавливаем
	MOVWF TX_ALL_CNT	;

;	BCF FLAG,4		; в конце цикла сбросить флаг ускорения
POP_TX

       	DECFSZ SEC_CNT, F	; SEC_CNT-1
	GOTO POP		; 
	MOVLW D'150'		; 300 секунд = 5 мин
	MOVWF SEC_CNT
	
	BTFSS FLAG,2		; если задержка активирована, то
	BSF FLAG,3		; через 5 мин после запуска поднимаем флаг
				; отмены задержки включения

	BTFSC FLAG,2		; если флаг разрешения работы установлен, начинаем отсчет 
				; задержки отключения
	DECF MIN_CNT,F		; MIN_CNT-1 минуты работы считаем после 
				; окончании задержки включения


	DECFSZ DELAY,F		; DELAY-1, пропустить след, если 0
	GOTO POP		; задержка окончилась
	BSF FLAG,2		; устанавливаем флаг разрешения работы	


POP	
	BCF PIR1,0		; сброс флага переполнения

END_ISR
	SWAPF TMPS,W		; восстанавливаем регистры W and SATUS
	MOVWF STATUS		;
	SWAPF TMPW,F		;
	SWAPF TMPW,W		;
	RETFIE			; возврат из прерывания

;==================================================================
;  Начало основной программы 
;==================================================================
START	
	MOVLW B'10001110'       ;
	BSF STATUS, RP0		; bank 1
	MOVWF OPTION_REG	; инициализация регистра option
	BCF STATUS, RP0		; bank 0	
			
	CLRF PORTA		; очистка порта A 
	CLRF PORTC		; очистка порта C

	MOVLW B'00000111'	; 
	MOVWF CMCON		; запрещаем работу компаратора

	BSF STATUS, RP0		; bank 1
	MOVLW B'00000000'	; 
	MOVWF TRISA		; порт A - все выходы
	MOVLW B'11111111'	; 
	MOVWF TRISC		; порт C - все входы
	BCF STATUS, RP0		; bank 0	

	CLRF TMR0		; на всякий случай. Говорят, надо...
	CLRWDT			; сбрасываем WDT

	BSF PORTA,2		; на 11 ноге висят подтягивающие резисторы,
				; подключенные к переключателю
				; после считывания напряжение с переключателя
				; снимается для экономии энергии

;==================================================================
; инициализация TMR1
;
	CLRF T1CON		; очистить TIMER1 control register
	CLRF TMR1H		; очистить верхний байт TMR1
	CLRF TMR1L		; очистить нижний байт TMR1
	CLRF INTCON		; запретить прерывания
	BSF STATUS,RP0		; bank 1
	CLRF PIE1		; очистить рег контроля периферийных прерываний
	BCF STATUS, RP0		; bank 0	
	CLRF PIR1		; очистить рег флагов периферийных прерываний
	MOVLW B'00001110'	; инициализация TIMER1 control register
	MOVWF T1CON		; с этого момента генератор 32.768 включен


;==================================================================

	MOVLW D'150'		; инициализация счетчика пар секунд
	MOVWF SEC_CNT		; 150 пар = 300 сек = 5 мин
        DECF SEC_CNT,F		; имитируем прерывание

	;MOVLW D'2'		; сколько пятиминуток будем работать	
	MOVLW D'96'		; сколько пятиминуток будем работать
	MOVWF MIN_CNT		; 96х5=8 час

;	MOVLW D'2'		; сколько пятиминуток задержка включения
	MOVLW D'24'		; сколько пятиминуток задержка включения
	MOVWF DELAY		; 24х5=120 мин

	MOVLW D'178'		; тон звука, 178 ~ 1000 Гц
	MOVWF SET_TONE		; чем больше, тем ниже частота

	BSF FLAG,0		; поднимаем флаг

;	BCF FLAG,4


;==================================================================
; если это включение питания, то выполняется задержка для
; гарантированного запуска генератора 32768 и его инициализация
; если другой сброс, то инициализация и задержка пропускаются
;
	BSF STATUS, RP0		; bank 1
	MOVF PCON,W		; PCON -> W
	BCF STATUS, RP0		; bank 0

	MOVWF TMPW		; W -> TMPW
	BTFSS TMPW,POR		; проверяем состояние POR, если 0, то был сброс
	GOTO DELAY_START	; по включению - задержка однозначно нужна
	BTFSC TMPW,BOR          ; а это был сброс по снижению напр питания
        GOTO SKIP_DELAY         ; или не был...
	
DELAY_START

	BCF FLAG,3		; при первом включении очистить FLAG,3

	; задержка 
	MOVLW D'255'		; скорость передачи 
	MOVWF CW_SPEED		; чем больше, тем медленней
	 
 	MOVLW 0X80	
	MOVWF CW_CHAR		; 
        CALL SEND_ONE_CHAR	; в качестве задержки предаем 7 точек

	BSF STATUS, RP0		; bank 1
	BSF PCON,POR		; устанавливаем POR=1
	BSF PCON,BOR		; устанавливаем BOR=1
	BCF STATUS, RP0		; bank 0

	SLEEP			; ожидаем запуск

SKIP_DELAY


;==================================================================
; читаем переключатель
;
        MOVF PORTC,W		; читаем порт C
	ANDLW B'00011100'	; маска 
	MOVWF SWITCH		; сохраняем состояние переключателя

        MOVF PORTC,W		; читаем порт C
	ANDLW B'00000011'	; маска двух младших бит

	BCF FLAG,2		; обнуляем флаг задержки
	BTFSC PORTC,5		; если перекл. on (на землю, 0) пропуск. след.
	BSF FLAG,2		; устанавливаем флаг, можно работать

	BCF PORTA,2		; отключаем подтягивающие резисторы

	ADDWF PCL,F		; таблица
	GOTO SW00
	GOTO SW01
	GOTO SW10
	GOTO SW11
SW00			; непрерывно
	MOVLW D'0'		; молчим последние 0 с
	MOVWF TX_OFF		;
	MOVLW D'30'		; цикл 60 сек
	GOTO END_SW
SW01			; цикл 30сек/120сек
	MOVLW D'60'		; молчим последние 120 с
	MOVWF TX_OFF		;
	MOVLW D'75'		; цикл 150 сек
	GOTO END_SW
SW10			; цикл 1 мин/1 мин
	MOVLW D'30'		; молчим последние 60 с
	MOVWF TX_OFF		;
	MOVLW D'60'		; цикл 120 сек
	GOTO END_SW
SW11			; цикл 1 мин/4 мин
	MOVLW D'120'		; молчим последние 4 m
	MOVWF TX_OFF		;
	MOVLW D'150'		; цикл 5 m

END_SW
	MOVWF TX_ALL		;
	MOVWF TX_ALL_CNT	; инициализация	
        DECF TX_ALL_CNT,F	; считаем, что 1 прерывание уже случилось

;==================================================================
; Окончание инициализации TIMER1
;

	MOVLW B'11000000'	; разрешить прерывания от периферийных модулей
	MOVWF INTCON

	BSF STATUS,RP0		; bank 1
	BSF PIE1,TMR1IE		; разрешить прерывания от TMR1
	BCF STATUS, RP0		; bank 0	
	BSF T1CON,TMR1ON        ; TMR1 ON


;==================================================================
; Если с момента запуска прошло 5 мин, то при сбросе задержку 
; включения игнорируем

	BTFSC FLAG,3		; FLAG,3 поднимается через 5 м после начала
				; работы
	BSF FLAG,2		; задержка включения не нужна

;==================================================================
; MAIN
; передача последовательности символов
; можно предавать любое количество, 0XFF означает конец последовательности,
; после чего формируется пауза и передача циклически повторяется
;
SEND_MSG
                                ; если автоотключение не нужно, то три 
				; нижеследующих строчки надо закомментировать
	MOVF MIN_CNT,F		; проверяем, не обнулился ли 
	SKPNZ			; счетчик пятиминуток
	GOTO POWER_OFF		; если да, то выключаемся

	BTFSS FLAG,2		; пропустить след, если задержка включения
				; кончилась (1-разрешение работы)
	GOTO FLASH		; мигнуть и sleep

        BTFSS FLAG,0		; если флаг сброшен, то идем спать
	GOTO TO_SLEEP
	
	MOVF SWITCH,W
	MOVWF CHAR_INDEX	; SWITCH -> CHAR_INDEX

GET_MSG
	MOVF CHAR_INDEX,W		
	BCF INTCON,GIE		; запрещаем прерывания
	BSF STATUS, RP0		; bank 1
	MOVWF EEADR		; значение CHAR_INDEX = адресу кода в EEPROM
	BSF EECON1,RD		; разрешаем чтение EEPROM
	MOVF EEDAT,W		; значение ячейки -> регистр W
	BCF STATUS, RP0		; bank 0	 
	BSF INTCON,GIE		; разрешаем прерывания
	;MOVLW 0x06
	MOVWF CW_CHAR		; W -> CW_CHAR	

	MOVLW 0XFF		; конец сообщения?
	SUBWF CW_CHAR,W		;
	SKPNZ
	GOTO END_MSG		; да, перейти к END_MSG

;	MOVLW D'60'		; скорость передачи быстро
;	BTFSS FLAG,4		; устанавливается за 10 с до конца цикла
	MOVLW D'160'		; скорость передачи медленно
	MOVWF CW_SPEED		; чем больше, тем медленней

	CALL SEND_CHAR		; передаем букву и паузу в 3 точки
                                ; или паузу 6 точек, если SPACE
	INCF CHAR_INDEX		; CHAR_INDEX+1	
	GOTO GET_MSG

END_MSG
	CALL WORD_SPACE         ; пауза 6 точек 
	GOTO SEND_MSG		;	

				; время работы закончилось
POWER_OFF			; отсюда выход только через RESET

	CLRF FLAG		; очистка регистра флагов
	CLRF T1CON		; очистить TIMER1 control register, выключаем
				; генератор 32768
	;BCF T1CON,TMR1ON       ; TMR1 OFF
	CLRF INTCON		; запретить прерывания

				; после сброса считаем, что это сброс по питанию
	BSF STATUS, RP0		; bank 1
	BCF PCON,POR		; устанавливаем POR=0
	BCF PCON,BOR		; устанавливаем BOR=0
	BCF STATUS, RP0		; bank 0

TO_SLEEP			;
	CLRF PORTA
	SLEEP
	NOP
	GOTO SEND_MSG
;========================================================================
; индикатор включенной задержки
; мигаем порт A.1
FLASH
	MOVLW D'60'		; скорость передачи 
	MOVWF CW_SPEED		; чем больше, тем медленней
	BSF PORTA,1
	MOVLW 0X01		;
	MOVWF NBR_SPACE		; пауза в 1 точку
	CALL SEND_SPACE		;
	BCF PORTA,1
	GOTO TO_SLEEP
;========================================================================
; SEND_CHAR
; Подпрограмма получает код символа в регистре CW_CHAR, побитно перебирает 
; его, и, в зависимости от состояния бита, передает: тире, если бит = 1;
; точку, если бит = 0.
; Знак передается, пока в слове есть хоть одна единица. Последняя единица
; "съедается", она означает конец слова. 
;
SEND_CHAR
	MOVLW 0X00		; пауза?
	SUBWF CW_CHAR,W		;
	SKPNZ			; 
	GOTO WORD_SPACE

SEND_ONE_CHAR 
        BTFSS FLAG,0		; обрываем передачу, если флаг сброшен
	RETURN

	CLRC			; очистить бит переноса
	RRF CW_CHAR, F		; сдвиг вправо через перенос
				; 
	MOVF CW_CHAR, F         ; проверяем содержимое CW_CHAR, если все "0"
	SKPNZ                   ; то Z=1, выполняем RETURN, иначе пропускаем
	GOTO PAUSE2		; конец буквы
	SKPC			; проверить бит переноса, пропустить, если=1
	GOTO SEND_A_DIT		; перейти к SEND_A_DIT

SEND_A_DAH			; передаем тире 
	MOVLW 0X03		; 1 тире = 3 точки
	MOVWF NBR_DIT
	MOVLW 0X01		;
	MOVWF NBR_SPACE		; после тире - пауза в 1 точку
	BSF PORTA,0		; включаем PORT A.2
	CALL SEND_TONE		; генериуем звук, оно же - пауза
	BCF PORTA,0		; выключаем PORT A.2
	CALL SEND_SPACE
	GOTO SEND_ONE_CHAR

SEND_A_DIT 
	MOVLW 0X01		; передаем точку
	MOVWF NBR_DIT
	MOVWF NBR_SPACE		; после точки - пауза в 1 точку
	BSF PORTA,0		; включаем PORT A.2
	CALL SEND_TONE          ; генерируем звук, оно же - пауза
	BCF PORTA,0		; выключаем PORT A.2
	CALL SEND_SPACE
	GOTO SEND_ONE_CHAR

PAUSE2
	MOVLW D'2'		; пауза в 2 точки после буквы	
	MOVWF NBR_SPACE		; 
	CALL SEND_SPACE         ;
	RETURN

WORD_SPACE
	MOVLW D'6'		; пауза в 6 точек между словами	
	MOVWF NBR_SPACE		; 
	CALL SEND_SPACE         ;
	RETURN

;==================================================================
; SEND_TONE
; Подпрограмма осуществляет задержку и одновременно формирует сигнал
; звуковой частоты (порт A.1)
;

SEND_TONE
 
	MOVF NBR_DIT, W		; NBR_DIT кол-во пропускаемых точек 
	MOVWF CTR_NBR		; 

DIT_LENGTH 
	MOVF CW_SPEED, W	; CW_SPEED скорость передачи
	MOVWF CTR_DIT		;

START_CYCLE 
	BSF PORTA,1		; A.1=1 в начале цикла
	MOVF SET_TONE,W		; 
	MOVWF TONE		; заносим значение в счетчик цикла задержки

HIGH_HALF 
	DECFSZ TONE, F		; считаем до нуля
	GOTO HIGH_HALF
	BCF PORTA,1		; A.1=0 в конце цикла

	MOVF SET_TONE,W		;
	MOVWF TONE

LOW_HALF 
	DECFSZ TONE, F		; 
	GOTO LOW_HALF
	DECFSZ CTR_DIT, F	;
	GOTO START_CYCLE
	DECFSZ CTR_NBR, F
	GOTO DIT_LENGTH		; 
	RETURN			; 

;================================================================
; SEND_SPACE
; Делает тоже самое, что и SEND_TONE, только вместо команд управления
; портами стоит команда NOP
;

SEND_SPACE
 
	MOVF NBR_SPACE, W	; 
	MOVWF CTR_NBR

DIT_LENGTH_SP 
	MOVF CW_SPEED, W	; 
	MOVWF CTR_DIT

START_CYCLE_SP
	NOP
	MOVF SET_TONE,W
	MOVWF TONE		; 

HIGH_HALF_SP 
	DECFSZ TONE, F		; 
	GOTO HIGH_HALF_SP
	NOP
	MOVF SET_TONE,W
	MOVWF TONE

LOW_HALF_SP 
	DECFSZ TONE, F		; 
	GOTO LOW_HALF_SP
	DECFSZ CTR_DIT, F	;
	GOTO START_CYCLE_SP
	DECFSZ CTR_NBR, F
	GOTO DIT_LENGTH_SP	; 
	RETURN			; 

;==================================================================
;==================================================================
; Идентификатор
	ORG  0x2000	; стартовый адрес

        DATA 0x0132
        DATA 0xF321
        DATA 0x0000
        DATA 0x0000

;==================================================================
; Слово конфигурации
	ORG  0x2007	; стартовый адрес

;	DATA 0x31E4
	DATA 0x1024	; вкл защиту данных
;	DATA 0x11A4
;==================================================================
; Запись в EEPROM при программировании
; Переключателем адресуется номер ячейки, кратный 4. Соответственно, маяк
; может передавать последовательно три символа Морзе, четвертым обязательно
; должен быть EOM
; В последнюю адресуемую ячейку можно записать большее количество символов

	ORG  0X2100	; стартовый адрес

	DATA 0x07	; M --    00000111
	DATA 0x0F	; O ---   00001111
        DATA 0xFF	; EOM     11111111
        DATA 0xFF	; EOM     11111111

	DATA 0x07	; M --    00000111
	DATA 0x0F	; O ---   00001111
        DATA 0x02	; E .     00000010  	
        DATA 0xFF	; EOM     11111111

	DATA 0x07	; M --    00000111
	DATA 0x0F	; O ---   00001111
	DATA 0x04	; I ..    00000100
        DATA 0xFF	; EOM     11111111

	DATA 0x07	; M --    00000111
	DATA 0x0F	; O ---   00001111
	DATA 0x08	; S ...   00001000
        DATA 0xFF	; EOM     11111111

	DATA 0x07	; M --    00000111
	DATA 0x0F	; O ---   00001111
	DATA 0x10	; H ....  00010000
        DATA 0xFF	; EOM     11111111

	DATA 0x07	; M --    00000111
	DATA 0x0F	; O ---   00001111
	DATA 0x20	; 5 ..... 00100000
        DATA 0xFF	; EOM     11111111

	DATA 0x07	; M --    00000111
	DATA 0x0F	; O ---   00001111
	DATA 0x03	; T -     00000011
        DATA 0xFF	; EOM     11111111

	DATA 0x0A	; R .-.   
        DATA 0x06	; A .-
        DATA 0x3E	; 1 .----
        DATA 0x06	; A .-
        DATA 0x07	; M --
        DATA 0x0F	; O ---
        DATA 0xFF	; EOM     11111111

	END

Вариант для управления радиостанцией, 30с/120с; 60с/60с; 1м/4м, передача позывного

Схема для управления маяком для городской охоты, возможно подключение обычной радиостанции

</pre>

на 11 ногу можно повесить управление TX (высокий уровень при передаче)
PIC16F630
WDT off, intLC, MCLR on, BOR on, PWRTE on

list P=16F630 radix HEX

====================================================================
именование пользовательских регистров
	CBLOCK	0X20	; начальный адрес пользовательских регистров
       TMPW		; временный регистр для хранения W во время прерывания

TMPS ; временный регистр для хранения STATUS SEC_CNT ; счетчик пар секунд MIN_CNT ; счетчик минут (пятиминуток, автовыключение) FLAG ; регистр флагов: ; FLAG,0 разрешает передачу позывного в свое время ; FLAG,2 флаг задержки включения (1-можно работать)

                       ; FLAG,3 флаг взводится через 5 мин после начала работы

; и отменяет задержку включения при сбросе ; FLAG,4 флаг устанавливается за 10 сек до конца цикла


DELAY ; счетчик пятиминуток, задержка включения TX_ALL_CNT ; счетчик пар секунд в цикле TX_OFF ; с какой секунды пауза TX_ALL ; сколько пар секунд в цикле

SWITCH ; состояние переключателя CHAR_INDEX ; номер передаваемого символа

CW_SPEED ; скорость передачи

процедура SEND_TONE

NBR_DIT ; NBR_DIT кол-во пропускаемых точек CTR_NBR ; счетчик пропускаемых точек TONE ; счетчик частоты SET_TONE ; установка тона передаваемого сигнала

процедура SEND_SPACE

NBR_SPACE ; колво пропускаемых точек CTR_DIT ; счетчик пропускаемых точек

процедура SEND_ONE_CHAR

CW_CHAR ; передаваемый символ ENDC


Именование регистров микроконтроллера

CMCON EQU 0X19 ; регистр контроля компаратора TMR0 EQU 0X01 ; timer0 TMR1L EQU 0X0E ; timer1 младший байт TMR1H EQU 0X0F ; timer1 старший байт T1CON EQU 0X10 ; timer1 control register PCL EQU 0X02 ; программный счетчик STATUS EQU 0X03 ; регистр status FSR EQU 0X04 ; указатель адреса в памяти данных PORTA EQU 0X05 ; порт A PORTC EQU 0X07 ; порт C PCLATH EQU 0X0A ; верхние 5 бит программного счетчика INTCON EQU 0X0B ; регистр контроля прерываний TRISA EQU 0X85 ; управляющий регистр порта A TRISC EQU 0X87 ; управляющий регистр порта C OPTION_REG EQU 0X81 ; регистр option EEADR EQU 0X9B ; адресный регистр EEPROM EECON1 EQU 0X9C ; содержит бит RD EEDAT EQU 0X9A ; прочитанные из EEPROM данные PCON EQU 0X8E ; регистр power control PIE1 EQU 0X8C ; регистр контроля периферийных прерываний PIR1 EQU 0X0C ; регистр флагов прерываний от ; периферийных модулей

присвоение значений символьным константам

RP0 EQU 0X05 ; бит-указатель страницы данных в STATUS W EQU 0X00 ; file register designator = W F EQU 0X01 ; file register designator = F Z EQU 0X02 ; бит нуля в STATUS C EQU 0X00 ; бит преноса в STATUS RD EQU 0X00 ; инициализация чтения EEPROM POR EQU 0X01 ; бит POR регистра PCON обнуляется, если был ; сброс по включению питания BOR EQU 0X00 ; сброс по снижению питания TMR1IF EQU 0X00 ; бит переполнения TMR1 in register PIR1 TMR1ON EQU 0X00 ; GIE EQU 0X07 ; TMR1IE EQU 0X00 ; бит разрешения прерываний от TMR1 PON EQU 0X00 ; POWER ON IN FLAG

=================================================================
vector table

ORG 0X000 ; стартовый адрес GOTO START ;

==================================================================
TIMER1 INTERRUPT

ORG 0X004 ; адрес прерывания MOVWF TMPW ; сохраняем W SWAPF STATUS,W MOVWF TMPS ; сохраняем STATUS

BTFSC PIR1,0 ; прерывание от TMR1? GOTO T1_INT ; да

       NOP			; обработчик левого прерывания

GOTO END_ISR ;

T1_INT MOVF TX_ALL_CNT,W ; вычитание SUBWF TX_OFF,W ; TX_OFF-TX_ALL_CNT

BCF FLAG,0 ; SKPC ; пропустить, если результат >=0 BSF FLAG,0 ;





MOVF TX_ALL_CNT,W ; ускоряемся за 10 сек до конца цикла
SUBLW D'125' ; ставим флаг, по которому во время передачи
SKPNZ ; меняем скорость
BSF FLAG,4 ; только при 5 мин цикле

; использовать либо верхнее, либо нижнее

;SUBLW D'250' ; а это костыль для ускорения за 10 сек ;SKPNZ ; до конца любого цикла, даже если ;BSF FLAG,4 ; работаем непрерывно

DECFSZ TX_ALL_CNT,F ; TX_ALL_CNT-1, пропустить, если 0 GOTO POP_TX MOVF TX_ALL,W ; восстанавливаем MOVWF TX_ALL_CNT ;

BCF FLAG,4 ; в конце цикла сбросить флаг ускорения

POP_TX

      	DECFSZ SEC_CNT, F	; SEC_CNT-1

GOTO POP ; MOVLW D'150' ; 300 секунд = 5 мин MOVWF SEC_CNT

BTFSS FLAG,2 ; если задержка активирована, то BSF FLAG,3 ; через 5 мин после запуска поднимаем флаг ; отмены задержки включения

BTFSC FLAG,2 ; если флаг разрешения работы установлен, начинаем отсчет ; задержки отключения DECF MIN_CNT,F ; MIN_CNT-1 минуты работы считаем после ; окончании задержки включения


DECFSZ DELAY,F ; DELAY-1, пропустить след, если 0 GOTO POP ; задержка окончилась BSF FLAG,2 ; устанавливаем флаг разрешения работы


POP BCF PIR1,0 ; сброс флага переполнения

END_ISR SWAPF TMPS,W ; восстанавливаем регистры W and SATUS MOVWF STATUS ; SWAPF TMPW,F ; SWAPF TMPW,W ; RETFIE ; возврат из прерывания

==================================================================
Начало основной программы
==================================================================

START MOVLW B'10001110'  ; BSF STATUS, RP0 ; bank 1 MOVWF OPTION_REG ; инициализация регистра option BCF STATUS, RP0 ; bank 0

CLRF PORTA ; очистка порта A CLRF PORTC ; очистка порта C

MOVLW B'00000111' ; MOVWF CMCON ; запрещаем работу компаратора

BSF STATUS, RP0 ; bank 1 MOVLW B'00000000' ; MOVWF TRISA ; порт A - все выходы MOVLW B'11111111' ; MOVWF TRISC ; порт C - все входы BCF STATUS, RP0 ; bank 0

CLRF TMR0 ; на всякий случай. Говорят, надо... CLRWDT ; сбрасываем WDT


==================================================================
инициализация TMR1

CLRF T1CON ; очистить TIMER1 control register CLRF TMR1H ; очистить верхний байт TMR1 CLRF TMR1L ; очистить нижний байт TMR1 CLRF INTCON ; запретить прерывания BSF STATUS,RP0 ; bank 1 CLRF PIE1 ; очистить рег контроля периферийных прерываний BCF STATUS, RP0 ; bank 0 CLRF PIR1 ; очистить рег флагов периферийных прерываний MOVLW B'00001110' ; инициализация TIMER1 control register MOVWF T1CON ; с этого момента генератор 32.768 включен


==================================================================

MOVLW D'150' ; инициализация счетчика пар секунд MOVWF SEC_CNT ; 150 пар = 300 сек = 5 мин

       DECF SEC_CNT,F		; имитируем прерывание

;MOVLW D'2' ; сколько пятиминуток будем работать MOVLW D'96' ; сколько пятиминуток будем работать MOVWF MIN_CNT ; 96х5=8 час

MOVLW D'2' ; сколько пятиминуток задержка включения

MOVLW D'24' ; сколько пятиминуток задержка включения MOVWF DELAY ; 24х5=120 мин

MOVLW D'178' ; тон звука, 178 ~ 1000 Гц MOVWF SET_TONE ; чем больше, тем ниже частота

BSF FLAG,0 ; поднимаем флаг

BCF FLAG,4


==================================================================
если это включение питания, то выполняется задержка для
гарантированного запуска генератора 32768 и его инициализация
если другой сброс, то инициализация и задержка пропускаются

BSF STATUS, RP0 ; bank 1 MOVF PCON,W ; PCON -> W BCF STATUS, RP0 ; bank 0

MOVWF TMPW ; W -> TMPW BTFSS TMPW,POR ; проверяем состояние POR, если 0, то был сброс GOTO DELAY_START ; по включению - задержка однозначно нужна BTFSC TMPW,BOR  ; а это был сброс по снижению напр питания

       GOTO SKIP_DELAY         ; или не был...

DELAY_START

BCF FLAG,3 ; при первом включении очистить FLAG,3

; задержка MOVLW D'255' ; скорость передачи MOVWF CW_SPEED ; чем больше, тем медленней

	MOVLW 0X80	

MOVWF CW_CHAR ;

       CALL SEND_ONE_CHAR	; в качестве задержки предаем 7 точек

BSF STATUS, RP0 ; bank 1 BSF PCON,POR ; устанавливаем POR=1 BSF PCON,BOR ; устанавливаем BOR=1 BCF STATUS, RP0 ; bank 0

SLEEP ; ожидаем запуск

SKIP_DELAY


==================================================================
читаем переключатель

BSF PORTA,2 ; на 11 ноге висят подтягивающие резисторы, ; подключенные к переключателю ; после считывания напряжение с переключателя ; снимается для экономии энергии


       MOVF PORTC,W		; читаем порт C

ANDLW B'00011100' ; маска MOVWF SWITCH ; сохраняем состояние переключателя

       MOVF PORTC,W		; читаем порт C

ANDLW B'00000011' ; маска двух младших бит

BCF FLAG,2 ; обнуляем флаг задержки BTFSC PORTC,5 ; если перекл. on (на землю, 0) пропуск. след. BSF FLAG,2 ; устанавливаем флаг, можно работать

BCF PORTA,2 ; отключаем подтягивающие резисторы

ADDWF PCL,F ; таблица GOTO SW00 GOTO SW01 GOTO SW10 GOTO SW11 SW00 ; непрерывно MOVLW D'0' ; молчим последние 0 с MOVWF TX_OFF ; MOVLW D'30' ; цикл 60 сек GOTO END_SW SW01 ; цикл 30сек/120сек MOVLW D'60' ; молчим последние 120 с MOVWF TX_OFF ; MOVLW D'75' ; цикл 150 сек GOTO END_SW SW10 ; цикл 1 мин/1 мин MOVLW D'30' ; молчим последние 60 с MOVWF TX_OFF ; MOVLW D'60' ; цикл 120 сек GOTO END_SW SW11 ; цикл 1 мин/4 мин MOVLW D'120' ; молчим последние 4 m MOVWF TX_OFF ; MOVLW D'150' ; цикл 5 m

END_SW MOVWF TX_ALL ; MOVWF TX_ALL_CNT ; инициализация

       DECF TX_ALL_CNT,F	; считаем, что 1 прерывание уже случилось
==================================================================
Окончание инициализации TIMER1

MOVLW B'11000000' ; разрешить прерывания от периферийных модулей MOVWF INTCON

BSF STATUS,RP0 ; bank 1 BSF PIE1,TMR1IE ; разрешить прерывания от TMR1 BCF STATUS, RP0 ; bank 0 BSF T1CON,TMR1ON  ; TMR1 ON


==================================================================
Если с момента запуска прошло 5 мин, то при сбросе задержку
включения игнорируем

BTFSC FLAG,3 ; FLAG,3 поднимается через 5 м после начала ; работы BSF FLAG,2 ; задержка включения не нужна

==================================================================
MAIN
передача последовательности символов
можно предавать любое количество, 0XFF означает конец последовательности,
после чего формируется пауза и передача циклически повторяется

SEND_MSG

                               ; если автоотключение не нужно, то три 

; нижеследующих строчки надо закомментировать MOVF MIN_CNT,F ; проверяем, не обнулился ли SKPNZ ; счетчик пятиминуток GOTO POWER_OFF ; если да, то выключаемся

BTFSS FLAG,2 ; пропустить след, если задержка включения ; кончилась (1-разрешение работы) GOTO FLASH ; мигнуть и sleep

       BTFSS FLAG,0		; если флаг сброшен

BSF PORTA,2 ; TX выключаем

       BTFSS FLAG,0		; если флаг сброшен, то идем спать

GOTO TO_SLEEP


BSF PORTA,2 ; на 11 ногу можно повесить управление TX


MOVF SWITCH,W MOVWF CHAR_INDEX ; SWITCH -> CHAR_INDEX

GET_MSG MOVF CHAR_INDEX,W BCF INTCON,GIE ; запрещаем прерывания BSF STATUS, RP0 ; bank 1 MOVWF EEADR ; значение CHAR_INDEX = адресу кода в EEPROM BSF EECON1,RD ; разрешаем чтение EEPROM MOVF EEDAT,W ; значение ячейки -> регистр W BCF STATUS, RP0 ; bank 0 BSF INTCON,GIE ; разрешаем прерывания ;MOVLW 0x06 MOVWF CW_CHAR ; W -> CW_CHAR

MOVLW 0XFF ; конец сообщения? SUBWF CW_CHAR,W ; SKPNZ GOTO END_MSG ; да, перейти к END_MSG

MOVLW D'60' ; скорость передачи быстро
BTFSS FLAG,4 ; устанавливается за 10 с до конца цикла

MOVLW D'80' ; скорость передачи медленно MOVWF CW_SPEED ; чем больше, тем медленней

CALL SEND_CHAR ; передаем букву и паузу в 3 точки

                               ; или паузу 6 точек, если SPACE

INCF CHAR_INDEX ; CHAR_INDEX+1 GOTO GET_MSG

END_MSG CALL WORD_SPACE  ; пауза 6 точек GOTO SEND_MSG ;

; время работы закончилось POWER_OFF ; отсюда выход только через RESET

CLRF FLAG ; очистка регистра флагов CLRF T1CON ; очистить TIMER1 control register, выключаем ; генератор 32768 ;BCF T1CON,TMR1ON  ; TMR1 OFF CLRF INTCON ; запретить прерывания

; после сброса считаем, что это сброс по питанию BSF STATUS, RP0 ; bank 1 BCF PCON,POR ; устанавливаем POR=0 BCF PCON,BOR ; устанавливаем BOR=0 BCF STATUS, RP0 ; bank 0

TO_SLEEP ; CLRF PORTA SLEEP NOP GOTO SEND_MSG

========================================================================
индикатор включенной задержки
мигаем порт A.1

FLASH MOVLW D'60' ; скорость передачи MOVWF CW_SPEED ; чем больше, тем медленней BSF PORTA,1 MOVLW 0X01 ; MOVWF NBR_SPACE ; пауза в 1 точку CALL SEND_SPACE ; BCF PORTA,1 GOTO TO_SLEEP

========================================================================
SEND_CHAR
Подпрограмма получает код символа в регистре CW_CHAR, побитно перебирает
его, и, в зависимости от состояния бита, передает
тире, если бит = 1;
точку, если бит = 0.
Знак передается, пока в слове есть хоть одна единица. Последняя единица
"съедается", она означает конец слова.

SEND_CHAR MOVLW 0X00 ; пауза? SUBWF CW_CHAR,W ; SKPNZ ; GOTO WORD_SPACE

SEND_ONE_CHAR

       BTFSS FLAG,0		; обрываем передачу, если флаг сброшен

RETURN

CLRC ; очистить бит переноса RRF CW_CHAR, F ; сдвиг вправо через перенос ; MOVF CW_CHAR, F  ; проверяем содержимое CW_CHAR, если все "0" SKPNZ  ; то Z=1, выполняем RETURN, иначе пропускаем GOTO PAUSE2 ; конец буквы SKPC ; проверить бит переноса, пропустить, если=1 GOTO SEND_A_DIT ; перейти к SEND_A_DIT

SEND_A_DAH ; передаем тире MOVLW 0X03 ; 1 тире = 3 точки MOVWF NBR_DIT MOVLW 0X01 ; MOVWF NBR_SPACE ; после тире - пауза в 1 точку BSF PORTA,0 ; включаем PORT A.2 CALL SEND_TONE ; генериуем звук, оно же - пауза BCF PORTA,0 ; выключаем PORT A.2 CALL SEND_SPACE GOTO SEND_ONE_CHAR

SEND_A_DIT MOVLW 0X01 ; передаем точку MOVWF NBR_DIT MOVWF NBR_SPACE ; после точки - пауза в 1 точку BSF PORTA,0 ; включаем PORT A.2 CALL SEND_TONE  ; генерируем звук, оно же - пауза BCF PORTA,0 ; выключаем PORT A.2 CALL SEND_SPACE GOTO SEND_ONE_CHAR

PAUSE2 MOVLW D'2' ; пауза в 2 точки после буквы MOVWF NBR_SPACE ; CALL SEND_SPACE  ; RETURN

WORD_SPACE MOVLW D'6' ; пауза в 6 точек между словами MOVWF NBR_SPACE ; CALL SEND_SPACE  ; RETURN

==================================================================
SEND_TONE
Подпрограмма осуществляет задержку и одновременно формирует сигнал
звуковой частоты (порт A.1)

SEND_TONE

MOVF NBR_DIT, W ; NBR_DIT кол-во пропускаемых точек MOVWF CTR_NBR ;

DIT_LENGTH MOVF CW_SPEED, W ; CW_SPEED скорость передачи MOVWF CTR_DIT ;

START_CYCLE BSF PORTA,1 ; A.1=1 в начале цикла MOVF SET_TONE,W ; MOVWF TONE ; заносим значение в счетчик цикла задержки

HIGH_HALF DECFSZ TONE, F ; считаем до нуля GOTO HIGH_HALF BCF PORTA,1 ; A.1=0 в конце цикла

MOVF SET_TONE,W ; MOVWF TONE

LOW_HALF DECFSZ TONE, F ; GOTO LOW_HALF DECFSZ CTR_DIT, F ; GOTO START_CYCLE DECFSZ CTR_NBR, F GOTO DIT_LENGTH ; RETURN ;

================================================================
SEND_SPACE
Делает тоже самое, что и SEND_TONE, только вместо команд управления
портами стоит команда NOP

SEND_SPACE

MOVF NBR_SPACE, W ; MOVWF CTR_NBR

DIT_LENGTH_SP MOVF CW_SPEED, W ; MOVWF CTR_DIT

START_CYCLE_SP NOP MOVF SET_TONE,W MOVWF TONE ;

HIGH_HALF_SP DECFSZ TONE, F ; GOTO HIGH_HALF_SP NOP MOVF SET_TONE,W MOVWF TONE

LOW_HALF_SP DECFSZ TONE, F ; GOTO LOW_HALF_SP DECFSZ CTR_DIT, F ; GOTO START_CYCLE_SP DECFSZ CTR_NBR, F GOTO DIT_LENGTH_SP ; RETURN ;

==================================================================
==================================================================
Идентификатор

ORG 0x2000 ; стартовый адрес

       DATA 0x0132
       DATA 0xF321
       DATA 0x0000
       DATA 0x0000
==================================================================
Слово конфигурации

ORG 0x2007 ; стартовый адрес

DATA 0x31E4

DATA 0x1024 ; вкл защиту данных

DATA 0x11A4
==================================================================
Запись в EEPROM при программировании
Переключателем адресуется номер ячейки, кратный 4. Соответственно, маяк
может передавать последовательно три символа Морзе, четвертым обязательно
должен быть EOM
В последнюю адресуемую ячейку можно записать большее количество символов

ORG 0X2100 ; стартовый адрес

DATA 0x07 ; M -- 00000111 DATA 0x0F ; O --- 00001111

       DATA 0xFF	; EOM     11111111
       DATA 0xFF	; EOM     11111111

DATA 0x07 ; M -- 00000111 DATA 0x0F ; O --- 00001111

       DATA 0x02	; E .     00000010  	
       DATA 0xFF	; EOM     11111111

DATA 0x07 ; M -- 00000111 DATA 0x0F ; O --- 00001111 DATA 0x04 ; I .. 00000100

       DATA 0xFF	; EOM     11111111

DATA 0x07 ; M -- 00000111 DATA 0x0F ; O --- 00001111 DATA 0x08 ; S ... 00001000

       DATA 0xFF	; EOM     11111111

DATA 0x07 ; M -- 00000111 DATA 0x0F ; O --- 00001111 DATA 0x10 ; H .... 00010000

       DATA 0xFF	; EOM     11111111

DATA 0x07 ; M -- 00000111 DATA 0x0F ; O --- 00001111 DATA 0x20 ; 5 ..... 00100000

       DATA 0xFF	; EOM     11111111

DATA 0x07 ; M -- 00000111 DATA 0x0F ; O --- 00001111 DATA 0x03 ; T - 00000011

       DATA 0xFF	; EOM     11111111

DATA 0x09 ; D DATA 0x02 ; E DATA 0x00 ; PAUSE DATA 0x0A ; R .-.

       DATA 0x06	; A .-
       DATA 0x3E	; 1 .----
       DATA 0x06	; A .-
       DATA 0x07	; M --
       DATA 0x0E	; W ---

DATA 0x00 ; PAUSE DATA 0x11 ; B DATA 0x02 ; E DATA 0x06 ; A DATA 0x15 ; C DATA 0x0F ; O --- 00001111 DATA 0x05 ; N

       DATA 0xFF	; EOM     11111111

END