CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to CCS Technical Support

IR wireless presenter
Goto page 1, 2  Next
 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
Rohit de Sa



Joined: 09 Nov 2007
Posts: 282
Location: India

View user's profile Send private message Visit poster's website

IR wireless presenter
PostPosted: Tue Sep 23, 2008 10:27 pm     Reply with quote

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

View user's profile Send private message Visit poster's website

PostPosted: Sun Oct 12, 2008 7:22 am     Reply with quote

I've managed to build the presenter, and it seems to be working ok.....well almost ok. Confused 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

View user's profile Send private message Visit poster's website

PostPosted: Sun Oct 12, 2008 7:32 am     Reply with quote

Oh, some of the code is newbie-style code Embarassed 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 Razz ) foresee any trouble. Comments?

Rohit
Rohit de Sa



Joined: 09 Nov 2007
Posts: 282
Location: India

View user's profile Send private message Visit poster's website

PostPosted: Mon Oct 13, 2008 2:12 am     Reply with quote

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

View user's profile Send private message Visit poster's website

PostPosted: Tue Oct 14, 2008 12:34 am     Reply with quote

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
PostPosted: Tue Oct 14, 2008 3:57 pm     Reply with quote

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

View user's profile Send private message Visit poster's website

PostPosted: Tue Oct 14, 2008 10:00 pm     Reply with quote

Hey thanks! Very Happy For a while I was thinking that I was out here on my own! Razz 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! Very Happy ). But an acknowledgment in the form of details or a link to your project would be nice. Very Happy All the best with your project!

Rohit
Rohit de Sa



Joined: 09 Nov 2007
Posts: 282
Location: India

View user's profile Send private message Visit poster's website

PostPosted: Wed Oct 15, 2008 1:20 am     Reply with quote

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 Very Happy, 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. Smile

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







PostPosted: Wed Oct 15, 2008 1:19 pm     Reply with quote

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

View user's profile Send private message Visit poster's website

PostPosted: Wed Oct 15, 2008 9:49 pm     Reply with quote

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! Very Happy

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! Razz (Yeah, as with all students I'm on a shoestring budget Rolling Eyes )

Rohit
Rohit de Sa



Joined: 09 Nov 2007
Posts: 282
Location: India

View user's profile Send private message Visit poster's website

PostPosted: Fri Oct 24, 2008 10:01 pm     Reply with quote

Andrew, who mailed me, had the following doubt, which I'm posting for the benefit of others:
Quote:
Hello ! Sorry to (maybe Smile ) 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

View user's profile Send private message Send e-mail

PostPosted: Tue Oct 28, 2008 3:01 am     Reply with quote

Hello Rohit ! Smile

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 !! Wink
Rohit de Sa



Joined: 09 Nov 2007
Posts: 282
Location: India

View user's profile Send private message Visit poster's website

PostPosted: Tue Oct 28, 2008 4:13 am     Reply with quote

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

View user's profile Send private message Send e-mail

PostPosted: Tue Oct 28, 2008 4:16 am     Reply with quote

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 ! Wink
Andrew83



Joined: 16 Sep 2008
Posts: 51

View user's profile Send private message Send e-mail

PostPosted: Tue Oct 28, 2008 4:24 am     Reply with quote

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 !!! Wink
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Goto page 1, 2  Next
Page 1 of 2

 
Jump to:  
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