In my previous blog post I showed how I started to build a “code learner" for infrared remote controls that I would then implement in my brainwaves appliance controller project. This way users can “teach” the brainwaves appliance controller the specific codes needed to turn on/off their television sets, to change channels, and to turn the volume up and down. The first step was to measure the infrared carrier frequency, which typically has values between 30kHz and 60kHz, and I described this step in my previous update. In this blog post I will show how I implemented the infrared signal decoding in the PSoC5LP chip.
My circuit has two infrared sensors: sensor 1 that demodulates the signal and provides a sequence of digital logic “high” and logic “low” pulses, and sensor 2 that measures the raw modulated carrier frequency signal. Below is an example of an infrared transmitted signal after demodulator measured by sensor 1 (upper trace) and raw signal that includes the carrier frequency measured by sensor 2 (lower trace).
The transmitted information is encoded in the length of the “high” and “low” pulses, and the number of pulses in the sequence can vary from around 20 to about 80. There are multiple protocols for encoding the information, so my code learner needs to be able to learn any protocol. My strategy is to measure the duration of logic high and logic low for each pulse in the sequence and store the information in an array. Later this information will be compressed and stored in a nonvolatile memory inside PSoC5LP, and then used by the brainwaves appliance controller.
Here is the schematic of the implementation in PSoC5LP:
Sensor 1 is connected to pin 6 and sensor 2 to pin 2. When the brainwaves appliance controller is put in learning mode by pressing a dedicated button the state of that button is read through pin 1 in the schematic above. While in learning mode the user points the remote control towards the infrared sensors and pushes the button that is to be learned.
Then the code learning algorithm measures the frequency of the infrared carrier frequency. This is done using Timer 1 in the schematic, which is set to trigger and capture on two consecutive edges of a frequency divided version of the signal measured by sensor 2. To verify that the measured value is correct I have written a function that post processes the Timer 1 output and prints the carrier frequency on the LCD display of the Cypress CY8CKIT-001 evaluation kit.
After measuring the carrier frequency code learning algorithm determines the duration of each logic “high” and logic “low” in the sequence of pulses measured by sensor 1, and stores the values in an array. This is accomplished by using Timer_2 for measuring logic “high” duration, Timer_3 for measuring logic “low” duration, and Timer_4 to determine when the sequence of pulses ends.
Timer_2 is configured to provide an interrupt on each rising edge. To make sure that it works properly I have routed the interrupt signal to an external pin and probed the signal with an oscilloscope. Here is a measurement of demodulated infrared signal (upper trace) and the interrupts generated by Timer_2 on each rising edge (lower trace):
In a similar way Timer_3 is configured to provide an interrupt on each falling edge, as I am showing in the picture below:
On each interrupt the MCU inside PSoC5LP reads the timer count value and computes the length of the logic “high” and logic “low” pulses. Each pulse length value is then stored in an array. To make sure that the measured values are correct I have setup a function that would read back the measured values from the array and display them on the LCD screen in sequence, like I am showing in the picture below and also in the video.
The “ON” string means that the values displayed on the upper row represent the characteristics of the logic high pulses, and the “OFF” string means that the values on the lower row represent the characteristics on logic low pulses. The 34 and 33 numbers on second column represent how many rising and falling edges have been measured. The first falling edge of the preamble is not captured, this is why the numbers differ by 1. The 4 in column 3 represent the pulse location in the sequence (and in the array) and column 4 represents the length of the pulse measured in microseconds.
In the video linked below I am showing this code learning process by first pressing the button that puts the system in learning mode, then pointing the infrared remote control to the sensors and pressing a button. We will then see the display showing the measured carrier frequency, after which I will press another button that will start the sequential display of pulse high and pulse low duration stored in the array.
In the picture below I am showing some of these values marked on the demodulated signal measured with the oscilloscope.
This is where I’ve gotten so far with developing the code learning algorithm. Next step will be to store the code in a non-volatile memory of the PSoC5LP and after that to develop a circuit and program that will read the stored values, regenerate the digital signal, and send it to an infrared transmitter LED.
That’s it for now; I will come back with a new update as I get more work done.