for Sony and the code for 16F84@4MHz written with CC5XFree follows. see if u can figure it :-) //=============cut--here================================= /* * IR reception * 05/Sep/1999 JLS & CAE * jls at certi.ufsc.br * cae at certi.ufsc.br * CC5xFree v3.0E (www.bknd.com) */ /* Sony Data format: 12 bits Bit zero: 400 +--+ +... | | | + +---+ 800 Bit one: 400 +--+ +... | | | + +------+ 1400 Frame: 400 400 --+ +--+ +--+ +--+ | | | | | | | +---2600---+ +---+ +------+ +... 800 1400 Decoding algorithm: - Detect 2600us pulse, - measure next high pulse as P1 (400us) - measure next low pulse as P2 (800/1400us) - store min(P1) - store max(P2) After all measurements: - calculate mean = (max-min)/2 + min - For all (P1,P2) measured: . Add P1+P2=P3 . If P3< mean => bit is zero . If P3>=mean => bit is one Measures with Timer0 & Prescaler:16 2600us = 162 1400us = 87 800us = 50 400us = 25 400+800 = 25+50 = 75 400+1400 = 25+87 = 112 mean ~= (112-75)/2+75 = 18+75 = 93 */ #define _16f84_ #include <16f84.h> #ifdef _12C508_ bit _TxOUT @ GP0; bit RxD_pin @ GP1; bit IR_input @ GP2; #else #define RP0 STATUS.5 #pragma update_RP 0 /* OFF */ #define DEF_TRISA 0 #define DEF_TRISB 6 bit Rele @ PORTA.1; bit IR_input @ PORTB.1; bit RxD_pin @ PORTB.2; bit _TxOUT @ PORTB.3; bit LED @ PORTB.4; #endif unsigned char size,x,y,med,min,max,rxBuf; unsigned char r[4]; unsigned char buff[32]; void TxSerial (unsigned char txBuf); /*--------------------------------------------------------------------------*/ void TxEnter (void) { /*--------------------------------------------------------------------------*/ TxSerial(0xD); TxSerial(0xA); } /*--------------------------------------------------------------------------*/ void TxHexAscii (unsigned char in) { /*--------------------------------------------------------------------------*/ unsigned char Hex; Hex = swap(in); // upper nibble Hex &= 0x0F; if (Hex<10) Hex += 0x30; else Hex += 0x37; TxSerial(Hex); Hex = in & 0x0F; if (Hex<0x0A) Hex += 0x30; else Hex += 0x37; TxSerial(Hex); } /*--------------------------------------------------------------------------*/ void Delay_uSeg (unsigned char timeout) { /*--------------------------------------------------------------------------*/ // delay = 3*timeout + 7uS (including call and return) while (1) { timeout--; if (timeout==0) { nop(); nop(); return; } } } /*--------------------------------------------------------------------------*/ void TxSerial (unsigned char txBuf) { /*--------------------------------------------------------------------------*/ /* ;---------------------------------------------------------------------------* ; Transmit 1 start bit Lo, 8 data bits and 1 stop bit Hi at 9600 bps ; No Parity ; Byte time = 1.040 mS ; Bit time = 104 uS (0.16% erro w/4.00 Mhz Internal RC) ; Input : W = byte to be transmitted ; Output: byte transmitted by serial pin ;---------------------------------------------------------------------------* */ char idx; while (1) { Carry = 0; // start bit for (idx=10; idx; idx--) // 3us { _TxOUT = Carry; // 4us Delay_uSeg(28); // 91us (28*3+7) Carry = 1; // 1us txBuf = rr(txBuf); // 1us nop(); // 1us } // 3us return; } } /*--------------------------------------------------------------------------*/ void RxSerial (void) { /*--------------------------------------------------------------------------*/ /* ;---------------------------------------------------------------------------* ; Receives 1 start bit Lo, 8 data bits and 1 stop bit Hi at 9600 bps ; No Parity ; Byte time = 1.040 mS ; Bit time = 104 uS (0.16% erro w/4.00 Mhz Internal RC) ; ; False start bit check ; ; Start bit hunting timeout = 4*1.283ms ; ; Input : none ; Output : Carry = 1 => success ; rxBuf = input byte ; Carry = 0 => error (timeout or stop bit=0) ;---------------------------------------------------------------------------* */ char idx; rxBuf = 4; // 5.135 ms timeout idx = 0; while (1) { while (RxD_pin) // input "high" { if ((-- idx)==0) { if ((-- rxBuf)==0) { Carry = 0; return; } } } Delay_uSeg(14); // 1/2 bit delay (14*3+7) if (RxD_pin) continue; // false start bit detection rxBuf = 0x80; // 8 bits counter and reception buffer nop(); nop(); // timming adjustment do { Delay_uSeg(30); // (30*3+7)us Carry = RxD_pin; // bit read rxBuf = rr(rxBuf); // store and count } while (Carry==0); Delay_uSeg(30); // 1 bit delay nop(); // timming adjustment Carry = RxD_pin; // stop bit read return; // 100 us availiable } } /*--------------------------------------------------------------------------*/ void main (void) { /*--------------------------------------------------------------------------*/ #ifdef _12C508_ // OSCCAL = W; // OscCal Value - OTP part OSCCAL = 0xB0; // OscCal Value - Windowed part GPIO = 0x00; TRIS = 0x08; // GP3 input OPTION = 0b11000011; // Prescaler Timer0 1:16 #else INTCON = 0; // no interrupts PCLATH = 0; // bank 0 PORTA = 0; PORTB = 0; RP0 = 1; // RAM bank 1 TRISA = DEF_TRISA; TRISB = DEF_TRISB; OPTION = 0b11000011; // Prescaler Timer0 1:16 RP0 = 0; // RAM bank 0 #endif while (1) { /* set vars to start */ FSR = buff; // pointer to buffer x = 12; // only 12 bits size = 0; // word size in bits min = 255; // min period max = 0; // max period /* start bit management */ while (IR_input==1); // wait for 0 /* 2600us start bit */ while (IR_input==0); // wait for 1 TMR0 = 0; // start counter do { /* measure high pulse */ INDF = 0; // period: default to zero while (TMR0==0); // wait TMR0 advance while (IR_input==1) // wait for 0 { if (TMR0==0) // timer overflow (4096us) ? goto frame_end; // yes, exit } INDF = TMR0; // store period TMR0 = 0; // start counter med = INDF; // save high period FSR++; // bump pointer INDF = 0; // period: default to zero size++; // inc bit counter /* measure low pulse */ while (TMR0==0); // wait TMR0 advance while (IR_input==0); // wait for 1 INDF = TMR0; // store period TMR0 = 0; // start counter med += INDF; // total period if (med>=max) max = med; // find max if (med<min) min = med; // find min FSR++; // bump pointer size++; // inc period counter x--; // dec max bits } while (x); frame_end: LED = 1; med = max - min; med /= 2; med += min; r[0] = 0; r[1] = 0; r[2] = 0; r[3] = 0; FSR = buff; FSR += size; x = size/2; do { Carry = 0; r[3] = rl(r[3]); r[2] = rl(r[2]); r[1] = rl(r[1]); r[0] = rl(r[0]); FSR--; max = INDF; FSR--; max += INDF; if (max>=med) r[3]++; } while (--x); /* now r[0],r[1],r[2], r[3] has the frame */ /* Tx the periods and the encoded word */ TxHexAscii(size); TxSerial(0x20); TxHexAscii(med); TxEnter(); for(x=0;x<size; x++) { TxHexAscii(buff[x]); TxSerial(0x20); } TxEnter(); TxHexAscii(r[0]); TxHexAscii(r[1]); TxHexAscii(r[2]); TxHexAscii(r[3]); TxEnter(); LED = 0; } }
Interested:
Code:
Hi, Here is a new routine to read the transmissions from a Sony type remote control. Unlike the ones I found on the site so far, this one is in ASM and is interrupt driven so allows the main control program to do something else while waiting for RC commands. Anyway, here is the code, Regards, Barry. ; Software to read the commands from a Sony remote control ; The timings in this file are for a clock speed of 400kHz. ; Different timings can be easily achieved by changing the ; cutoff constants and/or the timer prescaler. ; Because the reader routine is interrupt driven it allows ; a main program to run and control something on the basis ; of the current setting of the RC data variable. For ; example, it was developed originally to control a robot ; so the main program does the robot control and the ; interrupt routine reads the remote control. ; ; May be distributed under the terms of the Gnu Public ; License (GPL) ; ; Version: 0.1 ; (c) Barry Smith, 2002. R_W_SAVE equ 0x11 ; Saves W during interrupts R_ST_SAVE equ 0x12 ; Saves STATUS during interrupts R_NEED_BITS equ 0x13 ; Number of bits still needed R_CUR_DATA equ 0x15 ; Data being received R_OLD_DATA equ 0x16 ; Last read data R_SAVE_TMR equ 0x17 ; Save timer value at start of interrupt F_GOT_START equ 0 ; Got start flag F_RC_PIN equ 4 ; RB pin for RC T3_CUT equ 0x52 ; T3 cutoff timing T2_CUT equ 0x32 ; T2 cutoff timing list p=16F84A include P16F84A.inc __config ( _RC_OSC & _PWRTE_ON & _WDT_OFF & _CP_OFF ) org 0 goto main_start org 4 ; This is the routine called on interrupt. This happens when either ; a bit RB4:7 changes or the timer rolls over. ; First, save the W and STATUS details. The SWAPF is used because it ; does not effect the STATUS (Z) flags, unlike MOVF. movwf R_W_SAVE ; Save value of W swapf STATUS, W ; Save STATUS flags movwf R_ST_SAVE movf TMR0, W ; Store timer value now as its still movwf R_SAVE_TMR ; incrementing. clrf TMR0 ; Make sure timer doesn't fire again ; Now the main code which processes the events btfss INTCON, T0IF goto int_rb clrf R_NEED_BITS ; Reset everything clrf R_CUR_DATA goto int_end int_rb ; Interupt is on RB pin btfsc PORTB, F_RC_PIN goto int_pin_high clrf TMR0 ; Executed if pin is low goto int_end int_pin_high ; Pin has returned to high state movf R_SAVE_TMR, W sublw T3_CUT btfsc STATUS, C goto int_try_t2 ; incf PORTB, F movlw 0x08 movwf R_NEED_BITS goto int_end int_try_t2 movf R_NEED_BITS, F ; Check if more bits are btfsc STATUS, Z ; needed, otherwise end. goto int_end rrf R_CUR_DATA, F ; Prepare for next bit decf R_NEED_BITS, F movf R_SAVE_TMR, W sublw T2_CUT btfsc STATUS, C goto int_is_t1 bsf R_CUR_DATA, 7 goto int_bit_set int_is_t1 bcf R_CUR_DATA, 7 int_bit_set movf R_NEED_BITS, F btfss STATUS, Z goto int_end movf R_CUR_DATA, W movwf PORTB int_end ; Clear the interrupts movlw b'11111000' ; Clears the interrupt indicator bits andwf INTCON, F ; Restore pre-interrupt status for STATUS and W. swapf R_ST_SAVE, W movwf STATUS swapf R_W_SAVE, F ; Restore W value without changing swapf R_W_SAVE, W ; STATUS bits retfie main_start ; This is the initialisation section - the chip must be configured ; to use TMR0. The prescaler must be determined so that the timer ; will roll over during the quiet time between transmissions (about ; 35-40ms), but never during transmission, the longest pulse of ; which is about 1.8ms). This gives plenty of leeway. bsf STATUS, RP0 movlw b'11010000' ; Clears the zeros from the OPTION_REG andwf OPTION_REG, F ; setting internal clock. movlw b'00010000' movwf TRISB bcf STATUS, RP0 movlw b'10101000' ; Sets interrupts to occur on RB change movwf INTCON ; or timer overflow. clrf R_CUR_DATA clrf R_NEED_BITS mainloop goto mainloop end