Программа для самодельного ИК-приемника, протокол RC-5 (манчестерское кодирование)

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

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

1) Подпрограмма обработки прерывания проверяет принимаемый код на соответствие манчестерскому алгоритму, декодирует принятый код и записывает его в 2 байта:

MBC — 7,6 биты — стартовые; 5 — управляющий бит; 4…0 — номер системы

LBC — 7…2 биты — номер команды; 1,0 биты — не используются

если принимаемый код не манчестерский — загорается первый светодиод.

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

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

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

  1. Выход ILMS1836 — инвертированный, т.е. когда принимается "1" — на выходе фотоприемника "0" (низкий уровень), когда приема нет или принимается "0" — на выходе фотоприемника "1"(высокий уровень).
  2. Стартовый бит манчестерским кодом передается как последовательность "01", но первый полубит ("0") мы не отличим от отсутствия сигнала, т.е. фактически прием начинается со второго полубита.
  3. В процессе работы программа считывает значение на входе контроллера каждые 889 мкс и считает это значение — значением принятого полубита.
  4. Программа уходит в прерывание очень быстро — за несколько микросекунд, поэтому, чтобы читать значения подальше от границы полубитов, перед приемом первого полубита вводится пауза, примерно равная половине полубита.
  5. Для проверки на соответствие манчестерскому алгоритму используется следующее его свойство: никакие три последовательных полубита не могут быть одновременно нулями или единицами.
  6. Если записывать все четные полубиты, начиная со второго, то мы восстановим исходную посылку.
    То есть мы принимаем все полубиты, но! Четные — записываем и используем для проверки на соответствие манчестерскому алгоритму, нечетные — используем только для проверки.

Алгоритм:

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

Итак, пусть в аппаратной части мы имеем:

входы: PB3 — вход ИК-приемника

выходы: PB2, PB1, PB0, PB4 — выходы на транзисторы управления светодиодами.

RESET внешне подтянут к питанию; используется внутренний генератор.

Пусть мы ожидаем команду 2 управления светом (номер системы 29).

Текст программы под катом

.device ATtiny13
.include "tn13def.inc"
.list
;-- определяем свои переменные
.def  w=r16     ; это будет наш аккумулятор
.def  MBC=r17   ; старший байт посылки
.def  LBC=r18   ; младший байт посылки
.def  Sch=r19   ; счётчик принятых бит
.def  Preg=r20  ; проверочный регистр (для проверки на манчестер)
.def  N_bit=r21 ; номер бита для записи
.def  Schp=r22  ; счётчик для паузы
;-- определяем константы
.equ  T1=210    ; задержка около четверти бита (делитель на 64)
.equ  T2=123    ; задержка в половину бита (делитель на 64)
.equ  TP=10     ; задержка между приёмом посылок (делитель на 1024)
.equ  Sys=29    ; номер системы
.equ  CMD_1=4   ; 000001 00 младшие 2 бита не используются,
                ; поэтому код команды=1
;-- Используемые регистры
; SPL - указатель вершины стека
; ACSR - управление компаратором
; DDRB - направление работы ног
; PORTB - выходы порта
; PCMSK - разрешение прерываний на отдельных входах
; GIMSK - общее разрешение прерываний по входам
; GTCCR - сброс предделителя
; TCCR0B - управление таймером
; TIMSK0 - прерывания от таймера
;-- начало программного кода
        .cseg
        .org 0
        rjmp Init  ; переход на начало программы
;-- вектора прерываний
        reti       ; INT0
	rjmp Pch   ; Pin Change
	rjmp Timer ; 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,0b00010111 ; определяем входы и выходы порта
        out DDRB,w
	ldi w,0b11101000 ; включаем подтягивающие резисторы
	out PORTB,w      ; и определяем начальное состояние выходов
;-- (пока таймер не запущен - прерывание не произойдёт)
	ldi w,0b00000010
        out TIMSK0,w     ; разрешить прерывания от таймера
;-- разрешить прерывание от входов
        ldi w,0b00100000
	out GIMSK,w      ; разрешаем прерывание от входов
;-- разрешить прерывания на входе PB3
Start:  ldi w,0b00100000
        out GIFR,w       ; сбросить флаг прерываний от входов
        ldi w,0b00001000
	out PCMSK,w      ; разрешаем прерывания на входе PB3
        sei              ; разрешить глобальные прерывания
Scan:   nop
	rjmp Scan
;-- ОБРАБОТЧИК ПРЕРЫВАНИЯ ПО ВХОДУ
;-- инициализируем счётчик, адр.бита, пров.рег., адр.рег.записи
Pch:    sbic PINB,3     ; если на входе низкий уровень - пропуск.команду
        reti            ; это не приём - выходим
  ;---
        clr w
	out PCMSK,w     ; запрещаем прерывания от всех входов
	clr MBC         ; реинициализируем приёмные регистры
        clr LBC
        clr Sch         ; сбрасываем счётчик
        ldi N_bit,128   ; поднять 7-й бит в N_bit, остальные - сбросить
        clr Preg        ; три младших бита проверочного регистра=0
        ldi XL,0x11     ; загружаем в XL указатель на регистр r17
