Программа, рассмотренная в этой статье, разработана специально для самодельного ИК-приемника сигналов дистанционного управления на контроллере ATTiny13. Если вы измените аппаратную часть (например, будете использовать другой порядок ног, повесите внешний генератор), то программу так же нужно будет переделать.
Программа реализует следующие функции:
1) Подпрограмма обработки прерывания проверяет принимаемый код на соответствие манчестерскому алгоритму, декодирует принятый код и записывает его в 2 байта:
MBC — 7,6 биты — стартовые; 5 — управляющий бит; 4…0 — номер системы
LBC — 7…2 биты — номер команды; 1,0 биты — не используются
если принимаемый код не манчестерский — загорается первый светодиод.
2) В рабочей части программы реализуется управление тремя оставшимися светодиодами: если номер системы в принятом коде не тот, который мы ждали — загорается второй светодиод, если номер системы совпадает с ожидаемым, но номер команды не совпадает с ожидаемым — загорается третий светодиод, и, наконец, если и номер системы и номер команды совпадают с ожидаемыми — загорается четвертый светодиод.
Прежде чем разбираться с программой, советую посмотреть описание протокола RC-5.
Основные идеи алгоритма:
- Выход ILMS1836 — инвертированный, т.е. когда принимается "1" — на выходе фотоприемника "0" (низкий уровень), когда приема нет или принимается "0" — на выходе фотоприемника "1"(высокий уровень).
- Стартовый бит манчестерским кодом передается как последовательность "01", но первый полубит ("0") мы не отличим от отсутствия сигнала, т.е. фактически прием начинается со второго полубита.
- В процессе работы программа считывает значение на входе контроллера каждые 889 мкс и считает это значение — значением принятого полубита.
- Программа уходит в прерывание очень быстро — за несколько микросекунд, поэтому, чтобы читать значения подальше от границы полубитов, перед приемом первого полубита вводится пауза, примерно равная половине полубита.
- Для проверки на соответствие манчестерскому алгоритму используется следующее его свойство: никакие три последовательных полубита не могут быть одновременно нулями или единицами.
- Если записывать все четные полубиты, начиная со второго, то мы восстановим исходную посылку.
То есть мы принимаем все полубиты, но! Четные — записываем и используем для проверки на соответствие манчестерскому алгоритму, нечетные — используем только для проверки.
Алгоритм:
Итак, пусть в аппаратной части мы имеем:
входы: 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, например, напротив них должны стоять галочки.
Мм понятно обратная связь на высоте
При моделировании в proteus 7.7 не работает, в чем может быть дело?
Как очень вероятный вариант — в самом протеусе. Всё это проверялось в железе, а не в симуляторе. И в железе оно работало. Если хотите, чтобы кто-то с этим поковырялся — регайтесь на форуме, создавайте там тему и выкладывайте весь свой проект, чтобы его можно было посмотреть и повторить ваш опыт. Других вариантов нет.