CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to CCS Technical Support

Universal remote control

 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
Markdem



Joined: 24 Jun 2005
Posts: 206

View user's profile Send private message Send e-mail

Universal remote control
PostPosted: Sun Jul 09, 2006 2:19 am     Reply with quote

Hello all, sorry if this is a bit off topic. I am tiring to make an IR to RS232 converter. Basically I want to send commands from a universal remote control (Logitech harmony 880) and then send commands to a light controller (Clipsal C-BUS). My devise will not send IR commands. The universal remote is a learning type, but what do I need to do to teach it? Do I need to first make a device that can first program the remote, and then make the receiver, or is there another way, programming the remote from my PC’s IRDA port maybe? Also, what IR decoders should I use? I have found that a TSOP1738 is common, is it going to do what I need??

Thanks, Mark
Markdem



Joined: 24 Jun 2005
Posts: 206

View user's profile Send private message Send e-mail

PostPosted: Sun Jul 09, 2006 3:45 am     Reply with quote

I just read my question back to myself, and it made no sence Smile. i guess the question i should be asking is how can i program my universal remote without making somthing that can send it the commands in the first place? can somthing like this be done, or am i dreaming??

Thanks, Mark
asmallri



Joined: 12 Aug 2004
Posts: 1635
Location: Perth, Australia

View user's profile Send private message Send e-mail Visit poster's website

PostPosted: Sun Jul 09, 2006 4:57 am     Reply with quote

A universal remote attempts to repeat the infrared pattern it has detected. There are different encoding frequencies but if you make one with a 38KHz encoding frequency then most remotes should be able to learn the sequence. You could make it easier on yourself by basing you device on a common protocol. Even better when you emulate a specific remote.

Take an exisiting remote (Sony are common) and have your device emulate it. This has the advantage that you can preprogram the auto learning remote to replicate a Sony (for example) in this case it does not really need to learn plus it gives you a wide range of options in terms of what remote to use.

There are standard IR receivers that provide an output pulse stream corresponding to the encoded signal. You need to get one of these that matches the encoding frequency you are using. For example a 36KHz IR receiver works poorly with a 38KHz encoded signal.
_________________
Regards, Andrew

http://www.brushelectronics.com/software
Home of Ethernet, SD card and Encrypted Serial Bootloaders for PICs!!
deltatech



Joined: 22 Apr 2006
Posts: 87

View user's profile Send private message

PostPosted: Sun Jul 09, 2006 6:55 am     Reply with quote

Try this link you may find what you are looking for there

http://www.zilog.com/application/application.asp?appid=3
Douglas Kennedy



Joined: 07 Sep 2003
Posts: 755
Location: Florida

View user's profile Send private message AIM Address

PostPosted: Sun Jul 09, 2006 10:49 am     Reply with quote

To avoid re inventing the wheel use as was recommened an existing protocol and frequency. IR is very noisy mostly it's flourescent lights that make the mischief. The protocols that have been perfected by Sony and other TV manufacturers will reject this noise by either pulse width ( o and 1 are identified by the length of the pulse) encoding or space width encoding ( same as pulse only using space)or shift encoding ( 1 is long pulse short space 0 is short pulse long space) and further protect with redundancy ... sending the signal twice sending the signal followed by its inverse etc.
Here is some code that is the inverse of what you want...You wanted your PIC to train your universal remote but you are dead at the outset since you have no Tx capability. The code below is the PIC learning or at least identifying the signal from various remotes. It will not work on any remote only the ones I had laying around the house but the code might be of use to you.
Code:

//// v1 modified for time period T
//// AGC pulse is identified as 16T
//// AGC pause is identified as 8T
//// Pulse is T and space is minimum of 2T for space encoded
//// working with toshiba and magnavox  and leadtek 6/19/04
///  format is byte0 is address and byte1 its complement
//    byte 2  is the key scan code byte3 its complement

#include <18F452>
#fuses HS,noWDT,NOPROTECT,NOPUT,NOBROWNOUT,NOLVP
#device *=16 CCSICD=TRUE

#use delay(clock=20000000)
#use rs232 (debugger)

#define IR input(PIN_A0)
#define LED PIN_D0         //// flash led on valid code received
/////////////////////////////////////////////////////////////////////////////
////                        notes         ///////////////////////////////////
////////////////////////////////////////////////////////////////////////////
//// a long 9ms pulse is sent for AGC followed by a 4 ms space
///  the bits are code as follows
//// space coded  .... zero and one is encoded by the length of the space
///                    pulse=600us and fixed  space varies  0= 600us 1=1500us
//// pulse coded  .... zero and one is encoded by the length of the pulse
///  shift coded  .... zero =short pulse long space  one =long pulse short space
///////////////////////////////////////////////////////////////////////////////

