Go Down

Topic: NEC IR protocol (Read 7 times) previous topic - next topic

PlastBox

Ok, I need your help! I know posts have been written about interfacing using modulated IR before but I can't remember anything covering the NEC protocol, just Sharp/Sony etc.

From what I managed to gather online, this is the code I have come up with:
Code: [Select]
int irPin = 13;
int data[32] = {0,0,0,1,1,1,0,0,1,1,1,0,0,0,1,1,1,0,1,0,1,0,0,0,0,1,0,1,0,1,1,1};
//int data[32] = {0,0,0,1,1,1,0,0,1,1,1,0,0,0,1,1,1,1,1,0,1,0,0,0,0,0,0,1,0,1,1,1};

void setup()
{
 pinMode(irPin, OUTPUT);
}

void loop()
{

 //send preamble
 oscWrite(irPin, 9000);
 delayMicroseconds(4500);
 
 //send data
 for(int i = 0; i < 32; i++)
 {
   //space
   oscWrite(irPin, 565);
   
   //data
   if(data[i] == 0)
   {
     delayMicroseconds(560);
   }
   else
   {
     delayMicroseconds(1690);
   }
   
 }
 oscWrite(irPin, 565);
 delay(500);
 
}

void oscWrite(int pin, long time)
{
 for(int i = 0; i < (time / 26); i++)
 {
   digitalWrite(pin, HIGH);
   delayMicroseconds(13);
   digitalWrite(pin, LOW);
   delayMicroseconds(13);
 }
}


The data variable contains the signal for sending Mute to my tv and the commented data variable contains Volume Up. I found these by using an IR-demodulator to read the signals off of my remote so I know they should be good.

Still, it does nothing... During my testing the Mute-command worked twice, with no explanation for why! Also, I assume the carrier is good enough, since I wrote a program that uses oscWrite to output a continous carrier and that blocked the TV's remote completely.


Please help!
Dreaming of extra senses through sensory substitution/agumentation since.. well, for ever.. =P
Going to automate my home, just gotta find the perfect DIY solution first!

grinan

hmmmm.. i don't see "oscWrite" in the arduino reference.  What does it mean and where does it explain it in the reference here:  http://www.arduino.cc/en/Reference/HomePage

PlastBox

Thanks for the reply but did you read the code I posted? =P Hehe.

oscWrite is not in the refference because it doesn't exist. Or rather, I wrote it as you can see if you look at the code. =) It generates the 38KHz carrier needed to send info.
Dreaming of extra senses through sensory substitution/agumentation since.. well, for ever.. =P
Going to automate my home, just gotta find the perfect DIY solution first!

grinan

duhhhhhh i see it now.. i didn't then.. :)


PlastBox

Not much interest for replacing countless remotes lying around with a central system controlled from a cellphone/bluetooth-device, it seems.. :'(

Something occurred to me yesterday.. Could my data simply be wrong? The fact that the mute-command worked twice (with a program that transmitted it every 500ms) is very strange. Also, I have researched the NEC-protocol even more and can't find anything wrong with my code. What I am thinking is that the device code (first 8 bits, next 8 bits is device code inverted) is simply wrong. Don't know how this could happen as I read it straight off my working remote but when I get home from work today I will make a program that tests all 256 possible device codes. Hope it works!
Dreaming of extra senses through sensory substitution/agumentation since.. well, for ever.. =P
Going to automate my home, just gotta find the perfect DIY solution first!

PlastBox

There was surprisingly little interest in this topic but I will at least share the code I have now that I have finally gotten it to work. As far as I can see, the NEC-protocol works roughly as follows:

preamble:
8000us carrier ON
4000us OFF

device code:
8 bit code
8 bit code inverted (1 becomes 0, 0 becomes 1)

command code:
8 bit code
8 bit code inverted (1 becomes 0, 0 becomes 1)

560us carrier ON


For the data part, a 0 is transmitted as:
560us carrier ON
565us OFF

...and a 1 is transmitted as
560us carrier ON
1690us OFF

Here comes the code:
Code: [Select]
int irPin = 13;
int data[32];
int val;
int timeout = 0;

void setup()
{
 pinMode(irPin, OUTPUT);
 Serial.begin(115200);
 Serial.println("System ready!");
}

void loop()
{

 if(Serial.available())
 {
   //get and decode first byte
   val = Serial.read();
   Serial.print("Byte1: ");
   Serial.println(val);
   makedata(val, 0);
   
   //get and decode second byte
   timeout = millis();
   while(!Serial.available() && millis() < timeout + 100) {}
   if(Serial.available())
   {
     val = Serial.read();
     Serial.print("Byte2: ");
     Serial.println(val);
     makedata(val, 16);
   }
   
   //send preamble
   oscWrite(irPin, 8000);
   delayMicroseconds(4000);

   //send data
   for(int i = 0; i < 32; i++)
   {
     //space
     oscWrite(irPin, 560);
     
     //data
     if(data[i] == '0')
     {
       delayMicroseconds(565);
       Serial.print('0');
     }
     else
     {
       delayMicroseconds(1690);
       Serial.print('1');
     }
   }
   Serial.println();
   oscWrite(irPin, 560);
 }
 
}

