Sony RC5 [library]

General discussion on mikroC.
Post Reply
Author
Message
Madman07
Posts: 37
Joined: 06 Sep 2008 18:23
Location: Poland, Rawicz

Sony RC5 [library]

#1 Post by Madman07 » 25 Dec 2009 15:00

Here u got libraries to send and receive sony rc5 code. I found many codes, but they were complicated, or written in asm so I decided to do my own library. If u will notice any bugs, please report it here and I will check it out. That libraries are easy to use, just put everything and read and send like I'm doing that. And if u have some questions, ask! :D

Sending code. It was tested on PIC16f628 with 4.433619Mhz. Connect IR diode to hardware PWM output. Don't forget to put 130ms delay after sending code (but maybe it could work without that, I didn't tested that).

Code: Select all

void IR1() {
     PWM_Stop();
     delay_us(864);
     PWM_Start();
     delay_us(864);
}

void IR0() {
     PWM_Start();
     delay_us(864);
     PWM_Stop();
     delay_us(864);
}

void RC5_Send(short toggle, short adress, short command) {

     short i1;

     IR1();
     IR1();

     if(toggle) IR1();
     else IR0();

     for (i1 = 0; i1 <= 4; i1++) {
         if (adress & (1 << i1)) IR1();
         else IR0();
     }

     for (i1 = 0; i1 <= 4; i1++) {
         if (command & (1 << i1)) IR1();
         else IR0();
     }

     PWM_Stop();

}

void main() {

     TRISB.F3 = 0;

     PWM_Init(36000);
     PWM_Change_Duty(127);
     PWM_Stop();

     while (1) {

           RC5_Send(1,29,5);  // for example
           delay_ms(130);

     }
}

Receiving code. It was tested on PIC16F871 with 14.31818Mhz. Connect TSOP17xx to RB0. It use RB0 interrupt and timer0. U need to enter uc clock in MHz (without anything after dot), its required to calculate prescaler for timer0.

Code: Select all

unsigned short adr, comm, togg, count, error;
short RC5Len;

short check_byte() {

     unsigned short old;

     delay_us(1296);
     old = PORTB.F0;

     TMR0 = 0;
     INTCON.T0IF = 0;

     while (PORTB.F0 == old) {
           if (TMR0 > (RC5Len + 10)) return 127;
     }
     if (TMR0 < (RC5Len - 10)) return 127;

     return old;

}

short check_start_byte(char status) {

     TMR0 = 0;
     INTCON.T0IF = 0;

     while (PORTB.F0 == status) {
           if (TMR0 > ((RC5Len * 2) + 10)) return 127;
     }
     if (TMR0 < ((RC5Len * 2) - 10)) return 127;

     return 1;

}

unsigned short read_rc5(short *toggle, short *adress, short *command) {

        short tmp;
        short i1;

        *toggle  = 0;
        *adress  = 0;
        *command = 0;

        tmp = check_start_byte(0);
        if (tmp == 127) goto err1;
        tmp = check_start_byte(1);
        if (tmp == 127) goto err1;

        tmp = check_byte();
        if (tmp == 127) goto err1;
        if (tmp) *toggle = 1;

        for (i1 = 0; i1 <= 4; i1++) {
            tmp = check_byte();
            if (tmp == 127) goto err1;
            if (tmp) *adress = *adress | (1<<i1);
        }

        for (i1 = 0; i1 <= 5; i1++) {
            tmp = check_byte();
            if (tmp == 127) goto err1;
            if (tmp) *command = *command | (1<<i1);
        }

        err1:
        INTCON.T0IF = 0;
        if (tmp == 127) return 1;
        else return 0;
}

short rc5_init(short clock) {

     if (clock < 9) OPTION_REG = 0b10000100;
     else if (clock > 15) OPTION_REG = 0b10000110;
     else OPTION_REG = 0b10000101;

     INTCON.GIE = 1;
     INTCON.INTE = 1;
     INTCON.T0IE = 1;
     INTCON.T0IF = 0;
     TMR0 = 0;
     delay_us(432);
     return TMR0 - 2;

}

