How to control infrared LED?

I have a Infrared LED and want to replicate some IR commands on a remote I have. I have traced the ticks between bit switches via the Infrared Receiver. Now that I have the bit switch patterns, I need to control the Infrared LED, but I’m not sure how to do it.

Do I just alternate between true and false, using a thread.sleep in between? The thread.sleep takes milliseconds, while the data collected from the device is in ticks (10,000th of a millisecond), so it feels like that might be a problem.

Anyone dealt with this kind of thing before?

Thanks, Paul

This great tutorial from Lady Ada has some must-read background on how IR LEDs and sensors work:

Short version is that IR works by starting with a carrier frequency (usually in the 38-39khz range), and overlaying the on/off signal pattern over the carrier.

This is something you can potentially do by bit-banging if your code is fast enough, but depending on which board you’re using, you may be able to take advantage of OutputCompare, which is a feature of GHI’s premium libraries. For example, if you’re using FEZ Spider, you can use OutputCompare to generate the carrier frequency along with the signal in one simple command. Here’s the code I use to drive an IR LED Array module I made for .NET Gadgeteer:


using System;
using Microsoft.SPOT;
using Microsoft.SPOT.Hardware;
using GHIElectronics.NETMF.Hardware;
using GT = Gadgeteer;

namespace IRCommander
{
    class IRLEDArray
    {
        static Cpu.Pin outputPin;
        static OutputCompare IRCommandGenerator;

        public IRLEDArray(int socket)
        {
            outputPin = GT.Socket.GetSocket(socket, false, null, null).CpuPins[5];

            IRCommandGenerator = new OutputCompare(outputPin, true, 68);
        }

        public void SendCommand(uint[] buffer)
        {
            IRCommandGenerator.SetBlocking(true, buffer, 0, buffer.Length, 100, true, 38170);        
        }
    }
}

When I call SetBlocking above, the OutputCompare instance creates a carrier frequency of 38170Hz based on the last argument, and then overlays the commands in the buffer argument over it. and sends that to the designated output pin.

You can find out more about OutputCompare on the TinyCLR wiki here:

Check out, in particular, the section on sending control signals to TVs.

Hope that helps (if it does, please mark as answer)!

Check this codeshare as well:

http://www.tinyclr.com/codeshare/entry/208

Looking over @ gralin’s code, I’m curious why he’s using PWM to generate the frequency, when that’s built into OutputCompare? Are there advantages to using PWM to set the frequency?

He uses OutputCompare

Yes, but not for setting the carrier frequency. For the carrier, he’s using PWM, which is the part I found odd. Just trying to figure out whether I was missing something, in terms of one vs. the other.

@ devhammer - I’m using Fez Cobra / EMX module.

@ devhammer - It is an old project. Probably back then it was the way to set the frequency.

Spider is also EMX-based, so while your code would look a little different from mine (I’m using Gadgeteer, where yours would be plain NETMF), OutputCompare should be available, as EMX supports the premium libraries:

http://www.ghielectronics.com/offers

http://www.ghielectronics.com/catalog/compare?selected=1,3

@ devhammer - What assembly and namespace are the following classes located under:

  1. OutputCompare
  2. PWM - I found this in the .Net micro framework, but I don’t think that’s the assembly you are referring to is it? I assume you are referring to some GHI specific PWM assembly, right?

Thanks, Paul

OutputCompare is in GHIElectronics.NETMF.Hardware (make sure you have a reference to the assembly of the same name).

PWM is in the same assembly/namespace, but as I noted to Architect, you shouldn’t need it if you use SetBlocking with the extra carrierFrequency_hz argument (check Object Browser for the GHIElectronics.NETMF.Hardware assembly to see all the arguments for the SetBlocking method).

PS - if one of these posts answers your question, please remember to mark it as an answer.

This was renamed with signal generator in 4.2

@ Gus - I’m trying to use this in a .net MF 4.2 project, but the referenced assemblies are all in .net MF 4.1. Gus, you mentioned it was renamed with signal generator in 4.2, can you please provide some more specifics, like where I could find these libraries in .net MF 4.2? Thanks, Paul

So it looks like I might need to use the PWM class in 4.2. I have a start class implementation:

        public class Sender : IDisposable
        {
            private readonly PWM frequencyGenerator;
            private bool initialValue;

            public Sender(Cpu.Pin pin, bool initialValue, Cpu.Pin frequencyPwmPin, int frequency)
            {
                this.initialValue = initialValue;

                frequencyGenerator = new PWM(Cpu.PWMChannel.PWM_7, 38000, 50, false);
                
            }

            public void Send(uint[] pulseWidths, int pulseCount)
            {
                
            }

            public void Dispose()
            {
                frequencyGenerator.Dispose();
            }
        }

However, I’m struggling to implement the behavior that was provided by the OutputCompare class. Any ideas on how I can implement that behavior in the 4.2 microframework?

