AVR Assembler Source Blog

Ремонт частотных преобразователей AVR Assembler Source Blog: RC5_decoder_by_Leonid_Ivanovich

Sunday, October 6, 2013

RC5_decoder_by_Leonid_Ivanovich

настройка частотного преобразователя
                              ;----------------------------------------------------------------------------
                              ;Программа декодирования кода 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