Наш магазин на eBay Наш магазин на AliExpress Наш канал в telegram

Простейшая программа для самодельного ИК-приемника, протокол NEC (кодирование длиной паузы)

В этой статье рассмотрена простейшая программа для самодельного ИК-приемника сигналов дистанционного управления на контроллере PIC12F629. Если вы измените аппаратную часть (например, будете использовать другой порядок ног, повесите внешний генератор), то программу так же нужно будет переделать.

Программа реализует следующие функции:

1) Прием кода NEC, определение версии (стандартный или расширенный NEC).

2) В рабочей части программы реализуется управление четырьмя светодиодами. При получении адреса CB04h и команды 4Ah инвертируется состояние выходов GP0, GP1, GP2, GP4 (при старте на выходах GP2, GP4 установлен высокий уровень, а на GP0, GP1 — низкий).

Прежде чем разбираться с программой, советую посмотреть описание протокола NEC.

Основные идеи алгоритма:

1) Выход ILMS1836 — инвертированный, т.е. когда принимается "1" — на выходе фотоприемника "0" (низкий уровень), когда приема нет или принимается "0" — на выходе фотоприемника "1" (высокий уровень).

2) При появлении прерывания от входа фотоприёмника устанавливается специальный флаг, сигнализирующий о том, что идёт приём и запускается таймер на 16,4 мс. При последующих прерываниях проверяется уровень сигнала на входе и в специальный буфер записывается время (по таймеру) между прерываниями, произошедшими в результате перехода входного сигнала с высокого уровня на низкий. Таким образом измеряется длина каждого бита. Переполнение таймера сигнализирует об ошибке (в течении 16 мс уровень на входе не изменяется). После приёма всех бит пакета, мы из записанных 32 байт с длительностями импульсов восстанавливаем 4 байта исходного пакета.
Общий размер буфера 33 байта: длительности 32-х битов + длительность стартового импульса.

3) Если третий байт равен инвертированному четвёртому байту, то приём осуществлён без ошибок.

4) Если первый байт равен инвертированному второму байту, то мы имеем дело с обычным NEC, в противном случае — с расширенным NEC.

Алгоритм:

Алгоритм работы самодельного ИК-приёмника (протокол NEC)
Алгоритм работы самодельного ИК-приёмника (протокол NEC)
Алгоритм работы самодельного ИК-приёмника (протокол NEC)
Алгоритм работы самодельного ИК-приёмника (протокол NEC)
Текст программы под катом

 list    p = 12f629
 __config 01FC4h
;*** Переменные ******************************************
  CBLOCK 0x20    ; Начальный адрес блока пользовательской памяти
    Flags        ; регистр флагов
; 0 бит - приём, 1 бит - наличие необраб.инфы, 2 бит - наличие обработ.инфы
; 3-й бит Trial NEC, 4-й бит - Extended NEC
    Counter      ; резервная переменная
    ADDRESS_LOW  ; младший байт адреса
    ADDRESS_HIGH ; старший байт адреса
    COMMAND      ; команда
    INV_COMMAND  ; инвертированная команда
; далее 33 байт, в которые записываются длительности пауз
; адреса:26, 27-2Eh, 2Fh-36h, 37h-3eh, 3fh-46h
  ENDC
;**** Константы / Адреса регистров ************************
Status  equ  03h         ; выбор банка
GPIO    equ  05h         ; регистр управления защелками порта. (банк 0)
Cmcon   equ  19h         ; регистр Cmcon - компаратора (банк 0)
TrisIO  equ  05h         ; выбор направления работы выводов порта
INTCON  equ  0Bh         ; регистр разрешения(1)/запрета(0) прерываний
IOCB    equ  16h         ; индивидуальная настройка прерываний для входов
OPT_REG equ  01h         ; настройка таймера (банк 1)
TMR0    equ  01h         ; регистр таймера (банк 0)
OSCCAL  equ  10h         ; регистр хранения калибровочной константы
INDF    equ  0h          ; регистр косвенной адресации
FSR     equ  04h         ; регистр адреса при косвенной адресации
AL      equ  b'00000100' ; адрес 04h (заданный младший байт адреса)
AH      equ  b'11001011' ; адрес CBh (заданный старший байт адреса)
COM     equ  b'01001010' ; команда 4Ah, inv B5h
; код команды, при получении которой должны выполняться действия
;**********************************************************
; Пусть у нас GP5 - вход фотоприёмника, GP0, GP1, GP2, GP4 - выходы
;**********************************************************
 
     org 0