Thanks, Paul

@ Paul F. - What device are you trying to do this with? SignalGenerator is only part of the premium offerings from GHI.

In 4.2 the SignalGenerator is found in the following assembly and namespace

Assembly : GHI.Premium.Hardware.dll
Namespace : GHI.Premium.Hardware

http://www.ghielectronics.com/downloads/NETMF/Library%20Documentation%20v4.2/Premium/html/97eb5379-2a0a-4195-9fd1-c062253d6a91.htm

@ taylorza - Thanks, I was able to find the libraries. I am using FEZ Cobra / EMX board with .Net MF 4.2. I have captured the tick times from a remote I’m trying to replicate. The first tick is the zero state, it then alters between 1 and 0… Here is the raw data:


 public static class Ticks
    {
        public static long[] Red = new[]
                                       {
                                           129513653056071518,
                                           129513653056161762,
                                           129513653056205962,
                                           129513653056212141,
                                           129513653056217205,
                                           129513653056223362,
                                           129513653056228679,
                                           129513653056234493,
                                           129513653056239616,
                                           129513653056245765,
                                           129513653056250862,
                                           129513653056257033,
                                           129513653056262135,
                                           129513653056268114,
                                           129513653056273202,
                                           129513653056279369,
                                           129513653056284491,
                                           129513653056290382,
                                           129513653056295747,
                                           129513653056301718,
                                           129513653056318090,
                                           129513653056323966,
                                           129513653056340433,
                                           129513653056346572,
                                           129513653056362997,
                                           129513653056368925,
                                           129513653056385337,
                                           129513653056391456,
                                           129513653056407620,
                                           129513653056414204,
                                           129513653056430202,
                                           129513653056436175,
                                           129513653056452498,
                                           129513653056458691,
                                           129513653056474844,
                                           129513653056481001,
                                           129513653056497421,
                                           129513653056503380,
                                           129513653056508493,
                                           129513653056514682,
                                           129513653056519722,
                                           129513653056525916,
                                           129513653056542094,
                                           129513653056548315,
                                           129513653056553351,
                                           129513653056559531,
                                           129513653056564662,
                                           129513653056570608,
                                           129513653056575715,
                                           129513653056581937,
                                           129513653056586969,
                                           129513653056593167,
                                           129513653056598237,
                                           129513653056604232,
                                           129513653056620508,
                                           129513653056626492,
                                           129513653056642935,
                                           129513653056649097,
                                           129513653056654190,
                                           129513653056660122,
                                           129513653056676543,
                                           129513653056682722,
                                           129513653056699105,
                                           129513653056705197,
                                           129513653056721432,
                                           129513653056727569,
                                           129513653056743683,
                                           129513653056749924,
                                           129513653057148526,
                                           129513653057238605,
                                           129513653057260497,
                                           129513653057266736,
                                       };
    }

So I’m basically trying to replay the above sequence of ticks (times) through a signal generator, like this:


            var timings1 = new uint[Ticks.Red.Length-1];

            long previousTick = 0l;
            uint i = 0;
            foreach (var tick in Ticks.Red)
            {
                if (previousTick > 0)
                {
                    var diff = tick - previousTick;
                    timings1[i] = (uint)diff;
                    i++;
                }
                previousTick = tick;
            }
            var oc1 = new SignalGenerator(Cpu.Pin.GPIO_Pin7, true, timings1.Length);
            oc1.Set(false, timings1, 0, timings1.Length, false);

However the output from the above code is not matching up with the time diffs of the original captured ticks. I’m wondering if this is the right approach to “replaying” ticks? Thoughts?

Thanks, Paul

@ Paul F. - The SignalGenerator expects timings in micro-seconds, your code is passing timings in ticks. Something else to mention, when emulating IR remote signals you probably need to use a carrier frequency, check the overload of SetBlocking that accepts a carrier frequency.

I think you’re doing this the hard way. Please take a look at the wiki page I linked to earlier:

The section entitled “Sending Signal to Control a TV” shows code for both capturing a signal from a TV remote (which gives you an array of the timings between high and low of the pulses)using PinCapture, and how to replay that signal using OutputCompare (SignalGenerator in 4.2).

PinCapture and OutputCompare/SignalGenerator are your friends, and they play really nicely together. Rather than roll your own capture code, try the code on the wiki.

@ devhammer - I do not think PinCapture is included in the 4.2 libraries yet. I recall reading that GHI is working on improvements.

Well, that’s certainly inconvenient, since it’s a great way to capture IR signals.

@ Paul F., if you have a spare machine, it might be worth setting up a parallel environment with NETMF 4.1, and use it to capture the IR signal and save the timings off somewhere. Might be easier than trying to translate ticks to uSec.

Maybe @ Gus can chime in on the current status of PinCapture for 4.2?