Tutorial on IR - Questions for Nigel

Status
Not open for further replies.

atferrari

Well-Known Member
Most Helpful Member
Hola Nigel,

Today I've tried for the first time to decode SIRC packets following your tutorials. The emiter works like a charm but the decoder failed because I tried to get rid of the lines that I believed were not needed in my application.

Could you please explain what's the reason for the "*" marked lines so I can make a correct change to the soft?

I just need to decode simple commands sent by a PIC to another with no keyboard involved.

Since I can not appreciate if those lines are involved in the timing and how, I need your help even more. I will appreciate that :!:

Code:
Read_Pulse

      clrf	LoX
		btfss  IR_PORT, 	IR_In	;wait until high
      goto    $-1
		(*) clrf	 tmp1
		(*) movlw	0xC0			;delay to decide new keypress
		(*) movwf	tmp2			;for keys that need to toggle

Still_High	

      btfss   IR_PORT, 	IR_In	;and wait until goes low
      goto    Next
		(*)incfsz	tmp1,f
		(?)goto	  Still_High
		(*)incfsz	tmp2,f
		(?)goto	  Still_High
		(*)bsf	   Flags2,	New		;set New flag if no button pressed
		(?)goto	  Still_High

Next

		nop
		nop
		nop
		nop
 
For a start I would suggest you use the software EXACTLY as is, to prove everything works, before you try altering it!.

