# Sony IR decode using hi-tech C for PIC16F877A

Status
Not open for further replies.

#### stockton

##### New Member
Dear all~~~
I have a Sony IR decode Project.
I am using Hi-tech C program language.
My hardware is PIC16F877A whit 4M crystal.
I want to use CCP module.
I have find sample code in Google.
But it can not work correctly.
The CCPR1 is always not Sony IR code.
Does anyone have Hi-tech C sample code for me???
THX

##### Banned
You said so yourself, you already have sample code. Figure out what's wrong with what you have.

#### Nigel Goodwin

##### Super Moderator
There's code in assembler in my tutorials, but perhaps more helpful for you there's a description of how SIRC's works.

#### AtomSoft

##### Well-Known Member
Hey Nigel 1 question. When sending SIRC i know one must send out pulses to make the data aka start, one, zero but when receiving the data it comes back as solid blocks? Like i just have to read the start and see how long it is right? it doesnt receive actual pulses right like i wont have to read the PULSES right?

#### blueroomelectronics

##### Well-Known Member
The TSOP1138 (or equivalent) removes the carrier.

#### AtomSoft

##### Well-Known Member
yay! i think i finally understand it then. Thanks Bill and Nigel.

#### Mike - K8LH

##### Well-Known Member
Gosh Russ, it would take me less time to research and implement my own algorithms and method from scratch rather than try to analyze the stuff you have spread out across all those files (grin)...

#### AtomSoft

##### Well-Known Member
OMG i did it.:
Code:
/* **************************************************************************
;																			*
;	Filename: SIRC															*
;	Date: May 29, 2009														*
;	File Version: 001														*
;																			*
;	Author:   Jason Lopez													*
;	Company:  AtomSoft														*
;																			*
;****************************************************************************
; Notes:
; I am delaying in this code a nice even number every 200uS. Mainly because if
; i count each pulse it would be accurate but too many counts for a char type
; and i dont want to use a int. So i can get a 600 count by skipping every 300uS
; and the count will be a nice low number...3
;
; For a 1.2mS aka HIGH i should get a count of 6 and for the start 2.4mS i should
; get a count of 12. Since this isnt too accurate i range it about 1-2 numbers
; above or below the standard.
;
;****************************************************************************
*/
#include <p18f2525.h>
#include <delays.h>
#include <string.h>

#pragma config WDT = OFF, LVP = OFF, OSC = INTIO67, XINST = OFF

unsigned char lTime;
unsigned char ir_cmd;

#define irTris TRISCbits.TRISC4
#define irPin PORTCbits.RC4

void main(void);
void GetSIRC(void);

void main(void){
OSCCON = 0x72;      			//8MHz clock
while(!OSCCONbits.IOFS);		//wait for osc stable

irTris = 1;

GetSIRC();
while(1);
}

void GetSIRC(unsigned char *address, unsigned char *command){
char x;
StartLook:
while(irPin);			//wait for it to be low
lTime = 0;				//reset the counter
while(irPin == 0){		//while the pin is low which is our pulse count
lTime++;			//increment every 200uS until pin is high
Delay100TCYx(4);	//200uS delay
}

if(lTime <= 10)			//Start too short
goto StartLook;		//Restart
if(lTime >= 14)			//Start too long
goto StartLook;		//Restart

lTime = 0;
for(x=0;x<7;x++){			//repeat 7 times for command
ir_cmd >>= 1;			//if it was skipped or is done ORing then shift over the 1
while(irPin);			//wait for it to be low
lTime = 0;				//reset the counter
while(irPin == 0){		//while the pin is low which is our pulse count
lTime++;			//increment every 200uS until pin is high
Delay100TCYx(4);	//200uS delay
}
if(lTime >= 6)		//If its high then OR a 1 in else skip
ir_cmd |= 0x40;	//if its less than 6 its a 0 so dont OR it

}
for(x=0;x<5;x++){			//repeat 5 times for address/device
ir_add >>= 1;			//if it was skipped or is done ORing then shift over the 1
while(irPin);			//wait for it to be low
lTime = 0;				//reset the counter
while(irPin == 0){		//while the pin is low which is our pulse count
lTime++;			//increment every 200uS until pin is high
Delay100TCYx(4);	//200uS delay
}
if(lTime >= 6)		//If its high then OR a 1 in else skip
ir_add |= 0x10;	//if its less than 6 its a 0 so dont OR it
}
}
EDIT:
I fixed it up and commented like crazy... even a top part for how it works.

