|
|
View previous topic :: View next topic |
Author |
Message |
Rohit de Sa
Joined: 09 Nov 2007 Posts: 282 Location: India
|
IR wireless presenter |
Posted: Tue Sep 23, 2008 10:27 pm |
|
|
Hey all,
I was thinking of making a simple and cheap infrared wireless presenter to control slide shows on my laptop. I have the following in mind:
(Cheap Sony IR remote) --> (TSOP1738) --> (PIC18F2550) --> (USB HID keyboard/mouse device) --> (Control powerpoint slides)
Here in India I can build the whole thing for less than INR250 (USD5). Everything including the IR remote and the PIC are included in this cost.
Now I've got the remote to work with the TSOP and a 12F675 decoding the IR data, so it won't be too difficult to port this to a '2550. Separately, I've got the HID keyboard/mouse demo program included with CCS to work fine. So its a matter of combining these two.
I've got a rough idea of what I want my code to look like, but I needed help on something: would it be smart to put an ASM 'pop' statement in the code? This greatly reduces my work, and also seems to make the code run faster, but will it interfere with USB communications? (USB interrupts?)
My basic problem is that I would like to return to a specified address after the timer1 interrupt. Is this advisable with USB running onboard?
Sorry if the question sounds vague; here's some pseudo code to help:
Code: |
#int timer1 //timer1 is used to verify the length of
//IR pulses and convert them into bits
{
reset timer1
pop //if timer1 overflows it means that either
//the IR pulses have stopped, or that some
//error has occurred, so return from
//interrupt TO START OF CODE that detects
// IR 'start' pulse (this is my problem)
}
// it should now return to the specified PC
main()
{
init(); //initialization routine
while(1)
{
start: start_detect() //this detects whether a start pulse has
//been recd.
..
..
(decode remaining bits)
(if there is a timer1 overflow during this period, PC should goto 'start' label)
(check validity of bits, if not valid, set PC to 'start' label)
(send valid data over USB HID)
}
|
Suggestions as to how I may do this? Or if I should do this at all? :-P
Thanks,
Rohit |
|
|
Rohit de Sa
Joined: 09 Nov 2007 Posts: 282 Location: India
|
|
Posted: Sun Oct 12, 2008 7:22 am |
|
|
I've managed to build the presenter, and it seems to be working ok.....well almost ok. I'm having problems with the USB keyboard part. I'll just give you a bit of a quick overview of what works and what doesn't. The timer and IR parts work perfect, no problems at all. The USB enumerates fine and sends the character. The problem crops up here. I would like that when I press a key on the remote once, only one character is transmitted. I get an unending string of characters (I'm using Notepad to see the output). When I press a different key on the remote the character changes, but again, a never-ending string. Only when I press the power button on the remote (I've set this to give me a USB keyboard char of 0x00) does the string stop.
Any suggestions on how I can output just one character per button press?
I guess the problem is in function send_usb().
I'm using an 18F2550 with the Microchip PICDEM FSUSB bootloader. CCS compiler is 4.068, used in MPLABv8.14 . USB code lifted from ex_usb_kbmouse2. The descriptor file remains unmodified.
Code: | // This is code for a wireless IR presenter. It uses
// the 12 bit SIRC protocol.
//
// Hardware -
// Sample signal at TSOP data output (taken using
// PICKit2 as a logic analyzer):
//
// ------\________/--\__/--\__/--\__/--\__/--\__/--\__/--\__/--\____/--\__/--\__/--\__/--\__/-----
// (idle)| (start) | bit0| bit0| bit0| bit0| bit0| bit0| bit0| bit1 | bit0| bit0| bit0| bit0|(idle)
//
// example for remote button "1"
//
// Bit lengths:
// Start = 2.4ms + 0.6ms
// One = 1.2ms + 0.6ms
// Zero = 0.6ms + 0.6ms
//
// TSOP data is inverted; it idles high.
// [--\_ : negative going edge; _/-- : positive going edge]
//
// Rohit de Sa
// 05Oct08
// v1.0
// edited on 09Oct08
// working, with problems as of 12Oct08
#include <18F2550.h>
//#fuses HSPLL,NOWDT,NOPROTECT,NOLVP,NODEBUG,USBDIV,PLL5,CPUDIV1,VREGEN
#use delay(clock=48000000)
#build(reset=0x800, interrupt=0x808)
#org 0x0000,0x07ff{}
#use fast_io(c)
/// USB setup
#define __USB_PIC_PERIF__ 1
#define USB_HID_DEVICE TRUE
#define USB_EP1_TX_ENABLE USB_ENABLE_INTERRUPT
#define USB_EP1_TX_SIZE 8
#define USB_EP1_RX_ENABLE USB_ENABLE_INTERRUPT
#define USB_EP1_RX_SIZE 8
#include <pic18_usb.h>
#include <usb_desc_kbmouse2.h>
#include <usb.c>
#define one_min 10010 //no of counts to safely detect bit1
#define one_max 20000 //optimal @12 MIPS is 14400
#define zero_min 3000 //no of counts to safely detect bit0
#define zero_max 10000 //optimal @12 MIPS is 7200
#define start_min 23600 //no of counts to safely detect start
#define start_max 36000 //optimal @12 MIPS is 28800
#define IR_device_address 0x01
#define led pin_c0
#define tsop pin_c1
int16 start_address=0; //ROM address of 'Start' label
int8 addr=0;
int8 cmd=0;
int1 buffer[12];
#int_timer1 //if timeout error
void timer1_isr()
{
*0xffd=start_address; //modify return address in TOS
*0xffe=start_address/256;
}
void decode_ir()
{ //decode the address/data
int8 mask;
int8 i;
cmd=0;
addr=0;
mask=0x01; //format command
for (i=0;i<7;i++)
{
if (buffer[i])
cmd=cmd|mask;
mask<<=1;
}
mask=0x01; //format address
for (i=7;i<12;i++)
{
if(buffer[i])
addr=addr|mask;
mask<<=1;
}
//breaking down command, and equating it with keyboard
//scan codes
//check for command validity, if not valid set addr=0
switch (cmd)
{
case 0x00: cmd=0x1e; //numerical buttons
break;
case 0x01: cmd=0x1f;
break;
case 0x02: cmd=0x20;
break;
case 0x03: cmd=0x21;
break;
case 0x04: cmd=0x22;
break;
case 0x05: cmd=0x23;
break;
case 0x06: cmd=0x24;
break;
case 0x07: cmd=0x25;
break;
case 0x08: cmd=0x26;
break;
case 0x09: cmd=0x27;
break;
case 0x15: cmd=0x00; //pwr button
break;
default: addr=0x00;
break;
}
}
#separate
void send_usb() //send usb output
{
// tx_msg[0] = HID report id (2)
// tx_msg[1] = modifier (an 8bit bitmap of shift, tab, alt keypress)
// tx_msg[2] = const 0
// tx_msg[3:7] = an array of held down keys. a=4, b=5, etc.
// if msg[2:7]={0} then no keys are held down
//
// rx_msg[1] = HID report id (2)
// rx_msg[0] = 5bit bitmap of led status
//
/////////////////////////////////////////////////////////////////////////////
//void usb_keyboard_task(void) {
static int8 tx_msg[8]={2,0,0,0,0,0,0,0};
tx_msg[3]=cmd;
if usb_enumerated()
{
usb_put_packet(1,tx_msg,sizeof(tx_msg),USB_DTS_TOGGLE);
//this does not solve the problem
//tx_msg[3]=0;
//usb_put_packet(1,tx_msg,sizeof(tx_msg),USB_DTS_TOGGLE);
}
}
void main()
{
int8 ircount=0; //counts no if bits received
int16 timer_value=0;
int1 flag_one=0;
int1 irdone=false;
delay_ms(100); //setting up PIC
setup_adc_ports(no_analogs);
setup_adc(adc_off);
set_tris_c(0b00000111);
set_tris_a(0b00000111);
//set up usb hid keyboard mouse
usb_init();
usb_task();
start_address=label_address(start_ir);//ROM address of IR detection routine
delay_ms(100);
//timer prescaler dependent on oscillator speed
setup_timer_1(t1_internal|t1_div_by_1);
disable_interrupts(int_timer1);
enable_interrupts(global);
output_a(0x00);
output_b(0x55);
output_high(led); //'Ready' flash
delay_ms(50);
output_low(led);
delay_ms(50);
output_high(led);
delay_ms(50);
output_low(led);
while(1)
{
start_ir:
ircount=0;
irdone=false;
buffer[0]=0;
buffer[1]=0;
buffer[2]=0;
buffer[3]=0;
buffer[4]=0;
buffer[5]=0;
buffer[6]=0;
buffer[7]=0;
buffer[8]=0;
buffer[9]=0;
buffer[10]=0;
buffer[11]=0;
disable_interrupts(int_timer1);
clear_interrupt(int_timer1);
while(1)
{
while(input(tsop));
set_timer1(0); //start bit detected
enable_interrupts(int_timer1);
delay_us(10); //settling delay
while(!(input(tsop)));
timer_value = get_timer1();
set_timer1(0);
if (!((start_min < timer_value) && (timer_value < start_max)))
{
break;
}
delay_us(10); //settling delay
while(input(tsop));
timer_value = get_timer1();
set_timer1(0);
if (!((zero_min < timer_value) && (timer_value < zero_max)))
{
break;
}
delay_us(10); //settling delay
output_toggle(led);
////////////////////////////////////////////////////////////
for (ircount=0;ircount<11;ircount++) //individual bits start here
{
while(!(input(tsop)));
timer_value = get_timer1();
set_timer1(0);
if ((one_min < timer_value) && (timer_value < one_max))
{
flag_one=1; //bit1 detected
}
else if ((zero_min < timer_value) && (timer_value < zero_max))
{
flag_one=0; //bit0 detected
}
else
{
break;
}
delay_us(10); //settling delay
while(input(tsop));
timer_value = get_timer1();
set_timer1(0);
if (!((zero_min < timer_value) && (timer_value < zero_max)))
{
break;
}
delay_us(10); //settling delay
buffer[ircount] = flag_one;
if (ircount==10)
{
irdone=true;
}
}
if (irdone==false) //if all bits have not been decoded vector out
{
break;
}
while(!(input(tsop))); //last bit is always zero
timer_value = get_timer1();
set_timer1(0);
if (!((zero_min < timer_value) && (timer_value < zero_max)))
{
break;
}
decode_ir();
if (addr==IR_device_address) //USB send function
{
//if valid command flash leds
output_high(led);
send_usb();
irdone=false;
output_low(led);
}
break;
}
}
} |
|
|
|
Rohit de Sa
Joined: 09 Nov 2007 Posts: 282 Location: India
|
|
Posted: Sun Oct 12, 2008 7:32 am |
|
|
Oh, some of the code is newbie-style code Suggestions to improve it, please? Thanks.
Another thing, I'm actually directly messing with the hardware stack, as can be seen in the timer1 ISR. Is this 'good code', or can I avoid doing this? I haven't encountered problems by doing this, and I don't (more like can't ) foresee any trouble. Comments?
Rohit |
|
|
Rohit de Sa
Joined: 09 Nov 2007 Posts: 282 Location: India
|
|
Posted: Mon Oct 13, 2008 2:12 am |
|
|
I think I have a possible solution, but I'm at work and hence can't try it out. Will do so when I go home.
Right after I do a send_usb() I think I need to add another usb_put_packet() after a short delay, say 5ms. The first send_usb() sends out a 'make' (in PS/2 terms), so I would need to send the USB equivalent of a PS/2 'break'. This 'break' happens to be a 0x00.
Is this reasoning correct?
Rohit |
|
|
Rohit de Sa
Joined: 09 Nov 2007 Posts: 282 Location: India
|
|
Posted: Tue Oct 14, 2008 12:34 am |
|
|
It was exactly what I had thought! I needed to send a 'break' signal after each key. So the way to send a single character is:
(send hex value)
(wait)
(send 0x00, no event)
The modification is concerned with the last part of the code:
Code: |
.
.
.
disable_interrupts(int_timer1); //prevent timer1 from interrupting
clear_interrupt(int_timer1);
if (addr==IR_device_address) //USB send function
{
//if valid command flash leds
output_high(led); //turn on status led
send_usb(); //send HID message
irdone=false;
delay_ms(20);
}
delay_ms(100); //waiting for some time to prevent multiple instances of the same button to be sent, sort of like a 'debounce', but not exactly
while(!(usb_enumerated())) //wait until enumerated
cmd=0x00;
send_usb();
output_low(led); //turn off status led
////// modification ends ////////
break; |
I'll put up the modified code and a circuit diagram soon.
I'm still looking for suggestions to improve the code. Anyone?
Rohit |
|
|
kd5uzz_home Guest
|
Great work |
Posted: Tue Oct 14, 2008 3:57 pm |
|
|
I love the documentation. I'm glad you got it to work. I hope to use what I've learned from you in an upcomming project. Just letting you know someone IS watching/reading what you write! |
|
|
Rohit de Sa
Joined: 09 Nov 2007 Posts: 282 Location: India
|
|
Posted: Tue Oct 14, 2008 10:00 pm |
|
|
Hey thanks! For a while I was thinking that I was out here on my own! Glad to know that my code will be of help to you. I'm still making a few changes to the code, trying to see if modifying this, and adjusting that works. You are free to use the code or any part of it without permission (naturally, since I've posted it on an open forum! ). But an acknowledgment in the form of details or a link to your project would be nice. All the best with your project!
Rohit |
|
|
Rohit de Sa
Joined: 09 Nov 2007 Posts: 282 Location: India
|
|
Posted: Wed Oct 15, 2008 1:20 am |
|
|
Here is the full code, working properly. Please feel free to use, modify and redistribute the code. It would be nice if you can give my name a mention , but no compulsions. A word of caution - I will not be responsible if you mess up your PC or anything else in the process of making this project, though I doubt strongly that this will happen, since my PC is working fine.
As of now, only the keyboard part of it has been implemented. Since my project uses ex_kbmouse2.c as the reference, future plans are to remove the redundant mouse descriptors that tag along with the project. This may create a more compact project.
Another modification is to keep the mouse descriptors and add mouse support to the IR remote. This will be a nice touch.
Finally, I will be porting this whole project from IR to RF. This will require extensive code and hardware modification. For this, I'm thinking of using the RX/TX433 pair and maybe an accelerometer for mouse functionality. But these are long term plans.
So, the code:
edit
(for some reason BB code never accepts TABs, so all my comments are messed up and on different lines; here's a link to the text file which has slightly better formatting http://docs.google.com/Doc?id=dfq25rp8_46wkr88g5g The next update will be a pdf print from MPLAB ).
edit
Code: | // This is code for a wireless IR presenter. It uses
// the 12 bit SIRC protocol. The device appears as a
// standard HID keyboard to the PC. IR data is recieved
// from a standard remote, it is decoded, and the
// the appropriate keyboard data is sent to the PC.
// The design is optimized for MS Powerpoint.
//
// Hardware -
// TSOP1738 on Pin C1
// Status LED on Pin C0
//
//
// Sample signal at TSOP data output (taken using
// PICKit2 as a logic analyzer):
//
// ------\________/--\__/--\__/--\__/--\__/--\__/--\__/--\__/--\____/--\__/--\__/--\__/--\__/-----
// (idle)| (start) | bit0| bit0| bit0| bit0| bit0| bit0| bit0| bit1 | bit0| bit0| bit0| bit0|(idle)
//
// example for remote button "1"
//
// Bit lengths:
// Start = 2.4ms + 0.6ms
// One = 1.2ms + 0.6ms
// Zero = 0.6ms + 0.6ms
//
// TSOP data is inverted; it idles high.
// [--\_ : negative going edge; _/-- : positive going edge]
//
// Rohit de Sa
// 05Oct08
// v1.0
// edited on 09Oct08
// working, with problems as of 12Oct08
// Corrected all errors as of 13Oct08
#include <18F2550.h>
#fuses HSPLL,NOWDT,NOPROTECT,NOLVP,NODEBUG,USBDIV,PLL5,CPUDIV1,VREGEN
#use delay(clock=48000000)
//#build(reset=0x800, interrupt=0x808) //necessary if using Microchip bootloader
//#org 0x0000,0x07ff{} //comment out the #fuses line when using it
#use fast_io(c)
/// USB setup
#define __USB_PIC_PERIF__ 1
#define USB_HID_DEVICE TRUE
#define USB_EP1_TX_ENABLE USB_ENABLE_INTERRUPT
#define USB_EP1_TX_SIZE 8
#define USB_EP1_RX_ENABLE USB_ENABLE_INTERRUPT
#define USB_EP1_RX_SIZE 8
#include <pic18_usb.h>
#include <usb_desc_kbmouse2.h>
#include <usb.c>
//(you may need to experiment with this)
#define one_min 10010 //no of counts to safely detect bit1
#define one_max 20000 //optimal @12 MIPS is 14400
#define zero_min 3000 //no of counts to safely detect bit0
#define zero_max 10000 //optimal @12 MIPS is 7200
#define start_min 23600 //no of counts to safely detect start
#define start_max 36000 //optimal @12 MIPS is 28800
#define IR_device_address 0x01 //the address of your Sony remote may be different
#define led pin_c0
#define tsop pin_c1
int16 start_address=0; //ROM address of 'Start' label
int8 addr=0; //formatted IR address
int8 cmd=0; //formatted IR command
int1 buffer[12]; //temp buffer to store IR bits
#int_timer1 //if timeout error
void timer1_isr()
{
*0xffd=start_address; //modify return address in TOS
*0xffe=start_address/256;
}
void decode_ir()
{ //decode the address & data
int8 mask;
int8 i;
cmd=0;
addr=0;
mask=0x01; //format command
for (i=0;i<7;i++)
{
if (buffer[i])
cmd=cmd|mask;
mask<<=1;
}
mask=0x01; //format address
for (i=7;i<12;i++)
{
if(buffer[i])
addr=addr|mask;
mask<<=1;
}
//breaking down command, and equating it with keyboard
//scan codes
//check for command validity, if not valid set addr=0
//(the address and commands may be different for your Sony remote)
switch (cmd)
{
case 0x00: cmd=0x1e; //numerical buttons
break; //correspond to keyboard
case 0x01: cmd=0x1f; //numbers 1 through 9, and 0
break;
case 0x02: cmd=0x20;
break;
case 0x03: cmd=0x21;
break;
case 0x04: cmd=0x22;
break;
case 0x05: cmd=0x23;
break;
case 0x06: cmd=0x24;
break;
case 0x07: cmd=0x25;
break;
case 0x08: cmd=0x26;
break;
case 0x09: cmd=0x27;
break;
case 0x15: cmd=0x29; //pwr button = Esc
break;
case 0x10: cmd=0x4f; //ch+ = right arrow
break;
case 0x11: cmd=0x50; //ch- = left arrow
break;
//case 0x12: cmd=0x1a; //vol+ = n/a
// break;
//case 0x13: cmd=0x05; //vol- = n/a
// break;
case 0x3f: cmd=0x05; //Menu = B (black screen)
break;
case 0x28: cmd=0x1a; //Text = W (white screen)
break;
case 0x25: cmd=0x3e; //Source = F5
break;
case 0x3b: cmd=0x28; //Jump = Return / Enter
break;
default: addr=0x00;
cmd=0x00;
break;
}
}
#separate
void send_usb() //send usb output
{
// tx_msg[0] = HID report id (2)
// tx_msg[1] = modifier (an 8bit bitmap of shift, tab, alt keypress)
// tx_msg[2] = const 0
// tx_msg[3:7] = an array of held down keys. a=4, b=5, etc.
// if msg[2:7]={0} then no keys are held down
//
// rx_msg[1] = HID report id (2)
// rx_msg[0] = 5bit bitmap of led status
static int8 tx_msg[8]={2,0,0,0,0,0,0,0};
tx_msg[3]=cmd;
usb_put_packet(1,tx_msg,sizeof(tx_msg),USB_DTS_TOGGLE);
}
void main()
{
int8 ircount=0; //counts number of bits received
int16 timer_value=0;
int1 flag_one=0;
int1 irdone=false;
delay_ms(100); //setting up PIC
setup_adc_ports(no_analogs);
setup_adc(adc_off);
set_tris_c(0b00000111);
//set up usb hid keyboard mouse
usb_init();
usb_task();
start_address=label_address(start_ir); //ROM address of IR detection routine
delay_ms(100);
setup_timer_1(t1_internal|t1_div_by_1);
disable_interrupts(int_timer1);
enable_interrupts(global);
output_a(0x00);
output_b(0x55);
output_high(led); //'Ready' flash
delay_ms(50);
output_low(led);
delay_ms(50);
output_high(led);
delay_ms(50);
output_low(led);
while(1)
{
start_ir:
ircount=0;
irdone=false;
buffer[0]=0;
buffer[1]=0;
buffer[2]=0;
buffer[3]=0;
buffer[4]=0;
buffer[5]=0;
buffer[6]=0;
buffer[7]=0;
buffer[8]=0;
buffer[9]=0;
buffer[10]=0;
buffer[11]=0;
disable_interrupts(int_timer1);
clear_interrupt(int_timer1);
while(1)
{
while(input(tsop));
set_timer1(0); //start bit detected
enable_interrupts(int_timer1);
delay_us(10); //settling delay
while(!(input(tsop)));
timer_value = get_timer1();
set_timer1(0);
if (!((start_min < timer_value) && (timer_value < start_max)))
{
break;
}
delay_us(10); //settling delay
while(input(tsop));
timer_value = get_timer1();
set_timer1(0);
if (!((zero_min < timer_value) && (timer_value < zero_max)))
{
break;
}
delay_us(10); //settling delay
for (ircount=0;ircount<11;ircount++) //individual bits start here
{
while(!(input(tsop)));
timer_value = get_timer1();
set_timer1(0);
if ((one_min < timer_value) && (timer_value < one_max))
{
flag_one=1; //bit1 detected
}
else if ((zero_min < timer_value) && (timer_value < zero_max))
{
flag_one=0; //bit0 detected
}
else
{
break;
}
delay_us(10); //settling delay
while(input(tsop));
timer_value = get_timer1();
set_timer1(0);
if (!((zero_min < timer_value) && (timer_value < zero_max)))
{
break;
}
delay_us(10); //settling delay
buffer[ircount] = flag_one;
if (ircount==10)
{
irdone=true;
}
}
if (irdone==false) //if all bits have not been decoded
//vector out and goto label 'start_ir'
{
break;
}
while(!(input(tsop))); //last bit is always zero
timer_value = get_timer1();
set_timer1(0);
if (!((zero_min < timer_value) && (timer_value < zero_max)))
{
break;
}
decode_ir(); //format address & command
if (addr==IR_device_address) //USB send function
{
if (usb_enumerated())
{
output_high(led); //LED on
send_usb();
}
disable_interrupts(int_timer1);
clear_interrupt(int_timer1);
delay_ms(20);
cmd=0x00;
while(!(usb_enumerated())); //wait until enumerated
send_usb(); //send 'no event/break'(0x00)
delay_ms(100);
output_low(led) //LED off
}
irdone=false;
break;
}
}
} |
Rohit |
|
|
kd5uzz_work` Guest
|
|
Posted: Wed Oct 15, 2008 1:19 pm |
|
|
lynx has some very good 433mhz modules ~$30 for a pair, IIRC. Although not as compact another option would be XBee modules, ~$20 each. Lynx uses one chip for TX, another for RX. XBee uses one chip for both.
WindowsXP also has an option for (I think..) serialkeys. It allows the OS to accept keyboard/mouse input from the serial port (I think a USB HID device is the better option, just throwing it out there). |
|
|
Rohit de Sa
Joined: 09 Nov 2007 Posts: 282 Location: India
|
|
Posted: Wed Oct 15, 2008 9:49 pm |
|
|
Quote: | another option would be XBee modules | Thanks for the info. I'll have a look at the modules.
I already have the 433Mhz modules, though not from Linx (that's what you meant, right http://www.linxtechnologies.com/ ? and not 'Lynx') , just some generic unbranded ones. Got them for INR350 (~USD7). Data rates are 2400bps max. and line of sight range is about 100m (TX running at 9v, RX at 5v), which is reasonable. I could boost the range by making better antennae, but I don't think I'm ever going to control a ppt from over a hundred meters!
I'm going to check out the Zigbee modules. I already have the CYWM6934 from Cypress, which are 2.4GHz DSSS radios. Range is only 8-10m, though. Oh, has anyone used the MRF24J40MA modules from Microchip? http://www.microchip.com/wwwproducts/Devices.aspx?dDocName=en535967 They're only USD9.95 a pop, and since I'm still a student, I get a 25% discount! (Yeah, as with all students I'm on a shoestring budget )
Rohit |
|
|
Rohit de Sa
Joined: 09 Nov 2007 Posts: 282 Location: India
|
|
Posted: Fri Oct 24, 2008 10:01 pm |
|
|
Andrew, who mailed me, had the following doubt, which I'm posting for the benefit of others:
Quote: | Hello ! Sorry to (maybe ) disturb you ! I have a question concerning your code. First of all, i must tell you that i'm a newbie in the field of microcontrollers. So, the question sounds something like this : How did you came across the values for one_min and one_max ?
Please verify the following calculation:
- interrupt rate = (4/48000000)*65536 (16bit timer1) * 1 (prescaler value)
- in 1 ms there should be about =(0,001/(0,00000083))= 37 counts
Right ? So pls explain your results for one_min and one_max! Confused
THANK YOU VERY MUCH !! |
Well, if you look a little closer you'll see that I'm using the timer1 interrupt only to act like a sort of 'watchdog timer'. The durations of all my IR pulses should never exceed the timer1 rollover time. If they do, I know that they are erroneous pulses. Therefore I should reject that pulse stream.
Thus, the timer1 peripheral performs a dual function - the first being acting like a watchdog, catching 'bad' IR pulses. And the second, as a counter, counting the number of cycles for an IR pulse.
I arrived at the exact times for the SIRC protocol through Google, and optimized the range by actually checking my remote on a logic analyzer. The calculations for 0.6ms are:
Clock speed: 48MHz
Quadrature clocked, so effective clock speed = 48/4=12MHz
Now, (1 / 12000000) seconds for 1 clock/counter increment
Therefore for 0.0006 seconds, how many increments?
= 0.0006 x 12000000
= 7200 counts
7200 counts is the optimal time. But as with all real-world systems, you need to implement some leeway. Therefore, I used 3000 for zero_min and 10000 for zero_max.
The other parameters can be calculated in the same way.
A little explanation on the parameters to make things clear. The IR pulse from the remote for:
-a bit1 is represented by a high of duration [one_max to one_min] followed low of duration [zero_max to zero_min]
-a bit0 is represented by a high of duration [zero_max to zero_min] followed low of duration [zero_max to zero_min]
-the start pulse is represented by a high of duration [start_max to start_min] followed low of duration [zero_max to zero_min]
Your calculation is a bit wrong. (0.001/(0.000000083) = 12,000. You also missed a '0' in the divisor - there are seven '0's after the decimal point.
Rohit |
|
|
Andrew83
Joined: 16 Sep 2008 Posts: 51
|
|
Posted: Tue Oct 28, 2008 3:01 am |
|
|
Hello Rohit !
I have another question about your code.
I am trying to decode a REC80 IR protocol. The transmission consists of a header and 32 individual bits.
Now ... I've managed to succesfully detect the header of the transmission but for some reason I am unable to decode the entire code.
So ... I am using pic18f452, 4.4MHz clock, CCS C version 4.057 and a TSOP1738 IR receiver module.
From http://www.vishay.com/docs/80071/dataform.pdf I've got the following information :
- header : 9 ms-high and 4,5 ms low
- representation of a "1" :2,25 ms high
- representation of a "0" :1,125 ms low
Here is my variant of the code you so generously posted (I'm posting just the detection part of the code):
Code: |
#define one_min 2000 //no of counts to safely detect bit1
#define one_max 3000 //optimal @1,1 MIPS is 2464
#define zero_min 900 //no of counts to safely detect bit0
#define zero_max 1900 //optimal @1,1 MIPS is 1237,5
#define start0_min 8000 //no of counts to safely detect a "0" start
#define start0_max 12000 //optimal @1,1 MIPS is 9900
#define start1_min 3000 //no of counts to safely detect a "1" start
#define start1_max 6000 //optimal @1,1 MIPS is 4950
#define tsop pin_b0
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////
while(1)
{
while(input(tsop));
set_timer1(0);
enable_interrupts(int_timer1);
delay_us(10);
while(!(input(tsop)))
timer_value_one = get_timer1(); //header part
set_timer1(0); //header part
if (!((start0_min < timer_value_one) && (timer_value_one < start0_max))) //header part
{
break;
}
//else
//{ output_high(pin_b1); }
delay_us(10); //header part
while(input(tsop)); //header part
timer_value_zero = get_timer1(); //header part
set_timer1(0); //header part
if (!((start1_min < timer_value_zero) && (timer_value_zero < start1_max))) //header part
{
break;
} //header part
// else //header part
//{ //header part
//output_high(pin_b2); //header part
//} //header part
//printf("Valoare 1: %lu si valoare 2:%lu",timer_value_one,timer_value_zero); //header part
delay_us(10);
for (ircount=0;ircount<31;ircount++) //actual bits
{
while(!(input(tsop))); //actual bits
timer_value = get_timer1();
set_timer1(0); //actual bits
if ((one_min < timer_value) && (timer_value < one_max))
{
flag_one=1;
output_high(pin_b3);
}
else if ((zero_min < timer_value) && (timer_value < zero_max))
{
flag_one=0;
output_high(pin_b4);
}
else
{
break;
}
delay_us(10);
while(input(tsop));
timer_value = get_timer1();
set_timer1(0);
if (!((zero_min < timer_value) && (timer_value < zero_max)))
{
break;
}
delay_us(10);
buffer[ircount] = flag_one;
if (ircount==32)
{
irdone=true;
}
}
if (irdone==false)
{
break;
}
while(!(input(tsop)));
timer_value = get_timer1();
set_timer1(0);
if (!((zero_min < timer_value) && (timer_value < zero_max)))
{
break;
}
|
If I am commenting out the header detection part of the code and I am changing the Code: | while(!(input(tsop))); | to Code: | while((input(tsop))); | in the FOR statement, I am able to succesfully detect the bits. Why is that ? I can't figure it out ...
What am I doing wrong ?
Thank you for your patience and good will !
Cheers !! |
|
|
Rohit de Sa
Joined: 09 Nov 2007 Posts: 282 Location: India
|
|
Posted: Tue Oct 28, 2008 4:13 am |
|
|
Andrew,
The pdf link you posted has no description of the REC80 protocol. From my googling I've come to realize that this is a very old protocol. http://www.sbprojects.com/knowledge/ir/recs80.htm has a good description of the protocol specifics, but the funny thing is that they differ from your timing values. I just wanted to confirm the protocol that you are using - is it the RECS-80 protocol, or the NEC protocol?
According to the link I posted above, there may be one or two toggle bits in the pulse train to perform key debouncing. This may be the reason why the code works without the header. I'm not at all familiar with the RECS-80 protocol, so maybe if you have a logic analyzer or oscilloscope you could post a picture of the IR data waveform.
According to the timing specifications you have given me, the protocol looks like the NEC protocol. But as per this protocol, a bit1 is 560us high followed by 1690us low (2.25ms in total), and a bit0 is 560us high followed by 560us low (1.12ms in total). The header is, as you mentioned 9ms high followed by 4.5ms low ( http://www.sbprojects.com/knowledge/ir/nec.htm ).
You mentioned that you would be decoding 32 bits of data. The NEC code has 8 address bits (transmitted LSB first) twice, followed by 8 data bits (also transmitted LSB first) twice. The double transmission give data reliability, but more importantly, 8+8+8+8 bits = 32 bits. So it seems to me like you are using the NEC protocol. There is also the extended NEC protocol, which you can go through on the link.
Remember, the TSOP data output will be inverted. When the IR LED is not transmitting, the TSOP output will idle HIGH. You would like to start decoding the IR signal the instant and IR pulse is received. An IR signal will cause the TSOP to pull low. That is why to detect the header you will ask the PIC to stay in the while((input(tsop))); until the output swings low. The PIC will jump out of this instruction and then continue processing.
If you confirm the protocol you are using, I'll have a detailed look at the code.
Rohit |
|
|
Andrew83
Joined: 16 Sep 2008 Posts: 51
|
|
Posted: Tue Oct 28, 2008 4:16 am |
|
|
I think i have a possible solution for my problem.....i think that if i use a "if-then" instead of the "for" i might catch the pulses in time. But this solution poses another challenge for me: assembler code.
So...i will try this solution...and hopefully detect does nice bits ! |
|
|
Andrew83
Joined: 16 Sep 2008 Posts: 51
|
|
Posted: Tue Oct 28, 2008 4:24 am |
|
|
Ok ! Sorry for the mixup Rohit ! I am using the NEC protocol ! When i've written the post, i was looking in a book about IR commnunications and i've made a mistake.
The protocol is definately NEC! Sorry ! My bad...these things are kind'a new to me!
Thank you again !!! |
|
|
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|