PDA

View Full Version : IR Learner? Need ideas



Megahertz
- 3rd April 2011, 11:08
Hi, I am trying to build a program for my 16F676 which can help it learn at least 1 code from any IR transmitter. Two LEDs (red and green) to be connected to my PIC, one button & one IR receiver. When button is pressed PIC should go to the learning mode.
Then while in learning mode someone to press a button on ANY ir remote and PIC will learn that button code. Every time that particular button is pressed, green LED to glow for 1 sec else RED will stay ON.

I have a code I use currently, but it involves me making my own transmitter as well, since I can control pulses coming out from my own transmitter, it is easy to program the receiver to catch those pulses (Thanks to Bruce for his codes on his website).


PULSIN PORTA.3,0,PULSE_IN '// Read-in start pulse
IF (PULSE_IN < 200) OR (PULSE_IN = 0) OR (PULSE_IN > 270) THEN Decode2 '// Less than Start pulse, then keep looking

Verify:
FOR Index = 0 TO 15 '// Setup to read-in 16 pulses
PULSIN PORTA.3,0,IR_PULSE[Index] '// Read 13 low-going pulses on RA.7
NEXT Index '// Loop x times
DBYTE = $FF '// Start with all 1's and find each 0
ABYTE = $FF '// Start with all 1's and find each 0 in pattern
FOR Index = 0 TO 7 '// Get 8 "data" bits
IF IR_PULSE[Index] < 85 THEN DBYTE.0[Index]=0
IF IR_PULSE[Index+8] < 85 THEN ABYTE.0[Index]=0
NEXT Index
-------------------------------------------------------------------------------------------------------
Since now I want to train my PIC to learn any sort of pulse from any sort of transmitter, I am totally confused as to how my PIC will learn that. I have to sync with some start bit to make this happen. But there are so many protocols, that I need a little help to achieve this.

dhouston
- 3rd April 2011, 18:43
Your approach is far too limited. Some protocols use PulseWidthModulation (PWM), some use PulsePositionModulation (PPM) and some use something entirely different. Also the number of bits in a code can vary from less than 20 to more than 100. Most, but not all, use an extended silence between repeat copies of the code.

My interest has been more with RF than IR but the approach is similar except that most RF receivers are active high while most IR receivers are active low.

Here's some code I use with RF. You'll need to modify it for IR. And it will capture only PWM & PPM codes - there are other protocols.


'============================RECEIVER============= ===============
'PIC12F683 @ 8MHz <500 words
'Receives up to 44 bits of PDM/PWM RF with initial lead-in of 2-9mS
'outputs received codes via RS232 @ 9600bps on GPIO.4 (Pin 3)

@ __config _INTRC_OSC_NOCLKOUT & _WDT_OFF & _PWRTE_ON & _MCLRE_OFF & _BOD_ON & _CP_OFF & _CPD_OFF

DEFINE OSC 8 '8 MHz oscillator
DEFINE ADC_BITS 8
DEFINE ADC_CLOCK 3
DEFINE ADC_SAMPLEUS 25
DEFINE DEBUG_REG GPIO
DEFINE DEBUG_BIT 4 'GPIO.4 (Pin 3)
DEFINE DEBUGIN_BIT 3 'GPIO.3 (Pin 4)
DEFINE DEBUG_MODE 1 'Inverted logic
DEFINE DEBUG_BAUD 9600

Symbol Capture=PIR1.2 'CCP1 capture flag
Symbol PinChng=INTCON.0 'InterruptOnChange
Symbol RS232=GPIO.3 'GPIO.3 (Pin 2)
Symbol RS485=GPIO.0 'GPIO.0 (Pin 6)
RF VAR byte[6]
RS VAR byte[6]
cfg VAR byte[5]
ID VAR byte
pw VAR word
i VAR byte
bits VAR byte
bytes VAR byte
sof VAR word 'start of frame
minSOF VAR word 'minimum start pulse (1900-8500 ~1.9mS-8.5mS)
minBits VAR byte
adc VAR byte
id VAR byte
module VAR byte
addr VAR byte
rssi VAR word 'received signal strength indicator

DATA $01,$FE,$6C,$07,$0E,$01 'EEPROM module,id,minSOF (1900),minBits (14),adc