Last edited:

#### AtomSoft

##### Well-Known Member
Wanna use a POINTER instead then here ya go:
Code:
/* **************************************************************************
;																			*
;	Filename: SIRC															*
;	Date: May 29, 2009														*
;	File Version: 001														*
;																			*
;	Author:   Jason Lopez													*
;	Company:  AtomSoft														*
;																			*
;****************************************************************************
; Notes:
; I am delaying in this code a nice even number every 200uS. Mainly because if
; i count each pulse it would be accurate but too many counts for a char type
; and i dont want to use a int. So i can get a 600 count by skipping every 300uS
; and the count will be a nice low number...3
;
; For a 1.2mS aka HIGH i should get a count of 6 and for the start 2.4mS i should
; get a count of 12. Since this isnt too accurate i range it about 1-2 numbers
; above or below the standard.
;
;****************************************************************************
*/
#include <p18f2525.h>
#include <delays.h>
#include <string.h>

#pragma config WDT = OFF, LVP = OFF, OSC = INTIO67, XINST = OFF

unsigned char lTime;

unsigned char MyCmd;

#define irTris TRISCbits.TRISC4
#define irPin PORTCbits.RC4

void main(void);
void GetSIRC(unsigned char *address, unsigned char *command);

void main(void){
OSCCON = 0x72;      			//8MHz clock
while(!OSCCONbits.IOFS);		//wait for osc stable

irTris = 1;

while(1);
}

void GetSIRC(unsigned char *address, unsigned char *command){
unsigned char ir_cmd;
char x;
StartLook:

while(irPin);				//wait for it to be low
lTime = 0;					//reset the counter

while(irPin == 0){			//while the pin is low which is our pulse count
lTime++;				//increment every 200uS until pin is high
Delay100TCYx(4);		//200uS delay
}

if(lTime <= 10)				//Start too short
goto StartLook;			//Restart
if(lTime >= 14)				//Start too long
goto StartLook;			//Restart

lTime = 0;
for(x=0;x<7;x++){			//repeat 7 times for command
ir_cmd >>= 1;			//if it was skipped or is done ORing then shift over the 1

while(irPin);			//wait for it to be low
lTime = 0;				//reset the counter

while(irPin == 0){		//while the pin is low which is our pulse count
lTime++;			//increment every 200uS until pin is high
Delay100TCYx(4);	//200uS delay
}

if(lTime >= 6)			//If its high then OR a 1 in else skip
ir_cmd |= 0x40;		//if its less than 6 its a 0 so dont OR it

}
for(x=0;x<5;x++){			//repeat 5 times for address/device
ir_add >>= 1;			//if it was skipped or is done ORing then shift over the 1

while(irPin);			//wait for it to be low
lTime = 0;				//reset the counter

while(irPin == 0){		//while the pin is low which is our pulse count
lTime++;			//increment every 200uS until pin is high
Delay100TCYx(4);	//200uS delay
}

if(lTime >= 6)			//If its high then OR a 1 in else skip
ir_add |= 0x10;		//if its less than 6 its a 0 so dont OR it
}

*command = ir_cmd;
}

Last edited:

#### Mike - K8LH

##### Well-Known Member
Very nice Jason (AtomSoft), and all in a single file too (grin)...

So it seems Sony SIRC is something like this with base timing in intervals of 550 to 600 usecs?

#### Attachments

• 3.5 KB Views: 1,564
Last edited:

#### AtomSoft

##### Well-Known Member
Yeah exactly! Thanks! I also fixed the code on both my post here. The code is at 100% (i hope)

#### Mike - K8LH

##### Well-Known Member

(1) Is the signal from the TSOP1138 type decoders "active low" when it's receiving the IR signal (signals reversed from my drawing above)?

(2) Do those signal times vary considerably?

#### Nigel Goodwin

##### Super Moderator

(1) Is the signal from the TSOP1138 type decoders "active low" when it's receiving the IR signal (signals reversed from my drawing above)?
Yes, it's active low.

(2) Do those signal times vary considerably?
Yes they do, which is why you can't reliably just send RS232 serial data over the link.

So my tutorial doesn't check for specific pulse widths, but if it's within a certain range or not, here's the actual code, the values are simply scaled to fit within a single byte, and have no precise meaning.

Code:
; test if Zero, One, or Start (or error)

Chk_Pulse	clrf	Flags

