Douglas Kennedy
Joined: 07 Sep 2003 Posts: 755 Location: Florida
|
|
Posted: Fri Jul 29, 2005 4:23 am |
|
|
I experimented with several remotes I had around the house
I used a radio shack part to demodulate the infra red carrier.
Issues to watch for:
1)There is more than one carrier freq 38khz 40khz etc.
2)Each remote can and often does have its own way of encoding the signal.
3) Some have ways of detecting a button held down all try to reject a false signal from flourescent lights by repeating or complementing the key press code.
4) some remotes use space coding others pulse coding
Life would have been simpler and everyone wouldn't have a dozen different remotes had there been some industry agreement or government specification but it was urban sprawl and anything that works goes.
A scope is very helpful to probe into the specific formats
This code might help you tease out the specifics of the remote you have.
Code: | //// 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.h>
#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
///// globals //////////////////////
int16 AGC_pulse ; /// 30k*.2=6 ms AGC is typically 9ms
int16 AGC_space ;
int16 BIT_time ;
int8 timed_out,duration,index,str_index,space_terminated,maker;
int16 pulse_width,space_width,pulse_adj;
char model[21]; //// FTER IDENTIFICATION WILL HOLD MODEL NAME EX TOSHIBA-TV
struct {
int8 byte0;
int8 byte1;
int8 byte2;
int8 byte3;
int8 byte4;
int8 byte5;
} code;
char binstr[49]; // 48 char buffer of 0 or 1 bits as ascii
/////////////////////////////////////////
///////// 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)); // start of a new pulse but it could be just a glitch
// we got to this point if IR went high or we glitched low
if (IR==1) goto loop; /// ignore glitch of 1000*.2us or less and continue to time till high ends
/// this is the true end to the space since we have gone low for at least BIT_time
pulse_adj=get_timer1(); /// we encroached a wee bit into a valid pulse so we adjust
return(time);
}
/////////////////////////////////////////////////////////////
translate(int8 mode, int16 pulse, int16 space)
{
///// *code points to the code structure of 48 bits s points to the binstr
///// rotate the bit into the 48 bit structure
/////// code is the 48 bit global structure
/////// binstr is a 49 char string to hold the binary digits
/////// index is where we are in the translation
if ((mode==1) || (mode==2) )
{
//toshiba VC459 T space encoded or magnavox universal
// each byte of the 32 bit code is sent LSB first
// 8 bit address ex 0x44 and its complement 0xbb
// followed by key press code byte 0x01 for key '1' and lastly the inverse of the key byte 0xFe
if (space>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';
}
}
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';
}
;
}
}
////////////////////////////////////////////////////////////
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=30000;
AGC_space=12000;
BIT_time=100;
space_terminated=false;
return;
}
return;
}
main() {
int8 i,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
maker=TOSHIBA;
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=str_index;j>0;j--)binstr[j]='X';
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[48]=0;
////////////// transmission is assumed to be lsb first
str_index=47; /// string is filled lsb first so lasb goes to pos 48
pulse_width=pulse(); /// get the beginning agc pulse
if( (pulse_width<AGC_pulse) || (pulse_width==0xFFFF)) goto start; /// 30k*.2 =6 ms min for AGC
re_start:
pulse_table[0]=pulse_width; /// slot 0 is for the agc
space_width=space();
if ((space_width<AGC_space) || (space_width==0xFFFF)) goto start; /// to short a AGC space
space_table[0]=space_width; /// slot 0 is for the AGC
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>AGC_pulse) goto exit;
pulse_table[index]=pulse_width; // time of high part of bit
space_width=space();
if(space_width>AGC_space) 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:
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[48]=0; //// just in case 49 get overwritten
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",
code.byte5,code.byte4,code.byte3,code.byte2,code.byte1,code.byte0);
if (code.byte0==0x40 ) printf(" TOSHIBA_TV \n\r");
else if (code.byte0==0x44 ) printf(" TOSHIBA_VCR \n\r");
else if (code.byte0==0x04 ) printf(" MAGNAVOX_TV\n\r");
else if (code.byte0==0x03 ) printf(" LEADTEK \n\r");
else printf(" UNKNOWN \n\r");
for(i=0;i<6;i++)
{
for(j=0;j<8;j++)printf("%c",binstr[i*8+j]);
printf(":");
}
if (success==true ) printf(" OK bits %d",index-1);
else printf(" ERR bits %d",index-1);
goto start;
while(1);
}
|
|
|