void interrupt() {
     if (INTCON.T0IF) {
        count++;
        if (count == 200) count = 0;
        TMR0 = 0;
        INTCON.T0IF = 0;
        INTCON.T0IE = 1;
     }
     if (INTCON.INTF) {
        error = read_rc5(&togg, &adr, &comm);
        count = 0;
        INTCON.INTF = 0;
     }
}

void main() {

     RC5Len = rc5_init(14);
     TRISB.F0 = 1;

     while (1) {

        if (adr == 0) {
           if (togg) {
              //some code
              if (count > 60) comm = 0;
           }
           else {
                // again some code
           }

        }

        if (error) {
           error = 0;
           // error handling
        }

     }
}
P.S. Sorry for my bad English :)

mizort1989
Posts: 11
Joined: 25 Dec 2009 19:28

#2 Post by mizort1989 » 25 Dec 2009 19:30

hey thanks for this great job

but i wonder

Sony remotes use SIRC, which is totally different from the Philips RC5.

Madman07
Posts: 37
Joined: 06 Sep 2008 18:23
Location: Poland, Rawicz

#3 Post by Madman07 » 25 Dec 2009 20:05

Oh I mistaken Sony with Philips, sorry :oops:
P.S. Sorry for my bad English :)

mizort1989
Posts: 11
Joined: 25 Dec 2009 19:28

#4 Post by mizort1989 » 25 Dec 2009 23:18

can you add comments to your code please

Madman07
Posts: 37
Joined: 06 Sep 2008 18:23
Location: Poland, Rawicz

#5 Post by Madman07 » 26 Dec 2009 15:16

I cant edit my post so i will write it again. And I can't explain it better, just watch my code and watch rc5 signal, then everything will be clear :-)

Sending:

Code: Select all

void IR1() { // logic 1, first 864us of 0, then 864us of pwm signal
     PWM_Stop(); // dont forget that its manchester coding
     delay_us(864);
     PWM_Start();
     delay_us(864);
}

void IR0() { // logic 0, first pwm signal, then logic 0
     PWM_Start();
     delay_us(864);
     PWM_Stop();
     delay_us(864);
}

// main function
void RC5_Send(short toggle, short adress, short command) {

     short i1;

     IR1(); // send 2 times logic 1
     IR1();

     if(toggle) IR1(); //send toggle byte
     else IR0();

     for (i1 = 0; i1 <= 4; i1++) { // send 4 bytes of adress
         if (adress & (1 << i1)) IR1(); 
         else IR0();
     }

     for (i1 = 0; i1 <= 4; i1++) { // send 5 bytes of command
         if (command & (1 << i1)) IR1();
         else IR0();
     }

     PWM_Stop(); // to make sure that we not sending something

}

void main() {

     TRISB.F3 = 0; // its cp1

     PWM_Init(36000); // 36khz, 50% duty ratio for our ir diode
     PWM_Change_Duty(127);
     PWM_Stop();

     while (1) {

           RC5_Send(1,29,5);  // for example
           delay_ms(130); // 130ms delay, just like rc5 need

     }
}


Receiving

Code: Select all

unsigned short adr, comm, togg, count, error;
short RC5Len;

short check_byte() { // check if its logic 0 or logic 1

     unsigned short old;

     delay_us(1296); // delay 3/4 full time so after that we are in the
     old = PORTB.F0; // 1/4 part of first byte, and we reading data

     TMR0 = 0;
     INTCON.T0IF = 0; // prepare timer0 to count
     // wait until tsop will give us another signal than we saved in old
     // and check if that didnt take too long or too short
     // and compare that with rc5len that we calculated in rc5_init
     // and if its not good then return 127, else return old value
     // rclen should be equal to 432us (depend on sendind signal)
     // for 14mhz xtal it was 23
     while (PORTB.F0 == old) {  
           if (TMR0 > (RC5Len + 10)) return 127; 
     }
     if (TMR0 < (RC5Len - 10)) return 127;

     return old;

}