void oscWrite(int pin, int time)
{
 for(int i = 0; i < (time / 26) - 1; i++)
 {
   digitalWrite(pin, HIGH);
   delayMicroseconds(13);
   digitalWrite(pin, LOW);
   delayMicroseconds(13);
 }
}

void makedata(double foo, int ofs)
{
 for(int i = 0; i < 8; i++)
 {
   data[i + ofs] = '0';
   data[i + ofs + 8] = '0';
   if(foo / 2 > floor(foo / 2))
   {
     data[i + ofs] = '1';
   }
   else
   {
     data[i + ofs + 8] = '1';
   }
   foo = floor(foo / 2);
 }
}


And here is a small list of the 256 possible device codes (the numbers are ASCII-codes):
Code: [Select]
56 = device code for our TV

0-9 = channel 0-9
10 = -- (2 digit channel)
12 = channel up
13 = channel down

17 = "normal" (set volume low)

20 = TV/AV
21 = mute
22 = volume up
23 = volume down
24 = OK
25 = menu (says "sleep", don't know what this is)
26 = menu - color

28 = power
29 = last channel (P<->P)
64 = mono/stereo
66 = menu - color
69 = on-screen clock
70 = text tv
75 = sound bass?
76 = on-screen clock
85 = sound bass?
125 = volum max?! RETARDEEEED!
128 = volum max?! RETARDEEEED!


I haven't gotten further than 128. It was getting late last night and when I stumbled onto those two codes that set the volume to max I decided to stop for the time beeing before my girlfriend decided to take a roller to the back of my head or something. -__-'


Anyways, I'm waiting for my internet hookup and my brand new HTC S730 phone. With this, I will make a smooth interface to control the arduino (and thus the TV, DVD-player, a couple of LED-bars and who knows what else). I can hardly wait! =D
Dreaming of extra senses through sensory substitution/agumentation since.. well, for ever.. =P
Going to automate my home, just gotta find the perfect DIY solution first!

matthew venn

This really helped me out! Thanks!
I needed to shorten the timings a little to get it to look the same as my captured remote.

http://www.flickr.com/photos/matthewvenn/3452643310/

PlastBox

Nice! Good to be of service (and awesome that you mentioned me on your flicker site!) 8-)
Dreaming of extra senses through sensory substitution/agumentation since.. well, for ever.. =P
Going to automate my home, just gotta find the perfect DIY solution first!

coopermaa

Hi Plastbox,

Thanks for your share. I've borrowed your code and customize for BenQ MP612C Projector that speaks NEC IR protocol and it works fine.

here is my code:

Code: [Select]

#define TOPBIT 0x80000000
#define NEC_HDR_MARK      9000
#define NEC_HDR_SPACE     4500
#define NEC_BIT_MARK       560
#define NEC_ONE_SPACE     1690
#define NEC_ZERO_SPACE     560
#define NEC_BITS 32

#define DUTY_CYCLE         1/3       // Carrier duty cycle
#define PERIOD             26        // 38kHz, 1/38kHz =~ 26us
#define ACTIVE_HIGH       (PERIOD * DUTY_CYCLE)
#define ACTIVE_LOW        (PERIOD - (PERIOD * DUTY_CYCLE))

int IR_LED = 13;
unsigned long power = 0x000C40BF;    // BenQ Projector Power code

void setup()
{
 pinMode(IR_LED, OUTPUT);
}

void mark(long time)
{
 for(int i = 0; i < (time / PERIOD); i++)
 {
   digitalWrite(IR_LED, HIGH);
   delayMicroseconds(ACTIVE_HIGH - 4); // digitalWrite() takes 4us
   digitalWrite(IR_LED, LOW);
   delayMicroseconds(ACTIVE_LOW - 4); // digitalWrite() takes 4us
 }  
}

void sendNEC(unsigned long data)
{
   // Leader code
   mark(NEC_HDR_MARK);
   delayMicroseconds(NEC_HDR_SPACE);
 
   for (int i = 0; i < NEC_BITS; i++)
   {
     mark(NEC_BIT_MARK);
     if (data & TOPBIT)
       delayMicroseconds(NEC_ONE_SPACE);
     else
       delayMicroseconds(NEC_ZERO_SPACE);
 
     data <<=1;
   }
   
   // stop bit
   mark(NEC_BIT_MARK);
}  
 
void loop()
{  
 // send power IR signal to Projector every 5 seconds
 delay(5000);
 sendNEC(power);
}


Cooper Maa
My Arduino study notes:
http://coopermaa2nd.blogspot.com/

jshine

Interesting (and surprisingly quiet) thread.  I'm curious to try playing with NEC IR codes, but don't know how to read the codes coming out of my remotes.  I can see the NEC-looking pulses on a 'scope, but I don't have an application to read them conveniently.

Did you ever write a matching Arduino program to dump NEC command messages to the serial port?  Or is there some software tool (hopefully compatible with OSX or Linux) that can do this?  With no way to read codes, there's no way to really try writing them...

raron

Use the excellent IRremote library from Ken Shirriff: http://www.arcfn.com/2009/08/multi-protocol-infrared-remote-library.html
He has several example programs incuded, that you can use to read the IR from one of the supported protocolls.

Go Up