Panteltje's ir_pic page

Panteltje's ir_pic page

~

This project is released under the GPL license

Here you find the asm source code for a Microchip PIC 18F14K22 program to send infra red remote commands via USB from a terminal program or script at 115200 Bd.



The program sends command in NEC format, frequency about 38 kHz, lead tone, pause, 2 address bytes, 1 data byte, complement data byte, end tone.
Bytes are send LSB first.

This is how simple the hardware is, circuit diagram:


It uses this ebay USB to serial TTL module.
There are many similar ones for sale on ebay.

This is the asm source:
Click here to download ir_pic-0.1.asm
This source was assembled with gpasm-0.13.5 beta, may not work with mplab.

This is the hex file for those who do not have gpasm:
Click here to download ir_pic-0.1.hex

PCB top:


PCB bottom:


Build into a cut to size IC box:


I use it with my ptlrc terminal program like this:
# ptlrc -d /dev/ttyUSB2 -b 115200
Panteltje ptlrc-0.7 using device /dev/ttyUSB2
Escape exits.

Panteltje (c) ir_pic-0.1

Commands
AnnnnnENTER IR address, default 16 dec
CnnnENTER IR command value
h help (this)
v print status
SnnnENTER select channel
Z9874ENTER enter test mode
z disable test mode, default
{ channel down
] channel up

IR address 16 0x0010
IR command 0 0x00
test mode n


So for example, typing S123ENTER sets the device address, C19ENTER sends a command.


Here is how to use it from a script in Linux, 2 scripts:

script 1 /usr/local/sbin/cable_select_channel

if [ "$1" == "" ]
then
echo "Usage: cable_select_channel USB_device_name channel_number (0-999)"
exit 1
fi
if [ "$2" == "" ]
then
echo "Usage: cable_select_channel USB_device_name channel_number (0-999)"
exit 1
fi
stty -F $1 115200
echo -e "S$2\n" > $1
exit 0

That also sets the baudrate of the specified serial port to 115200


script 2 /usr/local/sbin/cable_on_off

if [ "$1" == "" ]
then
echo "Usage: cable_on_off USB_device_name on|off"
exit 1
fi
if [ "$2" == "" ]
then
echo "Usage: cable_on_off USB_device_name on|off"
exit 1
fi
stty -F $1 115200
echo -e "C0\n" > $1
# for 'on' 2 x zero
if [ "$2" == "on" ]
then
echo -e "C0\n" > $1
fi
exit 0



So, to switch the cable modem on at a specific time, and select some channels, you can do it with a few lines in crontab:
#MIN HOUR DAY MONTH DAYOFWEEK COMMAND
#18 20 * * * /usr/local/sbin/cable_on_off /dev/ttyUSB2 on
#21 20 * * * /usr/local/sbin/cable_select_channel /dev/ttyUSB2 1
#23 20 * * * /usr/local/sbin/cable_select_channel /dev/ttyUSB2 997
#24 20 * * * /usr/local/sbin/cable_on_off /dev/ttyUSB2 off

That will switch the cable modem on every day at 20:18,
select channel 1 at 20:21,
select channel 997 at 20:23,
switch cable modem off at 20:24.

Just an example right?
You are familiar with Linux cron?
type
crontab -l to see what is there.
Type
crontab -l > /root/crtab
to make your own.
Add the above lines at the end (my thing is on /dev/ttyUSB2, but whatever you use,
and remember Linux renumbers USB devices, probably because it was a stupid MS idea,
so if you have been plugging and unplugging USB devices... no guarantee, type dmesg directly after you plugged this thing in to see
what it is assigned to, or type ls -rtl /dev/ttyUSB* it is the last entry.

Anyways, after all that, type
contab /root/crtab to make crontab use it.
and wait for 20:18 :-) or change the times.

I know you should start the above script with something like #!/bin/bash or whatever,
but I not use bash, but zsh shell, zsh has much better command line processing, saves a lot of typing.


Some remarks


The LED must be an IR type, GAAIAs, high output.
I used an old one I bought in the eighties of last century's web search found better more output for the same current ones,
and higher current peak values.
You do not want a too narrow emission angle, then pointing becomes an issue.

For my Humax box the address bytes are 0016, assuming it is high byte first that makes 16,
and that is the default (saved in EEPROM).
You can set that address for your box with A123ENTER for address 123 (example), save in EEPROM,
range 0-65535.

You can send _any_ command code with:
C123ENTER (0-255).

The S option is only for my Humax and sets the channel directly, S997ENTER selects channel 997.
See the source for how that is done, change the source for whatever you have.

Test mode is not implemented, the whole universe is a test.


So what does it do?

Well
if
you actually build it, and figured out how to use it, and modified the code for your situation,
and found out the IR codes for your stuff,
then
you can control any IR based 'thing' that uses the NEC protocol from the PC or laptop.

In my case I needed this as I record from the cable modem on the PC with a mpeg2 encoder card,
and if there are 2 movies after each other on a different channel in the middle of the night
or when you are not there, now the PC can set the channel, the recorder software already has a timer.

I get about 4 meters range with this old LED.
It is all done timing with nops, routines called from serial interrupt.

I did chose not to use the PWM output, soft timing is in a way more accurate.

The PIC uses the internal oscillator, and runs on 64 MHz (4 x 16 MHz PLL) that makes accurate adjustment possible.
And IR 38 kHz is not that critical.


