This discussion deals with interfacing a Sony TV remote control unit with a BX24. The material was developed by Timothy Wallace as a part of his Senior Project (2 credits) in the Dept of Electrical and Computer Engineering at Morgan State University.
The TV remote control technology is mature and inexpensive and an infrared remote control might be used in many BX24 applications in place of a keypad or other means of inputting data. One need only look to the home entertainment industry to see that consumers insists on remote control and for the industry, they save on all of the fancy and expensive mechanics associated with knobs and buttons, usually providing but a bare minimum of locally controlled buttons.
Obvious applications are movement, e.g., turn a motor one way or another, turn it faster or slower or turn it 23 clicks in the defined direction. However, the remote might be used for virtually any data entry, e.g., perform a temperature measurement on sensor 1, or set a thermostat threshold to 28 degrees C.
A Sony TV remote was used in developing this discussion, simply because I happened to have a Sony TV remote control laying around. The following routine was also tested with a Sony CD remote (number keys only) and with two "One For All" universal remotes using TV programming code 000. However, this material was developed by reverse engineering the Sony remote. That is, we observed the operation of the remote on a high quality storage scope as opposed to consulting authoritative literature (if such exists). The danger here is assuming our observations extend to all Sony TV remotes. However, with a "Universal", you should be able to duplicate our results.
All that is required is a Sony TV remote or a "Universal" and a small 38 kHz three terminal infrared receiver which is available from
Note that the following routine uses the input capture capability of the BX24 which is associated with terminal 12 of the BX24
IR Receiver BX24 +5 VDC ------------------------------------ Term 12 GRD
When idle, the output of the IR receiver is high. When the receiver detects a 38 KHz burst of infrared, the output goes low for the duration of the burst.
We looked at the output of the IR receiver using a good quality storage scope and reached a number of conclusions.
1. When a button on the remote is depressed, a code consisting of a start pulse, immediately followed by twelve bits is sent. As long as the button is depressed, this is repeated with a substantial idle time between each sequence.
2. A start pulse is a burst of nominally 2.5 ms. I assume one reason for this length is to assure the automatic gain control (AGC) associated with the IR receiver has sufficient time to adjust to the proper level.
3. A zero bit consists of no burst for nominally 0.5 ms followed by a burst having a duration of nominally 0.75 ms. That is, the output of the IR receiver is high for 0.5 ms and then low for 0.75 ms.
4. A one bit consists of no burst for nominally 0.5 ms followed by a burst having a duration of nominally 1.25 ms.
5. The bits are sent, least significant bit first.
In function FetchCode(), terminal 12 is made an input and a pulse train is captured to array Pulses, beginning with the first negative going transition. Note that each count is 135.6 nanoseconds and we found it a bit more convenient to convert this to array Times, where the units of time are milliseconds.
From 2. above, for a valid pulse train, element 1 of array Times should be nominally 2.5 ms. We used limits in the range of 2.1 to 2.8 ms. From 2 and 3 above, each even element of the array should be nominally 0.5 ms. We used 0.32 to 0.6 ms. If, these two conditions are met, boolean variable valid is TRUE and the do loop is exited. Otherwise, another pulse train is captured and this continues until a valid pulse train is captured.
Function FetchCode() as Byte Dim Pulses(1 to 17) as New UnsignedInteger Dim Times (1 to 17) as Single Dim N as Integer Dim Valid as Boolean Dim Code as Byte Call PutPin(12, 2) ' make pin 12 an input Do Call InputCapture (Pulses, 17, 0) For N = 1 to 17 Times(N) = CSng(Pulses(N))* 135.6e-9 * 1000.0 ' times in msecs Next Call PrintArray(Times, 17) ' used for debugging Valid = True For N = 1 TO 8 If ( (Times(N*2) < 0.32) OR (Times(N*2) > 0.6) ) Then Valid = False End If Next If ((Times(1) < 2.1) OR (Times(1) > 2.8)) Then Valid = False End If Loop Until (Valid = True) Debug.Print "Success!!!!!!"Elements 3, 5, 7, .. 17 are then tested and if less than 1.0 ms (or greater than 1.0 ms), a logic zero (or one) is placed in the appropriate bit of byte variable code, beginning with the least significant bit. Code is thus a value in the range of 0 - 127.
We used only the Start bit plus eight information bits and thus the arrays consist of one plus eight times two transitions or 17 transitions. Had we desired to capture the entire twelve bits, the arrays would have contained 25 elements.
Code = 0 For N = 1 to 8 If (Times(2*N+1) < 1.0) Then Call PutBit(Code, CByte(N-1), 0) Else Call PutBit(Code, CByte(N-1), 1) End If Next FetchCode = Code End Function
In Sub Main(), the code is fetched. Only the lower five bits are used. If the code is in the range of 0 - 9, it is a number key 1 - 10 and either the red or green surface mount LED on the BX24 is flashed that number of times. Note that key 1 corresponds to code 0, key 2 to code 1, etc and thus the number of flashes is set to code plus 1.
The channel up (code 16) and channel down (code 17) are used to toggle the LED from red to green or green to red. Note that the LED is briefly flashed to provide some feedback to the user that the command was received. Similarly, volume up (code 18) and volume down (code 19) are used to adjust the speed at which the LED is flashed.
' Program IRRemote.Bas ' ' Illustrates an interface with a Sony TV remote control. ' ' A pulse train is fetched using the Capture function of the BX24 and converted to an array of singles which ' are the time between transitions in ms. This is displayed to the terminal using function PrintArray. ' ' The content of the array is checked; i.e., element 1 is nominally 2.5 ms and even elements are nominally 0.5 ms. ' If valid, a code is calculated using elements 3, 5, 7, etc, beginning with the least significant bit. ' ' If the code is a key, one of the surface mount LEDs is flashed the number of times corresponding to the ' value of the key. If the code is channel up or channel down, feedback is provided by a brief wink of the LED ' and the selected LED is changed from red to green or green to red. If the code is volume up or down, the delay ' time is adjusted to flash the LED faster or slower. ' ' The program continually loops. ' ' Compile with SerialPort.Bas ' ' copyright, Peter H Anderson, Timothy Wallace, Baltimore, MD, Dec, '01 Sub Main() Dim Code as Byte, LEDNum as Byte, NumFlashes as Byte, DelayVal as Single LEDNum = 25 DelayVal = 0.2 Call PutPin(25, 1) ' Turn off both surface mount LEDs Call PutPin(26, 1) Call OpenSerialPort(1, 19200) Do Code = FetchCode() AND &H1f ' take only the five least sig bits Debug.Print "******"; CStr(Code) If (Code < 10) Then ' its a number key NumFlashes = Code + 1 Call FlashLED(LEDNum, DelayVal, NumFlashes) ElseIf (Code = 16) Then ' up channel If (LEDNum = 25) Then LEDNum = 26 Else LEDNum = 25 End If Call FlashLED(LEDNum, 0.200, 1) ' give some feedback ElseIf (Code = 17) Then ' down channel If (LEDNum = 25) Then LEDNum = 26 Else LEDNum = 25 End If Call FlashLED(LEDNum, 0.200, 1) ' feedback to user ElseIf (Code = 18) Then ' up volume DelayVal = DelayVal - 0.05 ' faster If (DelayVal < 0.05) Then DelayVal = 0.05 End If Call FlashLED(LEDNum, 0.05, 3) ' feedback ElseIf (Code = 19) Then ' down volume DelayVal = DelayVal + 0.05 ' slower If (DelayVal > 0.50) Then DelayVal = 0.50 End If Call FlashLED(LEDNum, 0.05, 3) ' feedback Else Debug.Print "Unknown Code "; CStr(Code) End If Loop End Sub Function FetchCode() as Byte Dim Pulses(1 to 16) as New UnsignedInteger Dim Times (1 to 16) as Single Dim N as Integer Dim Valid as Boolean Dim Code as Byte Call PutPin(12, 2) ' make pin 12 an input Do Call InputCapture (Pulses, 16, 0) For N = 1 to 16 Times(N) = CSng(Pulses(N))* 135.6e-9 * 1000.0 ' times in msecs Next Call PrintArray(Times, 16) ' for examination of pulse train Valid = True For N = 1 TO 8 If ( (Times(N*2) < 0.32) OR (Times(N*2) > 0.6) ) Then Valid = False End If Next If ((Times(1) < 2.1) OR (Times(1) > 2.8)) Then Valid = False End If Loop Until (Valid = True) Debug.Print "Success!!!!!!" Code = 0 For N = 1 to 7 If (Times(2*N+1) < 1.0) Then Call PutBit(Code, CByte(N-1), 0) Else Call PutBit(Code, CByte(N-1), 1) End If Next FetchCode = Code End Function Sub FlashLED(ByVal LEDNum as Byte, ByVal DelayVal as Single, ByVal NumFlashes as Byte) Dim N as Byte Call PutPin(25, 1) ' first, turn off both LEDs Call PutPin(26, 1) For N = 1 to NumFlashes Call PutPin(LEDNum, 0) Call Sleep(DelayVal) Call PutPin(LEDNum, 1) Call Sleep(DelayVal) Next End Sub Sub PrintArray(ByRef X() as Single, ByVal NumEle as Integer) Dim N as Integer For N = 1 to NumEle Call PutS(X(N)) Call NewLine() Next Debug.Print "******************" ' separator End SubA Final Note.
In executing the Capture command, the processor will hang in this command if no transition on terminal 12 is encountered. Thus, depending on the application, one may wish to enable the watch dog timer prior to executing this command. However, in many applications, one may wish to simply hang in this command, and simply respond to the IR pulse train. In other applications, one might require the user to boot the BX24 with an input set to ground and fork to the code associated with fetching the information from the remote control.