;**********************************************************
;*** КОНФИГУРИРОВАНИЕ КОНТРОЛЛЕРА *************************
;*** Калибровка Генератора ********************************
start  bsf    Status,5
       Call   3FFh     ; Загрузить калибровочную константу в w
       movwf  OSCCAL
       goto   main
;*** ПОДПРОГРАММА ПРЕРЫВАНИЯ ******************************
     org 4
       movf   PIO,0
       btfss  INTCON,0 ; если бит 0 установлен - было прерывание от входов
       goto   errors
;--- Прерывание от входов ---
       btfsc  GPIO,5   ; если на входе низкий уровень - начало импульса
       goto   exit
;--- Проверка моих флагов ---
       btfss  Flags,0  ; если сброшен флаг 0, то у нас новый приём
       goto   new_rec
;--- Продолжение приёма ---
       movf   TMR0,0   ; считать и сохранить время
       movwf  INDF
;--- Перезапуск таймера ---
       clrf   TMR0
;---------------------------------------------------------
       incf   FSR,1    ; увеличить адрес
       movlw  47h      ; проверяем значение указателя
       xorwf  FSR,0
       btfss  Status,2 ; если указатель=47 - приём окончен
       goto   exit
;--- Окончание приёма ---
       bcf    Flags,0
       bsf    Flags,1  ; устанавливаем флаг наличия принятой информации
       bcf    INTCON,5 ; запрещаем прерывания
       bcf    INTCON,3
       return
;--- Новый приём ---
new_rec
       bsf    Flags,0
       movlw  26h
       movwf  FSR       ; установить адрес на приём
;--- Перезапуск таймера ---
       clrf   TMR0
;---------------------------------------------------------
       bcf    INTCON,2  ; сбросить флаг переполнения таймера
       bsf    INTCON,5  ; разрешить прерывание от таймера
exit   bcf    INTCON,0  ; сбросить флаг прерывания от входов
       retfie
;*** ПРОДОЛЖЕНИЕ КОНФИГУРИРОВАНИЯ ************************
;--- Установка направления работы ног --------------------
main   bcf    Status,5  ; перейти в банк 0
       clrf   GPIO      ; инициализация защелок (все выходы равны нулю)
       movlw  .7        ; биты 0..2 поднять
       movwf  Cmcon     ; компаратор выкл., GP0, GP1, GP2 - цифровые вх/вых
       bsf    Status,5  ; перейти в 1-й банк
 
       movlw  b'00000101'  ; настройка предделителя 1:64, 64*256=16,384 мс
       movwf  OPT_REG
       movlw  b'00101000'  ; настройка выходов (GP5,GP3 - входы)
       movwf  TrisIO
;--- Настройка прерываний --------------------------------
       bsf    IOCB,5     ; разрешить прерывание по входу GP5
       bcf    Status,5   ; перейти в банк 0
       bsf    INTCON,3   ; разрешить прерывания на входах GPIO
;---------------------------------------------------------
       bsf    GPIO,4     ; инвертированные выходы
       nop
       bsf    GPIO,2
;*** Включение прерываний ********************************
       bsf    INTCON,7   ; разрешить немаскированные прерывания
;*** РАБОЧАЯ ЧАСТЬ ***************************************
work   btfsc  Flags,1    ; если есть необработ-е данные - надо их обработать
       call   Convert
       btfsc  Flags,2    ; если есть обработ-е данные - надо выполнить действие
       call   action
       goto   work
;************************************************
Convert
       movlw  26h
       movwf  FSR         ; устанавливаем указатель на регистр,
                          ; в котором хранится длительность первого импульса
       movf   INDF,0
       addlw  .53         ; 53 - это (инверсия 203)+1, получается равносильно
                          ; вычитанию 211 (13,5мс=211 отсчётов TMR0)
       andlw  b'11110000' ; если кроме 2-х младших битов все остальные равны нулю,
                          ; то анализир-е знач-е лежит в диапаз. от 203 до 203+15
       btfss  Status,2    ; установился флаг Z?
       goto   errors      ; если не попадаем в тайминг, то это не наш протокол
