Netduino home hardware projects downloads community

Jump to content


The Netduino forums have been replaced by new forums at community.wildernesslabs.co. This site has been preserved for archival purposes only and the ability to make new accounts or posts has been turned off.
Photo

IR NEC Transmission code not working.


  • Please log in to reply
9 replies to this topic

#1 Davion

Davion

    New Member

  • Members
  • Pip
  • 4 posts

Posted 20 July 2013 - 02:11 PM

Hey guys,

 

We're trying to set up a IR transmitter and receiver combo on a pair of N+2s. We have leverage the work of Mario Vernari but there was a missing Transmitter code that we have unsuccessfully implemented with freely available specs online. We've included some helper code to calculate the pulse lengths based upon the specification timings, otherwise it's essentially the same as the Sony code just adjusted for the NEC spec.

 

We're testing the transmission on a separate N+2 that has a proven to be working code base that works with off the shelf television remotes. The wiring is confirmed to be accurate as we have tested it on a functioning Arduino board with NEC Transmission code.

 

The problem we seem to be experiencing is that there is a variable amount of pulse cycle counts being detected and none of the "START" sequence timings coming through.

 

So we're just simply asking for a helping hand with getting this NEC code up and running on our N+2s!

using System;using Microsoft.SPOT;/* * Copyright 2012 Mario Vernari (http://netmftoolbox.codeplex.com/) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * *     http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */namespace Toolbox.NETMF.Hardware{    /// <summary>    /// Class acting as driver for the NEC IR protocol    /// </summary>    /// <seealso cref="http://www.sbprojects.com/knowledge/ir/nec.php"/>    public class InfraredCodecNEC        : InfraredCodecBase    {        private const float CarrierFrequency = 38.0f;   //kHz        private const float PulseDuty = 0.5f; //0.25 or 0.33f        private const int firstBit = 9000; //9ms        private const int secondBit = 4500; //4.5ms        private const int oneTotal = 2250; //2.25ms        private const int oneOn = 560; //.56ms        private const int zeroTotal = 1120; //1.12ms        private const int zeroOn = 560; //.56ms        int pulseLength = 0;        /// <summary>        /// Create a new instance of codec        /// </summary>        /// <param name="transmitter">A valid reference for the transmitter to be used</param>        public InfraredCodecNEC(InfraredTransmitter transmitter)            : base(transmitter, CarrierFrequency, PulseDuty)        {            pulseLength = (int)((1 / CarrierFrequency) * 1000); //26us for 38khz        }        /// <summary>        /// Send a NEC message        /// </summary>        /// <param name="address">Specifies the address in the message</param>        /// <param name="command">Specifies the command to be sent</param>        public void Send(            int address,            int command)        {            //place the "START" pattern            this.MarkStart();            int origAddress = address;            //address (8 bits, LSB first)            for (int i = 0; i < 8; i++)            {                this.Modulate((address & 0x01) != 0);                address >>= 1;            }            // - address (8 bits, LSB first)            for (int i = 0; i < 8; i++)            {                this.Modulate((origAddress & 0x01) == 0);                origAddress >>= 1;            }            int origCommand = command;            //command (8 bits, LSB first)            for (int i = 0; i < 8; i++)            {                this.Modulate((command & 0x01) != 0);                command >>= 1;            }            // - command (8 bits, LSB first)            for (int i = 0; i < 8; i++)            {                this.Modulate((origCommand & 0x01) == 0);                origCommand >>= 1;            }            //send            this.Transmitter                .Send(this);        }        private void MarkStart()        {            //"START"            this.TotalPulseCount = (firstBit + secondBit) / pulseLength;             this.InitialPulseCount = firstBit / pulseLength;            this.FinalPulseCount = 0;            //append the defined pattern to the stream            this.Transmitter                .Append(this);        }        /// <summary>        /// Provide the modulation for the logic bit        /// </summary>        /// <param name="value">The logic value to be modulated</param>        private void Modulate(bool value)        {            if (value)            {                //logic "ONE"                this.TotalPulseCount = oneTotal / pulseLength;//84 64                this.InitialPulseCount = oneOn / pulseLength;                 this.FinalPulseCount = 0;            }            else            {                //logic "ZERO"                this.TotalPulseCount = zeroTotal / pulseLength;                this.InitialPulseCount = zeroOn / pulseLength;                 this.FinalPulseCount = 0;            }            //append the defined pattern to the stream            this.Transmitter                .Append(this);        }    }}


#2 Mario Vernari

Mario Vernari

    Advanced Member

  • Members
  • PipPipPip
  • 1768 posts
  • LocationVenezia, Italia

Posted 20 July 2013 - 04:20 PM

Hello Davion.

The above code should be okay against the reference specs site, however I don't have any NEC-enabled device to test with.

If I understand well, the transmitter works fine because you tested the codes on a NEC TV set?

So, what's the actual problem? On the receiver code?

Cheers


Biggest fault of Netduino? It runs by electricity.

#3 Davion

Davion

    New Member

  • Members
  • Pip
  • 4 posts

Posted 21 July 2013 - 12:22 AM

Hi Mario,

 

The problem we are experiencing is that the transmitter code is not being received correctly by your NEC receiver code. All the timings and pulse counts seem to be coming out incorrectly. The only thing we've tested it against is a few NEC compatible remote controls, this was to confirm that your receiver code is working correctly on our N+2 with consistent results.

 

So we're merely determining if our transmitter code is correct going by your working receiver code. We hope to further understand what's going on with our transmitter using a logic probe that is in the mail, which won't arrive for few weeks. We also have had difficulty understanding the concepts of the duty cycle and how it affects the end resulting signal (where the probe will come in handy), and pulse masks, google could not really help us here. In your base code it was coded for 16bit I believe, but as in the NEC code we have 32bit codes, altering these values did not really yield any differing results.

 

We're going to upgrade the boards to 4.2.2.2 from 4.2.2.0, as we noticed that there is a bug with the SPI clock that has been fixed. Hopefully that this will resolve the issue.



#4 Mario Vernari

Mario Vernari

    Advanced Member

  • Members
  • PipPipPip
  • 1768 posts
  • LocationVenezia, Italia

Posted 21 July 2013 - 04:26 AM

So, you have two Netduinoes: one for the pulse generation (transimitter) and the other for the pulse reception (receiver).

The receiver seems working fine because you tested it with a NEC remote control. However, when you use the N transmitter, the receiver won't work any more.

Is it correct?

 

In the transmitter, the SPI is used as a "pattern generator". When you set up a byte-array and you send it by the SPI, you'll notice the bit of the array perfectly reproduced on the MOSI output pin. Since the bit rate is very high, you can shape almost any kind of pattern.

 

The 16-bit mode used in the code has nothing related to the actual IR protocol. Instead, every word (16-bit) is a bit-block which is pushed out at the IR carrier rate. If the desired protocol needs a carrier of 38kHz, for instance, the MOSI will output a whole word (16 bits) in 26us (38kHz period).

At that point, the duty-cycle is shaped against the available 16 bits block: half block means 50% a dn so away.

Why a certain protocol requires a duty of 50% or 33%, just as an example, is totally another story: the smaller is the duty, the lower will be the power required by the led. However, the smaller is the duty, the shorter is the range of the IR irradiation.

 

I don't think the SPI clock bug is related in any way to the above problem. The transmitter code has been tested on both the Netduinoes (first and "2"), along several projects. I think it's reasonably reliable.

You should bear in mind that both the transmitter and the receiver relying on realtime assumptions: that is, the bit-array should be shifted out the MOSI pin with a precise clock rate, without any delay. However, this is *NOT* what usually happens in a managed-GC code, and the actual timing behavior is unpredictable.

That's the way I suggest to keep the transmitter (and also the receiver) code as simplest as possible, due to minimize the GC activity during the transmission. When the GC starts its activity, you may experience small delays within the pattern, with consequent impossibility of recognition by the receiver.

 

For sure, a scope or a logic analyzer would help a lot in the problem diagnosis.

Let me know.

Cheers


Biggest fault of Netduino? It runs by electricity.

#5 Davion

Davion

    New Member

  • Members
  • Pip
  • 4 posts

Posted 21 July 2013 - 06:06 AM

So, you have two Netduinoes: one for the pulse generation (transimitter) and the other for the pulse reception (receiver).

The receiver seems working fine because you tested it with a NEC remote control. However, when you use the N transmitter, the receiver won't work any more.

Is it correct?

 

This is correct.

 

We have updated the firmware on our N+2s and you were correct. It did not resolve the issue.

 

The Garbage Collector is indeed a troublesome issue and we'll be looking into suppressing the collector sometime this week.

 

NEC code is not essential to the project. We're just after an code that will work both encoding and decoding so we can communicate via IR (line of sight) to each other. Are you able to suggest if trying another format would be more reliable on the transmitter side? Furthermore we were looking at bumping up the transmitter to 56khz to enable outdoor usability, and upon your last suggestion a higher duty cycle to enable longer range of the beam.

 

Have you personally got a netduino to transmit to another netduino? How do you suggest we solve this issue?



#6 Mario Vernari

Mario Vernari

    Advanced Member

  • Members
  • PipPipPip
  • 1768 posts
  • LocationVenezia, Italia

Posted 21 July 2013 - 08:32 AM

This is correct.

 

We have updated the firmware on our N+2s and you were correct. It did not resolve the issue.

 

The Garbage Collector is indeed a troublesome issue and we'll be looking into suppressing the collector sometime this week.

 

NEC code is not essential to the project. We're just after an code that will work both encoding and decoding so we can communicate via IR (line of sight) to each other. Are you able to suggest if trying another format would be more reliable on the transmitter side? Furthermore we were looking at bumping up the transmitter to 56khz to enable outdoor usability, and upon your last suggestion a higher duty cycle to enable longer range of the beam.

 

Have you personally got a netduino to transmit to another netduino? How do you suggest we solve this issue?

 

The GC task cannot be paused or halted, AFAIK. What you can do is writing the code and use the data so that the GC will have (almost) nothing to do. For instance, instead of create-then-trash objects, favor the create-once and live-forever practice. That's a bit against the OOP, but we must find a compromise!

 

Well, honestly I never used two N as you want to do. I always used only one N, either running the transmitter or the receiver, together with some third-party device, such as remote commanders, etc.

I successfully (yet personally) tested the transmission of commands to a railroad model by Maerklin; the reception of commands from a Lego remote commander. A friend, Laurent Ellerbach, successfully used the hardware+software for commanding a Lego railroad.

The major problem is knowing the command codes, but I don't think the pattern generation would be an issue for other contexts.

 

Well, about using the IR outdoors, I believe you'll have hard time by expecting some decent result: I think that the sunlight, even indirect, is the biggest enemy of the IR way to exchange data. I don't know what you want to do, but I remember that even 10-20m, under a normal sunlight, was almost a dream...oh! We tested with a beam of 25 IR leds, full-powered.

I'd keep the IR for indoor use only.

 

I'll try explain better about the carrier.

Any IR protocol relies on a carrier modulation: that is for higher sensivity, noise rejection, yet pretty constant components (e.g. sun) immunity. Most of the IR receiver modules are tuned for 36, 38, 40 or even 56kHz. There's no much difference between 36 or 40kHz carrier: the same 36k receiver can work even with a beam tuned at 40k, but of course it will yield a lesser range.

56kHz is a somewhat strange frequency, but maybe someone use it. I don't think you'll have a wider range, but since you have a faster bit-rate, you should be able to fit the whole message in a shorter period. A shorter period means a better immunity to a low-frequency IR noise, such as bulbs, heaters, etc. Bear in mind that a incandescence bulb is a huge source of IR, yet having a smooth fluctuation at the double of mains frequency (100 or 120Hz). Such a fluctuation may be a problem for a long message, thus a faster bit rate may be a clue.

 

So why not using a pretty high carrier frequency all the time?

Because the higher is the frequency, the higher is the current needed for both the TX and the RX.

Also consider that a normal led, when lit, acts as a big capacitor, and you need current for charge and for discharge. For many battery-operated devices, that would be an issue.

 

A normal duty would be of 50%, however often the designers choose a narrow period for the led activity, than the led off. Of course that will require less current: that's the primary reason for doing that.

However, by shortening the pulse you'll fall back into the "higher-frequency" problem, as seen above. You know, a shorter period means an higher frequency.

 

Explain better what's your goal, then we'll see whether going further with IR or some other technique.

Cheers


Biggest fault of Netduino? It runs by electricity.

#7 hanzibal

hanzibal

    Advanced Member

  • Members
  • PipPipPip
  • 1287 posts
  • LocationSweden

Posted 22 July 2013 - 10:46 PM

If you insist on IR, I suggest you look at using a pair of IrDA tranceivers that connect to the UART of each Netduino. IrDA is designed to carry data back and forth using IR as its carrier. I guess, you could say an IrDA link works like a serial link and the Netduino can't tell the difference from a serial crossover cable. As for speed, it's pretty modest but I think you can reach 38400 baud on short range.

 

Below is an IrDA tranceiver module, you need two. I'm sure you can find cheaper ones too.

http://www.mikroe.co...ion/irda-proto/

 

...or you can build your own, kind of like this guy did:

http://pavouk.org/hw/en_irda.html

 

I nice thing is that you can use a serial crossover cable during development and then switch to IrDA when your protocol works. Also, there are IrDA USB dongles so you could write a test application for your PC to mimic one of the Netduinos during development.



#8 Davion

Davion

    New Member

  • Members
  • Pip
  • 4 posts

Posted 25 July 2013 - 10:06 AM

Hey guys

 

Worked out the problem, the output pin we were using was wrong, changed across to pin 11 and changed the code to suit. Works fine now.

 

Cheers



#9 LUDIO

LUDIO

    New Member

  • Members
  • Pip
  • 3 posts

Posted 24 May 2014 - 01:28 PM

Hello guys,

 

I know this thread is almost an year old, but I found it, which means others may do as well.

I have been building a small project where I want to control some home appliances with my N+2. I have an old GoldStar(LG) TV which I am using for tests. It uses the Nec protocol and thanks to the code of the OP I was able to send commands to the TV. At first the TV was not recognizing any commands so I tried sending data to the receiver code I have, which again I found on this forum. After some tinkering the decoding code started to recognize the commands I was sending from my N+2. I should probably mention that the decoder was always working with the TV remote control. One thing I noticed was that the last bit of the commands I was sending and decoding was always 0 which was not the case with the remote control. So I set to find out why and as you can see on the image below, courtesy of sbprojects.com

nectrain.gif

There is a short burst at the very end of the transmission. So what I have done is added a 0 to the end of the pulse train. This allows the receiver code to calculate the length of the last bit it receives. So here is the code that is working with my TV.

    /// <summary>    
    /// Class acting as driver for the NEC IR protocol    
    /// </summary>    
    /// <seealso cref="http://www.sbprojects.com/knowledge/ir/nec.php"/>
    public class NecTransmitter : InfraredCodecBase
    {
        private const float CarrierFrequency = 38.0f; //kHz        
        private const float PulseDuty = 0.5f; //0.25 or 0.33f
        private const int firstBit = 9500; //9ms        
        private const int secondBit = 4750; //4.5ms        
        private const int oneTotal = 2250; //2.25ms        
        private const int oneOn = 560; //.56ms        
        private const int zeroTotal = 1120; //1.12ms        
        private const int zeroOn = 560; //.56ms        
        int pulseLength = 0;
 
        /// <summary>        
        /// Create a new instance of codec        
        /// </summary>        
        /// <param name="transmitter">A valid reference for the transmitter to be used</param>        
        public NecTransmitter(InfraredTransmitter transmitter)
            : base(transmitter, CarrierFrequency, PulseDuty)
        {
            pulseLength = (int)((1 / CarrierFrequency) * 1000); //26us for 38khz        
        }
 
        /// <summary>      
        /// /// Send a NEC message    
        /// /// </summary>      
        /// /// <param name="address">Specifies the address in the message</param>      
        /// /// <param name="command">Specifies the command to be sent</param>    
        public void Send(int address, int command)
        {
            //place the "START" pattern      
            this.MarkStart();
            int origAddress = address;
 
            //address (8 bits, LSB first)
            for (int i = 0; i < 8; i++)
            {
                this.Modulate((address & 0x01) != 0);
                address >>= 1;
            }
 
            // - address (8 bits, LSB first)    
            for (int i = 0; i < 8; i++)
            {
                this.Modulate((origAddress & 0x01) == 0);
                origAddress >>= 1;
            }
 
            int origCommand = command;
            //command (8 bits, LSB first)    
 
            for (int i = 0; i < 8; i++)
            {
                this.Modulate((command & 0x01) != 0);
                command >>= 1;
            }
 
            // - command (8 bits, LSB first)    
            for (int i = 0; i < 8; i++)
            {
                this.Modulate((origCommand & 0x01) == 0);
                origCommand >>= 1;
            }
 
            //Append a control bit at the end. This will allow the last bit of the command to be calculated by a receiver.
            this.Modulate(false);
 
            //send        
            this.Transmitter.Send(this);
        }
 
        private void MarkStart()
        {
            //"START"    
            this.TotalPulseCount = (firstBit + secondBit) / pulseLength;
            this.InitialPulseCount = firstBit / pulseLength;
            this.FinalPulseCount = 0;
 
            //append the defined pattern to the stream    
            this.Transmitter.Append(this);
        }
 
        /// <summary>    
        /// /// Provide the modulation for the logic bit    
        /// /// </summary>  
        /// /// <param name="value">The logic value to be modulated</param>    
        private void Modulate(bool value)
        {
            if (value)
            {
                //logic "ONE"      
                this.TotalPulseCount = oneTotal / pulseLength;//84 64    
                this.InitialPulseCount = oneOn / pulseLength;
                this.FinalPulseCount = 0;
            }
            else
            {
                //logic "ZERO"  
                this.TotalPulseCount = zeroTotal / pulseLength;
                this.InitialPulseCount = zeroOn / pulseLength;
                this.FinalPulseCount = 0;
            }
 
            //append the defined pattern to the stream  
            this.Transmitter.Append(this);
        }
    }

If you are using the OP code for communication with devices that do not use the verification mechanism of the protocol you will have no problems. For devices with verification this one should do the trick.

 

Cheers



#10 Mario Vernari

Mario Vernari

    Advanced Member

  • Members
  • PipPipPip
  • 1768 posts
  • LocationVenezia, Italia

Posted 29 May 2014 - 08:12 AM

Hello guys,

 

I know this thread is almost an year old, but I found it, which means others may do as well.

I have been building a small project where I want to control some home appliances with my N+2. I have an old GoldStar(LG) TV which I am using for tests. It uses the Nec protocol and thanks to the code of the OP I was able to send commands to the TV. At first the TV was not recognizing any commands so I tried sending data to the receiver code I have, which again I found on this forum. After some tinkering the decoding code started to recognize the commands I was sending from my N+2. I should probably mention that the decoder was always working with the TV remote control. One thing I noticed was that the last bit of the commands I was sending and decoding was always 0 which was not the case with the remote control. So I set to find out why and as you can see on the image below, courtesy of sbprojects.com

nectrain.gif

There is a short burst at the very end of the transmission. So what I have done is added a 0 to the end of the pulse train. This allows the receiver code to calculate the length of the last bit it receives. So here is the code that is working with my TV.

    /// <summary>    
    /// Class acting as driver for the NEC IR protocol    
    /// </summary>    
    /// <seealso cref="http://www.sbprojects.com/knowledge/ir/nec.php"/>
    public class NecTransmitter : InfraredCodecBase
    {
        private const float CarrierFrequency = 38.0f; //kHz        
        private const float PulseDuty = 0.5f; //0.25 or 0.33f
        private const int firstBit = 9500; //9ms        
        private const int secondBit = 4750; //4.5ms        
        private const int oneTotal = 2250; //2.25ms        
        private const int oneOn = 560; //.56ms        
        private const int zeroTotal = 1120; //1.12ms        
        private const int zeroOn = 560; //.56ms        
        int pulseLength = 0;
 
        /// <summary>        
        /// Create a new instance of codec        
        /// </summary>        
        /// <param name="transmitter">A valid reference for the transmitter to be used</param>        
        public NecTransmitter(InfraredTransmitter transmitter)
            : base(transmitter, CarrierFrequency, PulseDuty)
        {
            pulseLength = (int)((1 / CarrierFrequency) * 1000); //26us for 38khz        
        }
 
        /// <summary>      
        /// /// Send a NEC message    
        /// /// </summary>      
        /// /// <param name="address">Specifies the address in the message</param>      
        /// /// <param name="command">Specifies the command to be sent</param>    
        public void Send(int address, int command)
        {
            //place the "START" pattern      
            this.MarkStart();
            int origAddress = address;
 
            //address (8 bits, LSB first)
            for (int i = 0; i < 8; i++)
            {
                this.Modulate((address & 0x01) != 0);
                address >>= 1;
            }
 
            // - address (8 bits, LSB first)    
            for (int i = 0; i < 8; i++)
            {
                this.Modulate((origAddress & 0x01) == 0);
                origAddress >>= 1;
            }
 
            int origCommand = command;
            //command (8 bits, LSB first)    
 
            for (int i = 0; i < 8; i++)
            {
                this.Modulate((command & 0x01) != 0);
                command >>= 1;
            }
 
            // - command (8 bits, LSB first)    
            for (int i = 0; i < 8; i++)
            {
                this.Modulate((origCommand & 0x01) == 0);
                origCommand >>= 1;
            }
 
            //Append a control bit at the end. This will allow the last bit of the command to be calculated by a receiver.
            this.Modulate(false);
 
            //send        
            this.Transmitter.Send(this);
        }
 
        private void MarkStart()
        {
            //"START"    
            this.TotalPulseCount = (firstBit + secondBit) / pulseLength;
            this.InitialPulseCount = firstBit / pulseLength;
            this.FinalPulseCount = 0;
 
            //append the defined pattern to the stream    
            this.Transmitter.Append(this);
        }
 
        /// <summary>    
        /// /// Provide the modulation for the logic bit    
        /// /// </summary>  
        /// /// <param name="value">The logic value to be modulated</param>    
        private void Modulate(bool value)
        {
            if (value)
            {
                //logic "ONE"      
                this.TotalPulseCount = oneTotal / pulseLength;//84 64    
                this.InitialPulseCount = oneOn / pulseLength;
                this.FinalPulseCount = 0;
            }
            else
            {
                //logic "ZERO"  
                this.TotalPulseCount = zeroTotal / pulseLength;
                this.InitialPulseCount = zeroOn / pulseLength;
                this.FinalPulseCount = 0;
            }
 
            //append the defined pattern to the stream  
            this.Transmitter.Append(this);
        }
    }

If you are using the OP code for communication with devices that do not use the verification mechanism of the protocol you will have no problems. For devices with verification this one should do the trick.

 

Cheers

 

Uh, oh!...I see just now your post. Anyway, I thank you very much for point this error. I'll correct ASAP.

Cheers

Mario


Biggest fault of Netduino? It runs by electricity.




0 user(s) are reading this topic

0 members, 0 guests, 0 anonymous users

home    hardware    projects    downloads    community    where to buy    contact Copyright © 2016 Wilderness Labs Inc.  |  Legal   |   CC BY-SA
This webpage is licensed under a Creative Commons Attribution-ShareAlike License.