В этой статье описываются алгоритмы и программы для микроконтроллеров, управляющих излучателем и приёмником ИК-барьера. Как вы помните, излучатель у нас сделан на микроконтроллере PIC12F629, а приёмник — на ATtiny13.
Начнём с излучателя. Он у нас занимается тем, что посылает чередующиеся сигналы «ON» (импульсы на частоте 36 кГц) и «OFF» (отсутствие импульсов). Длительность сигнала «ON» около 500 мкс, а длительность сигнала «OFF» около 1500 мкс.
За основу программы для излучателя возьмём программу, написанную нами ранее для реализации протокола RC-5. Отличие будет только в том, что в RC-5 длительности сигналов «ON» и «OFF» были одинаковы и равны 888,864 мкс. (описание протокола RC-5, реализация RC-5 на PIC12F629)
Переходим к приёмнику. При описанных выше сигналах излучателя, на выходе приёмника будут импульсы с периодом около 2 мс. Причём, поскольку сигнал на выходе фотоприёмника ILMS5360 инвертированный, то у этих импульсов время высокого уровня сигнала будет около 1500 мкс, а время низкого уровня около 500 мкс. Но это так, к слову. На самом деле нам важно не это. Нам важно, что на выходе фотоприёмника будут импульсы, то есть состояние выхода будет меняться не реже, чем 1 раз в 1500 мкс. Именно по этому факту мы и будем судить о том, что сигнал от излучателя не потерян.
В программе мы поступим следующим образом — запустим таймер, настроенный таким образом, что его переполнение произойдёт через время чуть меньше 2 мс (с запасом) и включим прерывание от изменения уровня сигнала на входе от фотоприёмника. При срабатывании прерывания от входа будем перезапускать этот таймер. Таким образом, пока фотоприёмник будет видеть сигнал — таймер не переполнится, а переполнение таймера будет признаком того, что сигнал от излучателя пропал.
Светодиод будет показывать состояние сигнала: гореть при наличии сигнала и не гореть при его отсутствии.
Кнопка нужна для переключения в рабочий режим. При включении, приёмник будет стартовать в настроечном режиме, в котором не будет срабатывать выходное реле (но будет работать светодиодная индикация), а через некоторое время после нажатия на кнопку, контроллер будет переводиться в рабочий режим, в котором уже при пропадании входного сигнала будет срабатывать реле.
Проверкой того, не нажата ли кнопка, контроллер будет заниматься в свободное от всех других дел время.
Ну вот, пожалуй и всё, переходим к алгоритмам:
list p = 12f629 __config 01FE4h ;********* Переменные *********************************** CBLOCK 0x20 ;Начальный адрес блока констант T_Cr ;таймер несущей C_imp ;счетчик количества импульсов ENDC ;******** Константы ************************************* Cr1 equ .2 ; длительность 1 несущей Cr0 equ .4 ; длительность 0 несущей NCr equ .19 ; кол-во импульсов несущей в пакете (500 uS) MCr equ .53 ; пауза между пакетами (1500 us) Status equ 03h ; Регистр выбора банка GPIO equ 05h ; Регистр управления защелками порта Cmcon equ 19h ; Регистр компаратора TrisIO equ 05h ; Регистр выбора направления работы выводов INTCON equ 0Bh ; Регистр разрешения(1)/запрета(0) прерываний OSCCAL equ 10h ; Регистр хранения калибровочной константы F equ 1 ; Результат направить в регистр. ;******************************************************** ; GP0 - выход на транзистор, GP1, GP2, GP4, GP5 - входы ;******************************************************** org 0 ;******** КОНФИГУРИРОВАНИЕ КОНТРОЛЛЕРА ****************** start ;****** Калибровка Генератора *************************** bsf Status,5 Call 3FFh ; Загрузить калибровочную константу в w movwf OSCCAL ;******** Установка направления работы выводов ********** bcf Status,5 ; перейти в банк 0 clrf GPIO ; инициализация защелок (везде нули) movlw .7 ; биты 0..2 поднять movwf Cmcon ; компаратор выкл, GP0-GP2 - цифровые bsf Status,5 ; перейти в 1-й банк movlw .62 ; Записать конфигурацию GPIO в W movwf TrisIO ; Скопировать конфиг. GPIO из W в TrisIO bcf Status,5 ; перейти в 0-й банк ;***** Передача единичного полубита ********************* RCY movlw NCr ; поместить константу NCr в аккумулятор movwf C_imp ; скопировать W в регистр C_imp Y_001 movlw Cr1 ; поместить константу Cr1 в аккумулятор movwf T_Cr ; скопировать W в регистр T_Cr (таймер несущей) bsf GPIO,0 ; установить на выходе GP0 единицу Cr1_Y decfsz T_Cr,F ; декремент T_Cr с ветвлением ; если результат не 0, - исполняется ; следующая инструкция, ; иначе - nop вместо неё goto Cr1_Y ; переход на метку Cr1_Y nop bcf GPIO,0 ; установить на выходе GP0 ноль movlw Cr0 ; поместить константу Cr0 в W movwf T_Cr ; скопировать W в регистр T_Cr Cr0_Y decfsz T_Cr,F goto Cr0_Y decfsz C_imp,F goto Y_001 ;***** Передача низкого уровня ************************** RCN movlw MCr ; поместить константу MCr в аккумулятор movwf C_imp ; скопировать W в регистр C_imp N_001 movlw Cr1 movwf T_Cr nop ; вместо bsf GPIO (для выравнивания) Cr1_N decfsz T_Cr,F goto Cr1_N nop nop nop ; вместо bсf GPIO movlw Cr0 movwf T_Cr Cr0_N decfsz T_Cr,F goto Cr0_N decfsz C_imp,F goto N_001 goto RCY ;******************************************************** end |
.device ATtiny13 .include "tn13def.inc" .list ;-- определяем свои переменные .def w=r16 ; это будет наш аккумулятор .def Flags=r17 ; если бит 0=1 - начинаем отсчёт для ; переключения в рабочий режим .def TTimer=r18 ; для отсчёта времени от нажатия на кнопку ; до переключения в рабочий режим .equ TTW=15 ; начальное значение TTimer .equ TTC=180 ; начальное значение TMR0 ;-------------------------- .equ IR_IN=2 ; вход фотоприемника PB2 .equ BUTTON=0 ; вход кнопка PB0 .equ LDIODE=4 ; выход светодиод PB4 .equ RELE=3 ; выход реле PB3 ;-- Используемые регистры ; SPL - указатель вершины стека ; ACSR - управление компаратором ; DDRB - направление работы ног ; PORTB - выходы порта ; GIMSK - общее разрешение прерываний от ног ; PCMSK - выбор от каких ног разрешить прерывание ; TCCR0B - управление таймером ; TIMSK0 - прерывания от таймера ; TCNT0 - значение таймера ; OCR0A - значение модуля сравнения ; TIFR0 - флаги прерываний от таймера ;-- начало программного кода .cseg .org 0 rjmp Init ; переход на начало программы ;-- вектора прерываний reti ; INT0 rjmp PinChange ; Pin Change rjmp TimerOverflow ; Timer reti ; EEPROM reti ; comparator reti ; timer compare match A reti ; timer compare match B reti ; watchdog reti ; ADC ;-- начало программы Init: ldi w,RAMEND ; устанавливаем указатель вершины out SPL,w ; стека на старший байт RAM sbi ACSR,7 ; выключаем компаратор ldi w,1<<LDIODE|1<<RELE ; определяем входы/выходы (1-вых, 0-вх) out DDRB,w com w ; подтягивающие резисторы включены cbr w,1<<IR_IN ; (кроме IR_IN), начальное out PORTB,w ; состояние выходов = 0 ;-- включить прерывания от ИК-приёмника ldi w,1<<IR_IN ; выбираем ногу, к которой подключен ИК out PCMSK,w ldi w,1<<PCIE ; разрешаем прерывание PinChange out GIMSK,w ;-- настраиваем таймер (сколько отводится на изменение сигнала на входе) clr w out TCCR0A,w ; вых.OCR0A, OCR0B откл., Normal Mode ldi w,TTC ; записываем начальное значение таймера out TCNT0,w ldi w, 1<<TOIE0 ; прерывание по переполнению out TIMSK0,w ldi TTimer,TTW ; начальное значение счетчика ;-- включаем таймер и прерывания ldi w,0b00000100 ; включить таймер, Normal Mode, /256 out TCCR0B,w sei ;-- начало работы Start: sbic PINB, BUTTON ; если кнопка нажата - rjmp Start ; пропустить эту команду sbr Flags,1<<0 ; устанавливаем 0-й бит (начинаем отсчёт ; до переключения в рабочий режим) rjmp Start ;---------------------------------------------------------------------- ;--- Interrupts --- ;--- если сработал таймер - действия в зависимости от режима TimerOverflow: cbi PORTB, LDIODE ; выключаем светик (сигнал пропал) brtc TR_and_TF ; если флаг T сброшен - прыгаем Work: sbi PORTB, RELE ; включаем реле rjmp Work ; и уходим в глухой цикл ;--- сбрасываем таймер и если надо - доотсчитываем до рабочего режима PinChange: sbi PORTB, LDIODE ; включаем светик TR_and_TF: ; (timer reset and flag test) ldi w,TTC ; записываем начальное значение таймера out TCNT0,w ; (то есть перезапускаем его) sbrs Flags,0 ; если 0-й флаг установлен - reti ; пропускаем эту команду inc TTimer ; увеличиваем счётчик breq Set_Work ; если переполнился - прыгаем reti ; выход Set_Work: ; переходим в рабочий режим set ; устанавливаем флаг T reti ; выход ;---------------------------------------------------------------------- |
Чтобы всё корректно работало — в тиньке должны быть «запрограммированы» фьюзы SPIEN, SUT0 и CKSEL0 (то есть в PonyProg напротив них должны стоять галочки). Кроме того, не затрите случайно калибровочную константу в пике.