OSCCON = %01110001 'INT HF OSC 8MHz
WHILE OSCCON.3>0:WEND 'OSC startup timeout
WHILE OSCCON.2=0:WEND 'INT HF OSC stable
CMCON0 =%00000111 'comparators off
TRISIO =%00101110 'make GPIO.0,4 outputs
GPIO =%00000000 'make GPIO.0,4 LOW
ANSEL =%00000010 'make GPIO.1 analog
ADCON0.7=1 'right justify ADC result for 10-bit
IOC =%00001001 'IOC Pins enabled
INTCON =%00000000 'disable interrupts
READ 0,module
DEBUG DEC module,32
READ 1,id
DEBUG DEC id,32
READ 2,minSOF.LowByte
READ 3,minSOF.HighByte
DEBUG DEC minSOF,32
READ 4,minBits
DEBUG DEC minBits,32
READ 5,adc
DEBUG DEC adc,10,13
init: RF[0]=0:RF[1]=0:RF[2]=0:RF[3]=0:RF[4]=0:RF[5]=0
CCP1CON=%00000101:Capture=0 'capture rising edge
While !Capture 'wait for rising edge
Wend
TMR1H=0:TMR1L=0:T1CON=%00010000 'prescale=2, tick=1uS
ADCIN 1, rssi 'read pulse amplitude
CCP1CON=0:Capture=0 'capture falling edge
While !Capture 'wait for falling edge
Wend
sof.HighByte=CCPR1H:sof.LowByte=CCPR1L
If (sof<minSOF) Then init '<min so abort
If (sof>9600) Then init '>max so abort
ADCIN 1, i 'read space amplitude
If (i<rssi) Then
rssi=rssi-i
Else
rssi=i-rssi
EndIf
CCP1CON=%00000101 'capture rising edge
bits=0:Capture=0:INTCON.2=0
While !Capture 'wait for rising edge
Wend
Repeat
TMR1H=0:TMR1L=0:T1CON=%00010000 'prescale=2, tick=1uS
TMR0=100 'overflow 156*16=2496uS (100+156=256)
OPTION_REG=%10000100:Capture=0 'TMR0 prescale=16
While !Capture 'wait rising edge
If INTCON.2=1 Then break 'TMR0 overflow (GAP>2.5mS)
Wend
pw.HighByte=CCPR1H:pw.LowByte=CCPR1L
If (pw<850) Then init '<0.85mS so abort
If (pw>1300) Then '>1.3mS
RF.0(i)=1 'set bit
EndIf
i=i+1
Until (i>43)
break: If (bits<>20) Then
bits=i+1
EndIf
If (bits<minBits) Then init
bytes=(bits)/8
If ((bits)//8>0) Then
bytes=bytes+1
EndIf
Debug bits
For i = 0 to bytes
Debug ihex2 RF[i]
RS[i]=RF[i]
Next
DEBUG ihex2 (sof/40)
If (adc>0) Then
DEBUG ihex2 (rssi>>2)
EndIf
debug 13,10
GoTo init

End

A more generalized method that can capture any protocol uses a bit array and samples the input at 25-50µS intervals, setting a bit when the sample is high. This gives you an image of the code with the resolution depending on the sample rate.

You might find some of the links on my web page useful.http://davehouston.org/ir-rf_fundamentals.htm
http://davehouston.org/learn.htm
http://davehouston.org/RFTipsTricks.htm

Megahertz
- 3rd April 2011, 21:04
A more generalized method that can capture any protocol uses a bit array and samples the input at 25-50µS intervals, setting a bit when the sample is high. This gives you an image of the code with the resolution depending on the sample rate.



Cheers Dave for the reply. I am still learning this stuff at my pace, can you please elaborate your point with few lines of code for my better understanding.

dhouston
- 3rd April 2011, 23:31
As my interest has been with RF, with PWM & PPM and with defined protocols, I've never needed to use the generalized method so I have no code. Also, most PICs (all but PIC18) are limited to a maximum array size of 256 bits. If we sample every 50µS (0.00005 secs) 256 bits can only record 0.00005x256=0.0128 secs or 12.8mS which is less than 1/10 the length of some IR codes.

This method was used by dedicated IR devices such as Slink-e and Ocelot which had more powerful processors and much more memory (external to the processor).

Megahertz
- 4th April 2011, 00:09
Thanks for the info Dave.

I have also gone through a lot of info about this today. I will narrow down my selection to only accept codes from 3 protocols only SIRC, NEC & RC5.

Can anyone advice on how to catch and write routines to save a particular button value coming from any of the remote operating on either of the above protocols. ( I am using 16F676)
Thanks a lot in advance

dhouston
- 4th April 2011, 01:42
The RF code I posted earlier in the thread will handle SIRC & NEC although you will need to modify it because IR is active low and it is expecting active high. You want to catch falling edges rather than rising edges.

RC5 is harder - there is no pronounced difference in its start sequence. IIRC Bruce Reynolds has code for it. He may have posted it here or it may be on his website.http://www.rentron.com/
This site is also quite helpful.http://www.sbprojects.com/knowledge/ir/ir.htm

Pimentel
- 4th April 2011, 02:20
I use the sony protocol. I think that is more easy to learning.
You can use some universal remote control (with sony protocol) to test and to learn.
My sample to help:

@ DEVICE pic16F628a, INTRC_OSC_NOCLKOUT ' System Clock Options
@ DEVICE pic16F628a, WDT_OFF ' Watchdog Timer
@ DEVICE pic16F628a, PWRT_OFF ' Power-On Timer
@ DEVICE pic16F628a, BOD_OFF ' Brown-Out Detect
@ DEVICE pic16F628a, MCLR_ON ' Master Clear Options (External)
@ DEVICE pic16F628a, LVP_OFF ' Low-Voltage Programming
@ DEVICE pic16F628a, CPD_OFF ' Data Memory Code Protect
@ DEVICE pic16F628a, PROTECT_OFF ' Program Code Protection
DEFINE OSC 4
'Definição das variáveis e declarações
INCLUDE "bs1defs.bas" 'inclui arquivo p/ compatibilizar com BS1
'p/entender as variáveis b0...b3, w0...w6 e bit0...bit13
CMCON = 7 'DEFINE PORTA COMO DIGITAL (COMPARADORES ANALÓGICOS:OFF)
symbol ir = PORTB.7 'entrada do sinal de IR
SYMBOL LED = PORTB.4
SYMBOL RELE = PORTB.0
TRISB = %10000000

'-------------------------------------------------------------------------------
PORTB = 0
LED = 1: PAUSE 100
'-------------------------------------------------------------------------------
'rotina principal
LOOP_1:
pulsin ir,0,w0 'wait start bit
if w0 < 200 then LOOP_1 'start bit is > 200
pause 20 'jump first sent
pulsin ir,0,b0 'wait 2º start bit
pulsin ir,0,b1
pulsin ir,0,b2 'read each bit from IR code
pulsin ir,0,b3
pulsin ir,0,b4
pulsin ir,0,b5
pulsin ir,0,b6
pulsin ir,0,b7

bit0=b1/96 ' LSB
bit1=b2/96
bit2=b3/96
bit3=b4/96
bit4=b5/96
bit5=b6/96
bit6=b7/96 ' MSB
bit7=0

if b0=21 then COMANDO 'test the values of your control
GOTO LOOP_1

COMANDO:
RELE = 1
LED = 1
PAUSE 500
RELE = 0
LED = 0
GOTO LOOP_1

'-------------------------------------------------------------------------------
end


Other article to learning from Experimenting_pbp.pdf:
"
Sony, infrared remote control Receiver
There are three main protocols used for the transmission and reception
of infrared signals . RC5, which is used by Philips, Rec-80, which is used
by Panasonic, and the Sony format (SIRCS), which will be described
here. Each form of infrared signalling has one thing in common, that is
the use of modulated infrared light. Modulation is used to enable a
certain amount of immunity from ambient light sources, especially
fluorescent lighting. The frequency of modulation varies from 36kHz to
40kHz, depending on the manufacturer . An infrared detector is required
to convert this modulated light into a digital signal . These are readily
available in just about every TV, VCR, and satellite receiver made within
the past 20 years . The type used for these series of experiments is the
Siemens SFH506-38, (unfortunately it's now out of production, but the
alternatives are the SFH5110 or the LT-1059) . These are small three
terminal devices that have a centre frequency of around 38kHz .
However, just about any type may be substituted, the only difference that
will be apparent will be a slight lack of range .
For the Sony protocol, the remote sends a start bit, sometimes called an
AGC pulse, that is 2.4ms in length . This allows the receiver to
synchronize, and adjust its automatic gain control, this occurs inside the
infrared detector module. After the start bit, the remote sends a series of
pulses . A 600us pulse represents a zero, and a 1200us pulse represents
a one, there is a 600us gap between each pulse. Not all manufacturers
stick stringently to these timings, so we will consider them as
approximates. All of these pulses build up a 12-bit serial signal called a
packet . This comprises of a 7-bit button value (the remote button
pressed), and a 5-bit device value (TV, VCR, etc) . The serial signal is
transmitted with the least significant bit sent first . "

fratello
- 4th April 2011, 13:21
Have somebody doing something like this (ir-remote, ir-learner, ir-repeater) but using RC10 protocol ?

Megahertz
- 4th April 2011, 14:45
I have been reading a good example of somewhat what I need (requires modifications) at this page: http://home.citycable.ch/flotulopex/REMI/REMI_Frames_e.htm

Few questions have arisen in my mind about this code:
1) Why in this code IRM_OUT is an output but being used as an input?