It's also pretty pointless removing sections at random?, the first section you've marked sets up a 16 bit register as a counter (comprising of two GPR's - tmp1 and tmp2). The second part uses this counter while waiting for the input to go LOW, which will be the start of the next pulse. If the counter times out, then you know that the following IR code is a new one, and not just the previous code repeated because the button is held down, in which case it sets a flag to let you know - this flag is used later, so you can toggle outputs ON and OFF using the same button.
 
Going further

Hi Nigel,

My application consists of a PIC decoding IR (in SIRC format) from another with no other external hardware involved.

Packs are sent but not repeated. At least not for now.

For the moment I intend to do some plain decoding.

The micro is supposed to decode the IR signal and generate a PWM signal for an RC servo (TMR1 & TMR2) and no buttons at all. This soft, AS IS, would make no sense there.

I just wanted to eliminate what I believe is not needed. Maybe I am not wise enough for this but I don't change things at random.

I tried my best and if you help me again, sure I will appreciate that.

Understanding other people's soft is not my strongest point

Gracias
 
After testing, found that this is the right change to decode one pack, once:


Code:
Read_Pulse

      clrf	LoX
		btfss  IR_PORT, 	IR_In	;wait until high
      goto    $-1
		
Still_High	

      btfss   IR_PORT, 	IR_In	;and wait until goes low
      goto    Next
		goto	  Still_High

Next

		nop
		nop
		nop
		nop
 
Yeah ur right...you can eliminate some of the code & it will still work... i tried that before...i even went more further to use TMR0 as a counter...But be sure of something, sometimes u'll get the right answer but it's not the fact that u have the right code, but that you have 2 mistakes that eliminate each other and this happens a lot during programming
 
Yes...

Hola Charly,

In this particular case is not "jus by chance" that I got it running.

I eliminated the timing for a function that I don't need. The rest is the core of what Nigel showed.

In my case, at least in paper, I found a way to get PWM interrupt-based signal using TMR1 only, quite simple, I would say. To be tested today late PM.

Next step to make the whole one 8-bit pack only, simplifying bit counting avoiding rotations to justify. Obvious, to say the least, I think.

May I know what was you application:?:

Interested :!:
 
Hi atferrari,

My application was to control a PLC wirelessly using a remote control
I didnt get right the 8-bit pack..Do you mean that you're not testing what's the status of the bit received?
Hope you can send me the code if it worked with u using PWM (or you mean Capture mode)??
good luck and give me ur feedback and ready for any help
 
You might find this useful?, it was sent to me by a gentleman called Joe Brown, and is a version of my IR routines using CCP1 - this demo version outputs via RS232.

Code:
;Based on: 	Tutorial 5_1
;			Read SIRC IR with LCD display
;			Nigel Goodwin 2002
; This version using CCP1 interrupts by:
; 			Joe Brown 2005
; 1st version works with 4Mhz xtal and outputs 2 bytes to serial at 31250 Baud (uncomment commented code marked !!!)
; 2nd version works with 20 Mhz xtal and prescaled timer 1

	LIST	p=16F628A		;tell assembler what chip we are using
	include "P16F628a.inc"		;include the defaults for the chip
	__CONFIG _HS_OSC & _WDT_OFF & _PWRTE_OFF & _CP_OFF & _BODEN_OFF & _LVP_OFF
; vars left from orig
Bit_Cntr EQU 0x21
Cmd_Byte EQU 0x22
Dev_Byte EQU 0x23

Flags EQU 0x25

; vars new for CCP1 version
midi_byte0 EQU 0x2a
counthi EQU 0x2b
countlo	EQU 0x2c
W_TMP EQU 0x2d
STATUS_TMP EQU 0x2e
FSR_TMP EQU 0x2f
timelo EQU 0x30
timehi EQU 0x31
periodlo EQU 0x32
periodhi EQU 0x33


StateFlags EQU 0x36
commandcomplete EQU 0x37
devicebyte EQU 0x38
commandbyte EQU 0x39

;delay constants
#define DELAYHI H'F3'    
#define DELAYLO H'FF'    

IR_In Equ 0x03	;changed to 3 from 2 JWB ;input assignment for IR data
LED	Equ	0x07 ; command rxd LED

ErrFlag		Equ	0x00
StartFlag	Equ	0x01			;flags used for received bit
One		Equ	0x02
Zero		Equ	0x03

#define GetCommand 0
#define GetDevice 1
#define Ready 0 ; bit 0 of 'commandcomplete' flags sequence completed


	org	0x0000		; reset vector
	goto	Start

   	org     0x0004 ; IRQ vector

 	movwf	W_TMP
	swapf	STATUS, W
	clrf	STATUS		; switch to bank 0
	movwf	STATUS_TMP
	movf	FSR, W
	movwf	FSR_TMP
	
IRQCheck
	; which IRQ received?
	btfsc PIR1,CCP1IF
		goto CaptureIRQ
IRQEnd
	movf	FSR_TMP, W
	movwf	FSR
	swapf	STATUS_TMP, W
	movwf	STATUS
	swapf	W_TMP, F
	swapf	W_TMP, W
	retfie

CaptureIRQ
	; 1st clear interrupt
	bcf PIR1,CCP1IF
	bcf STATUS,C
	movf timelo,W		; period = newtime - oldtime
	subwf CCPR1L,W
	movwf periodlo
	movf timehi,W
	subwf CCPR1H,W
	movwf periodhi
	; update timelo/hi
	movf CCPR1L, W
	movwf timelo
	movf CCPR1H, W
	movwf timehi

	bsf STATUS,RP0	; bank1
	bcf PIE1 ^ 0x80, CCP1IE ; disable CCP interrupt whilst changing direction 
	bcf STATUS, RP0 ; bank 0

	btfsc PORTB,3	; test line
		goto linehigh
linelow
	clrf CCP1CON
	movlw B'00000101' ; enable interrupts for rising edge
	movwf CCP1CON	
	goto DoneCCP1IRQ ; only process rising edge
linehigh
	clrf CCP1CON
	movlw B'00000100' ; enable interrupts for falling edge
	movwf CCP1CON

	; test the pulse length and set flags accordingly
	clrf Flags
TestError
;	goto TestZero
	movf periodhi,W
; !!!	addlw .255 - .1 ; if periodhi <= 1, pulse is an error
	addlw .255 - .1 ; if periodhi <= 1, pulse is an error
	btfsc STATUS,C
		goto TestZero
	bsf Flags, ErrFlag
	goto CalcByte
TestZero
	movf periodhi,W
; !!!	addlw .255 - .4 ; if periodhi <= 4, pulse is a zero
	addlw .255 - .5 ; if periodhi <= 5, pulse is a zero
	btfsc STATUS,C
		goto TestOne
	bsf Flags, Zero
	goto CalcByte
TestOne
	movf periodhi,W
; !!!	addlw .255 - .6 ; if periodhi <= 6, pulse is a one
	addlw .255 - .7 ; if periodhi <= 7, pulse is a one
	btfsc STATUS,C
		goto TestStart
	bsf Flags, One
	goto CalcByte
TestStart
	movf periodhi,W
; !!!	addlw .255 - .11 ; if periodhi <= 11, pulse is start pulse
	addlw .255 - .13 ; if periodhi <= 13, pulse is start pulse
	btfsc STATUS,C
		goto IsErr
	bsf Flags, StartFlag
	goto CalcByte
IsErr
	bsf Flags, ErrFlag

CalcByte
	btfss Flags, StartFlag
		goto chkerrflag
	; when we arrive here a atartbit has been found
	clrf Cmd_Byte ; clear accumulator for command
	clrf Dev_Byte ; and for device number
	clrf StateFlags ; clear old states
	movlw 0x07		; number of bits to get for command
	movwf Bit_Cntr
	bsf StateFlags, GetCommand ; indicate state = get cmd
	goto DoneCCP1IRQ

chkerrflag
	btfss Flags, ErrFlag
		goto chkstatecmd
	clrf StateFlags
	goto DoneCCP1IRQ

chkstatecmd	
	btfss StateFlags, GetCommand	
		goto chkstatedev
	bcf STATUS,C		; state = Get Command so check zero/one
	btfss Flags, Zero
		bsf STATUS,C
	rrf Cmd_Byte,F      ; rotate C into the accumulator
	decfsz Bit_Cntr,F
		goto DoneCCP1IRQ
	rrf Cmd_Byte,F ; correct alignment of the seven bits
	clrf StateFlags
	bsf StateFlags, GetDevice ; move state to state = get device num
	movlw 0x05		; num of bits for device
	movwf Bit_Cntr
	goto DoneCCP1IRQ

chkstatedev
	btfss StateFlags, GetDevice
		goto IsErr

	bcf STATUS,C		; state = Get Device so check zero/one
	btfss Flags, Zero
		bsf STATUS,C
	rrf Dev_Byte,F
	decfsz Bit_Cntr,F
		goto DoneCCP1IRQ
	rrf Dev_Byte,F ; correct alignment of the bits
	rrf Dev_Byte,F ; correct alignment of the bits
	rrf Dev_Byte,F ; correct alignment of the bits
	movf Dev_Byte,W
	movwf devicebyte ; make copy
	movf Cmd_Byte,W
	movwf commandbyte ; make copy
	bsf commandcomplete,Ready ; flag sequence complete
	bsf PORTB,7 ; switch on response LED
		 	
DoneCCP1IRQ
	bsf STATUS,RP0	; bank1
	bsf PIE1 ^ 0x80,CCP1IE ; re-enable CCP1 interrupt
	bcf STATUS,RP0 ; bank0
	bcf PIR1,CCP1IF ; clear any spurious interrupt (see data sheet for why)
	goto IRQEnd


; Main program starts here
Start
	movlw	0x07
	movwf	CMCON			;turn comparators off (make it like a 16F84)

Initialise	
	clrf	PORTA
	clrf	PORTB
	clrf	Flags
    clrf    Dev_Byte
	clrf	Cmd_Byte	

SetPorts	
	bsf STATUS,	RP0	;select bank 1
	
	movlw	0x00			;make PortA all output
	movwf	TRISA ^ 0x80
	movlw	b'01111011'		;make IR port pin input, RB7 output to LED, RB2 serial TX, RB4 i/p for switch
	movwf TRISB ^ 0x80
	; init serial for 31250 Baud
	movlw B'00100100'  ;BEGIN SERIAL PORT INITIALIZATION, SET TXEN=1, BRGH=1
	movwf	TXSTA ^ 0x80
; !!!	movlw 0x07 ; calc manually for 4 MHz clock using formula in data sheet
;	movlw .39 ; calc manually for 20 MHz clock using formula in data sheet
	movlw .129 ; 9600 Baud
	movwf	SPBRG ^ 0x80

	bcf 	STATUS,		RP0	;select bank 0

	; Configure Receive Status and Control Register
	movlw	(1 << SPEN) | (1 << CREN)
	movwf	RCSTA

	bsf PORTB,7 ; switch on LED
	call Delay
	call Delay
	call Delay
	call Delay
	bcf PORTB,7 ; switch LED Off

	; init timelo/hi
    movf TMR1L,W ;	timelo = TMR1L
	movwf timelo
	movf TMR1H,W ; timehi = TMR1H
	movwf timehi
	
	clrf CCP1CON
	movlw B'00000100' ; enable CCP1 interrupts for falling edge
	movwf CCP1CON

	bsf STATUS,RP0	; bank1
	bsf PIE1 ^ 0x80,CCP1IE ; enable CCP1 interrupt
	bcf STATUS,RP0 ; bank0

	clrf commandcomplete
	movlw (1 << GIE) | (1 << PEIE) ; enable global and peripheral interrupts
	movwf INTCON
; !!!	bsf T1CON,TMR1ON ; switch on Timer 1 (No prescale)
	movlw B'00100001'
	movwf T1CON		; 5,4 = 10 = 1:4 prescale

	movlw 0x55
	movwf midi_byte0
	call TxMidi			; send check byte to serial 

Main
	btfsc PORTB,4
		goto Main		; loop till button press
	bcf PORTB,7 		; switch off LED

maybe
	btfss commandcomplete,Ready ; if byte rxd from IR
		goto Main
	; display on MIDI Monitor the 2 hex bytes for device and command
	movf devicebyte,W
	movwf midi_byte0
	call TxMidi			; send device num to MIDI
	movf commandbyte,W
	movwf midi_byte0
	call TxMidi          ; send command num
	clrf commandcomplete
	goto Main

;=================
; Transmit to MIDI
;=================
TxMidi
	btfss PIR1, TXIF
		goto TxMidi ; poll til ready
	movf midi_byte0,W
	movwf TXREG
	return

;======================================
; Delay loop
;======================================
Delay           
		MOVLW   DELAYHI
        MOVWF   counthi
        MOVLW   DELAYLO
        MOVWF   countlo
DelayLoop
        NOP ;WASTE SOME TIME
        NOP
        NOP
        DECFSZ  countlo,F
        GOTO    DelayLoop
        DECFSZ  counthi,F
        	GOTO    Delaysetup2
        GOTO    Delaydone
Delaysetup2
        MOVLW    DELAYLO
        MOVWF   countlo
        GOTO    DelayLoop
Delaydone
        RETURN

		end
 
My application

ChArLyZzZ said:
Do you mean that you're not testing what's the status of the bit received?
:?: :? What do you actually mean?

Came too late from my last vessel, with little time sleeping in the last 72 hrs, so it's easier replying to you than going to the bench. Bed is waititng.. :?

My idea: a 3-legs bot. Each one with a 16F628 in charge of the motor (not sure yet if a common DC type or a modified RC servo).

One 16F877, sending a START pulse followed by an 8-bit pack (4 bits for "device ID" and 4 bits for "command"). The base is the SIRC protocol using the soft mentioned in the original post.

For the moment, to keep it simple, the three will recognize same ID. And four commands: Start / Stop / Increase / Decrease.

I recall my first tests to control DC motors where the aceleration rate was "built in" in the starting sequence. I couldn't find concrete advice on how to calculate that so I tested several variants until settling with something that seemed to work.

So, I think that eventually :?: I could go away with just "start" & "stop".

Once running I will look for error checking and "robustness". (I like this expression) Professionals use it quite a lot about soft and circuits.

A comment:

I was told: There is not reason to re-invent the wheel. And also told: unless you get a better wheel.

In fact I tend to refuse the idea of following a recipe putting nothing from my part. That's why I try to understand how code works.

:arrow: Back to you...

Lookinf for my landing strip, right now :cry:
 
Status
Not open for further replies.
Cookies are required to use this site. You must accept them to continue using the site. Learn more…