;---------------------------------------------------------
next1  bcf    Status,0    ; сбрасываем флаг переноса (если он вдруг установлен)
       rrf    ADDRESS_LOW,1
       incf   FSR,1
       movf   INDF,0
       addlw  .229        ; 229 - это (инверсия 27)+1, равносильно вычитанию 27
       andlw  b'11110000' ; если кроме 2-х младших битов все остальные равны нулю,
                          ; то анализ-мое знач-е лежит в диапазоне от 27 до 27+15
       btfss  Status,2    ; установился флаг Z?
       goto   Nol1        ; если не попадаем в тайминг "1", то проверяем на "0"
;---------------------------------------------------------
       bsf    ADDRESS_LOW,7 ; пишем "1" в старший бит ADDRESS_LOW
       goto   One1
Nol1   movf   INDF,0
       addlw  .246        ; 246 - это (инверсия 10)+1, равносильно вычитанию 10
       andlw  b'11110000' ; если кроме 2-х младших битов все остальные равны нулю,
                          ; то анализ-мое знач-е лежит в диапазоне от 10 до 10+15
       btfss  Status,2    ; установился флаг Z?
       goto   errors      ; если не попадаем в тайминг "0", то ошибка
;---------------------------------------------------------
One1   movf   FSR,0
       sublw  2eh         ; если отсчитали первые 8 бит - идём дальше
       btfss  Status,2    ; установился флаг Z?
       goto   next1       ; если не записали 8 бит - повторяем
;---------------------------------------------------------
next2  bcf    Status,0    ; сбрасываем флаг переноса (если он вдруг установлен)
       rrf    ADDRESS_HIGH,1
       incf   FSR,1
       movf   INDF,0
       addlw  .229        ; 229 - это (инверсия 27)+1, равносильно вычитанию 27
       andlw  b'11110000' ; если кроме 2-х младших битов все остальные равны нулю,
                          ; то анализ-мое знач-е лежит в диапазоне от 27 до 27+15
       btfss  Status,2    ; установился флаг Z?
       goto   Nol2        ; если не попадаем в тайминг "1", то проверяем на "0"
;---------------------------------------------------------
       bsf    ADDRESS_HIGH,7 ; пишем "1" в старший бит ADDRESS_HIGH
       goto   One2
Nol2   movf   INDF,0
       addlw  .246        ; 246 - это (инверсия 10)+1, равносильно вычитанию 10
       andlw  b'11110000' ; если кроме 2-х младших битов все остальные равны нулю,
                          ; то анализ-мое знач-е лежит в диапазоне от 10 до 10+15
       btfss  Status,2    ; установился флаг Z?
       goto   errors      ; если не попадаем в тайминг "0", то ошибка
;---------------------------------------------------------
One2   movf   FSR,0
       sublw  36h         ; если отсчитали вторые 8 бит - идём дальше
       btfss  Status,2    ; установился флаг Z?
       goto   next2       ; если не записали 8 бит - повторяем
;---------------------------------------------------------
next3  bcf    Status,0    ; сбрасываем флаг переноса (если он вдруг установлен)
       rrf    COMMAND,1
       incf   FSR,1
       movf   INDF,0
       addlw  .229        ; 229 - это (инверсия 27)+1, равносильно вычитанию 27
       andlw  b'11110000' ; если кроме 2-х младших битов все остальные равны нулю,
                          ; то анализ-мое знач-е лежит в диапазоне от 27 до 27+15
       btfss  Status,2    ; установился флаг Z?
       goto   Nol3        ; если не попадаем в тайминг "1", то проверяем на "0"
;---------------------------------------------------------
       bsf    COMMAND,7   ; пишем "1" в старший бит COMMAND
       goto   One3
Nol3   movf   INDF,0
       addlw .246         ; 246 - это (инверсия 10)+1, равносильно вычитанию 10
       andlw b'11110000'  ; если кроме 2-х младших битов все остальные равны нулю,
                          ; то анализ-мое знач-е лежит в диапазоне от 10 до 10+15
       btfss  Status,2    ; установился флаг Z?
       goto   errors      ; если не попадаем в тайминг "0", то ошибка
;---------------------------------------------------------
One3   movf   FSR,0
       sublw  3eh         ; если отсчитали третьи 8 бит - идём дальше
       btfss  Status,2    ; установился флаг Z?
       goto   next3       ; если не записали 8 бит - повторяем