///////////////////////////////////////////////////////////////////////
///// constants to filter glitches as from flourescent lights
//////////////////////////////////////////////////////////////////////////////


///// toshiba  agc_time 30000   bit_time 1000  space coded
///// leadtek  agc_time 30000   bit_time 1000  space coded


//#define AGC_time 1000    /// 30k*.2=6 ms  AGC is typically 9ms

#define MAX_DURATION 5    //// 10ms
#define TOSHIBA 1
#define MAGNAVOX 1
#define LEADTEK 1
#define ECHSTAR 2
/////        globals //////////////////////
int16 AGC_pulse ;   /// 30k*.2=6 ms  AGC is typically 9ms
int16  AGC_space ;
int16 BIT_time  ;
int16 T;
int8 timed_out,duration,index,str_index,space_terminated,maker;
int16 pulse_width,space_width,pulse_adj;
struct {
        int8 byte0;
        int8 byte1;
        int8 byte2;
        int8 byte3;
        int8 byte4;
        int8 byte5;
       } code;
char binstr[50];


/////////////////////////////////////////
/////////   isr /////////////////////////
/////////////////////////////////////////
#int_RTCC
isr_timer0()
{
/// the timer overflows every 256 counts
/// a count occurs every 4 * 4 =16 cycles at  20MHZ or 8us
/// so we get here every 256*8 =2048 us approx
/// longest pulse or space is approx 10ms ...max duration of 5
duration++;
if (duration>=MAX_DURATION)
  {
    duration=0;
    timed_out=true;
  }

}

///////////////////////////////////////
int16 pulse()
{
  int16 time;
/// measure time the carrier is high
/// carrier high means the demodulator is low
/// a glitch can not interrupt a carrier

/// set up the interrupt timeout clock timer0
/// if timeout is exceeded interrupt sets timed_out to true
   timed_out=false;
   duration=0;
   set_timer0(0);
loop:
  time=0;

  while((IR==1)&& (timed_out==false)); //wait for low

  if (timed_out==true) return(0xFFFF); /// timed out

  set_timer1(0); /// start timing


  while(IR==0); /// hold till low ends ...low will always end since the carrier pulse is always a burst
  time=get_timer1();
  //// ignore a short carrier pulse as a glitch
  if (time<BIT_time) goto loop; //// 200 us = .2ms  or shorter are ignored
  return (time);
}

////////////////////////////////////////////////
int16 space()
{
  int16 time;
/// measure time the carrier is absent
/// carrier absent means the demodulator is high
/// the space is vunerable to a noise glitch



  while(IR==0); //wait for high it will always go high since carrier is aburst
  /// set up the interrupt timeout clock timer0
  /// if timeout is exceeded interrupt sets timed_out to true
  timed_out=false;
  duration=0;
  set_timer0(0);
  time=0;
  set_timer1(0); /// start timing

 loop:
  while((IR==1) && (timed_out==false)); /// hold till high ends
  if(timed_out==true) return(0xFFFF);
  time+=get_timer1();
/// there could be a short duration noise glitch or a truly valid pulse beginning
/// so we encroach a short time on a valid pulse when testing to see if it was a glitch
 set_timer1(0); /// start timing possible glitch .. a very short duration low ( carrier burst)
  while((IR==0) && (get_timer1()<BIT_time>2*pulse) {
                              shift_right(&code,6,1); /// goes in lsb first
                              binstr[str_index]='1';
                             }
         else                {
                             shift_right(&code,6,0);
                             binstr[str_index]='0';
                             }
         str_index--;
         }
if(mode==3)
          {
          // pulse encoded
          if (pulse>2*space) {
                              shift_right(&code,6,1); /// goes in lsb first
                              binstr[str_index]='1';
                             }
         else                {
                             shift_right(&code,6,0);
                             binstr[str_index]='0';
                             }
         str_index--;
          }
}

////////////////////////////////////////////////////////////
int8 validate(int8 mode)
{
if ((mode==1) || (mode==2))
            {
            // toshiba or magnavox byte3 is complement of byte 2 and byte 1 complement of byte 0
            if (code.byte3 != (~code.byte2)) return false;
            if (code.byte1 != (~code.byte0)) return false;
            }



return(true);
}