IRM_Out VAR PORTA.1 'IR RX Module VDD (OUT)
TRISA = %00000000 'Set Input/Output

IRM_Out = 1 'set port HIGH

WHILE IRM_Out = 1 : WEND 'Wait here until a LOW signal is incoming
FOR Ctr_A = 1 TO Max_Bit
TMR1H = 0 'Reset Timer
TMR1L = 0 'Reset Timer
T1CON.0 = 1 'Start Timer
WHILE IRM_Out = 0 : WEND 'stay here as long as input signal is LOW
T1CON.0 = 0 'Stop Timer
V_Tmr.LowByte = TMR1L ' \
V_Tmr.HighByte = TMR1H ' > Store data to LOW_BIT var
L_Bit[Ctr_A] = V_Tmr ' /
TMR1H = 0 'Reset Timer
TMR1L = 0 'Reset Timer
T1CON.0 = 1 'Start Timer
WHILE IRM_Out = 1 : WEND 'stay here as long as input signal is HIGH
T1CON.0 = 0 'Stop Timer
V_Tmr.LowByte = TMR1L ' \
V_Tmr.HighByte = TMR1H ' > Store data to HIGH_BIT var
H_Bit[Ctr_A] = V_Tmr ' /
NEXT Ctr_A
C_Led = 0
PAUSE 1000 'wait before continue
2) It is declared that 'factor is a constant =0', then what does this routine do?

