PDA

View Full Version : Sony IR Remote



dirtbiker5627
- 6th May 2010, 01:32
I am trying to get the PIC to read the command portion of the sony protocol. I checked on the oscilloscope that the signals were correct. I also was able to determine that the PIC was reading the first pulse of the incoming signal but I can not figure out how to get it to return the 7 digit command out the serial pin.


pulse var Word
x var byte
signal var word

ANSEL = %00000000

Start:
Pulsin PORTC.3, 0, pulse
if (pulse < 220) or (pulse > 260) then start

signal = 0
x = 1

Loop:
pulsin PORTC.3, 0, pulse
if (pulse > 90) then ADD_X

READ_IR:
x = x * 2
if (x = 255) then start

serout PORTC.2, 2, [#signal]

goto loop

ADD_X:
signal = signal + x
goto read_ir

end

ScaleRobotics
- 6th May 2010, 03:44
Bruce had a great example here. http://www.picbasic.co.uk/forum/showthread.php?t=12555

It is made for a 18F2431 chip.

dirtbiker5627
- 6th May 2010, 22:29
I am only 17 and I have partially self taught myself PICBasicPro. Since I have not taken any engineering courses and I am still in high school I do not understand much. I checked out the example from this http://www.picbasic.co.uk/forum/showthread.php?t=12555. I have never used the CCP module before so I am a little lost. I need this code for a 12f683. I highlighted the parts in red that I do not understand. I need to transmit the the data to a 1 wire serial lcd using serout command not the debug but I dont know how to do that. Please help.

' Connections;
' IR detector output to PORTA.2 CAP1 input
' PORTB.0 ------/\/\/\/----|>|----GND LED on RB0 (for press/release indicator)
' PORTC.6 --MAX232---PC serial port RX (to print results)
DEFINE NO_CLRWDT 1 ' it's disabled in config
DEFINE LOADER_USED 1
DEFINE OSC 4
DEFINE DEBUG_REG PORTC
DEFINE DEBUG_BIT 6
DEFINE DEBUG_BAUD 9600
DEFINE DEBUG_MODE 0 ' 1 = inverted, 0 = true

NumPulses CON 26 ' total signal states to learn (26 for Sony)

T1 VAR WORD[NumPulses]
INDEX VAR BYTE
KeyNum VAR BYTE

SYMBOL Capture = PIR3.1

CLEAR

ANSEL0 = 0 ' all digital
TRISA.2 = 1 ' cap1 input pin (Capture input)
INTCON = 0 ' interrupts off
TMR1H = 0 ' clear high byte of TMR5 count
TMR1L = 0 ' clear low byte
T1CON = %00000001 ' prescale=1:1, int clock, TMR5=on

Main:
CAP1CON = %01001000 ' auto time base reset, capture on every state change
Capture = 0

FOR KeyNum = 0 TO 14 ' learn 15 total button codes
CAP1CON = %01001000 ' HIGH 0 ' indicate start (user press button)
Capture = 0 ' clear capture flag before starting

' Wait for 1st capture on state-change. Note: We don't care what the 1st capture
' value is since it's the beginning high-to-low edge (for IR), and of no significance.
' We only want the length of each high & low signal after the falling edge.
WHILE Capture = 0 : WEND
Capture = 0

FOR INDEX = 0 TO NumPulses-1 ' captures IR signal in 1uS increments
WHILE Capture = 0 : WEND ' wait for capture event
Capture = 0 ' clear int flag after each capture
T1[INDEX] = ((CAP1BUFH<<8) + CAP1BUFL) ' store capture values
Next INDEX
CAP1CON = 0 ' disable capture immediately after to avoid unwanted captures
Capture = 0
' if user holds transmitter button down too long.
LOW 0 ' indicates user should release transmitter button
PAUSE 1000

' print button codes
FOR INDEX = 0 TO NumPulses-1 STEP 2
DEBUG "low = ", DEC T1[INDEX],"uS",13,10 ' print low signal period
DEBUG "high = ",DEC T1[INDEX+1],"uS",13,10 ' print high signal period
NEXT INDEX
DEBUG 10,13
NEXT KeyNum

Finished: ' indicate finished
TOGGLE 0
PAUSE 200
GOTO Finished

END

gmglickman
- 9th May 2010, 14:55
Confused:

That code is specific to the 18F2431, with features not found in the 16F683.

Take a look at the code here http://www.rentron.com/PicBasic/IR_Chips.htm by the same author for a better understanding of decoding IR remote signals.

dirtbiker5627
- 10th May 2010, 00:48
That is one way to do it but I need a simple way to read the Sony protocol. I liked the way this code works because it doesnt require any hardware peripherals. Please help me figure out why this isnt working.
pulse var Word
x var byte
signal var word

ANSEL = %00000000

Start:
Pulsin PORTC.3, 0, pulse
if (pulse < 220) or (pulse > 260) then start

signal = 0
x = 1

Loop:
pulsin PORTC.3, 0, pulse
if (pulse > 90) then ADD_X

READ_IR:
x = x * 2
if (x = 255) then start

serout PORTC.2, 2, [#signal]

goto loop

ADD_X:
signal = signal + x
goto read_ir

end

gmglickman
- 10th May 2010, 16:41
For one thing, I would take the SEROUT out of your loop: SEROUT takes a fair amount of time, and you will lose any IR pulses after the first while servicing the SEROUT.Save pulses to an array as you capture them, then SEROUT when done with capture.

Also, the tolerance on this:

if (pulse < 220) or (pulse > 260) then start
might be a little tight to capture the 240msec AGC pulse at the start. See below.


From the link I gave you:



Decode: '// Shift right to remove bit RA.0
H_Add = (PORTA >> 1) & %00011111 '// AND with %00011111 to mask upper 3-bits
'// RA.1 to RA.5 = 5-bit hardware address
Decode2:
PULSIN PORTA.7,0,PULSE_IN '// Read-in start pulse
IF (PULSE_IN < 200) OR (PULSE_IN = 0) THEN '// Less than Start pulse, then keep looking
Loops = 0 '// Reset Loops on idle or key release
IF LM = 1 THEN Decode '// If mode = latching, don't change outputs.
PORTB = 0 '// Mode = momentary. Key = released or idle
GOTO Decode '// so clear outputs & return.
ENDIF

Verify: '// Read, Decode, then verify data
FOR Index = 0 TO 12 '// Setup to read-in 13 pulses
PULSIN PORTA.7,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
FOR Index = 0 TO 7 '// Get 8 "data" bits
IF IR_PULSE[Index] < 100 THEN DBYTE.0[Index]=0 '// Less than 1mS = 0
NEXT Index
ABYTE = $FF '// Start with all 1's and find each 0 in pattern
X=0 '// Initialize address bit index pointer to bit 0
FOR Index = 8 TO 12 '// Get 5 address bits from IR_PULSE bits 8-12
IF IR_PULSE[Index] < 100 THEN ABYTE.0[X]=0
X = X + 1 '// Increment address bit index pointer
NEXT Index
ABYTE = ABYTE & %00011111 '// Mask out upper 3-bits. Result = 5-bit address.



is a good start. ABYTE and DBYTE together give you the 12 bit decoded command.

flotulopex
- 11th May 2010, 11:53
if (pulse < 220) or (pulse > 260) then start
might be a little tight to capture the 240msec AGC pulse at the start. See below.
@ 4MHz, PULSIN has 10µs resolution.

If you need to capture 240msec, then you would have:

if (pulse < 22) or (pulse > 26) then start
I did something similar and left PULSIN by side - I use TMR1 instead. Have a look to the "code" section here http://home.citycable.ch/flotulopex/REMI/REMI_Frames_e.htm

HTH

dirtbiker5627
- 12th May 2010, 02:56
I dont think the timing is off becuase I used a portion of the first code to make shure the range of numbers was correct.



start:
if (pulse < 220) or (pulse > 260) then start
high GPIO.2
pause 100
low GPIO.2
goto start

I think this was the code but I used 220 through 260 and the led would flash every time it detected the ACG pulse. So I dont think the values are incorrect. I just dont know how to excecute the program.
I would really like to use this code below because I understand it, it's simple and I can do it all in software. If anyone can please tell me what is wrong with this code please let me know.

pulse var Word
x var byte
signal var word

ANSEL = %00000000

Start:
Pulsin PORTC.3, 0, pulse
if (pulse < 220) or (pulse > 260) then start

signal = 0
x = 1

Loop:
pulsin PORTC.3, 0, pulse
if (pulse > 90) then ADD_X

READ_IR:
x = x * 2
if (x = 255) then start

serout PORTC.2, 2, [#signal]

goto loop

ADD_X:
signal = signal + x
goto read_ir

end

flotulopex
- 12th May 2010, 17:37
PULSIN & PULSOUT have the same resolution (10µs @ 4MHz). So, for a test, use PULSOUT.

Try this small code and check with your oscillo if the pulse you read is really 240ms wide, you may be surprised.

START:
PULSOUT PORTC.3, 240
GOTO START:

Bruce
- 12th May 2010, 17:44
One Sony decoder chip comin up..;)

This should be easy to understand & modify for your PIC type. And you can easily change it to display buttons like channel-up, down, volume-up, down, etc..


DEFINE OSC 4
IR_PULSE VAR BYTE(12) ' IR data received
INDEX VAR BYTE ' Index pointer
DBYTE VAR BYTE ' IR data received

Main:
PULSIN PORTC.3,0,IR_PULSE '// Read-in start pulse
IF (IR_PULSE < 200) OR (IR_PULSE = 0) THEN Main

Verify: '// Read, Decode, then verify data
FOR Index = 0 TO 11 '// Setup to read-in 12 pulses
PULSIN PORTC.3,0,IR_PULSE[Index] '// Read 12 low-going pulses on RC.3
NEXT Index '// Loop x times

DBYTE = $7F '// Start with all 1's and find each 0

FOR Index = 0 TO 6 '// Get 7 "data" bits
IF IR_PULSE[Index] < 100 THEN DBYTE.0[Index]=0 '// Less than 1mS = 0
NEXT Index

DBYTE = DBYTE + 1 '// Button code #1 = 0, Button #2 = 1, so add 1
'// for actual button pressed for display

HSEROUT ["Button pressed was ",#DBYTE,13,10]
GOTO Main

END
This will print buttons #1 through #9. Buttons 0, channel, volume, etc will output the numeric values corresponding to buttons pressed.

I know you don't care about the device codes like TV, VCR, etc, but it's easier to keep in-synch if you read these in anyway.

fratello
- 12th May 2010, 18:34
Wow, Mr.Bruce, amazing job !!! I wonder if it's possible to create code (like this) for using with RC-10 infrared remote from Blaupunkt. I read something about remote with buttons here : http://dren.dk/lacetti-blaupunkt.html, but it' s more interesting to build one infrared remote. In the car that will make the difference ;)... I read all topics on this forum about IR, and Yours web pages too, but my level of knowledges it's (verry) low...so, if it's possible, every help it's wellcome.

ScaleRobotics
- 13th May 2010, 13:37
I wonder if it's possible to create code (like this) for using with RC-10 infrared remote from Blaupunkt.


Something like this might work. I thought I read the signals were repeated every 10ms, but now I can't find that, so I could be wrong about that.



LED=1
delay var word
i var byte

vol_up:
delay = 2600
gosub ir_out

ir_out:
for i = 1 to 10 'sends out command 10 times
led=0
pauseus delay
led=1
pauseus delay
led=0
pauseus 660
led=1
pause 10 'wait 10ms before repeating
next i
return

fratello
- 13th May 2010, 16:28
Thank You for repply ! Since I have on my car Radio-SD card Blaupunkt and I have the sensor (TSOP 34838) too, I intend to try to build one remote (using 12F675 ?!) ; Your code it's a good point to start !

fratello
- 14th May 2010, 07:21
Hope don't disturb if I continue here with "code" for RC10 remote...If necessary please move in separate topic. Thanks.
It's my (pseudo)code...Any advice it's wellcome !

' First variant for RC 10 Blaupunkt remote

; PIC12F675: +--U--+
; +5V [ ] GND
; key 5 |---/--- >[ ]< ---/---| key 1
; key 4 |---/--- >[ ]< ---/---| key 2
; pull-up! key 3 |---/--- >[ ]>--[4K7]-- NPN Transistor, IR LED

@ DEVICE PIC12F675, intrc_osc_noclkout, wdt_off, pwrt_on, mclr_off, bod_off

DEFINE OSC 4
CMCON=7
OPTION_REG = %00000111
TRISIO = %00111110
WPU=%00110111
ANSEL=0

but1 var gpio.1
but2 var gpio.2
but3 var gpio.3
but4 var gpio.4
but5 var gpio.5
LED var gpio.0

GIE var intcon.7 ' global interrupt enable 1=on ; 0=off
gpie var intcon.3 'port change interrupt enable 1=0n ; 0=off
gpif var intcon.0 'port change interrupt flag bit

GIE=0
GPIE=1

IOC.1=1 ' int-on-change for GPIO.1 enabled
IOC.2=1 ' int-on-change for GPIO.2 enabled
IOC.3=1 ' int-on-change for GPIO.3 enabled
IOC.4=1 ' int-on-change for GPIO.4 enabled
IOC.5=1 ' int-on-change for GPIO.5 enabled

LED=1
delay var word
i var byte


main:
@ sleep
pause 100

if but1=1 then vol_up
if but2=1 then vol_down
if but3=1 then btn_up
if but4=1 then btn_down
if but5=1 then mute

vol_up:
delay = 2600
gosub ir_out


vol_down:
delay = 3200
gosub ir_out


btn_up:
delay = 3800
gosub ir_out


btn_down:
delay = 4400
gosub ir_out


mute:
delay = 5000
gosub ir_out


GPIF=0 'Clear port change interrupt flag
Goto Main


ir_out:
for i = 1 to 10 'sends out command 10 times
led=0
pauseus delay
led=1
pauseus delay
led=0
pauseus 660
led=1
pause 10 'wait 10ms before repeating
next i
return

END ' of program

fratello
- 14th May 2010, 16:27
...because with the code posted up, ISIS show me this results for "vol_up" like in picture attached ; it's something wrong ?! Thanks for your attention & cooperation !

fratello
- 14th May 2010, 20:25
...with some modification ; the results are now OK (in simulation, hope in real-world too !).

TRISIO = %00111110
ANSEL=0
OPTION_REG.7=0
IOCB=%00111110
...and (of course !) ...

if but1=0 then vol_up
if but2=0 then vol_down
if but3=0 then btn_up
if but4=0 then btn_down
if but5=0 then mute
...and at last...

vol_up:
delay = 970 '(970 us low + 970 us high + 660 us low = 2600 us pulse total time)
gosub ir_out
The results are like in picture; hope testing "in vivo" tomorrow...

eggman
- 14th May 2010, 21:01
You should modulate your signal on a carrier of about 38 kHz. You can generate this with assembly or use a pic12f683 and use the internal pwm generator. Then you can modulate this signal by switching the trisio pin.

I once did it this way:
It sends a Sony DVD play command every five seconds (as an example)


@ device pic12F683, intrc_osc_noclkout, wdt_off, pwrt_on, mclr_off, protect_off, bod_off

INCLUDE "MODEDEFS.BAS"
DEFINE PULSIN_MAX 5000

GPIO = %00100000
TRISIO = %00001100
CCP1CON = %00001100 ' Mode select = PWM
T2CON = %00000100 ' Timer2 ON + 1:1 prescale (last two bits)
CCPR1L = %00001101 ' pwm duty 50%
PR2 = %00011001 ' Set PWM frequency to +/- 40kHz, set to 26 for 38kHz or 28 for 36kHz
ANSEL = %00000000
CMCON0 = %00000111

led var GPIO.5
counter VAR BYTE
counter2 VAR BYTE
command VAR WORD 'IR command to send
temp VAR WORD
bitcount VAR WORD
bitselector var word

rewind CON $79A 'sony DVD codes for testing
play CON $59A
postdata con $36

clear

loop:
command = play
gosub sendIR
pause 5000
goto loop

sendIR: ' send IR code
for counter = 1 to 5 ' five times
TRISIO.2 = 0
PauseUs 2450 ' Lead_in pulse
TRISIO.2 = 1
pauseus 450 ' (space)
bitcount = 11 ' send first 11 bits
temp = command
GoSub transmit
bitcount = 8 ' send remaining 8 bits
temp = postdata
GoSub transmit
TRISIO.2 = 0
PauseUs 650 ' ptrail (pulse)
TRISIO.2 = 1
Pauseus 13080
next counter
Return

transmit:
bitselector = 1 << (bitcount - 1)
For counter2 = 1 TO bitcount 'number of bits
TRISIO.2 = 0 'make output (pin active, led on)
PauseUs 540 'first part of bit, pulse
IF (temp & bitselector) = 0 Then 'if bit is 0
PauseUs 580 'send second part of bit ,pulse
EndIF
TRISIO.2 = 1 'make input (pin inactive, led off)
PauseUs 560 'space (no pulse)
temp = temp << 1 'shift one bit
Next counter2
Return

dirtbiker5627
- 15th May 2010, 03:25
I finally got the code working but it is very ineffecient. I am only 17 and I came up with the code with only a little help so give me some credit. Its not the best but if any of you have other ways to compress the code and make it more effecient please reply. Thanks


DEFINE OSC 4
ANSEL = %00000000

IR_PULSE var word(11)
SIGNAL var word
START_PULSE var word
INDEX var byte
X var byte

Main:

Pulsin PORTC.3, 0, start_pulse
if (start_pulse < 220) or (start_pulse > 260) then main


for index = 0 to 11
pulsin PORTC.3, 0, ir_pulse(index)
next index

Convert:

x = 1
signal = 0

for index = 0 to 11
if (ir_pulse(index) > 90) then ADD_X
READ_IR:
x = x * 2
next index

serout PORTC.2, 2, [#signal, 9]

clear

goto main

ADD_X:
signal = signal + x
goto read_ir


end

fratello
- 15th May 2010, 18:50
You should modulate your signal on a carrier of about 38 kHz. You can generate this with assembly or use a pic12f683 and use the internal pwm generator. Then you can modulate this signal by switching the trisio pin.

I intend to build remote using 12F675 (I have a lot...and none of 12F683). How generating a carrier of 39 kHz with assembly ? I found something about 40 kHz pulse on Mr.Bruce site, but...
Please, one clue ?!
?!?
Pulse: '// Emits # of 39kHz bursts held in variable Cycles
ASM ;// with auto delay between bursts
bsf gpio, 0 ;// 1uS, LED=on [need 25uS total ???????
goto $+1 ;// 3uS (2uS per goto $+1)
goto $+1 ;// 5uS
goto $+1 ;// 7uS
goto $+1 ;// 9uS
goto $+1 ;// 11uS
' goto $+1 ;// 13uS 'comment this for 39 kHz ???
bcf gpio, 0 ;// 14uS, LED=off
goto $+1 ;// 16uS
goto $+1 ;// 18uS
goto $+1 ;// 20uS
goto $+1 ;// 22uS
decfsz _Cycles,F ;// 23uS
goto _Pulse ;// 25us
ENDASM
PAUSEUS 500 '// 500uS delay between each data bit
RETURN '// Return to Main

...and next ?

fratello
- 16th May 2010, 17:44
I try to simulate this remote using 12F683 (because of PWM) :

@ device pic12F683, intrc_osc_noclkout, wdt_off, pwrt_on, mclr_off, protect_off, bod_off

INCLUDE "MODEDEFS.BAS"


GPIO = %00000010
TRISIO = %00000010
CCP1CON = %00001100 ' Mode select = PWM
T2CON = %00000100 ' Timer2 ON + 1:1 prescale (last two bits)
CCPR1L = %00001101 ' pwm duty 50%
PR2 = %00011001 ' Set PWM frequency to +/- 40kHz, set to 26 for 38kHz or 28 for 36kHz
ANSEL = %00000000
CMCON0 = %00000111

led var GPIO.5
but1 var GPIO.1

LED=0

delay var word
i var byte
timeX var byte
'=========================================
main:
pause 100

if but1=0 then vol_up
vol_up:
delay = 970 '(970 us low + 970 us high + 660 us low = 2600 us pulse total time)
while but1=0
gosub ir_out
gosub debounce
wend
PAUSE 50

Goto Main
'=========================================
ir_out:
led=1
pauseus delay

led=0
pauseus delay

led=1
pauseus 660

led=0
pause 10 'wait 10ms before repeating
return
'=========================================
Debounce :
For timeX= 1 to 50
Pause 5
next timeX
Return
'=========================================

END ' of program


But the results are similarly ; I really don't understand what I do wrong ...

eggman
- 16th May 2010, 21:07
Instead of led = 1 or led = 0 use this: TRISIO.2 = 0 or TRISIO.2 = 1
You have to connect your IR led to GPIO.2, not GPIO.5
Toggling TRISIO.2 will modulate your IR led

flotulopex
- 16th May 2010, 22:08
You may use GPIO.2 (CCP1) only and set the duty-cycle (CCPR1L) to its value for the time you need to generate high pulses.

Try a 25-30% duty-cycle value, 50% is too high and makes you loose efficiency.

For a 38kHz carrier, PR2 is 25 which will give you a CCPR1L value of 8 (which is ±30% of "25").

So, if your pattern would be something like 970µs high, 970µs low and 660µs high, it could look like this:
....
set CCPR1L to 8
pause for 970µs
set CCPR1L to 0
pause for 970µs
set CCPR1L to 8
pause for 660µs
set CCPR1L to 0
....

fratello
- 17th May 2010, 16:30
Ok, Thanks ! With 16F648A works (in ISIS :) ) great.
But...
I find in "Experimenting with the PicBasic Pro Compiler" by Les Johnson how to define subroutine "Pulse" ; so, I re-re-x-rewrite code for 12F675. I have some results but I don't understand how define the lenght of pulses. I put "?!" where I don't know if it's right.
Any advices ?

' PIC12F675: +--U--+
' +5V [ ] GND
' key 5 |---/--- >[ ]< ---/---| key 1
' key 4 |---/--- >[ ]< ---/---| key 2
' pull-up! key 3 |---/--- >[ ]>--[4K7]-- NPN Transistor, IR LED

@ DEVICE PIC12F675, intrc_osc_noclkout, wdt_off, pwrt_on, mclr_off, bod_off
INCLUDE "MODEDEFS.BAS"
DEFINE OSC 4

CMCON=7
OPTION_REG.7=0
TRISIO = %00111011
WPU=%00111011
IOCB=%00111011
ANSEL=0

but1 var gpio.0
but2 var gpio.1
LED var gpio.2
but3 var gpio.3
but4 var gpio.4
but5 var gpio.5


delay var word
BURST var word
i var byte
timeX var byte

GIE var intcon.7 ' global interrupt enable 1=on ; 0=off
gpie var intcon.3 ' port change interrupt enable 1=0n ; 0=off
gpif var intcon.0 ' port change interrupt flag bit

GIE=0
GPIE=1



'=========================================

main:

@ sleep
pause 100

IF but1=0 then ; VOLUME UP
DELAY=37 ; 970 us/ 26 us each pulse = 37 ?!
GOSUB IR_REMOTE
ENDIF

IF but2=0 then ; VOLUME DOWN
DELAY=1270
GOSUB IR_REMOTE
ENDIF

IF but3=0 then ; BUTTON UP
DELAY=1570
GOSUB IR_REMOTE
ENDIF

IF but4=0 then ; BUTTON DOWN
DELAY=1870
GOSUB IR_REMOTE
ENDIF

IF but5=0 then ; MUTE
DELAY=2170
GOSUB IR_REMOTE
ENDIF

GPIF=0 'Clear port change interrupt flag
PAUSE 50

Goto Main

'=========================================
ir_REMOTE:

FOR BURST=1 TO DELAY
GOSUB PULSE
NEXT BURST

pauseus (delay*26) ' ?!

FOR BURST=1 TO 25 ' 660/26 ?!
GOSUB PULSE
NEXT BURST

return
'=========================================
Pulse: ' 2+4+8+4+7+1=26 us
HIGH LED ' Turn on LED (4 cycles)
@ NOP
@ NOP
@ NOP
@ NOP
@ NOP ' each NOP takes 1 instruction cycle
@ NOP ' assumig 4 MHz
@ NOP
@ NOP
LOW LED ' turn off the LED (4 cycles)
@ NOP
@ NOP
@ NOP
@ NOP
@ NOP
@ NOP
@ NOP
RETURN ' return from the subroutine (1 cycle)

'=========================================
END ' of program

fratello
- 18th May 2010, 13:22
This is my last variant of code; works fine in ISIS, hope to my car too.

'
' Varianta cu ASM from www.rentron.com
' Thanks to Mr.Bruce !
'
' PIC12F675: +--U--+
' +5V [ ] GND
' key 5 |---/--- >[ ]< ---/---| key 1
' key 4 |---/--- >[ ]< ---/---| key 2
' pull-up! key 3 |---/--- >[ ]>--[4K7]-- NPN Transistor, IR LED

@ DEVICE PIC12F675, intrc_osc, wdt_off, pwrt_on, mclr_off, bod_off
INCLUDE "MODEDEFS.BAS"
DEFINE OSC 4

CMCON=7
OPTION_REG.7=0
TRISIO = %00111011
WPU=%00111011
IOCB=%00111011
ANSEL=0

but1 var gpio.0
but2 var gpio.1
LED var gpio.2
but3 var gpio.3
but4 var gpio.4
but5 var gpio.5

zecime CON 3 '// = ( 3 * 25uS) = 0.07 mS burst
zero CON 12 '// =( 12 * 25us) = 0.30 mS burst
unu CON 24 '// = (24 * 25uS) = 0.60 mS burst

delay var word
i var byte
cycles var byte
acycles var byte

GIE var intcon.7 ' global interrupt enable 1=on ; 0=off
gpie var intcon.3 ' port change interrupt enable 1=0n ; 0=off
gpif var intcon.0 ' port change interrupt flag bit

GIE=0
GPIE=1

'=========================================

main:

@ sleep
pause 100

IF but1=0 then ; VOLUME UP
acycles= unu + zero + zecime ' ~ 970 uS
delay=970
GOSUB IR_REMOTE
ENDIF

IF but2=0 then ; VOLUME DOWN
acycles= unu + unu + zecime ' ~ 1270 uS
delay= 1270
GOSUB IR_REMOTE
ENDIF

IF but3=0 then ; BUTTON UP
acycles= unu + unu + zero + zecime ' ~ 1570 uS
delay = 1570
GOSUB IR_REMOTE
ENDIF

IF but4=0 then ; BUTTON DOWN
acycles= unu + unu + unu + zecime ' ~ 1870 uS
delay = 1870
GOSUB IR_REMOTE
ENDIF

IF but5=0 then ; MUTE
acycles= unu + unu + unu + zero + zecime ' ~ 2170 uS
delay = 2170
GOSUB IR_REMOTE
ENDIF

GPIF=0 'Clear port change interrupt flag
PAUSE 50

Goto Main

'=========================================
ir_REMOTE:
cycles=acycles
call Pulse

pauseus delay

cycles=zero + zecime ' ~ 670 uS
call Pulse

return
'=========================================
Pulse: '// Emits # of 40kHz bursts held in variable Cycles
ASM ;// with auto delay between bursts
bsf gpio, 2 ;// 1uS, LED=on [need 25uS total
goto $+1 ;// 3uS (2uS per goto $+1)
goto $+1 ;// 5uS
goto $+1 ;// 7uS
goto $+1 ;// 9uS
goto $+1 ;// 11uS
goto $+1 ;// 13uS
bcf gpio, 2 ;// 14uS, LED=off
goto $+1 ;// 16uS
goto $+1 ;// 18uS
goto $+1 ;// 20uS
goto $+1 ;// 22uS
decfsz _Cycles,F ;// 23uS
goto _Pulse ;// 25us
ENDASM

RETURN '// Return to Main

'========================================
END

If see obviously mistakes, please tell me. Thank You, all !

fratello
- 19th May 2010, 18:19
" I have not failed. I've just found 10,000 ways that won't work". T.A.Edison
Code :

'
' PIC12F675: +--U--+
' +5V [ ] GND
' key 5 |---/--- >[ ]< ---/---| key 1
' key 4 |---/--- >[ ]< ---/---| key 2
' pull-up! key 3 |---/--- >[ ]>--[4K7]-- NPN Transistor, IR LED

@ DEVICE PIC12F675, intrc_osc, wdt_off, pwrt_on, mclr_off, bod_off
INCLUDE "MODEDEFS.BAS"
DEFINE OSC 4

CMCON=7
OPTION_REG.7=0
GPIO = %00000000 ' All outputs = 0 on boot
TRISIO = %00111011
WPU=%00111011
IOCB=%00111011
ANSEL=0


@ #DEFINE IRTX GPIO ; Define port to use for IR LED drive
@ #DEFINE PIN 2 ; Define port pin to use for IR LED




but1 var gpio.0
but2 var gpio.1
but5 var gpio.5

vplus CON 106 '// = ( 106 * 25uS) = 2650 uS burst
vminus CON 130 '// = ( 130 * 25us) = 3250 uS burst
vmute CON 202 '// = ( 202 * 25uS) = 5050 uS burst
vpuls CON 27 '// = ( 27 * 25uS) = 675 uS burst

delay var word
cycles var byte
acycles var byte
timeX var byte

GIE var intcon.7 ' global interrupt enable 1=on ; 0=off
gpie var intcon.3 ' port change interrupt enable 1=0n ; 0=off
gpif var intcon.0 ' port change interrupt flag bit


GIE=0
GPIE=1

'=========================================

main:

@ sleep
pause 100

IF but1=0 then ; VOLUME UP
acycles = vplus
delay = 2580
while but1=0
GOSUB IR_REMOTE
wend
ENDIF

IF but2=0 then ; VOLUME DOWN
acycles = vminus
delay = 3200
while but2=0
GOSUB IR_REMOTE
wend
ENDIF


IF but5=0 then ; MUTE
acycles = vmute
delay = 5000
while but5=0
GOSUB IR_REMOTE
wend
ENDIF

GPIF=0 'Clear port change interrupt flag
PAUSE 50

Goto Main

'=========================================
ir_REMOTE:
cycles=acycles
call Pulse

pauseus delay

cycles=vpuls ' ~ 670 uS
call Pulse


PAUSE 500
return

'=========================================
Pulse: '// Emits # of 39kHz bursts held in variable Cycles
ASM
bsf IRTX,PIN ; 1uS, LED=on
goto $+1 ; + 2uS = 3uS
goto $+1 ; + 2uS = 5uS
goto $+1 ; + 2uS = 7uS
goto $+1 ; + 2uS = 9uS
goto $+1 ; + 2uS = 11uS
goto $+1 ; + 2uS = 13uS
bcf IRTX,PIN ; 1uS, LED=off
goto $+1 ; + 2uS = 3uS
goto $+1 ; + 2uS = 5uS
goto $+1 ; + 2uS = 7uS
goto $+1 ; + 2uS = 9uS
decfsz _Cycles,f ; + 1uS = 10S
goto _Pulse ; + 2uS = 12uS
ENDASM

RETURN '// Return to Main

'================================================= ====
Debounce :
For timeX= 1 to 50
Pause 5
next timeX
Return
'========================================
END

Of course, zero result ! Even ISIS say it's ok, my RC Blaupuntk don't react ! I have one original RC 10 remote (and receiver, of course) from one friend; works fine. But, if I try to transmit something with my schematic...zero result ! Any advice, please ?!?

ardhuru
- 20th May 2010, 05:55
At this point, it might be a good idea to actually, visually compare the original signal with the one generated by your design. Capture the signals on your PC using the sound card, and open the captured file(s) with Goldwave / Audacity.

You'd immediately see whether the problem is to do with timing / protocol / logic or amplitude.

Regards,

Anand

Ioannis
- 20th May 2010, 08:47
Even better if you can afford the Logic from www.saleae.com to analyse digital signals. It saved me many times when trying to copy signals from similar cases.

Ioannis

fratello
- 20th May 2010, 14:54
I spend time with this "killer" code. Now I discover another strange phenomenon : anything I do, can't generate "train" of pulse.
Instead generating for 4 times this sequence : high 2650 ,pause 2500, high 660, pause 100
I have just ONE sequence for about 42.25 mS !!!
WHY ?!?
main:

zecime CON 106 '// = ( 106 * 25uS) = 2650 uS burst
unu CON 24 '// = (24 * 25uS) = 0.60 mS burst
delay CON 104


i var byte
cycles var byte
acycles var byte

;============================
Main:
IF but1=0 then ; VOLUME UP
goto ir_send
endif

Goto Main

'=========================================
ir_send:
cycles=zecime
acycles=unu
for i=1 to 4
call Pulse
pauseus delay
call Pulser
next i
Pauseus 100
Goto main ' or Return, have no result !

Pulse: ' Generate "Cycles" number of 40kHz pulses
ASM
bsf gpio, 2 ; 1uS, LED=on
goto $+1 ; + 2uS = 3uS
goto $+1 ; + 2uS = 5uS
goto $+1 ; + 2uS = 7uS
goto $+1 ; + 2uS = 9uS
goto $+1 ; + 2uS = 11uS
goto $+1 ; + 2uS = 13uS
bcf gpio, 2 ; 1uS, LED=off
goto $+1 ; + 2uS = 3uS
goto $+1 ; + 2uS = 5uS
goto $+1 ; + 2uS = 7uS
goto $+1 ; + 2uS = 9uS
decfsz _Cycles,f ; + 1uS = 10S
goto _Pulse ; + 2uS = 12uS
return ; Add 2uS for return to caller
ENDASM


Pulser: ' Generate "Cycles" number of 40kHz pulses
ASM
bsf gpio, 2 ; 1uS, LED=on
goto $+1 ; + 2uS = 3uS
goto $+1 ; + 2uS = 5uS
goto $+1 ; + 2uS = 7uS
goto $+1 ; + 2uS = 9uS
goto $+1 ; + 2uS = 11uS
goto $+1 ; + 2uS = 13uS
bcf gpio, 2 ; 1uS, LED=off
goto $+1 ; + 2uS = 3uS
goto $+1 ; + 2uS = 5uS
goto $+1 ; + 2uS = 7uS
goto $+1 ; + 2uS = 9uS
decfsz _Acycles,f ; + 1uS = 10S
goto _Pulser ; + 2uS = 12uS
return ; Add 2uS for return to caller
ENDASM

Thanks again for attention !

fratello
- 20th May 2010, 19:42
On first row: original Blaupunkt remote, volume up command.
On second row : my remote, volume up command.
Using same sensor (original Blaupunkt).
Original-work; my-NO !!! I'm stuck, dissapointed, sad...

ardhuru
- 21st May 2010, 06:17
Could you attach the 2 wav/mp3 files? I'll open them in a sound editor at my end; couldnt quite see the whole pulse train.

If this forum doesnt permit audio attachments, you could mail them to me at ardhuru_at_gmail.com.

Also, some remotes send the same frame twice; does your Blaupunkt need that?

Regards,

Anand.

fratello
- 23rd May 2010, 15:33
I try different variant of PBP code; no result.
I find the example of Mr.Bruce :

' IR carrier generator routines. Freq.inc.

Cycles VAR BYTE ' Number of carrier cycles

GOTO OverFreq ' jump over pulse routines

' Generate "Cycles" number of 40kHz pulses
ASM
_Pulse40
bcf IRTX,PIN ; 1uS, LED=on
goto $+1 ; + 2uS = 3uS
goto $+1 ; + 2uS = 5uS
goto $+1 ; + 2uS = 7uS
goto $+1 ; + 2uS = 9uS
goto $+1 ; + 2uS = 11uS
goto $+1 ; + 2uS = 13uS
bsf IRTX,PIN ; 1uS, LED=on
goto $+1 ; + 2uS = 3uS
goto $+1 ; + 2uS = 5uS
goto $+1 ; + 2uS = 7uS
goto $+1 ; + 2uS = 9uS
decfsz _Cycles,f ; + 1uS = 10S
goto _Pulse40 ; + 2uS = 12uS
return ; Return to caller
ENDASM

' Generate "Cycles" number of ~38.4kHz pulses
ASM
_Pulse38
bcf IRTX,PIN ; 1uS, LED=on
goto $+1 ; + 2uS = 3uS
goto $+1 ; + 2uS = 5uS
goto $+1 ; + 2uS = 7uS
goto $+1 ; + 2uS = 9uS
goto $+1 ; + 2uS = 11uS
goto $+1 ; + 2uS = 13uS
bsf IRTX,PIN ; 1uS, LED=on
goto $+1 ; + 2uS = 3uS
goto $+1 ; + 2uS = 5uS
goto $+1 ; + 2uS = 7uS
goto $+1 ; + 2uS = 9uS
nop ; + 1uS = 10uS
decfsz _Cycles,f ; + 1uS = 11S
goto _Pulse38 ; + 2uS = 13uS
return ; Return to caller
ENDASM

OverFreq:
so I write my program, for the hardware like in schematic ( for now I test just Volume Up) :

@ DEVICE PIC12F675, intrc_osc, wdt_off, pwrt_off, mclr_off, bod_off

DEFINE OSC 4
DEFINE OSCCAL_1K 1 ' Set OSCCAL for 1k -HELPS tuning the crystal for more accurate timing

@ #define IRTX GPIO ; Define port to use for IR out
@ #define PIN 1 ; Define port pin to use for IR out

INCLUDE "Freq.inc" '
but var gpio.5

GPIO.5=1
TRISIO.5=1
GPIO.1 = 1 ' IR LED off -----|<|----/\/\/\----+5
TRISIO.1 = 0 ' Output for IR signal
WPU = %00111101
CMCON = 7 ' Comparators disabled
ANSEL = 0 ' A/D disabled


Loops VAR BYTE


Main:

if but=0 then

FOR Loops = 1 TO 10
Cycles = 102 ' 102 * 26 = 2652 uS
CALL Pulse38

Pauseus 2580 ' accurate pause of 2580 uS ?!?

Cycles = 25 ' 25 * 26 = 650 uS ; maybe must EXACTLY 660 uS - how ?!?
CALL Pulse38

pauseus 50000
pauseus 50000
Next loops
endif
GOTO Main

END
but, OF COURSE ?!?, no results. Somebody, just one little help ? Please...

Ioannis
- 24th May 2010, 16:52
Are you sure your IR LED lights? I mean of course you cannot see it. But with camera or your mobil phone maybe you can see if the LED is lighting.

Do not trust this very much, since my SONY DSC-W17 does not see any IR at all! So test this first with a known IR transmitter to be sure.

Ioannis

fratello
- 24th May 2010, 17:43
I test the function of my schematic with two phones camera (Nokia & S-E) ; and with InfraX soft too. I capture the signal with TSOP 1738 on serial port, for "original" remote and for "PIC" remote...Works fine...but without results on my RC ! Thanks for support !

Ioannis
- 25th May 2010, 07:45
I see a 55us diffrence in the two shots. May be this is the problem.

Ioannis

fratello
- 25th May 2010, 10:16
...and I say in previous post :

Cycles = 102 ' 102 * 26 = 2652 uS
CALL Pulse38

Pauseus 2580 ' accurate pause of 2580 uS ?!?

Cycles = 25 ' 25 * 26 = 650 uS ; maybe must EXACTLY 660 uS - how ?!?

Suggestions ? Thank You for attention !

Ioannis
- 26th May 2010, 10:05
You may very well declare a 1234usec delay but this depends on the accuracy of the System Clock (Crystal resonator or what ever).

So you may have to trim a little the value of the pauseus to get exactly the time you want.

In general IR systems I eel are able to tolerate such skews...

Ioannis

fratello
- 26th May 2010, 18:00
After thousands of re-writing this code, I've got finally results :

@ DEVICE PIC12F675, INTRC_OSC_NOCLKOUT, wdt_off, pwrt_off, mclr_off, bod_off
DEFINE OSC 4

CMCON = 7 ' Comparators disabled
ANSEL = 0 ' A/D disabled

@ #define IRTX GPIO ; Define port to use for IR out
@ #define PIN 1 ; Define port pin for IR out


Puls_a CON 112 ' 112 x 26uS = 2912 mS ( pulse with carrier ON)

InterPulse CON 2800 ' 2.80mS (delay between pulses with carrier OFF)

Puls_b CON 28 ' 28 x 26uS = 728 uS ( pulse with carrier ON)





X VAR BYTE ' Data bit loop counter & bit index pointer
Duration VAR BYTE ' Duration of button press
Loops VAR BYTE ' Loop count
Cycles VAR BYTE BANK0 SYSTEM' Number of carrier cycles to generate


trisio=%11111101
option_reg.7=0
wpu =%11111101

but var gpio.5



GOTO Main ' Jump over pulse routine to Main

Pulse: ' Generate "Cycles" number of 40kHz pulses
ASM ; Keep this routine in code page 1, and jump over to Main
BSF IRTX,PIN ; 1 MAKE IR HIGH 35% Duty cycle = 9 uS
GOTO $+1
GOTO $+1
GOTO $+1
GOTO $+1
BCF IRTX,PIN ; 1 MAKE IR LOW 17 uS
GOTO $+1
GOTO $+1
GOTO $+1
GOTO $+1
GOTO $+1
GOTO $+1
DECFSZ Cycles,F
GOTO _Pulse ; 2 26 uS
ENDASM
return ' Return to caller

Main:

Duration = 2 ' Send it twice

IF BUT=0 THEN
For Duration = 1 to 2
Cycles = Synch ' carrier on
Call Puls_a ' Send pulse

PAUSEUS InterPulse ' Pause (carrier off)

Cycles = Logic0 ' carrier on
Call Puls_b ' Send pulse

Pauseus 50000
Pauseus 50000
Next Duration

ENDIF
GOTO Main ' Return for more

END

This is command for Volume Up only ; instead 102 cycles * 26 uS = 2650 uS, I put 112 * 26 = 2912, etc. So, the lenght of one pulse is 23.5 uS ?! Maybe with this PIC... Anyway, it's good to see that working, after hard work... Thank You all for support; every advice it's further wellcome !

Ioannis
- 26th May 2010, 19:36
It seems that the internal RC oscilator is not precise at least for the receiver you use.

It cannot tolerate small differencies of the transmission pulse width.

Either use a crystal oscillator or trim your delays so that they get precisely the value needed.

Ioannis

fratello
- 27th May 2010, 18:40
Using PIC 16F628A I build this remote-by-wire for my Blaupunkt Radio-SD Card. Work verry fine... even it's simple and can be improved.

;
; Simple Remote-by-wire for Blaupunkt ; use RC10 protocol
;
@ DEVICE pic16F628A, XT_OSC, WDT_OFF, PWRT_OFF, BOD_OFF, MCLR_ON, LVP_OFF, CPD_OFF, PROTECT_OFF

DEFINE OSC 4 ; USE 4 MHz crystal

TRISA= %00000000
TRISB= %00011111
CMCON=7

TO_BLAU VAR PORTA.0
TO_BLAU = 1

PULSA VAR WORD
PULSB VAR WORD
I VAR BYTE

DELAYS CON 660


MAIN :
PAUSE 500
IF PORTB.0 = 0 THEN 'volume +
PULSA=2650
PULSB=2580
GOSUB PULSE
ENDIF


IF PORTB.1 = 0 THEN 'volume -
PULSA = 3250
PULSB = 3200
GOSUB PULSE
ENDIF

IF PORTB.2 = 0 THEN 'mute
PULSA = 5050
PULSB = 5000
GOSUB PULSE
ENDIF

IF PORTB.3 = 0 THEN 'SRC aka Source
PULSA = 6875
PULSB = 6850
GOSUB PULSE
ENDIF

IF PORTB.4 = 0 THEN 'Next aka Right
PULSA = 5660
PULSB = 5630
GOSUB PULSE
ENDIF

GOTO MAIN

;SUBROUTINE

PULSE:
FOR I = 1 TO 10
LOW TO_BLAU
PAUSEUS PULSA
HIGH TO_BLAU
PAUSEUS PULSB
LOW TO_BLAU
PAUSEUS DELAYS
HIGH TO_BLAU
PAUSEUS 50000
PAUSEUS 50000
NEXT I
RETURN

END

flotulopex
- 27th May 2010, 21:13
Hi fratello,

Using PIC 16F628A I build this remote-by-wire for my Blaupunkt...Did you change your mind? No IR anymore?

If I'm wrong and you still want to go for wireless, then you can improve a few points.

You should modulate your signal on a carrier of about 38 kHz...Ignoring the use of a carrier frequency will make you very frustrated because of the very poor efficiency of your remote.

You can simply use the PWM module and PORTB.3 to do this; nothing else is necessary (not even assembly). The trick using PWM is to switch ON (set a value) and OFF (set to zero) the duty-cycle for the time of the HIGH and LOW pulses ;)

OR have a look here if you want to make it another way (adding external components): http://www.rentron.com/Infrared_Communication.htm

According to you schema, you need to "switch ON" permanently your circuit to be able to use it. What if you forget to switch it OFF during a few days? You may need to add a "soft-switch". A soft-switch will combine your buttons as command and power-switch; a simple search will help you.

fratello
- 28th May 2010, 13:07
Thank You for support !
I say in post #23 : with PWM work great ! I try with 16F628A and it's ok ( this PIC work in both variants -by wire and by infrared) ! I drive IR-LED through NPN transistor and the range is fine (It's necessarily only 30-40 cm !)
I say in post #37 : without PWM ( using assembly), I have good results with 12F675. Only problem is "detecting" the correct timming, because of inaccurate intr_osc. Maybe with external cristall the things are changed, but losing 2 pins...
Finally I decided to use by-wire remote (for 5 commands ), with 2 wires (to ADC-in of PIC and Ground) between steering wheel and RC Blaupunkt (see picture)...like in original schematic "interfacting a Lacetti to a Blaupunkt".
Anyway nice project !