///////////////////////////////////////////////////
init_IR_control( int8 mode)
{
 if ( mode==1) {
                //// typical 9ms agc pulse 4ms AGC space
                ///  600us pulse eithet 600us space or 1500 us space
                AGC_pulse=30000 ;   /// 30k*.2=6 ms  AGC is typically 9ms
                AGC_space=12000 ;
                BIT_time=100;
                space_terminated=true;
                return;
               }
 if (mode==2)
                {
                /// leadtek
                AGC_PULSE=3000;
                AGC_space=30000;
                BIT_time=100;
                space_terminated=true;
                return;
                }
 return;
}




main() {
int8 j,success;

   int16 pulse_table[49],space_table[49];

   setup_timer_0(RTCC_INTERNAL|RTCC_DIV_4);    /// start timer over flows 4*4*256 cycles =800us
   setup_timer_1(T1_INTERNAL|T1_div_by_1);    // Start timer 1 tick every 4 cycles or .2us at 20mhz


/// all tv remotes send out pulses of the carrier 38kz of various durations
/// pulses are separated by spaces (no carrier) of varying duration
/// the code will measure the pulse and space intervals in a train of pulses
/// the ir is demodulated so as to have a logic high when no carrier is detected
/// a timeout is used to  end a pulse train
/// a timing constant T is  assigned to each make of remote


maker=TOSHIBA;
T=2500;
printf("\n\r start maker=%d",maker);
 enable_interrupts(INT_timer0);
 enable_interrupts(global);

///// initialize AGC pulse and space
//init_IR_control(TOSHIBA);
init_IR_control(maker);


start:
  for(j=0;j<50;j++){ pulse_table[j]=0;space_table[j]=0;}
  code.byte0=0;
  code.byte1=0;
  code.byte2=0;
  code.byte3=0;
  code.byte4=0;
  code.byte5=0;
  for(j=0;j<48;j++)binstr[j]='X';
  binstr[49]=0;
  ////////////// transmission is assumed to be lsb first
  /////////////  the structure code is written  and the string binstr as bits are translated

  str_index=48; /// string is filled lsb first so lasb goes to pos 48

  ///////// a change to pulse from the idle (space) state starts the analysis
  pulse_width=pulse(); /// get the beginning agc pulse if any

  if ((pulse_width==0xFFFF) || (pulse_width<T))  goto start; /// we timed out instead of starting
                                        /// it's not that the pulse was this long
                                        /// just that we timed_out waiting for a pulse
                                        /// or pulse is to short to be valid
  /// we have either an AGC pulse or a bit

 re_start:


  str_index=48; /// string is filled lsb first so lsb goes to pos 48
                /// str is msb.................lsb when printed
                /// lsb was received first and msb last
                /// code.byte0 is 7..lsb
                /// code.byte1 is 15..8   etc until transmission ends
                /// transmission is assumed to end after 48 bits or earlier

  pulse_table[0]=pulse_width; /// slot 0 is for the agc
  space_width=space();

  if ((space_width==0xFFFF) || (space_width<T)) goto start;  /// to long AGC space
                                        /// it's not that the space was this long
                                        /// its just that we are detecting an idle condition
                                        /// or space is too short
  space_table[0]=space_width; /// slot 0 is for the AGC

  /// we we get here we have either an AGC pulse space pair
  ///                        or a bit pulse space pair

  index=1;
  next_bit:
  /// pick up the data payload usually 48 bits


  pulse_width=pulse_adj+pulse(); /// in testing for glitches we can encroach on a little into a valid pulse

  //// payload can be pulse terminated
  if (pulse_width<T>4*T)) goto exit;
  pulse_table[index]=pulse_width; // time of high part of bit
  space_width=space();
  if(space_width<T>4*T)) goto exit;
  space_table[index]=space_width;

  translate(maker,pulse_width,space_width); //// space or pulse encoded translation


  if (index<49) {index++; goto next_bit ;}
