Continue to Site

Welcome to our site!

Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

  • Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

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 :)
 
You said so yourself, you already have sample code. Figure out what's wrong with what you have.
 
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?
 
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 :)

different compiler, does not use ccp module but is C

**broken link removed**
 
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)...
 
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_add;
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:
		ir_add = ir_cmd = 0;
		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:
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 MyAdd;
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;

	GetSIRC(&MyAdd,&MyCmd);
	while(1);
}

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

	ir_add = ir_cmd = 0;

	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			
	}

	*address = ir_add;
	*command = ir_cmd;
}
 
Last edited:
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?

sony-sirc-png.29754
 

Attachments

  • Sony SIRC.PNG
    Sony SIRC.PNG
    3.5 KB · Views: 1,718
Last edited:
A couple more questions about SIRC, please?

(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?
 
A couple more questions about SIRC, please?

(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
 
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 :D
 
Last edited:
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?

sony-sirc-png.29779
 

Attachments

  • Sony SIRC.PNG
    Sony SIRC.PNG
    5.4 KB · Views: 1,479
Last edited:
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.
 
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 :D
 
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:
A good while back someone emailed me an interrupt driven version of my original receiver code, I meant to add it to my tutorials, but forgot all about it - and can't seem to find it any more.

I'll keep looking.
 
Status
Not open for further replies.

Latest threads

New Articles From Microcontroller Tips

Back
Top