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

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

Контроллер маяка на PIC16F630
Контроллер маяка на PIC16F630 в корпусе
; время работы 3 часа
; 11-06-05
; после прошествия 5 минут с момента начала отсчета задержки
; сброс приводит к запуску без задержки.
; Например, если сброс произошел не 3 минуте работы, то задержка включения
; будет отсчитываться с этого момента. Если сброс на 6 минуте, то 
; с этого момента начнется работа, состояние переключателя игнорируется.
; !! Выяснилась небольшая проблема - если при включенном питании переключить
; переключатель разрешения задержки в положение ON и при этом от первого запуска
; уже прошло 5 мин, задержка не включится.
; 10-06-05
; полностью переделана инициализация TMR1
; после _второго_ (и последующих) сброса задержка включения не выполняется,
; но из-за дребезга контактов кнопки сброс момент пуска с задержкой можно
; проскочить

; добавить: 
;	после _второго_ (и последующих) сброса задержка включения не выполняется
;	ускорение в конце минуты
;	всю индикацию выводить на A.1
; 07-06-04
; Задержка включения: проверяется установка перелючателя, в прерывании 
; уменьшается счетчик DELAY, когда ноль, устанавливается бит FLAG,2
; Если он 0, то каждые 2 сек мигает LED на PORTA,1, и контроллер
; уходит в SLEEP. Если 1, то разрешается работа.
; 04-06-05
; за основу взят mf21
; добавлен цикл 1м/4м
; 8 позывных, старт после включения питания, сброс обнуляет часы
;
; PORTA,0 манипуляция
; PORTA,1 выход звука, зеленый LED
; PORTA,2 подтягивающие резисторы
;
; 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 мин после начала работы
			; и отменяет задержку включения при сбросе

	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		;

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

       	DECFSZ SEC_CNT, F	; SEC_CNT-1
	GOTO POP		; 
	MOVLW D'150'		; 300 секунд = 5 мин
	MOVWF SEC_CNT
	
	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 ноге висят подтягивающие резисторы,
				; подключенные к переключателю
				; после считывания напряжение с переключателя
				; снимается для экономии энергии

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

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

;	MOVLW D'2'		; сколько пятиминуток задержка включения
	MOVLW D'24'		; сколько пятиминуток задержка включения
	MOVWF DELAY		; 24х5=120 мин
	
	MOVLW D'178'		; тон звука, 178 ~ 1000 Гц
	MOVWF SET_TONE		; чем больше, тем ниже частота

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


;==================================================================
; читаем переключатель
;
        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 прерывание уже случилось

;==================================================================
; если это включение питания, то выполняется задержка для
; гарантированного запуска генератора 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

	; инициализация 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'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

;==================================================================
; Окончание инициализации TIMER1
;
	CLRF TMR1H		; очистить верхний байт TMR1
	CLRF TMR1L		; очистить нижний байт TMR1

	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'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
	BCF T1CON,TMR1ON        ; TMR1 OFF
	CLRF INTCON		; запретить прерывания

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