exit:
  if(index<16 ) goto start;
  for (j=index;j<49;j++) shift_right(&code,6,0);//// need to fill in the remaining bits

  success=validate(maker);
  if (success==true) {
                     /// flash led
                     output_high(LED);
                     delay_ms(100);
                     output_low(LED);
                     delay_ms(100);
                    }
  binstr[49]=0;
  for(j=index+1;j<49;j++){ pulse_table[j]=0xFFFF;space_table[j]=0xFFFF;}

 // for (j=0;j<index;j++) printf("\n\r %02u %05lu  %05lu ",j,pulse_table[j]/5,space_table[j]/5);
  printf("\n\r %2x:%2x:%2x:%2x:%2x:%2x \n\r",
            code.byte5,code.byte4,code.byte3,code.byte2,code.byte1,code.byte0);

  if (success==true ) printf("\n\r %s OK bits %d",binstr,index-1);
  else printf("\n\r %s ERR bits %d",binstr,index-1);
  goto start;
  while(1);
}
newguy



Joined: 24 Jun 2004
Posts: 1908

View user's profile Send private message

PostPosted: Sun Jul 09, 2006 12:00 pm     Reply with quote

As was suggested, take existing code (there are at least two examples in the Code Library that I know of), and use that to create an IR receiver. Short of having a decent digital oscilloscope, there is no way to determine what code, or the code format, a remote control is sending. Once you know the code and format, then you can write a program to send these codes to the learning remote.

Some notes:
- There something like 6 major code formats, and almost all A/V equipment use one of these formats. Then there are a LOT of lesser-used codes, usually employed by such well known brands as Loewe Opta, Cmwell, and Alba. Very Happy
- The major codes usually follow a signaling scheme like this:

1. Lead in sequence - a long burst of IR at the carrier frequency (usually 38 - 40 kHz), followed by a shorter period of silence. May or may not be present (most Sony codes do not have a lead in sequence).
2. First data payload. Can be 8 - 32 bits long.
3. Lead out/pause. All formats employ a short pause (short IR burst followed by a relatively long pause - not as long as the lead-in, if present).
4. Repeat of data OR transmission of new data.
5. Pause. --> Usually the end of the transmission for most formats.
6. Repeat of data OR new data. Sony typically at a minimum will transmit 15 bits three times. In all cases I've examined, it's the same data.

As someone has already said, the actual 1 & 0 format varies as well. Here are the common ones:
- Short burst (constant), short pause = one state, short burst (constant), long pause = other state. I'm not actually going to say one is a 0 and the other is a 1 because I don't remember which is which (and this prevents someone from correcting me Twisted Evil )
- Short burst, short pause (constant), and long burst, short pause (constant).

There are many variations on this theme.

I developed a product that features an IR passthru feature - the operator points an ordinary IR remote at a touch screen, and is able to control the A/V equipment which is locked away in a vault. The commands are received, decoded, compressed and sent (via CAN bus) to the remote receiving unit where they are reconstructed and retransmitted. It took a couple of weeks for me to perfect the code, but it works perfectly now with a barely perceptable pause between the press of the button and the reaction of the equipment. The most difficult part was decoding all the different signaling formats (actually sorting through the received code to determine if a lead in sequence is present, what is the 0 & 1 format, actually decoding the data that was sent, etc). I managed to come up with an algorithm that recognizes almost all the codes in a universal remote - save for the famous brand names I mentioned earlier. Very Happy

Before you ask, no I can't share it. But a tip when it comes to transmitting the sequence (actually flashing the IR LED): use the PWM module to create a (approx) 40 kHz 50% duty cycle waveform - this drives the LED (or a transistor, which in turn drives the LED). Then write your code to switch the TRIS so that the PWM module gets connected to the LED to create the bursts, and disconnected to create the silences. Much better than using delays and output_high() and output_low() commands.
Markdem



Joined: 24 Jun 2005
Posts: 206

View user's profile Send private message Send e-mail

PostPosted: Sun Jul 09, 2006 3:55 pm     Reply with quote

Thank you for all your help guys.

I did not think of using a remote from another device that i dont have. The universal remote can be programed with predefinded sets of codes from the internet. So, what i am thinking i will do is take a device that i dont own eg. sony tv, and send the commands to my reciver that i will make. Then iwill make my reciver change the command from the remote, eg channel up, into a command i need, eg lights on.

Will this work??

Thanks again, Mark
asmallri



Joined: 12 Aug 2004
Posts: 1635
Location: Perth, Australia

View user's profile Send private message Send e-mail Visit poster's website

PostPosted: Sun Jul 09, 2006 7:05 pm     Reply with quote

Yes it will work, I used this approach myself.
_________________
Regards, Andrew

http://www.brushelectronics.com/software
Home of Ethernet, SD card and Encrypted Serial Bootloaders for PICs!!
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2005 phpBB Group