short check_start_byte(char status) { 
     // here everything is the same like before but we dont wait 3/4 full 
     // byte time,but just we waiting forlogic 1 or 0 (defined by status)
     // so its 1/2 of byte
     TMR0 = 0;
     INTCON.T0IF = 0;

     while (PORTB.F0 == status) {
           if (TMR0 > ((RC5Len * 2) + 10)) return 127;
     }
     if (TMR0 < ((RC5Len * 2) - 10)) return 127;
     // again read tmr0 and check if it wast tooshort or too long
     return 1;

}

unsigned short read_rc5(short *toggle, short *adress, short *command) {
     // its main function of reading rc5 code
        short tmp;
        short i1;

        *toggle  = 0;
        *adress  = 0;
        *command = 0;

        // here we checking our 2 start bytes, we just wait if tsop will make
        // falling or rising edge (its defined by status, 0 or 1);
        tmp = check_start_byte(0);
        if (tmp == 127) goto err1;
        tmp = check_start_byte(1);
        if (tmp == 127) goto err1;

        // and we reading toggle byte (dont forget about 127 for error)
        tmp = check_byte();
        if (tmp == 127) goto err1;
        if (tmp) *toggle = 1;

        // read adress and check for errors
        for (i1 = 0; i1 <= 4; i1++) {
            tmp = check_byte();
            if (tmp == 127) goto err1;
            if (tmp) *adress = *adress | (1<<i1);
        }

        // read command and check for errors
        for (i1 = 0; i1 <= 5; i1++) {
            tmp = check_byte();
            if (tmp == 127) goto err1;
            if (tmp) *command = *command | (1<<i1);
        }

        err1:         // and that will be done always, no matter for errors
        INTCON.T0IF = 0;
        if (tmp == 127) return 1; // if error then rc5_read = 1
        else return 0;
}

short rc5_init(short clock) {

     // it isnt perfect, we adjust prescaler for xtals, less than 9, and more
     // than 15, else its 1:64 (i suppose, i dont remember ;p )
     if (clock < 9) OPTION_REG = 0b10000100;
     else if (clock > 15) OPTION_REG = 0b10000110;
     else OPTION_REG = 0b10000101;

     // initialise timer0 and rbo external interrupt
     INTCON.GIE = 1;
     INTCON.INTE = 1;
     INTCON.T0IE = 1;
     INTCON.T0IF = 0;
     TMR0 = 0;
     delay_us(432);      //  here we calculate how much timer will count
     return TMR0 - 2;    // during 1/2 byte time, 432 us

}

void interrupt() {
     if (INTCON.T0IF) {
        // count is used to make sure that command is not cleared now, but
        // it wait if we will read some code (130ms), if not then we need 
        // to clear command, check it in main,after while (true)
        count++;
        if (count == 200) count = 0;
        TMR0 = 0;
        INTCON.T0IF = 0;
        INTCON.T0IE = 1;
     }
     if (INTCON.INTF) {      // if there is falling edge then read rc5
        error = read_rc5(&togg, &adr, &comm);
        count = 0;
        INTCON.INTF = 0;
     }
}

void main() {

     RC5Len = rc5_init(14); // rc5 init and calculate rc5len
     TRISB.F0 = 1; // our tsop data

     while (1) {

        if (adr == 0) {
           if (togg) {
              // toggle works like volume up and down or channel up and 
              // down, we press button once,and volume change several times
              //some code
              if (count > 60) comm = 0;
           }
           else {
                // again some code
               // we press button one time,and channel switch one time
           }

        }

        if (error) {
           error = 0;
           // error handling, do something with that,or delete that lines:)
        }

     }
}
P.S. Sorry for my bad English :)

mizort1989
Posts: 11
Joined: 25 Dec 2009 19:28

#6 Post by mizort1989 » 26 Dec 2009 22:37

thanks for the comments

Post Reply

Return to “mikroC General”