;----------------------------------------------------------------------------
;Программа декодирования кода RC-5.
;Каждый импульс вызывает внешнее прерывание;
;по таймеру производится несколько выборок на
;каждой половинке бита и по мажоритарному
;принципу вычисляется значение;
;затем проверяется валидность манчестерского кода.
;----------------------------------------------------------------------------
.include "2313def.inc"
;----------------------------------------------------------------------------
;Константы:
.equ FCLK=4000000 ;Hz
.equ PRE=64
.equ RC5_SLOT=1778 ;uS
.equ RC5_LENGTH=14 ;количество принимаемых бит
.equ SAMPLE_COUNT=3 ;количество выборок, должно быть
;нечетным, работал мажоритарный
;способ вычисления значения
.equ T_SAMPLE_US=RC5_SLOT/((SAMPLE_COUNT+1)*2)
.equ F_TIMER=FCLK/PRE
.equ T_SAMPLE=(T_SAMPLE_US*F_TIMER/100000+5)/10
;----------------------------------------------------------------------------
;Полезные макросы:
.macro ;clear bit in register
clbr
cbr @0,exp2(@1)
.endm
.macro ;set bit in register
stbr
sbr @0,exp2(@1)
.endm
.macro ;branch if bit in register clear
bbrc
sbrs @0,@1
rjmp @2
.endm
.macro ;branch if bit in register set
bbrs
sbrc @0,@1
rjmp @2
.endm
;----------------------------------------------------------------------------
.equ IR_Signal=PD3 ;выход ик-приемника на ноге РD3 (INT1)
;Байты направления портов:
.equ DIR_PORTB=0xFF ;направление для порта В.
.equ DIR_PORTD=~(1<
;Байты первоначального состояния портов:
.equ PUP_PORTB=0x00 ;после сброса весь порт B ставим в 0
.equ PUP_PORTD=(1<
;----------------------------------------------------------------------------
.DSEG ;сегмент данных
SysVar: .byte 1 ;сюда кладем принятый адрес системы
CommandVar: .byte 1 ;а сюда код команды
BitCounter: .byte 1 ;счетчик принятых бит
SampCnt: .byte 1
;----------------------------------------------------------------------------
;Глобальные регистровые переменные:
.def RC5_CodeL=r2 ;регистр принимаемого кода RC5 (мл. байт)
.def RC5_CodeH=r3 ;регистр принимаемого кода RC5 (ст. байт)
.def SampVal=r4
.def temp=r16 ;temporary register temp
.def Flags=r20 ;флаги
.equ PreVal=0 ;значение первой половины бита
;----------------------------------------------------------------------------
.CSEG ;сегмент кода
;Векторы прерываний:
.org 0 ;по адресу 0 вектор сброса
rjmp Init ;переход на основную программу
.org INT1addr ;прерывание по внешнему сигналу INT1
rjmp EdgeRC5
.org OVF0addr ;по адресу OVF0addr вектор прерывания по
rjmp Timer ;переполнению таймера 0
;----------------------------------------------------------------------------
;Программа начинает выполняться отсюда
;----------------------------------------------------------------------------
;Здесь пишем всякую инициализацию, которая должна
;выполняться один раз при старте программы.
Init:
ldi temp,low(RAMEND) ;константа RAMEND определена в tn2313def.inc
out SPL,temp ;инициализируем SatckPointer
ldi temp,high(RAMEND)
out SPH,temp
;Инициализация переменных:
ldi temp,RC5_LENGTH
sts BitCounter,temp ;инициализируем счетчик бит
stbr Flags,PreVal ;первая половина старт-бита = 1
clr temp
sts SysVar,temp ;очистка системы
sts CommandVar,temp ;очистка команды
;Настройка портов:
ldi temp,PUP_PORTB
out PORTB,temp ;включаем Pull-Up в PORTB
ldi temp,DIR_PORTB
out DDRB,temp ;настраиваем направление для PORTB
ldi temp,PUP_PORTD
out PORTD,temp ;включаем Pull-Up в PORTD
ldi temp,DIR_PORTD
out DDRD,temp ;настраиваем направление для PORTD
;Настройка оборудования:
ldi temp,(1<
out TCCR0,temp ;записываем в регистр TCCR0
in temp,MCUCR
ori emp,(1<
out MCUCR,temp
in temp,GIMSK
ori temp,(1<
out GIMSK,temp ;разрешаем внешнее прерывание INT1
sei ;global interrupts enable
;----------------------------------------------------------------------------
;Основной цикл программы.
;----------------------------------------------------------------------------
Main:
lds temp,CommandVar ;грузим код команды из переменной
out PORTB,temp ;выводим на порт
rjmp Main ;цикл
;----------------------------------------------------------------------------
;Обработчик внешнего прерывания:
;----------------------------------------------------------------------------
EdgeRC5:
sbi PORTD,PD4 ;контроль на PD4 внешнего прерывания
push temp ;сохранение темп
in temp,SREG
push temp ;сохранение SREG
;Загружаем таймер:
ldi temp,256-T_SAMPLE ;грузим интервал до первой выборки
out TCNT0,temp
;Разрешаем прерывания таймера:
ldi temp,(1<
out TIMSK,temp ;разрешаем прерывание по переполн ТС0
out TIFR,temp ;очищаем флаг прерывания таймера
;Инициализируем переменные:
ldi temp,SAMPLE_COUNT*2;количество выборок на периоде
sts SampCnt,temp
clr ampVal ;очищаем суммарное значение выборок
pop temp
out SREG,temp ;восст. SREG
pop temp ;восст. temp
cbi PORTD,PD4
reti ;выходим и разрешаем прерывания
;----------------------------------------------------------------------------
;Обработчик по переполнению ТС0:
;----------------------------------------------------------------------------
Timer:
sbi PORTD,PD5 ;контроль на PD5 прерывания таймера
push temp ;сохранение темп
in temp,SREG
push temp ;сохранение SREG
;Проверка признака таймаута:
lds temp,SampCnt
tst temp
brne DoSamp
rjmp RC5_Error ;если SampCnt = 0, ошибка таймаута
;Делаем выборки:
DoSamp:
sbis PIND,IR_Signal ;проверяем выход приемника
rjmp Bit0
Bit1:
inc SampVal ;если единица, то SampVal + 1
rjmp CheckSmp
Bit0:
dec SampVal ;если ноль, то SampVal - 1
;Проверка числа сэмплов:
CheckSmp:
dec temp ;уменьшаем количество сэмплов
sts SampCnt,temp
breq EvPre ;если ноль, то закончена вторая половина
cpi temp,SAMPLE_COUNT
breq EvThis ;закончена первая половина
ldi temp,256-T_SAMPLE ;продолжаем выборки с периодом T_SAMPLE
out TCNT0,temp
rjmp NextSam
;Оцениваем текущий бит по результатам сэмплирования первой половины:
EvThis:
ldi temp,256-T_SAMPLE*2;грузим интервал между сериями сэмплов
out TCNT0,temp
;Определяем состояние:
tst SampVal ;если SampVal > 0, то единица
brmi Store0 ;если SampVal < 0, то ноль
;Первая половина равна единице, бит равен нулю:
Store1:
bbrs Flags,PreVal,RC5_Error ;проверяем на ошибку Манчестера
clc
rjmp SaveBit
;Первая половина равна нулю, бит равен единице:
Store0:
bbrc Flags,PreVal,RC5_Error ;проверяем на ошибку Манчестера
sec
;Вдвигаем принятый бит:
SaveBit:
rol RC5_CodeL
rol RC5_CodeH
clr SampVal ;очищаем сумму выборок
rjmp NextSam ;приступаем ко второй половине
;Закончено сэмплирование второй половины бита:
EvPre:
ldi temp,256 - T_SAMPLE * 2 ;грузим интервал таймаута
out TCNT0,temp
;Определяем состояние:
tst SampVal
brmi Pre0
;Вторая половина равна единице, сохраняем в PreVal:
Pre1:
stbr Flags,PreVal
in temp,MCUCR
andi temp,~(1<
out MCUCR,temp
rjmp DecCnt
;Вторая половина равна нулю, сохраняем в PreVal:
Pre0:
clbr Flags,PreVal
in temp,MCUCR
ori temp,(1<
out MCUCR,temp
;Декремент счетчика бит:
DecCnt:
lds temp,BitCounter
dec temp ;BitCounter - 1
sts BitCounter,temp
breq EndRec ;0 - завершаем прием посылки
rjmp NextSam ;прием следующего бита посылки
;Прием закончен, раскладываем биты по переменным:
EndRec:
mov temp,RC5_CodeL
andi temp,0x3F ;чистим ненужные биты
sts CommandVar,temp ;сохраняем код команды в переменную
rol RC5_CodeL
rol RC5_CodeH
rol RC5_CodeL
rol RC5_CodeH
mov temp,RC5_CodeH
andi temp,0x3F ;чистим ненужные биты
sts SysVar,temp ;сохраняем адрес системы в переменную
;Перезагрузка счетчика бит:
RC5_Error:
ldi temp,RC5_LENGTH
sts BitCounter,temp ;перезагружаем счетчик бит
stbr Flags,PreVal ;первая половина старт-бита = 1
;Разрешаем прерывание по спаду:
in temp,MCUCR
andi temp,~(1<
out MCUCR,temp
;Запрещаем прерывание таймера:
ldi temp,0
out TIMSK,temp ;запрещаем прерывание таймера
NextSam:
pop temp ;восст SREG
out SREG,temp
pop temp ;восст temp
cbi PORTD,PD5
reti
;----------------------------------------------------------------------------
No comments:
Post a Comment