;-- настраиваем таймер для отсчёта длительности четверти бита
        ldi w,T1
        out TCNT0,w
;-- запустить таймер
        ldi w,0b00000001
        out GTCCR,w     ; сбросить предделитель
        ldi w,0b00000011
        out TCCR0B,w    ; запустить таймер с делителем на 64
        reti
;-- ОБРАБОТЧИК ПРЕРЫВАНИЯ ОТ ТАЙМЕРА
Timer:  clr  w
        out  TCCR0B,w   ; выключить таймер
;--
Priem:  ldi w,T2
        out TCNT0,w     ; настр-м таймер для отсчёта длит-ти полубита
;-- читаем значение на входе и сохраняем в пользовательский флаг
        clt             ; сбрасываем T
        sbis PINB,3     ; если на входе 1 - пропуск.следующую команду
        set             ; установить T (принятый сигнал инвертирован)
;-- если в счётчике чётное значение - восcтанавливаем значение
;-- полубита в байт и сохраняем для проверки на манчестер, иначе
;-- используем только для проверки
        sbrc Sch,0      ; если 0-й бит Sch=0 - пропуск следующ.команды
        rjmp Mtest      ; переходим к проверке на манчестер
        ld   w,X        ; читаем байт, в который будем восстанавливать
        brtc store0     ; если флаг T не установлен -
                        ; восстанавливаем 0, иначе - 1
store1: or   w,N_bit    ; поднимаем бит в нужной позиции
        rjmp Sbyte
store0: com  N_bit      ; инвертируем N_bit
        and  w,N_bit    ; сбрасываем бит в нужной позиции
        com  N_bit      ; возвращаем N_bit в прежнее состояние
Sbyte:  st   X,w        ; сохраняем новое значение байта
;-- сдвигаем номер записываемого бита
        clc             ; очищаем флаг переноса
        ror  N_bit      ; сдвигаем N_bit вправо через перенос
        brcc Mtest      ; если флаг C не установился - переходим
        ror  N_bit      ; ещё раз сдвинуть вправо (установить 7-й бит)
	inc  XL         ; сдвинуть указатель на следующий байт
;-- тест на манчестер
Mtest:  lsl  Preg       ; сдвигаем влево проверочный регистр
        bld  Preg,0     ; дописываем к нему справа принятый бит
        mov  w,Preg     ; копируем Preg в w
        andi w,0b00000111 ; отрезаем все биты, кроме трёх младших
        breq no_manch   ; если 3 младших бита=0, то это не манчестер
	com  w          ; инвертируем w
        andi w,0b00000111 ;если все младш.биты были=1, то получ-ся 0
        breq no_manch
;-- увеличиваем счётчик
        inc  Sch
;-- если счётч.полубитов=27 - перех.к паузе, иначе - продолж. приём
        cpi  Sch,27
        breq rab_chast
   ;---
        ldi w,0b00000011
        out TCCR0B,w        ; запустить таймер с делителем на 64
	reti
;-- РАБОЧАЯ ЧАСТЬ
;-- Проверка номера системы и команды
rab_chast: ldi  w,Sys       ; загружаем в w номер системы
        andi MBC,0b00011111 ; отрезаем от MBC старт. и управл.биты
        cpse w,MBC          ; если MBC=Sys - пропуск. следующ.команду
        rjmp Nosys
        ldi  w,CMD_1        ; загружаем в w код команды
        cpse w,LBC          ; если LBC=CMD_1 - пропуск. следующ.команду
	rjmp Nocom
;-- погасить все, зажечь 4-й
        ldi  w,0b11111000
        out  PORTB,w
        rjmp Epocket
;-- погасить все, зажечь 2-й
Nosys:  ldi  w,0b11101010
        out  PORTB,w
        rjmp Epocket
;-- погасить все, зажечь 3-й
Nocom:  ldi  w,0b11101001
        out  PORTB,w
        rjmp Epocket
;-- если мы имеем дело не с манчестером, то надо
;-- включить первый светодиод, выгрузить лишнее из
;-- стека и перейти к старту
no_manch:
        ldi w,0b11101100
        out PORTB,w    ; включить первый светодиод
Epocket:
        pop w
        pop w
        rjmp Start
;---------------------------------------------------------

[свернуть]

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

Кроме этого должны быть запрограммированы следующие фьюзы: SPIEN, SUT0, CKSEL0. Запрограммированы — то есть сброшены в ноль, то есть в Pony Prog, например, напротив них должны стоять галочки.

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