TryError	movf 	LoX,	w		; check if pulse too small
addlw 	d'255' - d'20'		; if LoX <= 20
btfsc   STATUS    , C
goto 	TryZero
bsf	Flags,	ErrFlag		; Error found, set flag
retlw	0x00

TryZero		movf 	LoX,	w		; check if zero
addlw 	d'255' - d'60'		; if LoX <= 60
btfsc   STATUS    , C
goto 	TryOne
bsf	Flags,	Zero		; Zero found, set flag
retlw	0x00

TryOne 		movf 	LoX,	w		; check if one
addlw 	d'255' - d'112'		; if LoX <= 112
btfsc   STATUS    , C
goto 	TryStart
bsf	Flags,	One		; One found, set flag
retlw	0x00

TryStart 	movf 	LoX,	w		; check if start
addlw 	d'255' - d'180'		; if LoX <= 180
btfsc   STATUS    , C
goto 	NoMatch
bsf	Flags,	StartFlag	; Start pulse found
retlw	0x00
NoMatch						; pulse too long
bsf	Flags,	ErrFlag		; Error found, set flag
retlw	0x00

;end of pulse measuring routines

#### AtomSoft

##### Well-Known Member
Im not 100% sure on my Receiver Part But I checked it with the PICKIT 2 Logic software and it seems to be active low. And inactive high. It maybe just my part now sure. I dont even have info on it. Ill try other receiver peice i have here and see if i get same results ok.

EDIT:
HEH i guess Nigel cleared that up

Last edited:

#### Mike - K8LH

##### Well-Known Member
Thanks guys. Good info'.

Is it important to measure the actual active-low portion of the signal or could you simply measure the time between active-low leading edges?

#### Attachments

• 5.4 KB Views: 1,322
Last edited:

#### Nigel Goodwin

##### Super Moderator
Thanks guys. Good info'.

Is it important to measure the actual active-low portion of the signal or could you simply measure the time from active-low leading edge to active-low leading edge?
It's important to measure the actual active-low time of each pulse, bear in mind it's not just a question of reading SIRC's, it's a question of rejecting all other types of IR signal.

#### AtomSoft

##### Well-Known Member
Knowing this info its real easy to create your own IR Protocol.

I think ill make one today. Ill call it AIRP or AIRC.

AtomSoft InfraRed Protocol
AtomSoft InfraRed Control

lol. Would be fun to do but would require a custom remote

#### Mike - K8LH

##### Well-Known Member
Jason,

I agree but one of the interesting aspects of this research is that I could use one of these very inexpensive "universal remotes" as the control head for some of my projects. There would be more unique key codes than I could ever possibly use.

Nigel,

Thank you for supplementing Pommie's and AtomSoft's excellent examples. I'd like to develop a simpler GetBit routine that qualifies each SIRC bit. Then I could decode the 12 bit style SIRC codes with a very simple routine like this;

Code:
;
;  the GetBit "blocking" sub' only returns on a valid SIRC bit
;
;    C = 1 for a valid <start> bit
;    C = 0 and Z = 1 for a '0' bit
;    C = 0 and Z = 0 for a '1' bit
;
GetSIRC
call    GetBit          ; a qualified <start> bit?        |B0
bnc     GetSIRC         ; no, branch, else                |B0
clrf    irCmd           ; clear 'irCmd' variable          |B0
bsf     irCmd,6         ; set counter bit for 7 bits      |B0
CmdLoop call    GetBit          ; get <data> bit in Z (C=0)       |B0
skpz                    ; bit = 0? yes, skip, else        |B0
bsf     irCmd,7         ; bit = 1                         |B0
rrf     irCmd,F         ; collected all 7 'Cmd' bits?     |B0
bnc     CmdLoop         ; no, branch, else                |B0
clrf    irDev           ; clear 'irDev' variable          |B0
bsf     irDev,4         ; set counter bit for 5 bits      |B0
DevLoop call    GetBit          ; get <data> bit in Z (C=0)       |B0
skpz                    ; bit = 0? yes, skip, else        |B0
bsf     irDev,5         ; bit = 1                         |B0
rrf     irDev,F         ; collected all 5 'Dev' bits?     |B0
bnc     DevLoop         ; no, branch, else                |B0
return                  ;                                 |B0
I'm not sure a "blocking" type subsystem like this will work in most of my projects though so I think I might also research ways to make this a background task.

Thanks again for all the info' guys.

Mike

Last edited: