Shop OBEX P1 Docs P2 Docs Learn Events
IR Remote - dumb question time? — Parallax Forums

IR Remote - dumb question time?

cavelambcavelamb Posts: 720
edited 2012-10-31 13:52 in Propeller 1
I've been trying to get the Tom Doyle's IR_RemoteTest.spin example running today.

I'm guessing this HAS to be a Sony remote (or a Unoversal set to Sony?) to work.
But I did get some activity from it using a Philips TC remote.
It toggles bit 3 (of the LCode) each time a button is pressed, but does not auto-repeat.
Strangest thing is that while the test program receives that from the driveer (bit 3 set = 8)
and pst prints 0001000 8 - but then says the code is 9.
(in the CASE LCODE section?

I don't think I can blame that on the brand of remote!


{{

      IR_Remote_NewCog.spin
      Tom Doyle
      2 March 2007
      REL  10-28-2012
      The IR_Remote.spin object receives and decodes keycodes from a Sony TV remote control.
      The procedure to read and decode is run in a separate cog. This eliminates the big
      problem of the mainline program hanging while waiting for a key to be pressed.
      When a keycode is received it is written into main memory (IRcode) by the cog.
      See IR_Remote.spin for       more information.
      An LED attached to pin 16 is flashed on and off in the main program loop
      to demonstrate that is does not hang waiting for someone to press a key on the remote.

      A Parallax PST is used to display keycode information.

}}
CON
  _CLKMODE = XTAL1 + PLL16X        ' 80 Mhz clock
  _XINFREQ = 5_000_000
  IRdetPin  =    2                   ' IR Receiver - Propeller Pin
  BlinkPin  = 16                     ' Proof of life

OBJ
  ir    : "IR_Remote"
  num   : "simple_numbers"
  pst   : "Parallax Serial Terminal"


VAR
  byte IRcode                                             ' keycode from IR Receiver
  
PUB Init | freq, index, cog, lcode
   pst.start(115200)
   pst.str(string("IR REMOTE",13))
   waitcnt(2000+cnt)
    
  dira[BlinkPin]~~
  !outa[BlinkPin] 
    cog := ir.Start(IRdetPin, @IRcode)  ' Propeller pin connected to the IR receiver, address of variable
    if cog > 0
      repeat
        If IRcode <> ir#NoNewCode
            lcode := IRcode
            ir.Start(IRdetPin, @IRcode)  ' set up for next code
                       
            pst.position(0,1)
            pst.str(num.bin(lcode, 7))
            pst.str(string("  "))
            pst.str(num.dec(lcode))
            pst.str(string("  "))

          case lcode
            ir#one   :  pst.str(string("<1>   "))
            ir#two   :  pst.str(string("<2>   "))
            ir#three :  pst.str(string("<3>   "))
            ir#four  :  pst.str(string("<4>   "))
            ir#five  :  pst.str(string("<5>   "))
            ir#six   :  pst.str(string("<6>   "))
            ir#seven :  pst.str(string("<7>   "))
            ir#eight :  pst.str(string("<8>   "))
            ir#nine  :  pst.str(string("<9>   "))
            ir#zero  :  pst.str(string("<0>   "))
            ir#chUp  :  pst.str(string("chUp "))
            ir#chDn  :  pst.str(string("chDn "))
            ir#volUp :  pst.str(string("volUp"))
            ir#volDn :  pst.str(string("volDn"))
            ir#mute  :  pst.str(string("mute "))
            ir#power :  pst.str(string("power"))
            ir#last  :  pst.str(string("last "))
            other    :  pst.str(string("      "))
        
        waitcnt((clkfreq / 1000) * 30 + cnt) 
          !outa[BlinkPin]
   
}}

{{
      IR_Remote_NewCog.spin
      Tom Doyle
      2 March 2007

      Panasonic IR Receiver - Parallax #350-00014

      Receive and display codes sent from a Sony TV remote control.
      See "Infrared Decoding and Detection appnote" and "IR Remote for the Boe-Bot Book v1.1"
      on Parallax website for additional info on TV remotes.

      The procedure uses counter A to measure the pulse width of the signals received
      by the Panasonic IR Receiver. The procedure waits for a start pulse and then decodes the
      next 12 bits. The entire 12 bit result is returned. The lower 7 bits contain the actual
      key code. The upper 5 bits contain the device information (TV, VCR etc.) and are masked off
      for the display.

      Most TV Remotes send the code over and over again as long as the key is pressed.
      This allows auto repeat for TV operations like increasing volume. The volume continues to
      increase as long as you hold the 'volume up' key down. Even if the key is pressed for a
      very short time there is often more than one code sent. The best way to eliminate the
      auto key repeat is to look for an idle gap in the IR receiver output. There is a period of
      idle time (20-30 ms) between packets. The getSonyCode procedure will wait for an idle period
      controlled by the gapMin constant. This value can be adjusted to eliminate auto repeat
      while maintaining a fast response to a new keypress. If auto repeat is desired the indicated
      section of code at the start of the getSonyCode procedure can be commented out.

      The procedure sets a tolerance for the width of the start bit and the logic level 1 bit to
      allow for variation in the pulse widths sent out by different remotes. It is assumed that a
      bit is 0 if it is not a 1.

      The procedure to read the keycode ( getSonyCode ) is run in a separate cog. This allows
      the main program loop to continue without waiting for a key to be pressed. The getSonyCode
      procedure writes the NoNewCode value (255) into the keycode variable in main memory to
      indicate that no new keycode is available. When a keycode is received it writes the keycode
      into the main memory variable and terminates. With only 8 cogs available it seems to be a
      good idea to free up cogs rather than let them run forever. The main program can fire off
      the procedure if and when it is interested in a new keycode.
        
}}
CON
  _CLKMODE = XTAL1 + PLL16X        ' 80 Mhz clock
  _XINFREQ = 5_000_000
  NoNewCode    =  255               ' indicates no new keycode received
  gapMin            =   2000             ' minimum idle gap - adjust to eliminate auto repeat
  startBitMin       =   2000             ' minimum length of start bit in us (2400 us reference)
  startBitMax      =   2800             ' maximum length of start bit in us (2400 us reference)
  oneBitMin        =   1000             ' minimum length of 1 (1200 us reference)
  oneBitMax       =   1400             ' maximum length of 1 (1200 us reference)

  ' Sony TV remote key codes
  ' these work for the remotes I tested however your mileage may vary
  one   =  0
  two   =  1
  three =  2
  four  =  3
  five  =  4
  six   =  5
  seven =  6
  eight =  7
  nine  =  8
  zero  =  9

  chUp  = 16
  chDn  = 17
  volUp = 18
  volDn = 19
  mute  = 20
  power = 21
  last  = 59

VAR
  byte  cog
  long  Stack[20]  

PUB Start(Pin, addrMainCode) : result
{{
   Pin - propeller pin connected to IR receiver
   addrMainCode - address of keycode variable in main memory
}}
    stop
    byte[addrMainCode] := NoNewCode
    cog := cognew(getSonycode(Pin, addrMainCode), @Stack) + 1
    result := cog

PUB Stop
{{
   stop cog if in use
}}
    if cog
      cogstop(cog~ -1)
PUB getSonyCode(pin, addrMainCode) | irCode, index, pulseWidth, lockID
{{
   Decode the Sony TV Remote key code from pulses received by the IR receiver
}}
   ' wait for idle period (ir receiver output = 1 for gapMin)
   ' comment out "auto repeat" code if auto key repeat is desired
   ' start of "auto repeat" code section
   dira[pin]~
   index := 0
   repeat
     if ina[Pin] == 1
       index++
     else
       index := 0
   while index < gapMin
   ' end of "auto repeat" code section

   frqa := 1
   ctra := 0
   dira[pin]~
   
   ' wait for a start pulse ( width > startBitMin and < startBitMax  )
   repeat      
      ctra := (%10101 << 26 ) | (PIN)                      ' accumulate while A = 0  
      waitpne(0 << pin, |< Pin, 0)                         
      phsa:=0                                              ' zero width
      waitpeq(0 << pin, |< Pin, 0)                         ' start counting
      waitpne(0 << pin, |< Pin, 0)                         ' stop counting                                               
      pulseWidth := phsa  / (clkfreq / 1_000_000) + 1    
   while ((pulseWidth < startBitMin) OR (pulseWidth > startBitMax))

   ' read in next 12 bits
   index := 0
   irCode := 0
   repeat
      ctra := (%10101 << 26 ) | (PIN)                      ' accumulate while A = 0  
      waitpne(0 << pin, |< Pin, 0)                         
      phsa:=0                                              ' zero width
      waitpeq(0 << pin, |< Pin, 0)                         ' start counting
      waitpne(0 << pin, |< Pin, 0)                         ' stop counting                                               
      pulseWidth := phsa  / (clkfreq / 1_000_000) + 1
      
    if (pulseWidth > oneBitMin) AND (pulseWidth < oneBitMax)
       irCode := irCode + (1 << index)
    index++
   while index < 11

   irCode := irCode & $7f                                   ' mask off upper 5 bits

   byte[addrMainCode] := irCode