'_________________________________________________ _____________
' Factorise (time compensation due to BASIC operations latency)
FOR Ctr_A = 1 TO Max_Bit
IF L_Bit[Ctr_A] >= Factor THEN L_Bit[Ctr_A] = L_Bit[Ctr_A] + Factor
IF H_Bit[Ctr_A] >= Factor THEN H_Bit[Ctr_A] = H_Bit[Ctr_A] + Factor
NEXT Ctr_A

3) Also it will be much appreciated if someone can explain the following three routines as well, as this purpose is not clear to me

'_______________________________________________
' Rescale values (according to acquiring method???)
FOR Ctr_A = 1 TO Max_Bit
IF L_Bit[Ctr_A] > 0 THEN L_Bit[Ctr_A] = L_Bit[Ctr_A]/2
IF H_Bit[Ctr_A] > 0 THEN H_Bit[Ctr_A] = H_Bit[Ctr_A]/2
NEXT Ctr_A

'______________________________________
' Find the longest H_Bit = interval bit
' This to determine how many bits in pattern
FOR Ctr_A = 1 TO Max_Bit
IF H_Bit[Ctr_A] > Itv_Bit THEN
Itv_Bit = (H_Bit[Ctr_A] + 100) 'store the highest H_Bit value in Itv_Bit
Bit_Cnt = Ctr_A 'is the count of bits in the original pattern --- How can bit_cnt count the bits in the original pattern if it only enters this loop if H_Bit[Ctr_A] > Itv_Bit
ENDIF
NEXT Ctr_A

'_________________________________________________ __
' Replace all "after pattern" bits with value "zero"
FOR Ctr_A = (Bit_Cnt + 1) TO Max_Bit
L_Bit[Ctr_A] = 0
H_Bit[Ctr_A] = 0
NEXT Ctr_A

Megahertz
- 7th April 2011, 13:41
Anyone there???

ScaleRobotics
- 7th April 2011, 14:10
It looks like he named it IRM_out, because it is the output of the infra red sensor, so an input on the PIC.

Not sure why he is setting it high, and I don't see it ever set to input.

Have you thought about emailing the author?

IRM_VDD VAR PORTA.0 'IR RX Module Out (VCC)
IRM_Out VAR PORTA.1 'IR RX Module VDD (OUT)

5329

Megahertz
- 7th April 2011, 14:24
It looks like he named it IRM_out, because it is the output of the infra red sensor, so an input on the PIC.


Thanks for the reply.

If it is an input to the PIC then why the TrisA register is set for it to be an output?