;---------------------------------------------------------
next4  bcf    Status,0    ; сбрасываем флаг переноса (если он вдруг установлен)
       rrf    INV_COMMAND,1
       incf   FSR,1
       movf   INDF,0
       addlw  .229        ; 229 - это (инверсия 27)+1, равносильно вычитанию 27
       andlw  b'11110000' ; если кроме 2-х младших битов все остальные равны нулю,
                          ; то анализ-мое знач-е лежит в диапазоне от 27 до 27+15
       btfss  Status,2    ; установился флаг Z?
       goto   Nol4        ; если не попадаем в тайминг "1", то проверяем на "0"
;---------------------------------------------------------
       bsf    INV_COMMAND,7 ; пишем "1" в старший бит INV_COMMAND
       goto   One4
Nol4   movf   INDF,0
       addlw  .246        ; 246 - это (инверсия 10)+1, равносильно вычитанию 10
       andlw  b'11110000' ; если кроме 2-х младших битов все остальные равны нулю,
                          ; то анализ-мое знач-е лежит в диапазоне от 10 до 10+15
       btfss  Status,2    ; установился флаг Z?
       goto   errors      ; если не попадаем в тайминг "0", то ошибка
;---------------------------------------------------------
One4   movf   FSR,0
       sublw   46h        ; если отсчитали четвертые 8 бит - идём дальше
       btfss  Status,2    ; установился флаг Z?
       goto   next4       ; если не записали 8 бит - повторяем
;---------------------------------------------------------
       bcf    Flags,1
       bsf    Flags,2
       return
;*********************************************************
action comf   INV_COMMAND,0 ; пишем в аккумулятор инвертир.команду INV_COMMAND
       xorwf  COMMAND,0   ; сравниваем
       btfss  Status,2    ; установился флаг Z?
       goto   errors      ; если команда не совпад. с инвертир.командой,- ошибка
;---------------------------------------------------------
       comf   ADDRESS_LOW,0  ; пишем в аккумулятор инвертированный адрес
       xorwf  ADDRESS_HIGH,0 ; сравниваем
       btfss  Status,2       ; установился флаг Z?
       goto   ext_nec        ; если не равны, то это Extended NEC
;---------------------------------------------------------
       bsf    Flags,3     ; если равны - поднимаем 3-й бит (Trial NEC)
       goto   next_trial
ext_nec
       bsf    Flags,4     ; если не равны - поднимаем 4-й бит (Extended NEC)
next_trial
       movf   ADDRESS_LOW,0 ; проверка адреса
       xorlw  AL
       btfss  Status,2    ; установился флаг Z?
       goto   errors      ; если адрес не совпадает, то ошибка
       movf   ADDRESS_HIGH,0 ; проверка адреса
       xorlw  AH
       btfss  Status,2    ; установился флаг Z?
       goto   errors      ; если адрес не совпадает, то ошибка
       movf   COMMAND,0   ; проверка адреса
       xorlw  COM
       btfss  Status,2    ; установился флаг Z?
       goto   errors      ; если команда не совпадает, то ошибка
;---------------------------------------------------------
       movlw  b'00010111' ; инвертируем выходы GP0, GP1, GP2, GP4
       xorwf  GPIO,1
;---------------------------------------------------------
errors clrf   Flags
       clrf   INTCON
       bsf    INTCON,3    ; разрешить прерывания на входах GPIO
       retfie
  end
;---------------------------------------------------------

[свернуть]

Скачать готовую прошивку и asm-файл

Спасибо товарищу jrman-у за доработку и тесты этой проги в железе.

Внимание. Во избежание затирания калибровочных констант — алгоритм заливки этой прошивки в контроллер следующий:

  1. Считываем текущую конфигурацию контроллера.
  2. Записываем значение битов калибровки схемы BOR (12-й, 13-й биты слова конфигурации, они же bandgap)
  3. Записываем значение последнего слова программного кода (слово по адресу 03FF) — биты калибровки генератора.
  4. Открываем нашу прошивку в программе программатора, и меняем в ней биты калибровки схемы BOR и генератора на считанные и записанные значения.
  5. Всё, теперь эту (исправленную для конкретного экземпляра PIC12) прошивку можно заливать в контроллер.

Добавить комментарий