Proton BASIC Compiler - New Article

  • PicŪ Basic

  • Work with Infra Red

    Given that I was seeking help here for Infrared signals I thought it best to post what I had discovered.

    The first problem I faced was to work out if the IR signal was modulated or not (most are from what I've read), and if so what frequency it was modulated at.

    The built in IR on the Proton development board is no good for this as it includes a built in demodulator fixed at 38Khz (if I remember). It will pick up outside of that range however its sensitivity reduces the further away you get from its primary frequency. In any case its important to know the real frequency the signal is modulated at if you want to retransmit it.

    To work out the modulation frequency I used part of the CIR ( project. I don't recommend creating this project as the software won't run under XP/2k/NT and it gives you a modulated signal with no idea how long each pulse is. I only created the Receiver section, but connected D25-13 to the +5v rail and D25-18 to the common rail. I then connected D25-3 to C0 on the PICŪ. To get enough resolution on the signal I had to use a 20Mhz XTAL. I used the code attached with the re-send section disabled. I'd like to thank the PICŪ basic users site - I used the example timer code on that to make the signal recorder.

    The results fed back to the serial port look a real mess, however all we are really interested in is a block of repeating numbers. These are always a 1 followed by a 0 in the left column. i.e.

    1 - 92 0 - 45 1 - 92 0 - 45 1 - 92 0 - 45 ......

    The ratio of a signal received to no signal received will depend on the output of your remote/device and the distance you hold it from the phototransistor. It isn't really relevant as all we are looking for is the peak-to-peak distance, this can be calculated by adding the 1 value to the 0 value, i.e. 92+45 in this case. The result is the total number of instruction cycles that the whole pulse took. In this case 137.

    The figure we have at the moment is instruction cycles, so multiply this by 4 to give us the clock ticks. 137 * 4 = 548. Given that this is a 20Mhz clock divide 20,000,000 by 548. The result is the number of Hz your signal is modulated at. 36496Hz in this case. Therefore the signal I detected was modulated at 36.5Khz.

    As a point of interest I looked at the board that originated the signal and noticed a crystal on it marked as 1.842Mhz. If you divide this by 50 you get 0.03684, very close to the frequency I detected. Tracing the ciruit I noticed this fed in to a binary adder which I guess generated the modulation. I'm not sure how much of the difference is down to my routine or the hardware being off slightly.

    Now we have detected the modulation frequency, we know if we can get a valid signal from the Proton built in IR receiver. In my case its close enough that I can get a reasonable range, although I've dug around and found that these receivers are available in various frequencies, including 36.7Khz - ideal for my project.

    The step I had to do is capture a signal and send it back out again. The challenge here is that the signal received has to be demodulated (easy enough using the built in receiver), stored, then re-modulated and retransmitted.

    To achieve the re-modulation I used a very simple circuit. Not being an electronics expert some or all the resistors may not be required - but it works with them so I'm leaving them there! I connected C1 to a 200ohm resistor and then connected the other end of the resistor to the base on a transistor (BC549), then did the same with C2. I then connected the collector of one of the transistors to the emitter of the other transistor. The rest of the circuit looks something like this:

    +5 ----- 40ohm ---- IRLED -- IRLED --- BC549 --- BC 549 ---- 0v

    The two BC549s operate is an AND gate. I then used C1 to replay the received signal and C2 to generate the carrier frequency.

    The 18F452 has a built in Pulse Width Modulator. Perfect for my needs! Now because of the way the phototransistor works its hard to know what the duty cycle to use is. I guessed it would be 50%. This seems quite common, although some signals use 25% to reduce power requirements. Duty cycle is the ratio of signal on to signal off within each pulse of the modulation.

    The PWM is quite an odd thing to program. The first problem is that Proton+ doesn't support above 32767 as a frequency. However I need about 4000 above this! Therefore we have to do our own calculations and program the registers. In this case:

    Notice that 137 has shown up again. This is the figure I got earlier from adding the 1 and 0 time periods together. As I'm still using a 20Mhz XTAL the number matches. The 68 comes from dividing 137 by 2. This results in a 50% duty cycle (approx). If you wanted a 25% then divide 137 by 4.

    Once the frequency is being generated we can simply turn C1 on and off to send the modulated signal. All that is required is to turn it on and off for the required time periods.

    I used the attached program to receive the signal, store it in memory and then retransmit it out after a short delay (in my case this was required as I'm using equipment that takes time to power up and is very sensitive so had to be off during the record stage. To make it easier I made various LEDs go on to indicate the status within the program. LED0 is lit when a signal is received, LED1 is lit when the signal is totally received or the IR buffer is full. LED2 is lit to indicate 5 seconds left before replay. Then LED4 is lit while the signal is sent.

    The end result of this program is that by retransmitting the signal you should be able to see if the program received a valid signal or not. If it is valid then the data you received via the serial port will be a valid IR signal.

    My next step was to work out what this IR signal contained. This is the result of one capture:

    0 6

    1 22397

    0 1835

    1 2417

    0 1700

    1 2297

    0 1830

    1 2152

    0 2095

    1 2032

    0 1970

    1 2032

    0 2100

    1 2147

    0 8330

    1 1907

    0 4300

    1 1907

    0 4175

    1 8387

    0 1975

    1 6312

    0 33353

    Fortunately for me it was quite simple. All the signals I received of a certain type were the same length. i.e. they lasted the same amount of time. After a quick look I realised that 1s were signified by a 2000 long pulse and 0s by a 2000 long zero state, and that was it! Obviously you have to allow a certain amount of error in the received signal either direction. Also I noticed there was always a 22000 long lead in pulse and a lead out pulse of at least 30000, although I don't think the system looks for this. There are many ways of encoding the 1s and 0s, check out the links at the end.

    When I broke the bit stream down this is what resulted:


    It is made up of 3 bytes 8 bits long. Always with a leading 0 and trailing 1. i.e.

    0 10101010 1 0 10000100 1 0 01111011 1

    The way this system validates its code appears to be by inverting the byte. The 2nd byte is the inverse of the 3rd byte. The 1st byte appears to be a command type indicator. While the 2nd/3rd byte is the data.

    I've investigated other packets of data sent over IR on this system, The above are very simple packets, however there are much more complex packets sent that use what I guess is a CRC.

    Any feedback ( mjt@vex.netThis e-mail address is being protected from spam bots, you need JavaScript enabled to view it ) on this would be most welcome. This is the first time I'm posting something containing info rather than asking for help, so would like to know if anyone finds it helpful!


    XTAL = 20
                    LCD_DTPIN = PORTD.4     
                    LCD_RSPIN = PORTE.0
                    LCD_ENPIN = PORTE.1
                    LCD_INTERFACE = 4       ' 4-bit Interface
                    LCD_LINES = 2
                    LCD_TYPE = 0
                    SCL_PIN = PORTC.3
            SDA_PIN = PORTC.4
                    SERIAL_BAUD = 19200     
                    RSOUT_PIN = PORTC.6
                    RSOUT_MODE = TRUE
                    RSOUT_PACE = 1
                    RSIN_PIN = PORTC.7
                    RSIN_MODE = TRUE
            HSERIAL_BAUD = 19200            ' Set baud rate to 9600
            HSERIAL_RCSTA = %10010000       ' Enable serial port and continuous receive
            HSERIAL_TXSTA = %00100100       ' Enable transmit and asynchronous mode 
            HSERIAL_CLEAR = On              ' Enable Error clearing on received characters
                    KEYPAD_PORT = PORTB
            CCP1_PIN = PORTC.2
                    CCP2_PIN = PORTC.1
                    Symbol T300 = 3313      NO_LIST
                    Symbol N300 = 3313 + $4000      NO_LIST
                    Symbol T600 = 1646      NO_LIST
                    Symbol N600 = 1646 + $4000      NO_LIST
                    Symbol T1200 = 813      NO_LIST
                    Symbol N1200 = 813 + $4000      NO_LIST
                    Symbol T2400 = 396      NO_LIST
                    Symbol N2400 = 396 + $4000      NO_LIST
                    Symbol T4800 = 188      NO_LIST
                    Symbol N4800 = 188 + $4000      NO_LIST
                    Symbol T9600 = 84       NO_LIST
                    Symbol N9600 = 84 + $4000 NO_LIST
                    Symbol OT2400 = 396 + $8000     NO_LIST       ' Open True
                    Symbol OT1200 = 813 + $8000     NO_LIST       ' Open True
                    Symbol OT9600 = 84 + $8000      NO_LIST      ' Open True
                    Symbol OT300  = 3313 + $8000    NO_LIST      ' Open True
                    Symbol ON2400 = 396 + $4000 + $8000     NO_LIST      ' Open Inverted
                    Symbol ON1200 = 813 + $4000 + $8000     NO_LIST      ' Open Inverted
                    Symbol ON9600 = 84 + $4000 + $8000      NO_LIST      ' Open Inverted
                    Symbol ON300  = 3313 + $4000 + $8000    NO_LIST     ' Open Inverted
                    Symbol HOME = 1 NO_LIST
                    Symbol BELL = 7 NO_LIST
                    Symbol BKSP = 8 NO_LIST
                    Symbol TAB = 9  NO_LIST
                    Symbol CR = 13  NO_LIST
            ALL_DIGITAL = TRUE      ' Set PORTA and PORTE to all digital
      Symbol IRTRAN=PORTC.0
      Input IRTRAN
      Dim BufferPos As Byte
      Dim BitLength[128] As Word
      Dim BitState[128] As Byte
      Dim IRCOUNT As Word
      Dim IROLDSTATE As Byte
      Dim IRNEWSTATE As Byte
      Dim BufCounter As Byte
    Dim TIMER1 As TMR1L.Word 
    Device 18F452
    DelayMS 1000
    RSOut "I AM AWAKE",13,10
      Output PORTD.0
      Low PORTD.0
      Input IRTRAN
      While IRTRAN=1 : Wend
      High PORTD.0
      Clear TIMER1
      Input IRTRAN
      While IRTRAN=1 
        If TIMER1>60000 Then GoTo ReceiveComplete
      Clear TIMER1
      Inc BufferPos
      Input IRTRAN
      While IRTRAN=0
        If TIMER1>60000 Then GoTo ReceiveComplete
      Clear TIMER1
      Inc BufferPos
      If BufferPos<50 Then GoTo ReceiveLoop
      Output PORTD.1
      Output PORTD.2
      High PORTD.1
      Low PORTD.2
      For BufCounter=1 To BufferPos-1
        RSOut HEX BitState[BufCounter],",", Dec BitLength[BufCounter],13,10
      Next BufCounter
      RSOut "IR Signal End",13,10
      DelayMS 5000
      High PORTD.2
      DelayMS 5000
      High PORTD.4
      RSOut "Sending IR Signal..."
      Output PORTC.2
      Output PORTC.1
      Low PORTC.2
      Low PORTC.1
    '  HPWM 1,127,3686
      For BufCounter=1 To BufferPos-1
      Next BufCounter
      DelayMS 200
      For BufCounter=1 To BufferPos-1
        If BitState[BufCounter]=0 Then Low PORTC.1 : Else High PORTC.1
            DelayUS BitLength[BufCounter]
      Next BufCounter
      Low PORTC.1
      Low PORTD.0
      Low PORTD.1
      Low PORTD.2
      Low PORTD.4    
      RSOut "Sent.",13,10
    GoTo CheckStart
    For reference on IR I'd recommend the following

    Useful circuit:

    Good IR basics and info on different protocols:

    Some good info, explains the differenced between photodiodes and phototransistors:

    A bit of info on RC5:

    How to use Timer1 on a PICŪ:

    contributed by mjturner.