ScaleRobotics
- 7th April 2011, 14:34
Thanks for the reply.

If it is an input to the PIC then why the TrisA register is set for it to be an output?

Yes, I am with you, confused. Have you tried emailing the author, Flutoloplex (http://www.picbasic.co.uk/forum/member.php?u=3502)?

Megahertz
- 7th April 2011, 15:04
Yes I did, but seems the author is a very busy man, so I believe experts here will be able to help me on this topic.

Pimentel
- 8th April 2011, 04:45
I Think that if he used a IR module, then just go work if TRISA.1 = 1, as input!

Pimentel

Megahertz
- 8th April 2011, 15:17
I Think that if he used a IR module, then just go work if TRISA.1 = 1, as input!

Pimentel
That could be fine if I just want to copy and replicate the code. But I am in a process to understand it fully. Making it input will settle question number 1 in my post above, but still looking for explanation on 2 & 3.

flotulopex
- 13th April 2011, 08:02
Hi there,

I've been working on some other things these last months so no much time for this forum left :-(

I'll come back with answers shortly.

flotulopex
- 13th April 2011, 22:07
I haven't been working on this project for months so sorry for not answering earlier.

I have updated my webpage because there were still pieces of code or comments that I left during the developpement phase; they have been now removed. Current REMI version is v2-1-2-5.


As already answered

It looks like he named it IRM_out, because it is the output of the infra red sensor, so an input on the PIC.So correct reading is:
IRM_VDD VAR PORTA.0 'IR RX Module's VDD
IRM_Out VAR PORTA.1 'IR RX Module's OUT




Why in this code IRM_OUT is an output but being used as an input?For any (to me) unknown reason, there is no need to declare this port as an Input... and it works. I'm always taking care not set ports as inputs to avoid any external noise and while doing this project, I accidentaly noticed that it works like this so I didn't change it up to now.

The port IRM_Out = 1 because the IR Module idles HIGH. Not setting this port to HIGH will make the LEARN: routine start immediately - not waiting for a real incomming signal.




It is declared that 'factor is a constant =0', then what does this routine do?"Factorise (time compensation due to BASIC operations latency)". Before using TIMER method to count the elapsed time within a pulse, I used PUSLIN & RCTIME. But PULSIN & RCTIME have a lower accuracy than counting cycles like I do it now.

Previous LEARN routine using PULSIN & RCTIME:
LEARN:
PULSIN IRM_Out, 0, l_Bit[0] 'wait for first Low pulse to start recording
TOGGLE led0
IF l_Bit[0] = 0 THEN LEARN:
Led0 = 1
RCTIME IRM_Out, 1, h_Bit[0] 'get first High pulse from IR Module
FOR Ctr_A = 1 TO (Max_Bit - 1)
RCTIME IRM_Out, 0, l_Bit[Ctr_A] 'get Low pulse (1 to 38) from IR Module
RCTIME IRM_Out, 1, h_Bit[Ctr_A] 'get High pulse (1 to 38) from IR Module
NEXT Ctr_A
RCTIME IRM_Out, 0, l_bit[Max_Bit] 'get last Low pulse from IR Module
RCTIME IRM_Out, 1, H_bit[Max_Bit] 'get last High pulse from IR Module
Led0 = 0
PAUSE 1000 'wait before continue




Also it will be much appreciated if someone can explain the following three routines as well, as this purpose is not clear to me"Rescale values" is ment to make the the result stored in the L_Bit and H_Bit variables equal to real time according to the oscillator used (4, 8 or 20MHz).

"Find the longest H_Bit" is ment to make the full signal pattern repeatable (next version of REMI) but also to cleanup and trim the freshly learned pattern. In LEARNING mode, one sends the command from the original remote continiously until REMI has stored 40 bits. I admit that REMI will always start learning the very first bit of the transmitted pattern. Since the original remote may send the command repetitively, REMI needs to find whitch bit is the longest that this could be most likely the "separator" of a pattern.

"Replace all 'after pattern' bits with value 'zero'" is an optional routine to check the µC's memory. It helped me to have a better view of what had been programmed in the PIC during debug. This routine can be omitted.

HTH

dhouston
- 13th April 2011, 22:40
The port IRM_Out = 1 because the IR Module idles HIGH. Not setting this port to HIGH will make the LEARN: routine start immediately - not waiting for a real incomming signal.I believe most of the IR receiver modules are open drain or open collector. They have a pullup to Vdd and are pulled low by the presence of IR. This also pulls the PIC pin low.