659 x 298 - 28K

Comments

  • kuronekokuroneko Posts: 3,623
    edited 2012-10-29 17:09
    ir#nine (defined as 8) will cause 9 to be printed. Assuming there is a reason for the off-by-one it all looks fine to me.
  • cavelambcavelamb Posts: 720
    edited 2012-10-29 19:03
    kuroneko wrote: »
    ir#nine (defined as 8) will cause 9 to be printed. Assuming there is a reason for the off-by-one it all looks fine to me.

    Thank you. I see it now. It was in the other file!
  • cavelambcavelamb Posts: 720
    edited 2012-10-29 20:31
    I bought a GE unoiversal remote ($4.95) at Home Depot tonight and started trying out
    set-up codes. The 9th one worked. So it's all happy now.

    But I discovered something else today while playing with this.
    Although the data sheet said this is a 5 volt part (4.5-5.5), it runs on 3.3 volts just fine.
    (Think QuickStart board - no 5v regulator)

    Since I haven't figured out how to set an index point on the POV display yet, I thought
    it might be fun to use the IR remote to adjust the dot clock timing while the fan is running.
    Maybe they can be synched up well enough that the display is actually readable.
    (but I'm still hoping to solve the index problem.
    It really has to have that. Solves many sins.)
  • LoopyBytelooseLoopyByteloose Posts: 12,537
    edited 2012-10-30 03:14
    YES! There is a reason for that 'off-by-one' output. The actual raw bit output is off by one and needs to be converted to reflect the numbers on the remote keys. Take a look at the Nuts n' Volts reprint for IR remote and you will find a good explaination.

    Or the document included below. Parallax sells universal remotes for $10USD that are sure to work.


    The rather vast choices in IR controller codes might get one bogged down. For now, I have a BS2 Homework board that works fine with a universal remote and Sony's most basic of codes. That provides me with more buttons that I really need.

    But if you really desire to somehow use the remote you have and it has modes that are NOT used (such as a VCR mode), the LiNUX community has done quite a bit for reverse engineering of remotes. They even have a large data base of remotes and these can be quite a wide variety of bit rates, handshaking and actually length of bits.

    Try LIRC for some useful information. http://www.lirc.org/

    If you don't want to install Linux on a computer, you might be able to install Linux on a USB or DVD or CD and boot from that when you want to work with LIRC. This is called the "LiveCD format".

    Still it is much easier to start out with a universal remote and Sony codes, then move on to other more ambitious customization.
  • cavelambcavelamb Posts: 720
    edited 2012-10-30 15:44
    Thanks, Loopy. Lots of reading there.

    As for the remote IR stuff, I probably read through that driver file a dozen times, but each time
    was looking for something specific, not reading for content. You know how it is when you have
    something buzzing around in your head. (I did say t was a dumb question)
    QS-IR.JPG


    The GE universal remote is working fine. And it really was $4.95. (and no shipping)

    I cobbled up the Quickstart "board" for the IR receiver. It can't ride the ceiling fan like that,
    but it is nice to know that the silly thing works before going to extremes.

    Here is my IR demo for the QuickStart.
    Numbers 0 through 7, Vol+/- and Chan +/- all play on the QS leds.
    The Vol and Chan key wrap around.
    Nothing much, but it might help someone else get started on this.
    (Although my wife was pretty amazed when she could move the lights with the remote :) )
    {{
          IR_Remote_NewCog.spin  Tom Doyle  2 March 2007
    
          Heavily messed with  REL  10-28-2012
          The IR_Remote.spin object receives and decodes keycodes from a Sony TV remote control.
          The procedure to read and decode is run in a separate cog. This eliminates the big
          problem of the mainline program hanging while waiting for a key to be pressed.
          When a keycode is received it is written into main memory (IRcode) by the cog.
          This program then lights up the appropriate LED.
    
          Numbers 7 through 8
          CH^ increments LED, CHv Decrements LED
          Vol < and > work backwards so the LEDs go in the same direction as the button.
          Vol and CH both wrap around
    }}
    CON
      _CLKMODE = XTAL1 + PLL16X        ' 80 Mhz clock
      _XINFREQ = 5_000_000
      IRdetPin  =    2                   ' IR Receiver - Propeller Pin
      BlinkPin  = 16                     ' Proof of life
    
    OBJ
      ir    : "IR_Remote"
      num   : "simple_numbers"
    
    VAR
      byte IRcode , LED                                            ' keycode from IR Receiver
      
    PUB Init | freq, index, cog, lcode
      outa[ 16..23 ] := $00       ' all LED pins off    
      dira[ 16..23 ] := $FF       ' all LED pins outputs   
      LED := 3
      LightIt(LED)
    
      cog := ir.Start(IRdetPin, @IRcode)  ' Propeller pin connected to the IR receiver, address of variable
      if cog > 0
         repeat
            If IRcode <> ir#NoNewCode        
                lcode := IRcode
                ir.Start(IRdetPin, @IRcode)  ' set up for next code
              case lcode
                ir#zero  :
                  LED := Lcode
                ir#one   :
                  LED := Lcode              
                ir#two   :
                  LED := Lcode            
                ir#three :
                  LED := Lcode            
                ir#four  :
                  LED := Lcode            
                ir#five  :
                  LED := Lcode            
                ir#six   :
                  LED := Lcode            
                ir#seven :
                  LED := Lcode              
                ir#eight :
                  LED := Lcode            
                ir#nine  :  
    'Channel
                ir#chUp  :  '.str(string("chUp "))
                  if LED < 7
                    LED++
                  else              ' wrap around
                     LED := 0
                     
                ir#chDn  :  'pst.str(string("chDn "))
                  if LED > 0
                     LED --
                  else
                     LED := 7
    'Volumn
                ir#volUp :  'pst.str(string("volUp"))
                 if LED > 0
                    LED--
                 else
                     LED := 7
    
                ir#volDn :  'pst.str(string("volDn"))
                  if LED < 7
                     LED ++
                  else              ' wrap around
                     LED := 0
    
            LightIt(LED)
     
    PRI LightIt(code)
       outa [16..23] := 0
       outa [16+code]:= 1
       
    
    
    600 x 450 - 50K
  • prof_brainoprof_braino Posts: 4,313
    edited 2012-10-30 17:14
    Moving lights with a remote qualifies as "guru"! You win!
  • cavelambcavelamb Posts: 720
    edited 2012-10-30 18:24
    Moving lights with a remote qualifies as "guru"! You win!

    Man, Braino, we need to raise the bar some!
  • prof_brainoprof_braino Posts: 4,313
    edited 2012-10-31 09:13
    cavelamb wrote: »
    Man, Braino, we need to raise the bar some!

    wife and small children are the only ones i need to impress, so i like the bar right where it is :)
  • ercoerco Posts: 20,256
    edited 2012-10-31 09:22
    I like the POV on a ceiling fan idea, other than throwing the fan out of balance! You gotta Youtube that!
  • cavelambcavelamb Posts: 720
    edited 2012-10-31 13:52
    erco wrote: »
    I like the POV on a ceiling fan idea, other than throwing the fan out of balance! You gotta Youtube that!

    It's not that far along yet.
    This was my first post on the subject...
    http://forums.parallax.com/showthread.php?141621-QuickStart-POV
    A couple of photos at the bottom of the thread.
    Without an index point it's really hard to do.
    But once that happens it ought to be great. (Well, that's what the IBM salesman said)

    As for balance, yes, it's easy to get that messed up.
    But simple weight and balance calculations worked out perfectly the first time.

    Weight x Arm (distance) = Moments (pound-inches, gram-centimeters, whatever units are used)

    The board weighs so many grams (times) distance from center = boards moments.

    Boards moments (divided by) battery weight (SAME UNITS!) = distance from center for the battery.

    That's why I'm trying to keep the number of pieces and locations down (to one each if possible!)
    The ceiling fan I'm using is a 6 blade unit, so there is a blade straight across.
    A 5 blade would be wicked to balance!

    Also, note that the same thing applies to a motor driven POV (as far as balance goes).

    Now then, having dealt with all of that, think about this....
    (if it ever goes to a custom board!)

    Radial scan pictures? (as opposed to raster scan)

    Think of it as maybe how some aliens did TV on their planet?
    :)
Sign In or Register to comment.