Finding your codes:

Since there are 65535 device addresses possible, and you do not even know the remote codes, trying them all (2^24) was not what I did.
But it can be done ;-)

No, I wrote a simple program called 'ir.c' that reads parport pin 15 on the PC, that pin is connected to this:




D1 is an IR detection diode that has to be covered with IR transmissive paint or something to prevent other light to activate the transistor
My mobo's parport delivers 3.3 V on pin 5 (software sets this high).
The above circuit acts as a low-pass for the 38 kHz, and outputs low for 38 kHz present, and high for not present.

ir.c source:
irc.c
compile with gcc -o ir irc.c

Menu:
Panteltje ir-0.1
Usage:
ir [-c command_file] [-d hex] [-h] [-l] [-t] [-v int]
-c command_file.
-d hex parallel port address, default 0x378.
-h help (this help).
-l learn mode.
-t I/O test.
-v int verbose, prints functions and arguments.

So ir.c has a lean opd e(I almost wanted to write 'remember' but OK,
sure funniest moment of the day so far),
anyways
Make a directory for the data,and for all this you need to be root, else no I/O.
mkdir -p /root/.lremote/commands/
put the IR diode against your remote control,
type nice -n -19 ./ir -l
nice -9 to grab all resources, to get as little influence as possible from other stuff running.
it will say: press ENTER to start.
Hit ENTER, then immediately press the button on the remote you are curious about.
After about a second reading pin 15 it will ask for a filename to save the data.
I ran 6 test, on the same key (channel up), named those sequentially.
panteltje12: ~ # l /root/.lremote/commands/
total 384
-rw-r--r-- 1 root root 62500 Feb 13 14:45 a.irc
-rw-r--r-- 1 root root 62500 Feb 13 14:45 b.irc
-rw-r--r-- 1 root root 62500 Feb 13 14:45 c.irc
-rw-r--r-- 1 root root 62500 Feb 13 14:45 d.irc
-rw-r--r-- 1 root root 62500 Feb 13 14:45 e.irc
-rw-r--r-- 1 root root 62500 Feb 13 14:45 f.irc

So those files (binary contain 0xff for no signal, and 0x00 for signal, and things in between for bad signals.
If the task switch happens in the data acquisition time, than you get unusable data, so try many times.

I wrote a second 'helper' program to replace all those 0xff and 0x00 by zero and ones, 0 fro 0xff, and 1 for 0x00:
convert_ir_read.c
compile with gcc -o convert_ir_read convert_ir_read.c
and run it like this:
cat /root/.lremote/commands/f.irc | ./convert_ir_read > f.ir

So now we have a text file f.ir
In that text file replace all double line feeds with 1 line feed.
Now replace the sequence line feed0 with just 0
Then you see this:
11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111
11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111
1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000


; 0000 0000 = 0
111111111111111111111111111111111111111111111110000000000000000000000000000000000
11111111111111111111111111111111111111111111110000000000000000000000000000000000
11111111111111111111111111111111111111111111111000000000000000000000000000000000
11111111111111111111111111111111111111100000000000000000

111111111111111111111111111111111111111111111110000000000000000000000000000000000
111111111111111111111111111111111111111111111111000000000000000000000000000000000
111111111111111111111111111111111111111111111110000000000000000000000000000000000
1111111111111111111111111111111111111111111111000000000000000000000000000

; 0001 0000 = 16
111111111111111111111111111111111111111111111100000000000000000000000000000000000
111111111111111111111111111111111111111111111110000000000000000000000000000000000
111111111111111111111111111111111111111111111100000000000000000000000000000000000
11111111111111111111111111111111111111111111110000000000000000000000000000000000

111111111111111111111111111111111111111111111100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
111111111111111111111111111111111111111111111100000000000000000000000000000000000
111111111111111111111111111111111111111111111100000000000000000000000000000000000
1111111111111111111111111111111111111111110000000000000000000000000000000000


; 0001 0000 = 16
1111111111111111111111111111111111111111111111100000000000000000000000000000000000
111111111111111111111111111111111111100000000000000000000000000000000000
11111111111111111111111111111111111111111111110000000000000000000000000000000000
111111111111111111111111111111111111111111111110000000000000000000000000000000000

111111111111111111111111111111111111111111111100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
11111111111111111111111111111111111100000000000000000000000
1111111111111111111111111111111111111111111111110000000000000000000000000000000000
1111111111111111111111111111111111111111111111100000000000000000000000000

; 1110 1111 = 239
11111111111111111111111111111111111111111111111100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
11111111111111111111111111111111111111111111111100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
111111111111111111111111111111111111111111100000000000000000000000000000000000000000000000000000000000000000000000
1111111111111111111111111111111111111111100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000

11111111111111111111111111111111111111111111110000000000000000000000000000000000
111111111111111111111111111111111111111111111100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
1111111111111111111111111111111111111111111111000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
111111111111111111111111111111111111111111000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000

11111111111


I added the numbers, BINGO, got the codes for channel up.
In the NEC encoding a 'zero' is 10, and a one is 100
Since we were much faster sampling (PCI bus) use the ratio of ones and zeros.
If you did it right you found leader, pause, 24 bits, and a short end signal

That is how I did it, there are simpler ways, some info on the codes for the various remotes can be found with google.
Code rules.


There is more to it, but this should get you going.


other projects